协议说明
数据包头 | 命令 | 分片标志 | 数据 | 包尾 |
---|---|---|---|---|
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) {}
}
}