超声波测距+蓝牙与App通信+控制开发板灯亮灭
模块:
超声波模块:VCC,GND,Trig(控制端),Echo(接收端)
蓝牙模块有:VCC,GND,TX,RX,STATE,EN
分析:
控制端需要初始化一个GPIO口,先拉高再拉低,持续10us,模块自动发送 8 个 40khz 的方波,自动检测是否有信号返回,有信号返回,通过 IO 输出一高电平,用32去检测高电平持续时间,高电平持续的时间就是超声波从发射到返回的时间.测试距离=(高电平时间声速 (340M/S))/2;
接收端需要检测模块该引脚的高电平持续时间,即初始化一个TIM(一个定时器有四个输入/输出通道),然后用输入捕获来测量时间,定时器中断函数可以用正点原子的代码,定义两个变量,TIM5CH1_CAPTURE_STA,TIM5CH1_CAPTURE_VAL。TIM5CH1_CAPTURE_STA的0~5标志着溢出次数,位6是捕获上升沿,位7是在捕获上升沿的基础上捕获到下降沿,即完成一次捕获的标志位。TIM5CH1_CAPTURE_VAL则是用来保存捕获比较寄存器的值即尾数。溢出次数定时器最大计数值(若设置为0XFFFF,72-1则是65535,72分频,一次计数就是1us)+TIM5CH1_CAPTURE_VAL即为超声波来返时间,通过声速即可计算出距离。
蓝牙模块选择串口三,32的PB10和PB11引脚,初始化USART3,开启接收中断,波特率9600,这里我借用了蓝牙模块配套的APP,虽然能接收到数据,但是APP不是自己做的,里面关于APP的发送和接受数据的机制就不太了解了,通过看与APP配套的STM32接收代码,可以知道APP里面每个键发送的数据是什么,然后在自己的中断函数中if判断该接收数据,可以实现App通过蓝牙控制开发板上的灯亮或灭。该蓝牙模块为BTO4,可以通过USB-TTL与电脑串口通信,在电脑XCOM上用AT指令可以查看配置蓝牙。
注意:
以下问题都是测试过程中遇到的问题
1,超声波模块需要5V供电。3.3V供电时也有数据,但是数据不对,且变化不太,即数据异常,发现5V供电后数据正常
2,定时器是计数满了之后,会有Updata即溢出更新事件,若开启溢出更新事件中断,可进入中断函数
3,超声波(即拉高拉低后延时60ms以上)建议测周期为 60ms 以上,以防止发射信号对回响信号的影响。
4,串口三要使用printf要修改相对应的USART1----------USART3,而且printf发送内容格式根据App有格式要求,而且从32发送到App需要延时一会,App的debug栏才会显示接收的数据
5,TIM5CH1_CAPTURE_STA状态标志位7,在主函数if判断了之后需要清0
6,串口可以开启接收中断,即RXNE(读寄存器非空),当该位为1时,就表示已经有数据接收到了,而且可以读出来了,即读USARTX->DR,通过读USARTX->DR可以使该位清0,若没有读,即RXNE没有置0,则会卡在中断函数中
代码:
…
//初始化定时器
//初始化GPIO
//初始化串口三
//中断分组也很重要(有些初始化函数里面若中断分组函数NVIC,则主函数不能再用中断分组,NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);,会出现意想不到的错误)
…
主函数
While(1)
{
//GPIO的拉高和延时和拉低
//不断判断TIM5CH1_CAPTURE_STA的位7,若满足条件加入if语句算出距离
//延时60ms以上以防止发射信号对回响信号的影响。
}
用到两个中断,要注意stm32收发数据和APP收发数据,stm32收数据用串口接收中断,发数据用
printf("{A%d:%d:%d:%d}$",distance,cnt,2,2);
两个中断函数,串口3和定时器
void USART3_IRQHandler(void)
{
if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
{
static int uart_receive=0;//蓝牙接收相关变量
uart_receive=USART_ReceiveData(USART3); //USART3->DR
if(uart_receive==0x59) PBout(5)=1;
if(uart_receive==0x58) PBout(5)=0;
}
}
void TIM5_IRQHandler(void)
{
//TIM_ClearITPendingBit(TIM5,TIM_IT_Update|TIM_IT_CC1);不能写在前面,因为后面函数还要判断标志位
if((TIM5CH1_CAPTURE_STA&0X80)==0)//还未成功捕获
{
if (TIM_GetITStatus(TIM5, TIM_IT_Update) != RESET)
{
if(TIM5CH1_CAPTURE_STA&0X40)//已经捕获到高电平了
{
if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//高电平太长了
{
TIM5CH1_CAPTURE_STA|=0X80;//标记成功捕获了一次
TIM5CH1_CAPTURE_VAL=0XFFFF;
}else TIM5CH1_CAPTURE_STA++;
}
}
if (TIM_GetITStatus(TIM5, TIM_IT_CC1) != RESET)//捕获1发生捕获事件
{
if(TIM5CH1_CAPTURE_STA&0X40) //捕获到一个下降沿
{
TIM5CH1_CAPTURE_STA|=0X80; //标记成功捕获到一次上升沿
TIM5CH1_CAPTURE_VAL=TIM_GetCapture1(TIM5);
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Rising); //CC1P=0 设置为上升沿捕获
}else //还未开始,第一次捕获上升沿
{
TIM5CH1_CAPTURE_STA=0; //清空
TIM5CH1_CAPTURE_VAL=0;
TIM_SetCounter(TIM5,0);
TIM5CH1_CAPTURE_STA|=0X40; //标记捕获到了上升沿
TIM_OC1PolarityConfig(TIM5,TIM_ICPolarity_Falling); //CC1P=1 设置为下降沿捕获
}
}
}
TIM_ClearITPendingBit(TIM5, TIM_IT_CC1|TIM_IT_Update); //清除中断标志位
}
硬件:
1,此模块不宜带电连接,如果要带电连接,则先让模块的 GND 端先连接。否则会影响模块工作。
2,测距时,被测物体的面积不少于 0.5 平方米且要尽量平整,否则会影响模块工作。