近来有时间,整理一下资料,自己近十年来,业余画了不少的开发测试板,在淘宝上也买了不少的板子与器件,一直以来,都喜欢DIY,今天整理了一下超声波模块HC-SR04的程序,网上资料应该不少,自己工作中也接触过。记录一下。
超声波如何设计的我不太关心,我只关心如何使用。这个模块可以+3.3V供电,四个引脚,使用STM32两个GPIO引脚控制即可,测试起来,简单。
超声波模块工作的原理:首先需要触发trig,就像是打开或是使能的作用,让超声波工作起来。然后,超声波通过echo返回一段高电平,高电平的时间,就是声音到达障碍物返回的时间,声速是固定的340m/S,因此,可以求得距离。这里是2倍距离的时间,因此计算公式为:2L = Vt = 340m/S * t,这里t单位为S(秒)。
STM32如何操作超声波模块呢?
(1)一个GPIO引脚Trig,用于触发。
(2)一个GPIO引脚接Echo,设置为外部中断,用来接收触发后返回来的高电平。
(3)一个定时器(计数器),用来测时间。
(4)可以使用另一个定时器,如Systick,隔一段时间用来触发一次超声波模块,从而不断获取当前的距离值。
(5)一个串口,用来打印输出测量的距离。
驱动代码如下:
/******************** (C) COPYRIGHT 2017 ************************** * 文件名 :Sonic.c * 描述 :超声波模块 测试例程 * 实验平台:STM32F103VET6 * 库版本 :ST3.5.0 * * 编写日期:2017-04-10 * 修改日期:2017-04-14 * 作者 : ****************************************************************************/ #include "Sonic.h" /******************************************************************************* * Sonic Init *******************************************************************************/ u32 Distance = 0; u8 Done; u32 __IO time_1ms = 0; void TIM6_Init(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //NVIC_InitTypeDef NVIC_InitStructure; /* TIM6 clock enable */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6, ENABLE); /* Time base configuration */ TIM_TimeBaseStructure.TIM_Period = 0xFFFF; TIM_TimeBaseStructure.TIM_Prescaler = 142; //144分频,500K的计数器 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure); TIM_ITConfig(TIM6, TIM_IT_Update, DISABLE); TIM_Cmd(TIM6, DISABLE); } void Sonic_Init(void) { NVIC_InitTypeDef NVIC_InitStructure; EXTI_InitTypeDef EXTI_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC| RCC_APB2Periph_AFIO,ENABLE); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; //PC4 Trig GPIO_Init(GPIOC,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode= GPIO_Mode_IPD; GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5; //PC5 Echo GPIO_Init(GPIOC,&GPIO_InitStructure); GPIO_WriteBit(GPIOC,GPIO_Pin_4,(BitAction)0); //trig //EXTI_DeInit(); EXTI_ClearITPendingBit(EXTI_Line5); GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource5); EXTI_InitStructure.EXTI_Line= EXTI_Line5; EXTI_InitStructure.EXTI_Mode= EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger= EXTI_Trigger_Rising_Falling; EXTI_InitStructure.EXTI_LineCmd=ENABLE; EXTI_Init(&EXTI_InitStructure); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority= 0; NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; NVIC_Init(&NVIC_InitStructure); Distance = 0; Done = 1; } void Sonic_Trig(void) { u16 i = 0; if((Done == 1)&&(time_1ms > 100)) { time_1ms = 0; GPIO_WriteBit(GPIOC,GPIO_Pin_4,(BitAction)1); for(i=0;i<0xf0;i++); GPIO_WriteBit(GPIOC,GPIO_Pin_4,(BitAction)0); Done = 0; } } void EXTI9_5_IRQHandler(void) { static u8 flag_Sta = 0; if(EXTI_GetITStatus(EXTI_Line5) != RESET) { EXTI_ClearITPendingBit(EXTI_Line5); if(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_5)==1) { TIM_SetCounter(TIM6,0); flag_Sta=1; TIM_Cmd(TIM6, ENABLE); } else { TIM_Cmd(TIM6, DISABLE); if(flag_Sta) { Distance = TIM_GetCounter(TIM6); Distance = Distance /29; if(Distance > 300) Distance = 300; Done = 1; } flag_Sta=0; } } } /******************* (C) COPYRIGHT 2017 *END OF FILE************/
SysTick中断作的处理:
/** * @brief This function handles SysTick Handler. * @param None * @retval None */ void SysTick_Handler(void) { time_1ms++; time_120ms++; if(time_120ms>=80) { Sonic_Trig(); //50ms Trig Sonic time_120ms=0; } TimingDelay_Decrement(); }
/* * 函数名:main * 描述 : "主机"的主函数 * 输入 :无 * 输出 : 无 */ int main(void) { SysTick_Init(); USART1_Config(115200); /* 初始化USART1 */ LED_GPIO_Config(); /* 运行LED初始化 */ TIM2_Config(); /* 定时器TIM2初始化 */ TIM6_Init(); //TIM6 Init Sonic_Init(); //Sonic_Init LED1(OFF); LED2(OFF); LED3(OFF); LED4(OFF); LEDR(OFF); printf("STM32F103VET6_Sonic Test!\r\n"); printf("2017-04-14 9:00\r\n\r\n"); while(1) { Delay_ms(1000); printf("The Distance is:%d\r\n",Distance); } }
测试下来,基本符合要求,关于距离的测量,总结如下:
(1)超声波模块,如果前方没有障碍物,就可能不返回,这样程序里,需要有超时的处理,不能死等,否则会影响其他程序的正常进展,采集用的计数器会超时,重新计数,距离也不正确。
如超声波最大测距为:4米,则 2*4 = vt = 340m/s *Tm Tm为最大的时间,约为:30ms。加上一些余量,60ms差不多可以完成一次采集任务。我这里使用:100ms一次。计数器:每个数为:2us,可以计到最大2*65535=130ms中断并重新计数。
(2)计算公式:
2* L = VT = 340m/s * n * 2us = 340*2*n/1000000(m)=34*2*n/1000(cm)
L= 34*n/1000 (cm),这里单位为厘米。
L= n/29.4 约为:L=n/30
这样,根据定时计数器的值,就可计算得到距离(单位为:cm)
(3)最大值限制:如超声波最大测距为:4米,程序里根据要求,可以限制到3.5米。如果超过,则等于3.5米,
工程如下:感兴趣的可以一起讨论。
可以通过git clone本工程:
https://gitee.com/fsmd/STM32F103VE_sonic_t0.git
Keil5 工程下载