下面是我写的一个完成多个下位机(单片机)与一个上位机(PC机)的一主多从串口通讯程序,用的STC89C52RC,定时器2做串口通讯波特率发生器。
完成功用是这样的:
用调试帮手向单片机发送一个数据包。
通讯协议是这样的:
数据包的格局如下所示(共10个字节组成):
0x2A,0xEB,0x8D,地址码,指令码,数据长度码,数据码,数据码,校验码,0xAD
前面三个字节为帧头,即开端符。
地址码: 欲传送的意图地址,即选定哪一个单片机。
指令码:向单片机发送的指令
数据长度码: 用于指示后边有用数据的个数
数据码:传送的数据,合作指令码的纯数据。
校验码: 累加和校验,对地址码,指令码,数据长度码,数据码进行累加,用来查验数据的完整性和正确性。
0xAD : 帧尾,即结束符。
本程序完成功用是这样的:
用调试帮手向单片机发送一个数据包,单片机收到后对数据解析,再回传指定的数据。
例如发送:2a eb 8d 01 03 01 01 06 ad
指令码为01,单片机接纳到后解析,回传0xce 0x7b 0x11 0xed。其间前两个字节为开端符,最终一个字节为结束符。同理,若收到的指令码为02,回传0xce 0x7b 0x12 0xed。以此模仿操控单片机操作。
若接纳过错,即累加校验码不等于单片机实践核算的累加和,回传0xce 0x7b 0x02 0xed,提示接纳过错,要求PC重发数据(模仿,需求上位机软件合作才行)。
单片机开机初始化后即向PC发送一个数据0xce 0x7b 0x00 0xed,用于指示单片机与PC通讯已衔接。
下面是程序:
#define ID 0x01 //单片机地址
uint8 rec_data; //串口通讯接纳数据
uint8 state_flag=0; //通讯协议解析状况标志,初始化为0
uint8 retval=0; //通讯协议解析函数返回值,初始化为0
uint8 cmd; //指令码
uint8 Data[2]; //数据码
uint8 data_count; //数据长度码
程序大体思维是:
首要界说了几个全局变量,接纳到数据后,串口中止子程序顶用变量rec_data存储一个字节的数据,随后对数据进行解析:首要判别数据包的完整性,正确性,然后提取指令码,数据码等数据,寄存起来用于主程序处理。
协议解析过程中,运用一个变量state_flag的全局变量作为协议解析状况标志,用于确认当时字节处于一帧数据中的那个部位,一起在接纳过程中主动对接纳数据进行校验和处理,在数据包接纳完的一起也进行了校验的比较。因而当帧尾结束符接纳到的时分,则表明一帧数据现已接纳结束,而且也经过了校验,要害数据也保存到了缓冲区(cmd和Data[])中。主程序即可经过查询retval的标志位来进行协议的解析处理。假如retval=1; //过错标志,数据包传送不正确。假如retval=2; //接纳成功标志,数据包传送成功。
接纳过程中,只需哪一步收到的数据不是预期值,则直接将状况标志复位,用于下一帧数据的判别,防止状况自锁。
以下是程序:
void PortInit(); //各端口初始化
void TimerInit(); //定时器初始化
void UsartInit(); //串口初始化
void usart_cmd_scan(); //串口指令扫描
void Data_analysis(); //通讯协议解析函数
void Send(uint8 sendcmd); //数据发送函数
/*——————————– 串口中止服务子程序 ————————————*/
void ser() interrupt 4
{
RI=0;
rec_data=SBUF; //读取接纳到的数据
Data_analysis();//数据解析
}
/*
* 函数名:Data_analysis
* 描 述:通讯协议解析函数
* 输 入:无
* 输 出:无
* 备 注:解析串口接纳到的数据