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

{ TI = 0; //及时 清除发送中断 的标志,避免 一直无 缘无故的进入 中断。 //以下可以添 加一个全局变 量的标志位的 相关代 码,通知主函 数已经发送完 一个字节的数 据了。 } } 【131.2 通信协议。 】 数据头( EB) :占 1 个字 节,作为“起始 字节” ,起 到“接头暗号 ”的作用,平 时用来 过滤无关的数 据。 数据类型( 01) :占用 1 个字 节。数据类型 是用来定义 这串数据 的用途。 数据长度…

100%1 / 836
Gu32ReceCnt++;
if(Gu32ReceCnt>=6) //前 6 个数据。接收完了“数据类型”和“数据长度”
{
Gu8ReceType=Gu8ReceBuffer[1]; //提取“数据类型”
pu32Data=(unsigned long *)&Gu8ReceBuffer[2];
Gu32ReceDataLength=*pu32Data; //提取“数据长度”
if(Gu32ReceCnt>=Gu32ReceDataLength) //靠“数据长度”来判断是否完成
{
Gu8FinishFlag=1; //接收完成标志“ 1”,通知主函数处理。
Gu8ReceStep=0; //及时切换回接头暗号的步
}
else //如果还没结束,继续切换到下一个步骤,接收“有效数据”
{
//以下几行代码是本节的破题关键!!!
if(0x02==Gu8ReceType) //如果是文件类,把指针关联到 Gu8FileBuffer
{
pGu8ReceBuffer=(unsigned char *)&Gu8FileBuffer[0];//下标 0
Gu32ReceCntMax=40+6; //最大缓存
}
else //如果是常规类,继续把指针关联 Gu8ReceBuffer 本身的数组
{
pGu8ReceBuffer=(unsigned char *)&Gu8ReceBuffer[6];//下标 6
Gu32ReceCntMax=20; //最大缓存
}
Gu8ReceStep=2; //切换到下一个步骤
}
}
break;
case 2: //“后部分的”数据
pGu8ReceBuffer[Gu32ReceCnt-6]=SBUF; //这里的指针就是各种不同内存的化身!!!
Gu32ReceCnt++; //每接收一个字节,数组下标都自 1,为接收下一个数据做准
//靠“数据长度”来判断是否完成。也不允许超过数组的最大缓存的长
if(Gu32ReceCnt>=Gu32ReceDataLength||Gu32ReceCnt>=Gu32ReceCntMax)
{
Gu8FinishFlag=1; //接收完成标志“置 1”,通知主函数处理。
Gu8ReceStep=0; //及时切换回接头暗号的步骤
}
break;
}
}
}
else //发送数据引起的中
{
TI = 0; //及时清除发送中断的标志,避免一直无缘无故的进入中断。
//以下可以添加一个全局变量的标志位的相关代码,通知主函数已经发送完一个字节的数据了。
}
}
【131.2 通信协议。
数据头(EB):占 1 个字节,作为“起始字节”,起到“接头暗号”的作用,平时用来过滤无关的数据。
数据类型(01):占用 1 个字节。数据类型是用来定义这串数据的用途。
数据长度(00 00 00 0B):占 4 个字节。用来告诉通信的对方,这串数据一共有多少个字节。
其它数据(03 E8):此数据根据不同的“数据类型”可以用来做不同的用途,根据具体的项目而定。
动态密匙(00 01):这两个字节代表一个 unsigned int 类型的数据,数据范围是 0 65535,但是考
虑到数据更加安全可靠,一般丢弃了首尾的 0(十六进制 00 00) 65535(十六进制的 FF FF)只保
1 65534 的变化。大部分的通信模型都是主机对从机“一问一应答”模式,也就是,主机每发送一条
指令给从机,从机才返回一条消息作为应答。如果主机发送了信息后,在规定的时间内,没有收到从机的应
答指令,主机就继续发送信息给从机,但是此时,从机本来应该应答主机当前指令的可能因为某种情况导
致反馈的信息发生了延时,导致此时应答的数据是主机的上一条指令,从而造成“一问一应答”的数据帧发
送了错位,这种情况加上“动态密匙就能使问题得到有效的解决。主机每发送一条信息,信息里都携带了
2 个字节的“动态密匙”从机每收到主机的一条信息在应答此信息时都把收到的“动态密匙”原封不动的
反馈给主机,主机再查看发送的“动态密匙”与接收到的“动态密匙”是否一致,以此来判断应答数据是否
有效。“动态密匙”像流水号一样,每发送一次指令后都累加 1,不断发生变化, 1 65534,依次循环
这是数据校验的一种方式
异或(0B)“异或”放在数据串的最后一个字节是前面所有字节的异或结果(不包括自己本身的字节)
比如:本例子中,数据串是:EB 01 00 00 00 0B 03 E8 00 01 0B。其中最后一个字节 0B 就是“异或”字
节,前面所有字节相“异或等于十六进制的 0B。验证“异或”的方法,可以借用电脑“附件”自带的“计
算器”软件来实现,打开“计算器”软件后,在“查看”的下拉菜单里,选择“程序员”,然后选择“十六
进制”该计算器软件的异或运算按键是“Xor。不管是主机还是从机,每接收到一串数据后,都要自己
算一次“异或”把自己计算得到的“异或”与接收到的最后一个字节“异或”进行对比,来判断接收到
的数据是否发生了丢失或者错误。
【131.3 程序例程。
上图 131.3.1 有源蜂鸣器电路
上图 131.3.2 232 串口电路
程序功能如下:
(9)单片机模拟从机,上位机的串口助手模拟主机。在上位机的串口助手里,发送一串数据,控制
鸣器发出不同长度的声音。数据类型为 01 时,把“后部分的”数据发送给“常规控制类内存”;数据类
型为 02 时,把“后部分的”数据发送给“文件类内存”
(10)本节因为还没有讲到数据发送的内容因此应答“动态密匙那部分的代码暂时不写,只写验证
“异或”那部分的代码。
(11)波特 9600,校验位 NONE(无),数据位 8,停止位 1。
(12)十六进制的数据格式: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 代表前面所有字节的异或结果。
比如:
数据类型 01,“后部分的”数据发给“常规控制类内存”,让蜂鸣器鸣叫 1000 毫秒,密匙为 00 01,
发送十六进制的:EB 01 00 00 00 0B 03 E8 00 01 0B
数据类型 02“后部分的”数据发给“文件类内存”,让蜂鸣器鸣 100 毫秒, 密匙为 00 02,发
送十六进制的:EB 02 00 00 00 0B 00 64 00 02 84
#include "REG52.H"
#define RECE_TIME_OUT 2000 //通信过程中字节之间的超时时间 2000ms
#define REC_BUFFER_SIZE 20 //常规控制类数组的长度
#define FILE_BUFFER_SIZE 40 //文件类数组的长度