协议设计练习
2016-07-04 19:00
330 查看
协议说明
数据包头 | 命令 | 分片标志 | 数据 | 包尾 |
---|---|---|---|---|
1字节 | 1字节 | 1字节 | n字节 | 2字节 |
包头:0xaa
包尾:0x0d 0x0a
命令:0x01 查询从机状态
0x02 数据请求
0x03 控制命令
发送信息示例:
查询命令:0xaa | 0x01 | 0x00 | 0x0d 0x0a
数据请求:0xaa | 0x02 | 0x00 | 0x0d 0x0a
控制命令:0xaa | 0x03 | 0x00 | 0x01 | 0x00 | 0x0d | 0x0a
(字节编号从0开始)字节3为执行器(0x01led灯,0x02beep,0x03风扇)
字节4为执行器的开关(0x00关,0x01开)
从机—->主机:
包头:0xbb
包尾:0x0d 0x0a
命令:0x01 就绪
0x02 忙
0x03 出错
0x11 命令执行成功
0x12 忙
0x13 命令执行出错,命令不存在
发送信息示例:
0xbb | 0x01 | 0x01 | data | 0x0d 0x0a
0xbb | 0x11 | 0x00 | 0x01 | 0x00 | 0x0d 0x0a
(字节编号从0开始)字节3为执行器(0x01led灯,0x02beep,0x03风扇)
字节4为执行器的状态(0x00关,0x01开)
协议示例
下面是一个stm32f103中蓝牙透传的协议的练习,蓝牙使用串口3。为了简便此协议并没有实现校验。由于安卓中蓝牙每次接收数据最大长度只有20字节,故将数据包进行拆包,数据报最大长度为20字节。
数据拆包传输完整的实现了,从机状态信息函数void slaveState()没有根据现实的机器信息进行反馈,
只简单返回了一个信息。主机控制从机的部分,采取一次行发送所有控制信息,没有再进行细分。
#ifndef _protocal_H #define _protocal_H #include "usart.h" //包头 #define HOST_TO_SLAVE_H 0xaa //主机->从机 包头 #define SLAVE_TO_HOST_H 0xbb //从机->主机 包头 #define MESSAGE_TAIL_F 0x0d //包尾结束标志 0x0d 0x0a #define MESSAGE_TAIL_B 0x0a #define DIVIDE_ENABLE 0x01 //有分片 #define DIVIDE_DISABLE 0x00 //无分片 //主机->从机 命令 #define HOST_CMD_CHECK 0x01 //查询从机状态 #define HOST_CMD_READ 0x02 //读取从机数据 #define HOST_CMD_WRITE 0x03 //向从机中写入数据 //从机->主机 从机状态命令 #define SLAVE_STA_READY 0x01 //从机准备就绪 #define SLAVE_STA_BUSY 0x02 //从机忙 #define SLAVE_STA_ERROR 0x03 //从机出错 //从机->主机 从机执行状态命令 #define SLAVE_EXU_SUCCE 0x11 //命令执行成功 #define SLAVE_EXU_BUSY 0x12 //从机忙 #define SLAVE_EXU_ERROR 0x13 //命令执行出错,命令不存在 //执行器 #define LEDCONTROL 0x01 #define BEEPCONTROL 0x02 #define FANCONTROL 0x03 #define ONSTATE 0x01 //开 #define OFFSTATE 0x00 //关 #define MES_HEAD_LEN 3 //包头长度 #define MES_TAIL_LEN 2 //包尾长度 enum MixData { TMPH, TMPL, //温度 HUMH, HUML, //湿度 PRETH,PRETL, // bmp1750 ut值 PRESH, PRESL, // bmp1750 up值 LIGH, LIGL, //光强 PRE_REG_AC1H, PRE_REG_AC1L, //bmp1750 ac1-ac6,b1,b2,mb-md的值 PRE_REG_AC2H, PRE_REG_AC2L, PRE_REG_AC3H, PRE_REG_AC3L, PRE_REG_AC4H, PRE_REG_AC4L, PRE_REG_AC5H, PRE_REG_AC5L, PRE_REG_AC6H, PRE_REG_AC6L, PRE_REG_B1H, PRE_REG_B1L, PRE_REG_B2H, PRE_REG_B2L, PRE_REG_MBH, PRE_REG_MBL, PRE_REG_MCH, PRE_REG_MCL, PRE_REG_MDH, PRE_REG_MDL, TOTAL_DATA }; extern unsigned char All_Info_Char[TOTAL_DATA]; //信息数组,将传感器采集的信息放入此数组中,存储次序为上方的MixData表 int messageAnalysis(u8 USART_RX_BUF[USART_REC_LEN]); //报文解析 void slaveState(); void slaveSendM(); void slaveRecM(u8 USART_RX_BUF[USART_REC_LEN]);
#include "protocal.h" #include "crc16.h" #include "app.h" #include "string.h" #include "delay.h" unsigned char All_Info_Char[TOTAL_DATA] = {0}; int messageAnalysis(u8 USART_RX_BUF[USART_REC_LEN]) //报文解析 { if(USART_RX_STA&0x8000) { //当包尾为0d 0a时进行处理 if(USART_RX_BUF[1] == HOST_CMD_CHECK) { slaveState(); USART_RX_STA = 0; }else if(USART_RX_BUF[1] == HOST_CMD_READ) { slaveSendM(); USART_RX_STA = 0; }else if(USART_RX_BUF[1] == HOST_CMD_WRITE) { slaveRecM(USART_RX_BUF); USART_RX_STA = 0; }else{ USART_RX_STA = 0; } } } void slaveState() { unsigned char message[7] = {0}; message[0] = SLAVE_TO_HOST_H; message[1] = SLAVE_EXU_SUCCE; message[2] = DIVIDE_DISABLE; message[5] = MESSAGE_TAIL_F; message[6] = MESSAGE_TAIL_B; message[3] = LEDCONTROL; //执行器 message[4] = LedState; //状态 USART_SendMessage(USART3, message, 7); delay_ms(50); message[3] = BEEPCONTROL; message[4] = BeepState; USART_SendMessage(USART3, message, 7); delay_ms(50); message[3] = FANCONTROL; message[4] = FanState; USART_SendMessage(USART3, message, 7); delay_ms(50); } void slaveSendM() //从机向主机发送信息 { int i = 0,j = 0, len; volatile int k = 0; int totaldata = TOTAL_DATA; unsigned char message[TOTAL_DATA+MES_HEAD_LEN+MES_TAIL_LEN] = {0}; for(i = 0; i < TOTAL_DATA / 15; i++) { //分片,每片最多20字节 message[0] = SLAVE_TO_HOST_H; message[1] = SLAVE_STA_READY; message[2] = DIVIDE_ENABLE; for(j = MES_HEAD_LEN; j < 15 + MES_HEAD_LEN; j++, k++) { message[j] = All_Info_Char[k]; } message[18] = MESSAGE_TAIL_F; message[19] = MESSAGE_TAIL_B; USART_SendMessage(USART1, message, 20); delay_ms(10); } len = k; message[0] = SLAVE_TO_HOST_H; message[1] = SLAVE_STA_READY; message[2] = DIVIDE_DISABLE; for(j = MES_HEAD_LEN; j < TOTAL_DATA+MES_HEAD_LEN - k; j++, k++) { message[j] = All_Info_Char[k]; } message[TOTAL_DATA+MES_HEAD_LEN+MES_TAIL_LEN -len-2] = MESSAGE_TAIL_F; message[TOTAL_DATA+MES_HEAD_LEN+MES_TAIL_LEN - 1-len] = MESSAGE_TAIL_B; USART_SendMessage(USART1, message, TOTAL_DATA+MES_HEAD_LEN+MES_TAIL_LEN - len); } void slaveRecM(u8 USART_RX_BUF[USART_REC_LEN]) { // USART_SendMessage(USART3, "ok3", 3); unsigned char message[7] = {0}; if(USART_RX_BUF[3] == LEDCONTROL) { LED_Cont(USART_RX_BUF[4]); LedState = USART_RX_BUF[4]; message[1] = SLAVE_EXU_SUCCE; }else if(USART_RX_BUF[3] == BEEPCONTROL) { Buzzer_Cont(USART_RX_BUF[4]); BeepState = USART_RX_BUF[4]; message[1] = SLAVE_EXU_SUCCE; }else if(USART_RX_BUF[3] == FANCONTROL) { Fan_Cont(USART_RX_BUF[4]); FanState = USART_RX_BUF[4]; message[1] = SLAVE_EXU_SUCCE; }else { message[1] = SLAVE_EXU_ERROR; } message[0] = SLAVE_TO_HOST_H; message[2] = DIVIDE_DISABLE; message[3] = USART_RX_BUF[3]; //执行器 message[4] = USART_RX_BUF[4]; //状态 message[5] = MESSAGE_TAIL_F; message[6] = MESSAGE_TAIL_B; USART_SendMessage(USART3, message, 7); }
串口1的中断处理函数,作用是当判断收到的信息为aa时开始接收,将信息放入USART_RX_BUF数组中,当信息为0d 0a时,结束接收。交与下面进行报文的解析。
#define USART_REC_LEN 200 //定义最大接受字节数 200 u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大接收USART_REC_LEN个字符 //接收状态 //bit15, 接收完成标志 //bit14, 接收到0x0d //bit13~0 接收到的有效字节数 u16 USART_RX_STA=0; //接收状态标记 u16 USART_RX_S_STA=0; //帧起始标志 void USART1_IRQHandler(void) //串口1中断服务程序 { uint16_t Res; if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(aa开始0d0a结束) { Res =USART_ReceiveData(USART1); //(USART1->DR); //读取收到的数据 // USART_SendData(USART1,Res); if(Res == HOST_TO_SLAVE_H && USART_RX_S_STA == 0) { //包头标志0xaa USART_RX_S_STA = 1; } if(USART_RX_S_STA) { if((USART_RX_STA&0x8000)==0) //接收未完成 { if(USART_RX_STA&0x4000) //接收到0x0d { if(Res!=0x0a)USART_RX_STA=0; //接收错误,重新开始 else { USART_RX_STA|=0x8000; //接收完成 //bit31表明是否接收到0x0a USART_RX_BUF[USART_RX_STA&0X3FFF]= '\0'; USART_RX_S_STA = 0; } } else //还没接收到0x0d { if(Res==0x0d) USART_RX_STA|=0x4000; //bit30表明是否接收到0x0d else { USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ; USART_RX_STA++; if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收 } } } // printf("%s", USART_RX_BUF); } } void USART_SendMessage(USART_TypeDef* USARTx, u8 *buf, u8 len) { u8 i; for (i = 0; i < len; i++) { USART_SendData(USARTx,buf[i]); while (USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET) {} } }
相关文章推荐
- 我是运营,我没有假期
- Linux C函数参考手册(PDF版)
- 一步一步跟我学易语言之第二个易程序菜单设计
- DB2数据库的安装
- C#实现把指定数据写入串口
- “传奇”图象数据存储方式
- C# partial关键字说明
- 修复mysql数据库
- Lua教程(十七):C API简介
- 简单谈谈lua和c的交互
- C#用链式方法表达循环嵌套
- 浅析SQL数据操作语句
- SQLServer 数据导入导出的几种方法小结
- 简述MySQL分片中快速数据迁移
- MySQL数据备份之mysqldump的使用详解
- C#实现窗体间传递数据实例
- 基于逻辑运算的简单权限系统(原理,设计,实现) VBS 版
- C#中的委托数据类型简介
- 51CTO学院新课发布~~带你遇见更好的自己(二))(2017.10.23-10.29)