单片机与PC机多机通讯的程序

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

下面是我写的一个实现多个下位机(单片机)与一个上位机(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

* 描述:通信协议解析函数

* 输入:无

* 输出:无

* 备注:解析串口接收到的数据

/*-------------------------------- 多机通信协议格式------------------------------------*/ /* 数据包的格式如下所示(共10个字节组成):*/

/* 0x2A,0xEB,0x8D,地址码,指令码,数据长度码,数据码,数据码,校验码,0xAD */

void Data_analysis()

{

static uchar recdata_sum=0; //存放累加和

static uchar lencnt=0; //数据长度计数器

switch (state_flag)

{

case 0:

{

if(rec_data == 0x2A) // 是否帧头第一个数据

state_flag = 1;

else

state_flag = 0; // 标志复位

break;

}

case 1:

{

if(rec_data == 0xEB) // 是否帧头第二个数据

state_flag = 2;

else

state_flag = 0; // 标志复位

break;

}

case 2:

{

if(rec_data == 0x8D) // 是否帧头第三个数据

state_flag = 3;

else

state_flag = 0; // 标志复位

break;

}

case 3:

{

if(rec_data == ID) // 判断目的地址是否正确

{

state_flag = 4;

recdata_sum=rec_data; //开始累加

}

else

state_flag = 0; // 标志复位

break;

}

case 4:

{

state_flag = 5;

cmd=rec_data; //指令码存储

recdata_sum+=rec_data; //累加

break;

}

case 5:

{

lencnt = 0; //数据长度计数器清零

data_count=rec_data; //数据长度码存储

recdata_sum+=rec_data; //累加

if (data_count!=0) //后面有数据码

state_flag=6;

else

state_flag=8;

相关文档
最新文档