一.自定义协议
帧头1:0x5A
帧头1:0xA5
命令类型:
0x01 ADC 读取电压
0x02 外部flash写入
0x03 外部flash 读取
0x04 内部flash 写入
0x05 内部flash 读取
0x06 EEPROM 写入
0x07 EEPROM 读取
数据长度 :三位数据(接收数据不固定的情况下)
帧尾:0x16
帧头1 | 帧头2 | 数据类型 | 数据长度 | 地址 | 数据块 | 校验 |
---|---|---|---|---|---|---|
校验和 or 异或校验 or CRC校验 |
1.数据包较为复杂,先接收到数据缓存区中,在主程序处理。
uint8_t Rx_buf[MAX_REv_NUM]; //接收缓存区地址
void uart_service (uint_8 *buf)
{
unsigned char recv_index;
if(Rx_buf[recv_index+0] == 0x68); //判断第一个是不是帧头
{
if(Rx_buf[recv_index+1] == 0x68);
}
}
2.另一种在串口中断里,边接收边处理。接收一帧,判断是否为帧头,如果不是直接退出。
/*****************************/
//利用switch 做状态机,在中断内实现
unsigned char state = 0; //设置状态位
uint8_t Rx_buf[MAX_REv_NUM]; //接收缓存区地址
unsigned int Rw_buf; //写入和读取的数据
switch(state)
{
case 0:
Rx_buf[0] = SBUF;
if(Rx_buf[0] == 0x68)
{
state = 1;
cnt = 2;
}
else
{
state = 0;
}
break;
case 1 :
Rx_buf[cnt] = SBUF; //cnt 定时器计次
cnt++;
if(cnt > 4) //代表三帧数据接收完成
{
state = 2;
}
else
{
state = 1;
}
break;
case 2 :
Rx_buf[cnt] = SBUF;
if(Rx_buf[cnt] == 0x16) //已接收到帧尾
{
switch(Rx_buf[2])
{
case 1: //取buf内容赋值给 函数内容
Rw_buf = Rx_buf[3];
break;
case 2:
break;
default:
break;
}
}
break;
default:
break;
}
最后利用串口发送函数将 Rx_buf[ ] 发送出去
例如:
ADC 读取电压 : 68 01
外部flash:帧头1 5A 帧头2 A5 命令 02 长度 地址 数据 帧尾16
外部flash :
/*****************************/
uint8_t recv_data //串口接收数据保存
void USART1_IRQHandler(void)
{
static unsigned int flag = 1;
static unsigned int flag = 0; //只要求第一次为0,每次竟然不在初始化为0,所以用static 。
unsigned char state = 0; //设置状态位
uint8_t Rx_buf[MAX_REv_NUM]; //接收缓存区地址
unsigned char ch;
while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE) == SET)
{
if( ch == 0x68)
{
Rx_buf[0] =ch;
state = 1;
}
if(ch != 0x68 && flag ==1)
{
Rx_buf[i++] = ch;
if(i == 5)
{
flag = 0;
i=1;
if(arr[i] + arr[2]) ==arr[3]) && arr[4] ==0x16);
switch(arr[1])
{
case 0x01:
if(arr[2] == 0x01)
//实现0x01 功能
case 0x02:
}
}
主机——>下位机正常接收,需要返回一段指令
正确:0x5A A5 80 00 校验值
和校验错误:0x5A A5 81 00 校验值