代码采用外部中断方式进行时间采样,采集的时间加以转换就是超声波模块测得的的距离值。
引脚接线:VCC--3.3V或5V电源
GND--接地线
TRIG--触发控制信号输入(PA6)
ECHO--回响信号输出(PA7)
时序图:
基本工作原理:
(1)采用IO口TRIG触发测距,给最少10us的高电平信号;
(2)模块自动发送8个40kHz的方波,自动检测是否有信号返回;
(3)有信号返回,通过IO口ECHO输出一个高电平,高电平持续时间就是超声波从发射到返回的时间。
测距公式=高电平时间(us)/58 ,单位cm。
超声波模块初始化代码如下:
void Ultrasonic_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
EXTI_InitTypeDef EXTI_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_7;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource7);
EXTI_InitStruct.EXTI_Line=EXTI_Line7;
EXTI_InitStruct.EXTI_LineCmd=ENABLE;
EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Rising_Falling;
EXTI_Init(&EXTI_InitStruct);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStruct.NVIC_IRQChannel=EXTI9_5_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStruct);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period=1000-1; //1MS
TIM_TimeBaseInitStruct.TIM_Prescaler=72-1;
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);
NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=2;
NVIC_Init(&NVIC_InitStruct);
TIM_Cmd(TIM2,DISABLE);
}
我配置PA6为TRIG引脚,IO模式为推挽输出;PA7引脚作为接受引脚ECHO,IO模式为浮空输入,开启定时器2中断和PA7引脚的外部中断来实现记录高电平时间,需特别注意的地方是,定时器配置的为1ms执行一次中断;
超声波模块起始信号:
void Ulstasonic_Startup(void)
{
GPIO_SetBits(GPIOA,GPIO_Pin_6);
delay_us(20);
GPIO_ResetBits(GPIOA,GPIO_Pin_6);
}
我们使用软件方式让TRIG引脚输出20us的高电平,作为超声波测距的触发信号;
中断代码如下:
void EXTI9_5_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line7)==SET)
{
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_7)==1)
{
TIM2_Counter=0;
TIM_SetCounter(TIM2,0);
TIM_Cmd(TIM2,ENABLE);
}
if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_7)==0)
{
TIM_Cmd(TIM2,DISABLE);
distance=(TIM2_Counter*1000+TIM_GetCounter(TIM2))/58; //单位cm
}
}
EXTI_ClearITPendingBit(EXTI_Line7);
}
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==SET)
{
TIM2_Counter++;
}
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
PA7外部中断配置为上升下降沿触发,当PA7检测电平变化时,判断PA7的电平状态为1时,开启定时器2的时钟,时钟开始计时,直到下一次下降沿到来关闭时钟,同时计算定时器记的值(TIM2_Counter,单位为ms)和定时器内还未更新的cnt的值(us),最后将时间单位统一成us计算超声波测得距离;
测距代码:
u32 distance_sum=0;
u16 distance_max=0;
u16 distance_min=9999;
u16 distance_counter=0;
u16 distance_average;
u16 Get_distance(void)
{
Ulstasonic_Startup();
if(distance<distance_min) distance_min=distance;
if(distance>distance_max) distance_max=distance;
distance_sum+=distance;
distance_counter++;
if(distance_counter==12)
{
distance_average=(distance_sum-distance_max-distance_min)/(distance_counter-2);
distance_sum=0;
distance_max=0;
distance_min=9999;
distance_counter=0;
}
return distance_average;
}
此代码是对最后测距结果进行处理,若读者不太能理解可以看博主历史博客,有详细讲解。