前言:
為了友善檢視部落格,特意申請了一個公衆号,附上二維碼,有興趣的朋友可以關注,和我一起讨論學習,一起享受技術,一起成長。
github:my github
注:部落格所涉及的關于 stm32 的代碼,均在倉庫【stm32f013_study】下,包括底層驅動和應用測試代碼。
本文設計的檔案包含:
(1)hcsr04.c:超音波驅動檔案
(3)頭檔案:
hcsr04.h :超音波頭檔案
1. 原理
本工作原理:
(1)采用 IO 口 TRIG 觸發測距,給最少 10us 的高電平信号;
(2)子產品自動發送 8 個 40khz 的方波,自動檢測是否有信号傳回;
(3)有信号傳回, 通過 IO 口 ECHO 輸出一個高電平, 高電平持續的時間就是超聲
波從發射到傳回的時間。 測試距離 = (高電平時間*聲速(340M/S))/2。
引腳說明:
引腳 | 解釋 | 實際連接配接 |
---|---|---|
VCC | 5V 供電 | VCC5V |
TRIG | 觸發控制信号輸入 | PB9 |
ECHO | 回響信号輸出 | PB8 |
GND | 接地 | GND |
2. 時序
3. 實作
TIM_ICInitTypeDef tim_ic_init;
//g_cap_state:捕獲狀态标志(bit7:完成捕獲; bit6:捕獲高電平;bit5-bit0:捕獲高電平溢出次數)
u16 g_cap_state, g_cap_val;
u32 g_cap_distance; //超音波測量距離
//---------------------------------------------------------------------------------------------------------------------------------------------
// 函 數 名: timer4_cap_init
// 功能說明: TIM4初始化
// 形 參: timer_arr:自動重裝值; timer_psc:時鐘分頻系數
// 返 回 值: 無
// 日 期:
// 作 者:
// 備 注:
//---------------------------------------------------------------------------------------------------------------------------------------------
void timer4_cap_init(u16 timer_arr, u16 timer_psc)
{
GPIO_InitTypeDef gp_init;
TIM_TimeBaseInitTypeDef tim_base_init;
NVIC_InitTypeDef nvic_init_config;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //使能TIM2時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能GPIOB時鐘
gp_init.GPIO_Pin = GPIO_Pin_8;
gp_init.GPIO_Mode = GPIO_Mode_IPD; //PB8 輸入 (ECHO)
GPIO_Init(GPIOB, &gp_init);
gp_init.GPIO_Pin = GPIO_Pin_9;
gp_init.GPIO_Mode = GPIO_Mode_Out_PP; //PB9 輸出 (TRIG)
gp_init.GPIO_Speed = GPIO_Speed_2MHz; //2M
GPIO_Init(GPIOB, &gp_init);
//初始化定時器4 TIM4
tim_base_init.TIM_Period = timer_arr; //設定計數器自動重裝值
tim_base_init.TIM_Prescaler = timer_psc; //預分頻器
tim_base_init.TIM_ClockDivision = TIM_CKD_DIV1; //設定時鐘分割:TDTS = Tck_tim
tim_base_init.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上計數模式
TIM_TimeBaseInit(TIM4, &tim_base_init); //根據TIM_TimeBaseInitStruct中指定的參數初始化TIMx的時間基數機關
//初始化TIM4輸入捕獲參數
tim_ic_init.TIM_Channel = TIM_Channel_3; //CC1S=03 選擇輸入端 IC3映射到TI1上
tim_ic_init.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕獲
tim_ic_init.TIM_ICSelection = TIM_ICSelection_DirectTI;
tim_ic_init.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置輸入分頻,不分頻
tim_ic_init.TIM_ICFilter = 0x00;//配置輸入濾波器 不濾波
TIM_ICInit(TIM4, &tim_ic_init);
//中斷分組初始化
nvic_init_config.NVIC_IRQChannel = TIM4_IRQn; //TIM4中斷
nvic_init_config.NVIC_IRQChannelPreemptionPriority = 3; //先占優先級2級
nvic_init_config.NVIC_IRQChannelSubPriority = 3; //從優先級0級
nvic_init_config.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
NVIC_Init(&nvic_init_config); //根據NVIC_InitStruct中指定的參數初始化外設NVIC寄存器
TIM_ITConfig(TIM4, TIM_IT_Update|TIM_IT_CC3, ENABLE);//允許更新中斷 ,允許CC3IE捕獲中斷
TIM_Cmd(TIM4, ENABLE); //使能定時器3
}
//---------------------------------------------------------------------------------------------------------------------------------------------
// 函 數 名: hcsr04_read_distance
// 功能說明: 超音波測量距離
// 形 參: 無
// 返 回 值: 無
// 日 期:
// 作 者:
// 備 注:
//---------------------------------------------------------------------------------------------------------------------------------------------
void hcsr04_read_distance(void)
{
GPIO_SetBits(GPIOB, GPIO_Pin_9); //啟動超音波測量
delay_us(15);
GPIO_ResetBits(GPIOB, GPIO_Pin_9);
if (g_cap_state & 0X80) //捕獲一次高電平
{
g_cap_distance = g_cap_state & 0X3f;
g_cap_distance *= 65535;
g_cap_distance += g_cap_val;
g_cap_distance = g_cap_distance * 170 / 1000; //計算距離(mm)
g_cap_state = 0X00;
}
}
void TIM4_IRQHandler(void)
{
u16 sta_val;
sta_val = TIM4->SR;
if ((g_cap_state & 0X80) == 0X00) //未捕獲
{
if (sta_val & 0X01) //溢出
{
if (g_cap_state & 0X40) //捕獲到高電平
{
if ((g_cap_state & 0X3f) == 0X3f) //高電平時間過長
{
g_cap_state |= 0X80; //記錄一次捕獲
g_cap_val = 0Xffff; //溢出時間
}
else
{
g_cap_state++; //繼續捕獲
}
}
}
if (sta_val & 0X08) //捕獲3(通道3)發生捕獲事件
{
if (g_cap_state & 0X40) //捕獲下降沿
{
g_cap_state |= 0X80; //标記成功捕獲一次高電平
g_cap_val = TIM4->CCR3; //擷取目前捕獲值
TIM4->CCER &= ~(1<<9); //CC1P=0 設定為上升沿捕獲
}
else
{
g_cap_state = 0;
g_cap_val = 0;
g_cap_state |= 0X40; //标記捕獲到上升沿
TIM4->CNT = 0; //清空計數器
TIM4->CCER |= (1<<9); //CC1P=1 設定為下降沿捕獲
}
}
}
TIM4->SR = 0; //清除中斷标志位
}
4. 主函數測試
//超音波測試函數
int main_hcr(void)
{
delay_init(); //延時函數初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 設定中斷優先級分組2
uart_init(1, 115200 * 8); //序列槽初始化為961200
Bsp_LedInit(); //初始化與LED連接配接的硬體接口
timer4_cap_init(0Xffff, 72 - 1);
while (1)
{
hcsr04_read_distance();
delay_ms(500);
LED0 = 1;
delay_ms(500);
LED0 = 0;
printf("g_cap_distance = %d \r\n", g_cap_distance); //用序列槽1列印輸出
}
}