近来有时间,整理一下资料,自己近十年来,业余画了不少的开发测试板,在淘宝上也买了不少的板子与器件,一直以来,都喜欢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 工程下载