使用STM32定時器寫超聲波模塊HC-SR04程式
- 前言
- 超聲波模塊小介紹
- 原理和兩種程式
- 原理
- 程式
前言
首先,來說說大伙常見的超聲波模塊,一般就倆,HC-SR04和HY-SRF05,這兩種模塊電路有些許不一樣,但是就功能來說,沒什么區別,甚至可以兼容用,所以也沒必要糾結用哪一個,就我來說,遇到的一個小區別或者說小問題大概就是,貌似HY-SRF05有時候只能用5V供電,3.3V用不了?是不是都這樣得看大家具體的情況,
本文用HC-SR04,關于這個超聲波模塊使用了兩種程式,本次為使用定時器功能,完整程式和工程檔案見文末,另外還有使用輸入捕獲的程式:常用模塊原理程式秘技——超聲波模塊HC-SR04(2),
超聲波模塊小介紹

HC-SR04

HY-SRF05
電氣引數:

原理和兩種程式
原理
下面是寫程式的關鍵部分,時序圖:

從這個圖里面可以看到,首先你的主控MCU要發出觸發信號給模塊,這個觸發信號有要求,必須是10us的高電平(當然你長一點點也可以),模塊收到這個觸發信號,它發射一個超聲波脈沖信號到空氣中,這個脈沖信號是頻率40KHz的8個脈沖方波,經前方物體平面反射后,模塊自己又接收到了這個脈沖信號,回傳一個回響信號給主控MCU,
從發射起的時間點,輸出回響信號由低電平變為高電平,接收到反射的時間點,輸出回響信號又變回低電平,
所以,很簡單可以看出,這個高電平的時間和超聲波在空氣中的傳輸時間有關,即和到反射物體的距離相關,并且是正相關,
這個高電平的時間和到反射物體的距離的關系為:
距離=時間*340/2
340是聲速(如果你可以測出當下的聲速最佳哈),單位M/S,所以算出的距離單位為M,
程式
重點來了,程式(本程式基于STM32F103,開發板是正點原子的迷你板),引腳連接(若你使用HY-SRF05,OUT引腳不連即可,無影響):
| MCU | HC-SR04 |
|---|---|
| 3.3V | VCC |
| PC5 | Trig |
| PC4 | Echo |
| GND | GND |
首先Trig給模塊一個10us的高電平,然后就可以計算時間,接著使用公式轉換一下得到距離,計算時間的方式可以使用STM32的輸入捕獲,但是如果你僅僅使用這一個模塊,可以簡單一點,不使用輸入捕獲,僅使用定時器算個時間,本詳解會給出兩種程式并都解釋!
首先第一種簡單點的,初始化GPIO和定時器這里我用的TIM3,
這是對超聲波模塊引腳初始化的函式,觸發信號TRIG引腳接PC5,回響信號ECHO接PC4,
void hc_sr04_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC ,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_ResetBits(GPIOC,GPIO_Pin_5);//觸發信號
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOC, &GPIO_InitStructure);//echo信號
GPIO_ResetBits(GPIOC,GPIO_Pin_4);
}
定時器TIM3初始化,定時器頻率為72M/(71+1)=1MHz,自動重裝值arr給65535是因為給了個CNT暫存器一個盡量可以記到最大的數(我給了最大的65535,雖然可能用不到哈)(注意和定時器中斷給值的區別!)另外還有注意最后,不是給TIM3使能,是DISABLE,
//arr:自動重裝值,
//psc:時鐘預分頻數
void TIM3_Int_Init()
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //時鐘使能
TIM_TimeBaseStructure.TIM_Period = 65535; //設定在下一個更新事件裝入活動的自動重裝載暫存器周期的值 計數到5000為500ms
TIM_TimeBaseStructure.TIM_Prescaler =71; //設定用來作為TIMx時鐘頻率除數的預分頻值 10Khz的計數頻率
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //設定時鐘分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上計數模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根據TIM_TimeBaseInitStruct中指定的引數初始化TIMx的時間基數單位
TIM_Cmd(TIM3, DISABLE);
}
這是得到回響信號時間的函式(劃重點),首先給一個10us的高電平觸發信號(我給了12us,可以多一點點!),
后面這兩個while回圈,是判斷回響信號的高低電平,若回響信號一直是低電平則會在第一個while內一直回圈,給TIM3->CNT暫存器一個0值,同時保持失能TIM3,
當回響信號變為高電平時,來到了第二個while回圈,會使TIM3保持使能有效狀態,TIM3->CNT開始正常計數,
回響信號變回低電平后,來到了value=TIM_GetCounter(TIM3);這一句,這個時候獲得TIM3->CNT暫存器的值,然后回傳這個值,
u16 Gets(void)
{
GPIO_SetBits(GPIOC,GPIO_Pin_5);
delay_us(12);
GPIO_ResetBits(GPIOC,GPIO_Pin_5);//高電平觸發信號
while(PCin(4)==0)
{
TIM_SetCounter(TIM3, 0);
TIM_Cmd(TIM3,DISABLE);
}
while(PCin(4)==1)
{
TIM_Cmd(TIM3,ENABLE);
}
value=TIM_GetCounter(TIM3);
return value;
}
主程式中的while(1),僅第一句為得到距離,后面部分為顯示資訊在LCD顯示屏上,
Get()函式的回傳值為TIM3->CNT的值,這個值的大小計算了回響信號的高電平時間,定時器頻率為1M,所以TIM3->CNT里的值加1的時間是1us,所以前面距離和時間的關系公式在程式里是如此的,
LCD的顯示部分我將小數點往左移了三位,所以單位是米M,
int main(void)
{
delay_init();
TIM3_Int_Init();
LCD_Init();
POINT_COLOR=RED;
hc_sr04_init();
LCD_ShowString(80,100,200,24,24,"Distance");
while(1)
{
distance=(Gets()*340/1000/2); //單位mm
LCD_ShowNum(100,150,distance/1000,1,24);
LCD_ShowChar(112,150,'.',24,0);
LCD_ShowNum(124,150,distance%1000/100,1,24);
LCD_ShowNum(136,150,distance%100/10,1,24);
LCD_ShowNum(148,150,distance%10,1,24);
LCD_ShowString(160,150,24,12,24,"M");
delay_ms(100);
}
}
將以上的部分,加上變數的定義和函式的宣告,即可完成程式,奉上完整工程,
鏈接:https://pan.baidu.com/s/1xCUNQlRYu-oCdomhcPbr8w 提取碼:6757
另一種程式使用輸入捕獲來計算時間,在這貼出常用模塊原理程式秘技——超聲波模塊HC-SR04(2)!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/245746.html
標籤:其他
上一篇:Cisco Packet Tracer:基于模擬器的物聯網設備配置與應用
下一篇:最實用的chrome插件
