这两天买了个蓝牙模块研究,发现串口接收到的数据没有规律,不好检测到底接收完了没有。查阅了些资料发现了比较好的方法,为了帮助跟我一样的萌新可以更好的学习,我决定发个帖子,也算是给自己做个笔记。
1、IDLE中断
IDLE就是串口收到一帧数据后,发生的中断。什么是一帧数据呢?比如说给单片机一次发来1个字节,或者一次发来8个字节,这些一次发来的数据,就称为一帧数据,也可以叫做一包数据。
如何判断一帧数据结束,就是我们今天讨论的问题。因为很多项目中都要用到这个,因为只有接收到一帧数据以后,你才可以判断这次收了几个字节和每个字节的内容是否符合协议要求。
看到这个第一反应就是“好东西”,可惜51单片机好像没有,所以只是做了粗略的了解,有兴趣的各位可以去找些资料看看,随便查一下资料还挺多的
2、自定义结束符
在一帧数据尾部添加一个字符,比如传输的每一帧数据尾部都是“#”,当单片机接收到“#”后,说明已经接收完毕,然后立个Flag,就可以开始处理这些接收到的数据了,如下:
- u8 xdata RxLen=0; //接收计数
- u8 xdata RxFlag=0; //接收完毕标志位
- u8 xdata Uart4_Rx_Buffer[33]; //接收到的数据
- void Uart4_Init() //蓝牙串口4,选择定时器2为波特率发生器,波特率57600
- {
- S4CON = 0x10; //8位数据,可变波特率
- S4CON &= 0xBF; //串口4选择定时器2为波特率发生器
- AUXR |= 0x04; //定时器2时钟为Fosc,即1T
- T2L = 0x7E; //设定定时初值
- T2H = 0xFF; //设定定时初值
- AUXR |= 0x10; //启动定时器2
-
- IE2|=0X10; //打开串口中断4
- EA=1; //打开总中断
- }
- void S4_Routine() interrupt 18 //串口4中断函数
- {
- if(S4CON&0x01) //接收中断
- {
- S4CON&=0xFE; //清除接收中断
- Uart4_Rx_Buffer[RxLen]=S4BUF;
- if(Uart4_Rx_Buffer[RxLen] == '#') //是结束符,说明接收完毕,就可以拿着RxFlag出去搞事情了
- {
- RxFlag=1;
- }
- else //不是结束符,老实接收下一个数据
- {
- RxLen++;
- }
- }
- }
- void BLE_Allot() //数据分配
- {
- if(RxFlag)
- {
- RxFlag=0;
- RxLen=0;
- /*干一些你想干的事情*/
- }
- }
复制代码 3、用另外一个定时器检测
具体的思路是,因为每一位传输的时间间隔由波特率决定都是一样,所以每一个字节的传输时间也是一样的。那么我们每传输一个字节时,把定时器初值复位,以保证定时器不会溢出。定时器时间取传输一个字节的1.5倍,这样一来,当定时器超时时候,就意味着串口接收数据停止了。此时同样立一个flag开始处理这些接收到的数据,如下:
PS:大佬用的是滴答定时器,我发现51单片机还是没有,欲哭无泪,所以只好自己做一个了
- u8 xdata RxLen=0; //接收计数
- u8 xdata RxFlag=0; //接收完毕标志位
- u8 xdata Uart4_Rx_Buffer[33]; //接收到的数据
- void Timer1_Init() //定时器1初始化
- {
- AUXR |= 0x40; //定时器时钟1T模式
- TMOD &= 0x0F; //设置定时器模式
- TL1 = 0x82; //设置定时初值
- TH1 = 0xE7; //设置定时初值
- TF1 = 0; //清除TF1标志
- TR1 = 0; //这里先不开始计时,等传输信号的时候开始计时
-
- ET1=1;
- EA=1;
- }
- void Timer0_Rountine() interrupt 3
- {
- TR1 = 0; //定时器1停止计时
- TF1 = 0; //清除TF1标志
- RxFlag=1; //串口接收完毕
- }
- void Uart4_Init() //蓝牙串口4,选择定时器2为波特率发生器,波特率57600
- {
- S4CON = 0x10; //8位数据,可变波特率
- S4CON &= 0xBF; //串口4选择定时器2为波特率发生器
- AUXR |= 0x04; //定时器2时钟为Fosc,即1T
- T2L = 0x7E; //设定定时初值
- T2H = 0xFF; //设定定时初值
- AUXR |= 0x10; //启动定时器2
-
- IE2|=0X10; //打开串口中断4
- EA=1; //打开总中断
- }
- void S4_Routine() interrupt 18 //串口4中断函数
- {
- if(S4CON&0x01) //接收中断
- {
- S4CON&=0xFE; //清除接收中断
- Uart4_Rx_Buffer[RxLen]=S4BUF; //将数据放到数组中
- RxLen++; //下次进来数据存放地址+1
- TR1=0; //定时器1停止计时(这里搞了好久,一定要先停止,不然会出现错误)
- TL1=0x82; //设置定时初值
- TH1=0xE7; //设置定时初值
- TR1=1; //定时器1开始计时
- }
- }
- void BLE_Allot() //数据分配
- {
- if(RxFlag)
- {
- RxFlag=0; //标志清零
- RxLen=0; //计数清零
- /*干一些你想干的事情*/
- }
- }
复制代码 最后,感谢大佬在网上发布的好资料能给我们参考,也希望大佬能进来多讨论,多给点意见和建议
|