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

unsigned c har Gu8Re ceBuffer_B[R ECE_BUFFE R_SIZE]; //双缓 存其中 之一的缓存 B unsigned l ong Gu32R eceCnt_B=0; / /缓存 B 的数 组下标与计数 器,必须初始 化为 0,做好接收 准备 unsigned c har Gu8Re ceFeedDog=1; / /“喂狗” 的操作变量 。 unsigned c har Gu8Fi nishFlag…

100%1 / 836
上图 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,做好接收准备
unsigned char Gu8ReceBuffer_B[RECE_BUFFER_SIZE]; //双缓存其中之一的缓存 B
unsigned long Gu32ReceCnt_B=0; //缓存 B 的数组下标与计数器,必须初始化为 0,做好接收准备
unsigned char Gu8ReceFeedDog=1; //“喂狗”的操作变量
unsigned char Gu8FinishFlag=0; //接收完成标志。0 代表还没有完成,1 代表已经完成了一次接收
volatile unsigned char vGu8ReceTimeOutFlag=0;//通信过程中字节之间的超时定时器的开关
volatile unsigned int vGu16ReceTimeOutCnt=0; //通信过程中字节之间的超时定时器,“喂狗”的对象
volatile unsigned char vGu8BeepTimerFlag=0;
volatile unsigned int vGu16BeepTimerCnt=0;
void main()
{
SystemInitial();
Delay(10000);
PeripheralInitial();
while(1)
{
UsartTask(); //串口接收的任务函
}
}
void usart(void) interrupt 4
{
if(1==RI)
{
RI = 0;
Gu8FinishFlag=0; //此处也清零,意味深长,当主函数正在处理数据时,可以兼容多次接收完
Gu8ReceFeedDog=1; //看门狗的“喂狗”操作,给软件定时器继续“输血
if(0==Gu8CurrentReceBuffer_Sec) //0 代表选择缓 A
{
if(Gu32ReceCnt_A<RECE_BUFFER_SIZE)
{
Gu8ReceBuffer_A[Gu32ReceCnt_A]=SBUF;
Gu32ReceCnt_A++; //记录当前缓存 A 的接收字节数
}
}
else //1 代表选择缓 B
{
if(Gu32ReceCnt_B<RECE_BUFFER_SIZE)
{
Gu8ReceBuffer_B[Gu32ReceCnt_B]=SBUF;
Gu32ReceCnt_B++; //记录当前缓存 B 的接收字节
}
}
}
else //发送数据引起的中
{
TI = 0; //及时清除发送中断的标志,避免一直无缘无故的进入中断。
//以下可以添加一个全局变量的标志位的相关代码,通知主函数已经发送完一个字节的数据了。
}
}
void UsartTask(void) //串口接收的任务函数,放在主函数内
{
static unsigned char *pSu8ReceBuffer; //“指针切换关联”中的指针,切换内存
static unsigned char Su8Lock=0; //用来避免一直更新的临时变量
static unsigned long i; //用在数据处理中的循环变量
static unsigned long Su32ReceSize=0; //接收到的数据大小的临时变量
if(1==Gu8ReceFeedDog) //每被“喂一次狗,就及时更新一次“超时检测的定时器”的初值
{
Gu8ReceFeedDog=0;
Su8Lock=0; //解锁。用来避免一直更新的临时变量
//以下三行代码是看门狗中的“喂狗”操作。继续给软件定时器“输血”
vGu8ReceTimeOutFlag=0;
vGu16ReceTimeOutCnt=DOG_TIME_OUT;//正在通信时,两个字节间隔的最大时间,本节选用 20ms
vGu8ReceTimeOutFlag=1;
}
else if(0==Su8Lock&&0==vGu16ReceTimeOutCnt) //超时,代表一串数据已经接收完成
{
Su8Lock=1; //避免一直进来更新
Gu8FinishFlag=1; //两个字节之间的时间超时,因此代表了一串数据已经接收完
}
if(1==Gu8FinishFlag) //1 代表已经接收完毕一串新的数据,需要马上去处理
{
if(0==Gu8CurrentReceBuffer_Sec)
{
Gu8CurrentReceBuffer_Sec=1; //以最快的速度先切换接收内存,避免丢失新发过来的数据