从单片机基础到程序框架(全集 2019pdf版).pdf - 第791页

第一百三十二节: “转发、透传、多种协议并存”的双缓存串口程序框 架。 【132.1 字节间隔时间、双缓存切换、指针切换关联。 】 在一些通讯 模块的项目 中, 常常涉及数 据的转发, 透传, 提取关 键字的处理 , 单片机接收 到的数据不 许 随意丢失,必须全部暂存,然后提取关 键字,再把整包数据“原封不动”或者 “略作 修改”转发给“下家” 。 这类项目的 特点是, 通讯 协议不是固 定唯一的,因此, 前面章节那 种接头暗号(数据头…

100%1 / 836
BeepOpen();
}
else
{
vGu16BeepTimerCnt--;
if(0==vGu16BeepTimerCnt)
{
Su8Lock=0;
BeepClose();
}
}
}
}
第一百三十二节:“转发、透传、多种协议并存”的双缓存串口程序框架。
【132.1 字节间隔时间、双缓存切换、指针切换关联。
在一些通讯模块的项目中,常常涉及数据的转发,透传,提取关键字的处理单片机接收到的数据不
随意丢失,必须全部暂存,然后提取关键字,再把整包数据“原封不动”或者“略作修改”转发给“下家”
这类项目的特点是,通讯协议不是固定唯一的,因此,前面章节那种接头暗号(数据头)的程序框架不适
这里,本节跟大家分享另外一种程序框架。
第一个要突破的技术难点是,既然通讯协议不是固定唯一的那么,如何识别一串数据已经接收完毕?
答案是靠接收每个字节之间的间隔时间来识别。当一串数据正在接收时,每个字节之间的间隔时间是短暂
的相对均匀的”当一串数据已经接收完毕时每个字节之间的间隔时间是“突然变长的”代码的具体实现,
是靠一个软件定时器,模拟单片机“看门狗”的“喂狗”原理
第二个要突破的技术难点是,既然通讯协议不是固定唯一的数据内容带有随机性,甚至字节之间的间
隔时间的长短也带有随机性和不确定性,那么,如何预防正在处理数据时突然“接收中断”又接收到的新数
据覆盖了尚未来得及处理的旧数据,或者,如何预防正在处理旧数据时丢失了“突然又新过来的本应该
收的新数据”?答案是用双缓存轮流切换的机制。双缓存一个用在处理刚刚接收到的旧数据,另一个用在
时刻准备着接收新数据,轮流切换,两不误。
第三个要突破的技术难点是,既然是用双缓存轮流切换的机制,那么,在主程序里如何统一便捷地处
两个缓存的数组?这里的“统一”是关键,要把两个数组“统一”成(看成是)一个数组,方法是,只需用
“指针切换关联”的技术就可以了。
【132.2 程序例程。
上图 132.2.1 有源蜂鸣器电路
上图 132.2.2 232 串口电路
程序功能如下:单片机接收任意长度(最大一次不超 30 节)的一串数据。如果发现连续有三个字
节是 0x02 0x03 0x04,蜂鸣器则“短叫”100ms 提示;如果发现连续有四个字节是 0x06 0x07 0x08 0x09,
蜂鸣器则“长叫”2000ms 提示。
比如测试“短叫”100ms,发送十六进制的数据串:05 02 00 00 02 03 04 09
比如测试“长叫”2000ms,发送十六进制的数据串:02 02 06 07 08 09 01 08 03 00 05
代码如下:
#include "REG52.H"
#define DOG_TIME_OUT 20 //理论上,9600 波特率的字节间隔时间大 0.8ms 左右,因此取 20ms 足够
#define RECE_BUFFER_SIZE 30 //接收缓存的数组大小
void usart(void); //串口接收的中断函
void T0_time(); //定时器的中断函数
void UsartTask(void); //串口接收的任务函数,放在主函数内
void SystemInitial(void) ;
void Delay(unsigned long u32DelayTime) ;
void PeripheralInitial(void) ;
void BeepOpen(void);
void BeepClose(void);
void VoiceScan(void);
sbit P3_4=P3^4;
unsigned char Gu8CurrentReceBuffer_Sec=0; //当前接收缓存的选择标志。0 代表缓存 A,1 代表缓存 B
unsigned char Gu8ReceBuffer_A[RECE_BUFFER_SIZE]; //双缓存其中之一的缓存 A
unsigned long Gu32ReceCnt_A=0; //缓存 A 的数组下标与计数器,必须初始化为 0,做好接收准备