天天看點

STM32F103 HC-SR04超音波測距

前言:

為了友善檢視部落格,特意申請了一個公衆号,附上二維碼,有興趣的朋友可以關注,和我一起讨論學習,一起享受技術,一起成長。

STM32F103 HC-SR04超音波測距

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。

STM32F103 HC-SR04超音波測距

引腳說明:

引腳 解釋 實際連接配接
VCC 5V 供電 VCC5V
TRIG 觸發控制信号輸入 PB9
ECHO 回響信号輸出 PB8
GND 接地 GND

2. 時序

STM32F103 HC-SR04超音波測距

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列印輸出
	}
}
           

繼續閱讀