微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 第40节:常用的自定义串口通讯协议

第40节:常用的自定义串口通讯协议

时间:11-22 来源:互联网 点击:
开场白:

上一节讲了判断数据头的程序框架,但是在很多项目中,仅仅靠判断数据头还是不够的,必须要有更加详细的通讯协议,比如可以包含数据类型,数据地址,有效数据长度,有效数据,数据校验的通讯协议。这一节要教会大家三个知识点:

第一个:常用自定义串口通讯协议的程序框架。

第二个:累加校验和的校验方法。累加和的意思是前面所有字节的数据相加,超过一个字节的溢出部分会按照固定的规则自动丢弃,不用我们管。比如以下数据:

eb 00 55 01 00 02 0028 6b

其中eb 00 55为数据头,01为数据类型,00 02为有效数据长度,00 28 分别为具体的有效数据,6b为前面所有字节的累加和。累加和可以用电脑系统自带的计算器来验证。打开电脑上的计算器,点击“查看”下拉的菜单,选“科学型”,然后选左边的“十六进制”,最后选右边的“字节”,然后把前面所有的字节相加,它们的和就是6b,没错吧。

第三个:原子锁的使用方法,实际上是借鉴了"红金龙吸味"关于原子锁的建议,专门用来保护中断与主函数的共享数据。

具体内容,请看源代码讲解。

(1)硬件平台:

基于朱兆祺51单片机学习板

(2)实现功能:

波特率是:9600.

通讯协议:EB 00 55 GG HH HH XX XX …YYYY CY

其中第1,2,3位EB 00 55就是数据头

其中第4位GG就是数据类型。01代表驱动奉命,02代表驱动Led灯。

其中第5,6位HH就是有效数据长度。高位在左,低位在右。

其中第5,6位HH就是有效数据长度。高位在左,低位在右。

其中从第7位开始,到最后一个字节Cy之前,XX..YY都是具体的有效数据。

在本程序中,当数据类型是01时,有效数据代表蜂鸣器鸣叫的时间长度。当数据类型是02时,有效数据代表Led灯点亮的时间长度。

最后一个字节CY是累加和,前面所有字节的累加。

发送以下测试数据,将会分别控制蜂鸣器和Led灯的驱动时间长度。

蜂鸣器短叫发送:eb 00 55 01 00 02 00 28 6b

蜂鸣器长叫发送:eb 00 55 01 00 02 00 fa 3d

Led灯短亮发送:eb 00 55 02 00 02 00 28 6c

Led灯长亮发送:eb 00 55 02 00 02 00 fa3e

(3)源代码讲解如下:

#include "REG52.H"

/* 注释一:

* 请评估实际项目中一串数据的最大长度是多少,并且留点余量,然后调整const_rc_size的大小。

* 本节程序把上一节的缓冲区数组大小10改成了20

*/

#define const_rc_size 20 //接收串口中断数据的缓冲区数组大小

#define const_receive_time 5 //如果超过这个时间没有串口数据过来,就认为一串数据已经全部接收完,这个时间根据实际情况来调整大小

void initial_myself(void);

void initial_peripheral(void);

void delay_long(unsigned int uiDelaylong);

void T0_time(void); //定时中断函数

void usart_receive(void); //串口接收中断函数

void usart_service(void); //串口服务程序,在main函数里

void led_service(void); //Led灯的服务程序。

sbit led_dr=P3^5; //Led的驱动IO口

sbit beep_dr=P2^7; //蜂鸣器的驱动IO口

unsigned int uiSendCnt=0; //用来识别串口是否接收完一串数据的计时器

unsigned char ucSendLock=1; //串口服务程序的自锁变量,每次接收完一串数据只处理一次

unsigned int uiRcregTotal=0; //代表当前缓冲区已经接收了多少个数据

unsigned char ucRcregBuf[const_rc_size]; //接收串口中断数据的缓冲区数组

unsigned int uiRcMoveIndex=0; //用来解析数据协议的中间变量

/* 注释二:

* 为串口计时器多增加一个原子锁,作为中断与主函数共享数据的保护,实际上是借鉴了"红金龙吸味"关于原子锁的建议.

*/

unsigned char ucSendCntLock=0; //串口计时器的原子锁

unsigned int uiVoiceCnt=0; //蜂鸣器鸣叫的持续时间计数器

unsigned char ucVoiceLock=0; //蜂鸣器鸣叫的原子锁

unsigned char ucRcType=0; //数据类型

unsigned int uiRcSize=0; //数据长度

unsigned char ucRcCy=0; //校验累加和

unsigned int uiRcVoiceTime=0; //蜂鸣器发出声音的持续时间

unsigned int uiRcLedTime=0; //在串口服务程序中,Led灯点亮时间长度的中间变量

unsigned int uiLedTime=0; //Led灯点亮时间的长度

unsigned int uiLedCnt=0; //Led灯点亮的计时器

unsigned char ucLedLock=0; //Led灯点亮时间的原子锁

void main()

{

initial_myself();

delay_long(100);

initial_peripheral();

while(1)

{

usart_service(); //串口服务程序

led_service(); //Led灯的服务程序

}

}

void led_service(void)

{

if(uiLedCnt

{

led_dr=1; //开Led灯

}

else

{

led_dr=0; //关Led灯

}

}

void us

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top