本文主要是介绍超声波传感器-HC-SR04,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
HC-SR04 超声波测距模块可提供 2cm-400cm 的非接触式距离感测功能,测距精度可达高到 3mm;
一、超声波工作原理
1、CH-SR04 相关电气参数
二、计算公式(理解时参考时序图)
(1)采用 IO 触发测距,给至少 10us 的高电平信号;
(2)模块自动发送 8 个 40khz 的方波,自动检测是否有信号返回;
(3)有信号返回,通过 IO 输出一高电平,高电平持续的时间就是超声波从发射到返回的时间
(4)超声波从发射到返回的时间.测试距离=(高电平时间*声速(340M/S))/2;
在此只需要提供一个 10uS 以上脉冲触发信号,该模块内部将循环发出 8 个 40kHz 周期电平并检测回波。一旦检测到有回波信号则输出回响信号。 回响信号的脉冲宽度与所测的距离成正比。由此通过发射信号到收到的回响信号时间间隔可以计算得到距离。公式:uS/58=厘米或者 uS/148=英寸;或是:距离= 高电平时间 * 声速(340M/S)/2;建议测量周期为 60ms 以上,以防止发射信号对 回响信号的影响。
三、超声波时序图
四、定时器计时原理
● 计数器寄存器(TIMx_CNT)
● 预分频寄存器(TIMx_PSC)
● 自动重装载寄存器(TIMx_ARR)
- 时钟源(CK_INT)
定时器时钟 TIMxCLK,即内部时钟 CK_INT,经 APB1 预分频器后分频提供,如果 APB1 预分频系数等于 1,则频率不变,否则频率乘以 2,库函数中 APB1 预分频的系数是 2,即 PCLK1=36M,所以定时器时钟 TIMxCLK=36*2=72M - 预分频器(PSC)
PSC 是一个 16 位的预分频器,可以对定时器时钟 TIMxCLK 进行 1~65536 之间的任何一个数进行分频。具体计算方式为: CK_CNT=TIMxCLK/(PSC+1)
- 计数器(CNT)
计数器 CNT 是一个 16 位的计数器,只能往上计数,最大计数值为 65535。当计数达到自动重装载寄存器的时候产生更新事件,并清零从头开始计数。
- 自动重装载寄存器(ARR)
自动重装载寄存器 ARR 是一个 16 位的寄存器,这里面装着计数器能计数的最大数值。当计数到这个值的时候,如果使能了中断的话,定时器就产生溢出中断。
定时器预分频器设置
// 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断TIM_TimeBaseStructure.TIM_Period = BASIC_TIM_Period; // 时钟预分频数为TIM_TimeBaseStructure.TIM_Prescaler= BASIC_TIM_Prescaler;
当内部时钟经过PSC预分频器分频后,1000 000Hz, 也就是1us ,ARR设置为1000,意味着,CNT计数器每1us记录一次 , 当1ms 时ARR寄存器清零。
五、公式推导
因为时钟以微秒为最小计算单位,所有方便理解,将所有的转换成微妙计算
distance = 定时器时间 (s)* 340(m/s) / 2
distance = 定时时间(us)* 34000 / 2 / 1000 000 = 定时时间(us)* 0.017
另一种算法:distance = 定时时间(us) / 58
六、相关注意事项:
1、此模块不宜带电连接,若要带电连接,则先让模块的 GND 端先连接,否则会影响 模块的正常工作。
2、测距时,被测物体的面积不少于 0.5 平方米且平面尽量要求平整,否则影响测量的结果
3、当传感器紧贴物体表面时,会出现数值错误,
七、参考文献
(19条消息) 超声波测距为什么除以58_超声波测距公式为什么除以58_总结所学的博客-CSDN博客
深圳市捷深科技有限公司 (raincorn.top)
相关代码
Ultrasonic.c
/*** @brief 超声波相关引脚初始化* @param NULL* @retval NULL*/
static void UltrasonicGpioModeConfig(void)
{GPIO_InitTypeDef GPIO_InitStruct;RCC_TE_PeriphClockCmd(ECHO_TRIG_CLK_ENR,ENABLE); //引脚时钟使能GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStruct.GPIO_Pin = TRIG_PIN; GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(TRIG_PORT,&GPIO_InitStruct); //TRIG 引脚GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; //ECHO 设置为上拉输入,接受信号GPIO_InitStruct.GPIO_Pin = ECHO_PIN;// GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(ECHO_PORT,&GPIO_InitStruct); //ECHO 引脚TRIG_LOW(); /* 让两引脚初始化时处于低电平 */ECHO_LOW();
}/*** @brief 定时器中断配置* @param NULL* @retval NULL*/
static void NVIC_TIME_Config(void)
{NVIC_InitTypeDef NVIC_InitStruct;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);NVIC_InitStruct.NVIC_IRQChannel = BASIC_TIM_IRQ;NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStruct.NVIC_IRQChannelSubPriority = 3; NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStruct);}
static void BASIC_TIM_Mode_Config(void)
{TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;// 开启定时器时钟,即内部时钟CK_INT=72MBASIC_TIM_APBxClock_FUN(BASIC_TIM_CLK, ENABLE);// 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断TIM_TimeBaseStructure.TIM_Period = BASIC_TIM_Period; // 时钟预分频数为TIM_TimeBaseStructure.TIM_Prescaler= BASIC_TIM_Prescaler;// 时钟分频因子 ,基本定时器没有,不用管//TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;// 计数器计数模式,基本定时器只能向上计数,没有计数模式的设置//TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; // 重复计数器的值,基本定时器没有,不用管//TIM_TimeBaseStructure.TIM_RepetitionCounter=0;// 初始化定时器TIM_TimeBaseInit(BASIC_TIM, &TIM_TimeBaseStructure);// 清除计数器中断标志位TIM_ClearFlag(BASIC_TIM, TIM_FLAG_Update);// 开启计数器中断TIM_ITConfig(BASIC_TIM, TIM_IT_Update,ENABLE);// 使能计数器
// TIM_Cmd(BASIC_TIM, ENABLE);
}/*** @brief 超声波触发信号* @param NULL* @retval NULL*/
void WAVE_Start(void)
{TRIG_HIGH(); //TRIG设置为高电平CPU_TS_Tmr_Delay_US(20); //延时大于10usTRIG_LOW();
}/*** @brief 超声波相关初始化* @param NULL* @retval NULL*/
void WAVE_Init(void)
{UltrasonicGpioModeConfig();NVIC_TIME_Config();BASIC_TIM_Mode_Config();
}
Ultrasonic.h
#define TRIG_RCC_CLK_ENR RCC_APB2Periph_GPIOA
#define RCC_TE_PeriphClockCmd RCC_APB2PeriphClockCmd
#define TRIG_PORT GPIOA
#define TRIG_PIN GPIO_Pin_4#define ECHO_RCC_CLK_ENR RCC_APB2Periph_GPIOA
#define RCC_ECHO_ClockCmd RCC_APB2PeriphClockCmd
#define ECHO_PORT GPIOA
#define ECHO_PIN GPIO_Pin_5#define ECHO_TRIG_CLK_ENR (ECHO_RCC_CLK_ENR|TRIG_RCC_CLK_ENR)#define BASIC_TIM6 // 如果使用TIM7,注释掉这个宏即可#ifdef BASIC_TIM6 // 使用基本定时器TIM6
#define BASIC_TIM TIM6
#define BASIC_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd
#define BASIC_TIM_CLK RCC_APB1Periph_TIM6
#define BASIC_TIM_Period (1000-1)
#define BASIC_TIM_Prescaler (72-1) // 72000000/72 *1000= 1000us = lms
#define BASIC_TIM_IRQ TIM6_IRQn
#define BASIC_TIM_IRQHandler TIM6_IRQHandler#else // 使用基本定时器TIM7
#define BASIC_TIM TIM7
#define BASIC_TIM_APBxClock_FUN RCC_APB1PeriphClockCmd
#define BASIC_TIM_CLK RCC_APB1Periph_TIM7
#define BASIC_TIM_Period 1000-1
#define BASIC_TIM_Prescaler 71
#define BASIC_TIM_IRQ TIM7_IRQn
#define BASIC_TIM_IRQHandler TIM7_IRQHandler#endif #define TRIG_HIGH() GPIO_SetBits(TRIG_PORT,TRIG_PIN)
#define TRIG_LOW() GPIO_ResetBits(TRIG_PORT,TRIG_PIN)#define ECHO_HIGH() GPIO_SetBits(ECHO_PORT,ECHO_PIN)
#define ECHO_LOW() GPIO_ResetBits(ECHO_PORT,ECHO_PIN) void WAVE_Init(void);
void WAVE_Start(void);
main.c
float distance;
volatile uint32_t time=0;
uint32_t TIME = 0;int main(void)
{uint8_t i;USART_Config();SysTick_Init();LED_GPIO_Config();WAVE_Init();while (1){for (i = 0; i < 5; i++) //求均值,避免误差{WAVE_Start(); // 开启信号while (GPIO_ReadInputDataBit(ECHO_PORT, ECHO_PIN) == RESET); // ECHO 为高电平TIM_SetCounter(BASIC_TIM, 0);time =0;TIM_Cmd(BASIC_TIM, ENABLE);while(GPIO_ReadInputDataBit(ECHO_PORT, ECHO_PIN) == SET); // 等待ECHO 低电平TIM_Cmd(BASIC_TIM, DISABLE);TIME += ((time*1000)+ TIM_GetCounter(BASIC_TIM));printf("采集到的时间为 %d us\n", TIME);}printf("采集到的时间平均值 %d ms\n", (TIME/5));distance = (TIME/5 * 0.017 ); //第一种算法//distance = (((TIME) /58 )); //第二种算法printf("Distance:%f cm\r\n", distance);TIME=0;Delay_ms(2000);}
}
stm32f10x_it.h
extern volatile uint32_t time ;void TIM6_IRQHandler(void)
{if(TIM_GetITStatus(BASIC_TIM,TIM_IT_Update)!=RESET){time++;TIM_ClearITPendingBit(BASIC_TIM, TIM_IT_Update);}}
这篇关于超声波传感器-HC-SR04的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!