从单片机基础到程序框架(全集 2019pdf版).pdf - 第811页
}; unsigned c har Gu8Qu eueReceUpdat e=0; //1 代表“队列 发送数据后, 收到了 新的数据” struct Struc tBigBuffe rUsart GtBig BufferUsart ;//此结构体变 量专门 用来控制读取 大数组的通讯 事件 volatile u nsigned c har vGu8BigB ufferUsar tTimerFlag=0 ; //过程控制的 超时定时器 …

//发送带协议的函数
void UsartSendMessage(const unsigned char *pCu8SendMessage,unsigned long u32SendMaxSize);
void SystemInitial(void) ;
void Delay(unsigned long u32DelayTime) ;
void PeripheralInitial(void) ;
void BeepOpen(void);
void BeepClose(void);
void VoiceScan(void);
void KeyScan(void);
void KeyTask(void);
sbit P3_4=P3^4; //蜂鸣器的驱动输出口
sbit KEY_INPUT1=P2^2; //K1 按键识别的输入口。
//下面表格数组的数据与下位机的表格数据一模一样,目的用来检测接收到的数据是否正确
code unsigned char Cu8TestTable[]=
{
0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,
0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,
0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,
0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,
0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,
0x51,0x52,0x53,0x54,0x55,0x56,0x57
};
unsigned char Gu8ReceTable[57]; //从下位机接收到的表格数据的数组
//把一些针对某个特定事件的全局变量放在一个结构体内,可以让全局变量的分类更加清晰
struct StructBigBufferUsart //控制读取大数组的通讯过程的结构体
{
unsigned char u8Status; //通讯过程的状态 0 为初始状态 1 为通讯成功 2 为通讯失败
unsigned char u8ReSendCnt; //重发计数器
unsigned char u8Step; //通讯过程的步骤
unsigned char u8Start; //通讯过程的启动
unsigned long u32NeedSendSize; //一共需要发送的全部数据量
unsigned long u32AlreadySendSize; //实际已经发送的数据量
unsigned long u32CurrentAddr; //当前批次需要发送的起始地址
unsigned long u32CurrentSize; //当前批次从起始地址开始发送的数据量
unsigned char u8QueueSendTrig;//队列驱动函数的发送的启动
unsigned char u8QueueSendBuffer[30]; //队列驱动函数的发送指令的数组
unsigned char u8QueueStatus; //队列驱动函数的通讯状态 0 为初始状态 1 为通讯成功 2 为通讯失败

};
unsigned char Gu8QueueReceUpdate=0; //1 代表“队列发送数据后,收到了新的数据”
struct StructBigBufferUsart GtBigBufferUsart;//此结构体变量专门用来控制读取大数组的通讯事件
volatile unsigned char vGu8BigBufferUsartTimerFlag=0; //过程控制的超时定时器
volatile unsigned int vGu16BigBufferUsartTimerCnt=0;
volatile unsigned char vGu8QueueSendTimerFlag=0; //队列发送的超时定时器
volatile unsigned int vGu16QueueSendTimerCnt=0;
volatile unsigned char vGu8BeepTimerFlag=0;
volatile unsigned int vGu16BeepTimerCnt=0;
volatile unsigned char vGu8KeySec=0;
unsigned char Gu8SendByteFinish=0; //发送一个字节完成的标志
unsigned char Gu8ReceBuffer[REC_BUFFER_SIZE]; //常规控制类的小内存
unsigned char *pGu8ReceBuffer; //用来切换接收内存的“中转指针”
unsigned long Gu32ReceCntMax=REC_BUFFER_SIZE; //最大缓存
unsigned long Gu32ReceCnt=0; //接收缓存数组的下标
unsigned char Gu8ReceStep=0; //接收中断函数里的步骤变量
unsigned char Gu8ReceFeedDog=1; //“喂狗”的操作变量。
unsigned char Gu8ReceType=0; //接收的数据类型
unsigned char Gu8Rece_Xor=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(); //串口收发的任务函数
KeyTask();
}

}
void KeyTask(void) //按键任务函数,放在主函数内
{
if(0==vGu8KeySec)
{
return; //按键的触发序号是 0 意味着无按键触发,直接退出当前函数,不执行此函数下面的代码
}
switch(vGu8KeySec) //根据不同的按键触发序号执行对应的代码
{
case 1: //1 号按键。K1 的独立按键
//GtBigBufferUsart.u8Start 在开机初始化函数里必须初始化为 0!这一步很关键!
if(0==GtBigBufferUsart.u8Start) //只有在还没有启动的情况下,才能启动
{
GtBigBufferUsart.u8Status=0; //通讯过程的状态 0 为初始状态
GtBigBufferUsart.u8Step=0; //通讯过程的步骤 0 为从当前开始的步骤
GtBigBufferUsart.u8Start=1; //通讯过程的启动
}
vGu8KeySec=0; //响应按键服务处理程序后,按键编号必须清零,避免一致触发
break;
}
}
/* 注释一:
* 每一个通讯事件都对应的一个独立的“通讯过程的控制涵数”,一个系统中有多少个通讯事件,就存在
* 多少个“通讯过程的控制涵数”。该函数负责某个通讯事件从开始到结束的整个过程。比如本节项目,
* 在通讯过程中,如果发现接收到的数据错误,则继续启动重发的机制。当发现接收到的累加字节数等于
* 预期想要接收的数量时,则结束这个通讯的事件。
*/
void BigBufferUsart(void) //读取下位机大数组的“通讯过程的控制涵数”
{
static const unsigned char SCu8ReSendCntMax=3; //重发的次数
static unsigned long *pSu32Data; //用于数据与数组转换的指针
switch(GtBigBufferUsart.u8Step) //过程控制,我首选 switch 语句!
{
case 0:
if(1==GtBigBufferUsart.u8Start) //通讯过程的启动
{
//根据实际项目需要,在此第 0 步骤里可以添加一些初始化相关的数据
GtBigBufferUsart.u8ReSendCnt=0; //重发计数器清零