使用的超声波模块
展示效果
使用的三个模块在不同位置发送超声波,然后接收端得出接收端与三发送端的距离,如果已知三发送端的坐标,根据三个距离值即可计算出接收端的坐标。
发送端用的一个stm32来控制,发送与接收的同步信号使用的红外,接收端接收到红外信号后开启1us的定时器计时,发送端每个超声波模块发送间隔40ms(避免间隔时间太短,声波反射干扰)。
这里需要用逻辑分析仪或者示波器来查看发送和接收的时间差,进行微调,以及消除某些干扰信号。
红外模块
接收端没有使用模块的echo引脚,因为模块本身有抗干扰措施,如果没有使用trig发送,echo是不会返回信号的,如果要直接获取接收到的信号,可连接图中的引脚
各信号时序
接收到的超声波信号是40k的矩形波,需要注意其他干扰信号
红外信号从发送到接收的时间基本保持一致,并且每次红外发送完成后就发送超声波,我们就在接收端掐准时间,从接收到红外信号固定一个延时,到发送超声波就开始计时,直到接收到超声波信号即可停止。定时器计数值*计数周期即可算得时间,再乘上声速即可算得距离。
发送端实现代码:
标准库
TIM_Cmd(TIM3, ENABLE);
TIM3->CNT=0;//开始计时
TIM_Cmd(TIM2, ENABLE);
TIM_SetCompare2(TIM2,13);//红外发送信号,38khz
while(TIM3->CNT<500);
TIM_SetCompare2(TIM2,0);//停止发送,发送不能太长,也不能太短,
//太长没必要,太短会发送不成功
GPIO_WriteBit(GPIOB,GPIO_Pin_0,Bit_SET);//超声波模块1发送引脚,trig
TIM3->CNT=0;
while(TIM3->CNT<15);
GPIO_WriteBit(GPIOB,GPIO_Pin_0,Bit_RESET);//15us后关闭,要超过10us
TIM3->CNT=0;
while(TIM3->CNT<40000);//等待40ms
GPIO_WriteBit(GPIOB,GPIO_Pin_1,Bit_SET);//超声波模块1发送引脚,trig
TIM3->CNT=0;
while(TIM3->CNT<15);
GPIO_WriteBit(GPIOB,GPIO_Pin_1,Bit_RESET);//15us后关闭
TIM3->CNT=0;
while(TIM3->CNT<40000);
LED3=1;
TIM3->CNT=0;
while(TIM3->CNT<15);
LED3=0;
TIM3->CNT=0;
while(TIM3->CNT<40000);
TIM_Cmd(TIM3, DISABLE);
hal库
htim2.Instance->ARR=26-1;//设置频率为38k,具体看芯片时钟
htim2.Instance->CNT=0;
htim2.Instance->CCR4=0;
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_4);
HAL_TIM_Base_Start(&htim3);//开启计时,周期为1us
__HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_4,13);//给红外发送模块38khz
htim3.Instance->CNT=0;
while(htim3.Instance->CNT<500);//实际情况可修改发送时长
htim2.Instance->CCR4=0;//停止红外信号
HAL_TIM_Base_Stop(&htim3);
//ir_send
HAL_TIM_Base_Start(&htim3);
HAL_GPIO_WritePin(trig4_GPIO_Port,trig4_Pin,GPIO_PIN_SET);
htim3.Instance->CNT=0;
while(htim3.Instance->CNT<15);
HAL_GPIO_WritePin(trig4_GPIO_Port,trig4_Pin,GPIO_PIN_RESET);
HAL_TIM_Base_Stop(&htim3);//15us高电平发送
HAL_TIM_Base_Start(&htim3);
htim3.Instance->CNT=0;
while(htim3.Instance->CNT<40000);//等待40us
HAL_TIM_Base_Stop(&htim3);
HAL_TIM_Base_Start(&htim3);
HAL_GPIO_WritePin(trig2_GPIO_Port,trig2_Pin,GPIO_PIN_SET);
htim3.Instance->CNT=0;
while(htim3.Instance->CNT<15);
HAL_GPIO_WritePin(trig2_GPIO_Port,trig2_Pin,GPIO_PIN_RESET);
HAL_TIM_Base_Stop(&htim3);//15us高电平发送
HAL_TIM_Base_Start(&htim3);
htim3.Instance->CNT=0;
while(htim3.Instance->CNT<40000);//等待40us
HAL_TIM_Base_Stop(&htim3);
接收
标准库
void EXTI15_10_IRQHandler(void)//中断处理红外同步信号
{
//读取GPIO14中断线的状态
if(EXTI_GetITStatus(EXTI_Line10) == SET)
{
EXTI_ClearITPendingBit(EXTI_Line10);
get_dis();
}
}
unsigned char i_get=0;
extern int dis_1,dis_2,dis_3;
int count_temp=0;
int t_assist[2]={-30,-1950};//后两个模块接收计时校准参数
void get_dis()
{
t_count=0;
int i, j, N;
i_get=0;
TIM_Cmd(TIM2, ENABLE);
TIM2->CNT=0;
while(TIM2->CNT<270);//计时校准延时,实际可能需要用示波器或者逻辑分析仪查看
start_listen:
TIM2->CNT=0;//开始计时
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14)==Bit_SET&&TIM2->CNT<10000);//持续高电平等待低电平脉冲,也就是滤除干扰
sr04_dis[i_get]=TIM2->CNT;
TIM2->CNT=0;
goon://这里goto语句是两个及以上的发送模块时需要
while(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_14)==Bit_RESET)//记录低电平脉冲时间
if(TIM2->CNT>10||TIM2->CNT<4) goto goon;//过低或过高都重计
sr04_dis[i_get]+=(TIM2->CNT>20000)? 20000:TIM2->CNT;
t_count=sr04_dis[i_get];
sr04_dis[i_get]-=7;
i_get++;
TIM2->CNT=0;
while(TIM2->CNT<(40000-t_count-t_assist[i_get-1]));//等待40ms
if(i_get<3) goto start_listen;
end:
;
}
hal库,这个有问题,还没有修改,可参考标准库的代码修改
float get_dis()
{
i_get=0;
t_count=0;
int i, j, N;
while(i_get++<5)
{
HAL_TIM_Base_Start(&htim3);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_11,GPIO_PIN_SET);
htim3.Instance->CNT=0;
while(htim3.Instance->CNT<15);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_11,GPIO_PIN_RESET);
while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_12)==GPIO_PIN_RESET&&htim3.Instance->CNT<65000);
htim3.Instance->CNT=0;
while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_12)==GPIO_PIN_SET);
while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_12)==GPIO_PIN_SET);
while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_12)==GPIO_PIN_SET);
while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_12)==GPIO_PIN_SET);
while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_12)==GPIO_PIN_SET);
HAL_TIM_Base_Stop(&htim3);
t_count+=(htim3.Instance->CNT>35000)? 35000:htim3.Instance->CNT;
HAL_Delay(20);
}
sr04_dis=t_count/5.0;
return sr04_dis;
}