
CH_SR04
一、簡介
1.產(chǎn)品特點(diǎn)
HC_SR04超聲波測距模塊可提供2cm-400cm的非接觸式測距感測功能,測距精度高達(dá)3mm;模塊包括超聲波發(fā)射器,接收器與控制電路。
基本工作原理:
(1)采用IO口TRIG觸發(fā)測距,需要給最少10us的高電平。
(2)模塊自動(dòng)發(fā)送8個(gè)40kHz的方波,自動(dòng)檢測是否有信號(hào)返回。
(3)有信號(hào)返回,通過IO口ECHO輸出一個(gè)高電平,高電平持續(xù)時(shí)間就是超聲波從發(fā)射到返回的時(shí)間。
距離計(jì)算公式:uS/58=厘米,uS/148=英尺,距離=高電平時(shí)間*聲速(340m/s)/2。
建議測量周期為60ms以上,以防止發(fā)射信號(hào)對回波信號(hào)的影響。
注:此模塊不易帶電連接,若要帶電連接,則需將模塊的GND先連接,否則容易接線錯(cuò)誤影響正常使用。測距時(shí),被測物體的面積不少于0.5平方米且平面盡量要求平整,否則影響測量結(jié)果。
2.實(shí)物圖
VCC:供5V電源
GND:為地線
TRIG:觸發(fā)控制信號(hào)輸入
MCHO:回響信號(hào)輸出

實(shí)物圖
3.電氣特性
電氣參數(shù) |
HC-SR04超聲波模塊 |
工作電壓 |
DC 5V |
工作電流 |
15mA |
工作頻率 |
40kHz |
最遠(yuǎn)射程 |
4m |
最近射程 |
2cm |
測量角度 |
15° |
輸入觸發(fā)信號(hào) |
10uSTTL脈沖 |
輸出回響信號(hào) |
輸出TTL電平信號(hào) |
規(guī)格尺寸 |
45*20*15mm |
4.時(shí)序圖

時(shí)序圖
以上時(shí)序圖表明只需要提供一個(gè)10us以上的脈沖觸發(fā)信號(hào),該模塊內(nèi)部將發(fā)出8個(gè)40kHz周期電平并檢測回波。一旦檢測到有回波信號(hào)則輸出回響信號(hào),回響信號(hào)的脈沖寬度與所測的距離成正比。

