搞了2整天的协议,查阅了很多博客,资料,对自定义数据传输大体都是这样:
帧头、地址信息、数据类型、数据长度、数据块、校验码、帧尾
那么首先说一下吧,之前我也不是很了解这个,直到我替人做了一个双机通讯的的例子后,发现接收端一直是丢数据或者显示错误数据,这时候,我才想到了定制自己的串口协议。本程序参考了坚哥的跟MODBUS。
接下来,我说一下自己定义的协议吧:
一帧数据总共有7个数据,分别为:
eb 01 30 xx xx 39 ed
eb 02 30 xx xx 39 ed
定义种类两种,如上面两行:
eb:数据头
01、02:功能位
30、39:校验和位
ed:数据尾
xx xx:数据位
我的程序实现功能是,当接收到数据串1时,执行LED1状态翻转
当接收到数据串2时,执行LED2状态翻转
首先来看个思维导图吧:
就是这么个思路,接下来自己看程序吧,很详细,简短:
#include "reg52.h"
typedef unsigned char uchar;
typedef unsigned int uint;
typedef unsigned long ulong;
sbit LED1 = P1^0;
sbit LED2 = P1^2;
uchar BUF[10]; //数据存储缓冲区
uchar Usart_Step; //用来切换程序步
uchar Usart_Cnt; //用来计数接收到数据的个数
uint LED1_Date_Move;//用来了;累计计数
uint LED2_Date_Move;
bit LED1_Flag;//LED状态
bit LED2_Flag;
void Usart_Init(void)
{
SCON = 0x50;
TMOD |= 0x20;
TL1 = TH1 = 0xfd;
TR1 = 1;
ES = 1;
EA = 1;
}
void main(void)
{
Usart_Init();
while(1)
{
if(LED1_Flag)//标记位为1时执行状态翻转
{
LED1_Flag = 0;
LED1 = !LED1;
}
if(LED2_Flag)//标记位为1时执行状态翻转
{
LED2_Flag = 0;
LED2 = !LED2;
}
}
}
void USART_IRQ() interrupt 4
{
if(RI) //接收中断标记位
{
RI = 0; //清除中断标记
switch(Usart_Step)
{
case 0: //进入程序步0
{
BUF[0] = SBUF; //缓冲区接收第一个数
if(BUF[0] == 0xeb) //判断是不是数据头
{
BUF[0] = 0; //清除以便下次接收数据
Usart_Cnt = 1; //计数加1
Usart_Step = 1; //切换到程序步1
}
}break;
case 1: //进入程序步1
{
BUF[Usart_Cnt] = SBUF; //将剩余的数据传送到缓冲区
Usart_Cnt++; //计数累加
if(Usart_Cnt >= 7) //当加到7个数时
{
if(BUF[6] == 0xed) //判断数据尾是不是为0xed
{
BUF[6] = 0; //清零数据尾,方便下次接收
switch(BUF[1]) //选择不同BUF【1】执行不同的功能
{
case 0x01: //数据0x01时
{
LED1_Date_Move = BUF[2];
LED1_Date_Move = LED1_Date_Move<<8;
LED1_Date_Move += BUF[5];//上面的三个步骤负责累加数值 0x30<<8+0x39(十六进制)=12345(十进制)
if(LED1_Date_Move == 12345)//判断累加数据是否为12345,进而准确接收数据位,当然我这没有写接收两个数据位实现什么
{
LED1_Flag = 1;//让标记位为1
}
}break;
case 0x02:
{
LED2_Date_Move = BUF[2];
LED2_Date_Move = LED2_Date_Move<<8;
LED2_Date_Move += BUF[5];//上面的三个步骤负责累加数值 0x30<<8+0x39(十六进制)=12345(十进制)
if(LED2_Date_Move == 12345)//判断累加数据是否为12345,进而准确接收数据位,当然我这没有写接收两个数据位实现什么
{
LED2_Flag = 1;//让标记位为1
}
}break;
}
}Usart_Step = 0;//数据解析完后,返回程序步0,执行下一帧数据
}break;
}
}
}
else
{
TI = 0;
}
}