从单片机基础到程序框架(全集 2019pdf版).pdf - 第809页
上图 134.5.1 设置 编译的环境 【134.7 例程的上位机程序。 】 #include " REG52.H" #define RE CE_TIME_O UT 2000 //通讯 过程中字节之 间的超时 时间 2000ms #define RE C_BUFFER_ SIZE 30 //常规 控制类数组的 长度 #define KE Y_FILTER_ TIME 25 //按键 滤波的“稳定 时间” void u…
00 00 00 07 代表整个指令的数据长度。
ED 是前面所有字节数据的异或结果,用来作为校验数据。
(2)下位机返回十六进制的数据:EB 01 00 00 00 0C XX XX XX XX ZZ。
EB 是数据头。
01 是指令类型,01 代表返回大数组的容量大小。
00 00 00 0B 代表整个指令的数据长度
XX XX XX XX 代表大数组的容量大小
ZZ 是前面所有字节数据的异或结果,用来作为校验数据。
(三)上位机读取下位机的大数组的分段数据的指令。
(1)上位机发送十六进制的数据:EB 02 00 00 00 0F RR RR RR RR YY YY YY YY ZZ
EB 是数据头
02 是指令类型,02 代表请求下位机返回当前分段的数据。
00 00 00 0F 代表整个指令的数据长度
RR RR RR RR 代表请求下位机返回的数据的“请求起始地址”
YY YY YY YY 代表请求下位机从“请求起始地址”一次返回的数据长度
ZZ 是前面所有字节数据的异或结果,用来作为校验数据。
(2)下位机返回十六进制的数据:EB 02 TT TT TT TT RR RR RR RR YY YY YY YY HH ...HH ZZ
EB 是数据头
02 是指令类型,02 代表返回大数组当前分段的数据
TT TT TT TT 代表整个指令的数据长度
RR RR RR RR 代表下位机返回数据时的“请求起始地址”
YY YY YY YY 代表下位机从“请求起始地址”一次返回的数据长度
HH ...HH 代表中间有效的数据内容
ZZ 是前面所有字节数据的异或结果,用来作为校验数据。
【134.6 解决本节例程编译不过去的方法。】
因为本节用到的全局变量比较多,如果有初学者在编译的时候出现“error C249: 'DATA': SEGMENT TOO
LARGE”的提示,请按下图的窗口提示来设置一下编译的环境。

上图 134.5.1 设置编译的环境
【134.7 例程的上位机程序。】
#include "REG52.H"
#define RECE_TIME_OUT 2000 //通讯过程中字节之间的超时时间 2000ms
#define REC_BUFFER_SIZE 30 //常规控制类数组的长度
#define KEY_FILTER_TIME 25 //按键滤波的“稳定时间”
void usart(void); //串口接收的中断函数
void T0_time(); //定时器的中断函数
void BigBufferUsart(void); //读取下位机大数组的“通讯过程的控制涵数”。三大核心函数之一
void QueueSend(void); //发送的队列驱动涵数。三大核心函数之一
void ReceDataHandle(void); //接收数据后的处理涵数。三大核心函数之一
void UsartTask(void); //串口收发的任务函数,放在主函数内
unsigned char CalculateXor(const unsigned char *pCu8Buffer, //异或的算法函数
unsigned long u32BufferSize);
//比较两个数组的是否相等。返回 1 代表相等,返回 0 代表不相等
//u32BufferSize 是参与对比的数组的大小
unsigned char CmpTwoBufferIsSame(const unsigned char *pCu8Buffer_1,
const unsigned char *pCu8Buffer_2,
unsigned long u32BufferSize);
void UsartSendByteData(unsigned char u8SendData); //发送一个字节的底层驱动函数

//发送带协议的函数
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 为通讯失败