1. 程式人生 > >STM32驅動超聲波模組測距

STM32驅動超聲波模組測距

 HC-SR04超聲波測距模組可提供2cm到400cm的非接觸式距離感測功能,測距精度可達3mm。

一、基本工作原理

(1)給TRIG引腳至少10us的高電平訊號觸發測距。

(2)模組自動傳送8個40KHz的方波,自動檢測是否有訊號返回

(3)有訊號返回,通過Echo引腳輸出一個高電平,高電平的持續時間就是超聲波從發射到返回的時間。

(4)測量距離 = (高電平的持續時間 * 聲速(340m/s))/ 2。

二、接線

ultrasonic STM32
VCC VCC(5V)
Trig PB5
Echo PB6
GND GND

 

 

 

 

 

 

三、模組時序圖

 四、驅動程式

    在瞭解了上述內容後,我們便可以根據上述知識便可以編寫驅動程式了。觸發訊號Trig很簡單直接通過IO輸出和延時給一個大於10us的高電平即可觸發。Echo引腳需要接收並記錄高電平的持續時間,大致有3種實現的思路:

(1)在傳送觸發訊號後一直等待Echo引腳的響應(變為高電平)並開啟定時器計時直到Echo變為低電平,關閉定時器記錄下計時時間。

(2)在傳送觸發訊號後,Echo響應後(上升沿)觸發外部中斷,開啟定時器計時直到Echo變為低電平,關閉定時器記錄下計時時間。

(3)在傳送觸發訊號後,通過定時器的輸入捕獲引腳抓取Echo引腳上升沿,開啟定時器計時直到Echo變為低電平,關閉定時器記錄下計時時間。

第一種方式完全在主程序中完成,比較佔用主程序資源,比較適合於超聲波模組的測試應用。第二種和第三種方式在主程序中傳送觸發訊號中斷中處理接收計算距離比較適合於實際專案的應用。

 下面為第二種方式的驅動程式:

#ifndef __HC_SR04_H
#define __HC_SR04_H

#include "stm32f10x.h"

#define HC_SR04_TRIG_CLK   RCC_APB2Periph_GPIOA
#define HC_SR04_TRIG_PORT  GPIOA
#define HC_SR04_TRIG_PIN   GPIO_Pin_4

#define HC_SR04_ECHO_CLK   RCC_APB2Periph_GPIOA
#define HC_SR04_ECHO_PORT  GPIOA
#define HC_SR04_ECHO_PIN   GPIO_Pin_5

#define HC_SR04_ECHO_EXTI_PORT_SOURCE   GPIO_PortSourceGPIOA
#define HC_SR04_ECHO_EXTI_PIN_SOURCE  GPIO_PinSource5

extern float Distance;


void HC_SR04_init(void);
void HC_SR04_start(void);


#endif /* __HC_SR04_H*/
#include "jsn-sr04t.h"
#include "delay.h"
#include "usart.h"
#include "timer.h"

float Distance;



void HC_SR04_init(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	EXTI_InitTypeDef EXTI_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_APB2PeriphClockCmd(HC_SR04_TRIG_CLK, ENABLE);	 //使能PC埠時鐘
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//外部中斷,需要使能AFIO時鐘

	GPIO_InitStructure.GPIO_Pin = HC_SR04_TRIG_PIN;				 // 脈衝觸發埠(Trig)配置
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推輓輸出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度為50MHz
	GPIO_Init(HC_SR04_TRIG_PORT, &GPIO_InitStructure);					 //根據設定引數初始化埠
	//GPIO_ResetBits(HC_SR04_TRIG_PORT,HC_SR04_TRIG_PIN);						 //埠初始化為低電平

	GPIO_InitStructure.GPIO_Pin = HC_SR04_ECHO_PIN;				 // 回波接收埠(Echo)配置
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; 		 //上拉輸入
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度為50MHz
	GPIO_Init(HC_SR04_ECHO_PORT, &GPIO_InitStructure);					 //根據設定引數初始化埠


	//接收埠 中斷線以及中斷初始化配置
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource5);

	EXTI_InitStructure.EXTI_Line=EXTI_Line5;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;//上升沿觸發
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);	 	//根據EXTI_InitStruct中指定的引數初始化外設EXTI暫存器

	NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;			//使能按鍵所在的外部中斷通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;	//搶佔優先順序2, 
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;					//子優先順序1
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;								//使能外部中斷通道
	NVIC_Init(&NVIC_InitStructure);

	TIM3_Int_Init(49999,7199);  //初始化TIM3定時器,計數一次為1/10000S(0.1ms),每500ms觸發一次定時中斷
  //TIM_Cmd(TIM3,DISABLE);
}
	
//傳送20us的脈衝觸發訊號
void HC_SR04_start(void)
{
	GPIO_SetBits(HC_SR04_TRIG_PORT,HC_SR04_TRIG_PIN);
	delay_us(20);
	GPIO_ResetBits(HC_SR04_TRIG_PORT,HC_SR04_TRIG_PIN);
	delay_ms(10);
}



void EXTI9_5_IRQHandler(void)
{			
	delay_us(10);
	
	if(EXTI_GetITStatus(EXTI_Line5) != RESET)
	{
		//while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_5) == RESET);
		TIM_SetCounter(TIM3,0);  //計數清零
		TIM_Cmd(TIM3,ENABLE);  //使能TIM3定時器
		
		while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_5));  //等待電平變為低電平
		
		TIM_Cmd(TIM3,DISABLE); //關閉定時器
		
		Distance = TIM_GetCounter(TIM3)*340/200.0;  //計算距離:cnt * 1/10000 * 340 / 2(單位:m)
		
		//printf("Counter:%d\n",TIM_GetCounter(TIM3));
		printf("Distance:%f cm\r\n",Distance);
			
		EXTI_ClearITPendingBit(EXTI_Line5);
	}  
}