視頻演示
以上對HC_SR04超聲波測距模塊的介紹在說明書中都有介紹。以下開始對HC_SR04進(jìn)行配置。
二、程序設(shè)計(jì)
1.準(zhǔn)備
硬件:
(1)單片機(jī)最小系統(tǒng)(筆者用的是 STM32F103ZET6 開發(fā)板)
(2)HC-SR超聲波測距模塊
(3)0.96寸OLED屏
(4)杜邦線
主芯片相關(guān)外設(shè):
(1)RCC時(shí)鐘
(2)GPIO
(3)TIM定時(shí)器
(4)EXTI外部中斷
(5)Systick系統(tǒng)滴答定時(shí)器
開發(fā)環(huán)境: KEIL_5
2.硬件連接
HC-SR04超聲波模塊 | |
TRIG |
PD_0 |
MCHO |
PD_1 |
3.驅(qū)動(dòng)編寫
編程思路:
使能GPIO,AFIO,TIM,EXTI。
①TRIG為主機(jī)發(fā)送觸發(fā)信號(hào)端,可將對應(yīng)io配置為輸出模式,并拉低電平。觸發(fā)信號(hào):io口輸出高電平持續(xù)10us以上再輸出低電平。
②MCHO為從機(jī)輸出回響信號(hào)端,由主機(jī)接收信號(hào),可將對應(yīng)io配置為輸入模式。配置外部中斷,檢測io電平變化。
③使用TIM6,在MCHO上升沿時(shí)啟動(dòng)定時(shí)器,記錄MCHO高電平持續(xù)時(shí)間;在下降沿時(shí)關(guān)閉定時(shí)器,并清空計(jì)數(shù)器,保存高電平持續(xù)時(shí)間。
④使用TIM7,定時(shí)發(fā)送觸發(fā)信號(hào)。
⑤配置中斷,設(shè)置中斷優(yōu)先級,編寫中斷服務(wù)函數(shù)。
⑥main函數(shù)負(fù)責(zé)向oled輸出實(shí)測距離。
(1)GPIO引腳和外部中斷配置
void HC_SR04_PinInit(void)
{
//1.配置GPIO模式
GPIO_InitTypeDef hc_sr04_gpioInit;
hc_sr04_gpioInit.GPIO_Pin = GPIO_Pin_1;
hc_sr04_gpioInit.GPIO_Mode = GPIO_Mode_IPD; //下拉輸入模式
hc_sr04_gpioInit.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD,&hc_sr04_gpioInit);
hc_sr04_gpioInit.GPIO_Pin = GPIO_Pin_0;
hc_sr04_gpioInit.GPIO_Mode = GPIO_Mode_Out_PP; //通用推挽輸出
GPIO_Init(GPIOD,&hc_sr04_gpioInit);
HC_SR04_TRIG_0;//拉低電平
//2.配置外部中斷
EXTI_InitTypeDef hc_sr04_extiInit;
hc_sr04_extiInit.EXTI_Line = EXTI_Line1;
hc_sr04_extiInit.EXTI_Mode = EXTI_Mode_Interrupt;//中斷模式
hc_sr04_extiInit.EXTI_Trigger = EXTI_Trigger_Rising_Falling;//雙邊沿對齊
hc_sr04_extiInit.EXTI_LineCmd = ENABLE;//使能
EXTI_Init(&hc_sr04_extiInit);
//3.選擇外部中斷線
GPIO_EXTILineConfig(GPIO_PortSourceGPIOD,GPIO_PinSource1);//選擇PD1作為外部中斷線
//EXTI_GenerateSWInterrupt(EXTI_Line1);//產(chǎn)生一個(gè)軟件中斷
EXTI_ClearFlag(EXTI_Line1);//清除掛起標(biāo)志位
}
(2)TIM配置
/*
\brief: 基本TIM初始化
\param: TIMx: where x can be 1 to 17 to select the TIM peripheral.
psc:預(yù)分頻系數(shù)
arr:重裝載值
\retval: none
*/
static void TIMx_Init(TIM_TypeDef* TIMx,uint16_t psc,uint16_t arr)
{
//1.復(fù)位TIM
TIM_DeInit(TIMx);
//2.配置TIM
TIM_TimeBaseInitTypeDef TIMx_timeBaseInit;
TIMx_timeBaseInit.TIM_Prescaler = psc-1; //設(shè)置預(yù)分頻系數(shù)為psc
TIMx_timeBaseInit.TIM_CounterMode = TIM_CounterMode_Up; //向上計(jì)數(shù)
TIMx_timeBaseInit.TIM_RepetitionCounter = 0; //重復(fù)計(jì)數(shù)值
TIMx_timeBaseInit.TIM_Period = arr; //重裝載值
TIMx_timeBaseInit.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIMx,&TIMx_timeBaseInit);
//3.中斷配置
TIM_ITConfig(TIMx,TIM_IT_Update,ENABLE); //使能更新中斷
TIM_ClearFlag(TIMx,TIM_FLAG_Update); //清除掛起標(biāo)志
//4.失能定時(shí)器
TIM_Cmd(TIMx,DISABLE);
}
(2)配置中斷優(yōu)先級
/*
\brief: 配置中斷優(yōu)先級
\param: NVIC_IRQChannel:中斷號(hào)
PreemptionPriority:搶占優(yōu)先級
SubPriority:子優(yōu)先級
\retval: none
*/
static void nvic_InitConfig(uint8_t IRQChannel,uint8_t PreemptionPriority,uint8_t SubPriority)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);//配置優(yōu)先級分組
NVIC_InitTypeDef ch_sr04_NVIC_init;
ch_sr04_NVIC_init.NVIC_IRQChannel = IRQChannel;
ch_sr04_NVIC_init.NVIC_IRQChannelPreemptionPriority = PreemptionPriority;
ch_sr04_NVIC_init.NVIC_IRQChannelSubPriority = SubPriority;
ch_sr04_NVIC_init.NVIC_IRQChannelCmd = ENABLE; //使能中斷
NVIC_Init(&ch_sr04_NVIC_init);
}
(3)初始化HC_SR04
使用外部中斷需要開啟AFIO時(shí)鐘。
觸發(fā)信號(hào)發(fā)送周期建議大于60ms,此處為200ms定時(shí)發(fā)送觸發(fā)信號(hào)。
/*
\brief: CH_SR04超聲測距模塊初始化配置
\retval: none
*/
void HC_SR04_Init(void)
{
//1.打開外設(shè)時(shí)鐘
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE);//使能TIM6
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7,ENABLE);//使能TIM7
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);//使能GPIOD
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//使能AFIO
//2.GPIO初始化
HC_SR04_PinInit();
//3.TIM初始化
TIMx_Init(TIM6,72,0xFFFF); //72分頻 1us 用于記錄MCHO高電平時(shí)間
TIMx_Init(TIM7,720,20000); //200ms發(fā)一次脈沖
TIM_Cmd(TIM7,ENABLE);
//4.配置中斷優(yōu)先級
nvic_InitConfig(EXTI1_IRQn,1,0);
nvic_InitConfig(TIM6_IRQn,2,0);
nvic_InitConfig(TIM7_IRQn,3,0);
}
//觸發(fā)信號(hào)
void HC_SR04_TriggerSignal(void)
{
HC_SR04_TRIG_1;
Delay_us(20); //延時(shí)10us以上
HC_SR04_TRIG_0;
}
(4)中斷服務(wù)函數(shù)
為了使用us計(jì)數(shù),將TIM6進(jìn)行72分頻,最大計(jì)數(shù)值為65535us,而MCHO高電平最大持續(xù)時(shí)間為400*58=23200us,所以將TIM6的重裝載寄存器的值設(shè)為0xFFFF,完全夠用于記錄MCHO的高電平持續(xù)時(shí)間。如果TIM一次計(jì)數(shù)到溢出所用的時(shí)間小于23200us,可定義一個(gè)變量記錄一次回響信號(hào)TIM6進(jìn)中斷的次數(shù),再進(jìn)行時(shí)間計(jì)算。
本文中的tim6_IT_count就顯得有些多余。
uint16_t tim6_IT_count=0;
//ECHO 中斷線服務(wù)函數(shù)
void EXTI1_IRQHandler(void)
{
if(RESET != EXTI_GetITStatus(EXTI_Line1))
{
EXTI_ClearITPendingBit(EXTI_Line1);//清除中斷標(biāo)志位
if(HC_SR04_ECHO()) //上升沿
{
TIM_Cmd(TIM6,ENABLE); //啟動(dòng)定時(shí)器
}
else //下降沿
{
TIM_Cmd(TIM6,DISABLE); //關(guān)閉定時(shí)器
Dist_cm = (tim6_IT_count*0xFFFF+TIM_GetCounter(TIM6))/58.0;//計(jì)算距離
TIM_SetCounter(TIM6,0x00); //清空計(jì)數(shù)器
tim6_IT_count=0; //計(jì)數(shù)數(shù)清零
}
}
}
//基本定時(shí)器TIM6 輔助MCHO高電平期間計(jì)數(shù)
void TIM6_IRQHandler(void)
{
if(RESET != TIM_GetITStatus(TIM6,TIM_IT_Update))
{
TIM_ClearITPendingBit(TIM6,TIM_IT_Update);//清除標(biāo)志位
tim6_IT_count++;
}
}
//基本定時(shí)器TIM7 定時(shí)發(fā)送CH_SR04載波發(fā)送
void TIM7_IRQHandler(void)
{
if(RESET != TIM_GetITStatus(TIM7,TIM_IT_Update))
{
TIM_ClearITPendingBit(TIM7,TIM_IT_Update);//清除標(biāo)志位
HC_SR04_TriggerSignal();//觸發(fā)信號(hào)
}
}
三、實(shí)驗(yàn)結(jié)果

