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

void BeepO pen(void) ; void BeepC lose(void ); void Voice Scan(void ); sbit P3_4= P3^4; volatile u nsigned c har vGu8Beep TimerFlag =0; volatile u nsigned i nt vGu16BeepTi merCnt=0; unsigned c har Gu8Re ceBuffer[REC _BUF…

100%1 / 836
上图 130.3.2 232 串口电路
程序功能如下:
(5)单片机模拟从机,上位机的串口助手模拟主机。在上位机的串口助手里,发送一串数据,控制
鸣器发出不同长度的声音
(6)本节因为还没有讲到数据发送的内容,因此应答“动态密匙”那部分的代码暂时不写,只写验证
“异或”那部分的代码。
(7)波特 9600,校验 NONE(无,数据位 8,停止位 1。
(8)十六进制的数据格式:EB 01 00 00 00 0B XX XX YY YY ZZ 。其中:
EB 是数据头。
01 是代表数据类型。
00 00 00 0B 代表数据长度是 11 个(十进制
XX XX 代表一个 unsigned int 的数据,此数据的大小决定了蜂鸣器发出声音的长度。
YY YY 代表一个 unsigned int 的动态密匙,每收发一条指令,此数据累加一次 1,范围 1 65534。
ZZ 代表前面所有字节的异或结果。
比如:
让蜂鸣器鸣 1000 毫秒,密匙 00 01,发送十六进制的:EB 01 00 00 00 0B 03 E8 00 01 0B
让蜂鸣器鸣 100 毫秒, 密匙 00 02,发送十六进制的:EB 01 00 00 00 0B 00 64 00 02 87
#include "REG52.H"
#define RECE_TIME_OUT 2000 //通信过程中字节之间的超时时间 2000ms
#define REC_BUFFER_SIZE 20 //接收数据的缓存数组的长度
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;
volatile unsigned char vGu8BeepTimerFlag=0;
volatile unsigned int vGu16BeepTimerCnt=0;
unsigned char Gu8ReceBuffer[REC_BUFFER_SIZE]; //开辟一片接收数据的缓存
unsigned long Gu32ReceCnt=0; //接收缓存数组的下
unsigned char Gu8ReceStep=0; //接收中断函数里的步骤变量
unsigned char Gu8ReceFeedDog=1; //“喂狗”的操作变量
unsigned char Gu8ReceType=0; //接收的数据类型
unsigned int Gu16ReceYY=0; //接收的动态密匙
unsigned char Gu8ReceZZ=0; //接收的异或
unsigned long Gu32ReceDataLength=0; //接收的数据长度
unsigned char Gu8FinishFlag=0; //是否已接收完成一串数据的标
unsigned long *pu32Data; //用于数据转换的指
volatile unsigned char vGu8ReceTimeOutFlag=0;//通信过程中字节之间的超时定时器的开关
volatile unsigned int vGu16ReceTimeOutCnt=0; //通信过程中字节之间的超时定时器,“喂狗”的对象
void main()
{
SystemInitial();
Delay(10000);
PeripheralInitial();
while(1)
{
UsartTask(); //串口接收的任务函
}
}
void usart(void) interrupt 4 //串口接发的中断函数,中断号为 4
{
if(1==RI) //接收完一个字节后引起的中断
{
RI = 0; //及时清零,避免一直无缘无故的进入中断。
/* 注释一:
* 以下 Gu8FinishFlag 变量的用途。
* 此变量一箭双雕,0 代表正处于接收数据的状态,1 代表已经接收完毕并且及时通知主函数中的处理函数
* UsartTask()去处理新接收到的一串数据。除此之外,还起到一种“自锁自保护”的功能,在新数据
* 没有被主函数处理完毕的时候,禁止接收其它新的数据,避免新数据覆盖了尚未处理的数据。
*/
if(0==Gu8FinishFlag) //1 代表已经完成接收了一串新数据,并且禁止接收其它新的数据
{
/* 注释二:
* 以下 Gu8ReceFeedDog 变量的用途。
* 此变量是用来检测并且识别通信过程中相邻的字节之间是否存在超时的情况。
* 如果大家听说过单片机中的“看门狗”这个概念,那么每接收到一个数据此变量就“置 1”一次,它的
* 作用就是起到及时“喂狗”的作用。每接收到一个数据此变量就“置 1”一次,在主函数里,相关
* 的定时器就会被重新赋值,只要这个定时器能不断及时的被补充新的“能量”新的值,那么这个定时器
* 就永远不会变成 0,只要不变成 0 就不会超时。如果两个字节之间通信时间超过了固定的长度,就意
* 着此定时器变成了 0,这时就需要把中断函数里的接收步骤 Gu8Step 及时切换到“接头暗号”的步骤。
*/
Gu8ReceFeedDog=1; //每接收到一个字节的数据,此标志就置 1 及时更新定时器的值。
switch(Gu8ReceStep)
{
case 0: //接头暗号的步骤。判断数据头的步骤。
Gu8ReceBuffer[0]=SBUF; //直接读取刚接收完的一个字节的数据
if(0xeb==Gu8ReceBuffer[0]) //等于数据头 0xeb,接头暗号吻合。
{
Gu32ReceCnt=1; //接收缓存的下标
Gu8ReceStep=1; //切换到下一个步骤,接收其它有效的数据
}
break;
case 1: //数据类型和长度
Gu8ReceBuffer[Gu32ReceCnt]=SBUF; //直接读取刚接收完的一个字节的数据。
Gu32ReceCnt++; //每接收一个字节,数组下标都自 1,为接收下一个数据做准
if(Gu32ReceCnt>=6) //前 6 个数据。接收完了“数据类型”和“数据长度”
{
Gu8ReceType=Gu8ReceBuffer[1]; //提取“数据类型”
//以下的数据转换,在第 62 节讲解过的指针法
pu32Data=(unsigned long *)&Gu8ReceBuffer[2]; //数据转换
Gu32ReceDataLength=*pu32Data; //提取“数据长度”
if(Gu32ReceCnt>=Gu32ReceDataLength) //靠“数据长度”来判断是否完成
{
Gu8FinishFlag=1; //接收完成标志“ 1”,通知主函数处理。
Gu8ReceStep=0; //及时切换回接头暗号的步
}
else //如果还没结束,继续切换到下一个步骤,接收“其它数据”
{
Gu8ReceStep=2; //切换到下一个步骤
}