測量值不會(huì)很準(zhǔn)確,當(dāng)測量距離小于2cm時(shí),或者測量斜面時(shí),數(shù)值會(huì)跳動(dòng)很大。如果需要增加精準(zhǔn)度,可通過排序取中間值或其他方式減小誤差。
四、代碼
hc_sr04.c
#include "hc_sr04.h"
/*
配置GPIO
\pin: ECHO - PD1 觸發(fā)控制信號(hào)
TRIG - PD0 回響信號(hào)
*/
#define HC_SR04_ECHO() GPIO_ReadInputDataBit(GPIOD,GPIO_Pin_1)//讀取輸入電平
#define HC_SR04_TRIG_0 GPIO_ResetBits(GPIOD,GPIO_Pin_0) //寫0
#define HC_SR04_TRIG_1 GPIO_SetBits(GPIOD,GPIO_Pin_0) //寫1
float Dist_cm;//測量距離
void HC_SR04_PinInit(void)
{
//1.配置GPIO模式
GPIO_InitTypeDef hc_sr04_gpioInit;
hc_sr04_gpioInit.GPIO_Pin = GPIO_Pin_1;
hc_sr04_gpioInit.GPIO_Mode = GPIO_Mode_IPD; //下拉輸入模式
hc_sr04_gpioInit.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOD,&hc_sr04_gpioInit);
hc_sr04_gpioInit.GPIO_Pin = GPIO_Pin_0;
hc_sr04_gpioInit.GPIO_Mode = GPIO_Mode_Out_PP; //通用推挽輸出
GPIO_Init(GPIOD,&hc_sr04_gpioInit);
HC_SR04_TRIG_0;//拉低電平
//2.配置外部中斷
EXTI_InitTypeDef hc_sr04_extiInit;
hc_sr04_extiInit.EXTI_Line = EXTI_Line1;
hc_sr04_extiInit.EXTI_Mode = EXTI_Mode_Interrupt;//中斷模式
hc_sr04_extiInit.EXTI_Trigger = EXTI_Trigger_Rising_Falling;//雙邊沿對齊
hc_sr04_extiInit.EXTI_LineCmd = ENABLE;//使能
EXTI_Init(&hc_sr04_extiInit);
//3.選擇外部中斷線
GPIO_EXTILineConfig(GPIO_PortSourceGPIOD,GPIO_PinSource1);//選擇PD1作為外部中斷線
//EXTI_GenerateSWInterrupt(EXTI_Line1);//產(chǎn)生一個(gè)軟件中斷
EXTI_ClearFlag(EXTI_Line1);//清除掛起標(biāo)志位
}
/*
\brief: 基本TIM初始化
\param: TIMx: where x can be 1 to 17 to select the TIM peripheral.
psc:預(yù)分頻系數(shù)
arr:重裝載值
\retval: none
*/
static void TIMx_Init(TIM_TypeDef* TIMx,uint16_t psc,uint16_t arr)
{
//1.復(fù)位TIM
TIM_DeInit(TIMx);
//2.配置TIM
TIM_TimeBaseInitTypeDef TIMx_timeBaseInit;
TIMx_timeBaseInit.TIM_Prescaler = psc-1; //設(shè)置預(yù)分頻系數(shù)為psc
TIMx_timeBaseInit.TIM_CounterMode = TIM_CounterMode_Up; //向上計(jì)數(shù)
TIMx_timeBaseInit.TIM_RepetitionCounter = 0; //重復(fù)計(jì)數(shù)值
TIMx_timeBaseInit.TIM_Period = arr; //重裝載值
TIMx_timeBaseInit.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIMx,&TIMx_timeBaseInit);
//3.中斷配置
TIM_ITConfig(TIMx,TIM_IT_Update,ENABLE); //使能更新中斷
TIM_ClearFlag(TIMx,TIM_FLAG_Update); //清除掛起標(biāo)志
//4.失能定時(shí)器
TIM_Cmd(TIMx,DISABLE);
}
/*
\brief: 配置中斷優(yōu)先級
\param: NVIC_IRQChannel:中斷號(hào)
PreemptionPriority:搶占優(yōu)先級
SubPriority:子優(yōu)先級
\retval: none
*/
static void nvic_InitConfig(uint8_t IRQChannel,uint8_t PreemptionPriority,uint8_t SubPriority)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);//配置優(yōu)先級分組
NVIC_InitTypeDef ch_sr04_NVIC_init;
ch_sr04_NVIC_init.NVIC_IRQChannel = IRQChannel;
ch_sr04_NVIC_init.NVIC_IRQChannelPreemptionPriority = PreemptionPriority;
ch_sr04_NVIC_init.NVIC_IRQChannelSubPriority = SubPriority;
ch_sr04_NVIC_init.NVIC_IRQChannelCmd = ENABLE; //使能中斷
NVIC_Init(&ch_sr04_NVIC_init);
}
/*
\brief: CH_SR04超聲測距模塊初始化配置
\retval: none
*/
void HC_SR04_Init(void)
{
//1.打開外設(shè)時(shí)鐘
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6,ENABLE);//使能TIM6
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM7,ENABLE);//使能TIM7
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);//使能GPIOD
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//使能AFIO
//2.GPIO初始化
HC_SR04_PinInit();
//3.TIM初始化
TIMx_Init(TIM6,72,0xFFFF); //72分頻 1us 用于記錄MCHO高電平時(shí)間
TIMx_Init(TIM7,720,20000); //200ms發(fā)一次脈沖
TIM_Cmd(TIM7,ENABLE);
//4.配置中斷優(yōu)先級
nvic_InitConfig(EXTI1_IRQn,1,0);
nvic_InitConfig(TIM6_IRQn,2,0);
nvic_InitConfig(TIM7_IRQn,3,0);
}
//觸發(fā)信號(hào)
void HC_SR04_TriggerSignal(void)
{
HC_SR04_TRIG_1;
Delay_us(20); //延時(shí)10us以上
HC_SR04_TRIG_0;
}
uint16_t tim6_IT_count=0;
//ECHO 中斷線服務(wù)函數(shù)
void EXTI1_IRQHandler(void)
{
if(RESET != EXTI_GetITStatus(EXTI_Line1))
{
EXTI_ClearITPendingBit(EXTI_Line1);//清除中斷標(biāo)志位
if(HC_SR04_ECHO()) //上升沿
{
TIM_Cmd(TIM6,ENABLE); //啟動(dòng)定時(shí)器
}
else //下降沿
{
TIM_Cmd(TIM6,DISABLE); //關(guān)閉定時(shí)器
Dist_cm = (tim6_IT_count*0xFFFF+TIM_GetCounter(TIM6))/58.0;//計(jì)算距離
TIM_SetCounter(TIM6,0x00); //清空計(jì)數(shù)器
tim6_IT_count=0; //計(jì)數(shù)數(shù)清零
}
}
}
//基本定時(shí)器TIM6 輔助MCHO高電平期間計(jì)數(shù)
void TIM6_IRQHandler(void)
{
if(RESET != TIM_GetITStatus(TIM6,TIM_IT_Update))
{
TIM_ClearITPendingBit(TIM6,TIM_IT_Update);//清除標(biāo)志位
tim6_IT_count++;
}
}
//基本定時(shí)器TIM7 定時(shí)發(fā)送CH_SR04載波發(fā)送
void TIM7_IRQHandler(void)
{
if(RESET != TIM_GetITStatus(TIM7,TIM_IT_Update))
{
TIM_ClearITPendingBit(TIM7,TIM_IT_Update);//清除標(biāo)志位
HC_SR04_TriggerSignal();//觸發(fā)信號(hào)
}
}
hc_sr04.h
#ifndef _HC_SR04_H_
#define _HC_SR04_H_
#include "stm32f10x.h"
#include "systick.h"
extern float Dist_cm;//測量距離 cm
void HC_SR04_Init(void);
#endif
main.c
#include "stm32f10x.h"
#include "hc_sr04.h"
#include "systick.h"
#include "oled.h"
#include <stdio.h>
#include <string.h>
/*
超聲測距實(shí)驗(yàn)
*/
int main(void)
{
/* 相關(guān)外設(shè)初始化 */
HC_SR04_Init(); //hc_sr04初始化
systick_config(); //系統(tǒng)滴答
OLED_Init(); //oled初始化
uint8_t buff[10];
while(1)
{
snprintf((char *)buff,10,"%0.1f%s",Dist_cm,"cm"); //拼接字符串
OLED_Display_String(20,16,12,24,buff); //oled顯示字符串
OLED_Refresh(); //刷新函數(shù)
OLED_GRAM_Init(); //初始化oled緩存
memset(buff,0,10); //清零buff
}
}
其他代碼:略。
源碼下載:
鏈接:https://pan.baidu.com/s/1mfZma1C0xWdlEr6bNz4KCg?pwd=1234
提取碼:1234
文章如有錯(cuò)誤,還望在評論區(qū)指正!文章來源:http://www.zghlxwxcb.cn/news/detail-580711.html
2023/1/13文章來源地址http://www.zghlxwxcb.cn/news/detail-580711.html
到了這里,關(guān)于【STM32篇】驅(qū)動(dòng)HC_SR04超聲波測距模塊的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!