uart与uart之间的通信(协议、队列缓存)
本文基于stm32介绍usat之间的通信,最主要的介绍基于在usat协议基础上再次封装自己的协议,以及接受usat数据队列的缓存等问题。
1.涉及的知识点如下
- uart的基础知识,可自行搜索,不在这里赘述。
- 队列的基础知识,可自行搜索,不在这里赘述。
2.实现概述
1.针对stm32,首先实现uart的初始化(比如串口2),能够正常的uart正常的接受发送一个字节,接受通过接收
中断,为了调试方便,printf的移植。
2.针对stm32设置好usat参数,接受中断每次只能接受一个字节,把这些字节依次存放一个队列中,数量达到一定的长度,再去解析数据的具体意义。
3.队列要记录位置信息,比如队列的头部(header)在哪个位置,尾部(tailer)在哪个位置,以及当前的数量,数量可以用两者的绝对值之差,为了简单起见,可以用个变量(count)记录队列中有多少需要处理的信息数量。
3.具体实现过程
1.首先实现一个结构体如下
#define UART_BUF_LEN (1024*2)
struct uart_struct {
vu16 header; //记录队列的头
vu16 tailer; //记录队列的尾
vu16 count; //记录队列需要处理数据的个数
vu8 buffer_temp[100]; //临时缓冲区
vu8 buffer[UART_BUF_LEN]; //队列的大小2k
};
2.中断没接收到一个数据要放到缓冲区中
//uart中断中调用此函数
static void uart_receive_data(u8 data,struct uart_struct * puart_t)
{
puart_t->buffer[puart_t->header] = data; //放到队列中去
puart_t->header = (puart_t->header+1)%UART_BUF_LEN; //考虑偏移问题,取模2048,这样数据永远在0-2047中存放
puart_t->count++;
if(puart_t->count >= WIFI_BUF_LEN){ //如果出现队满,清楚掉里面所有信息,实际使用中不应该满,可修改队列大小
printf("#"); //提示一个错误信息
puart_t->count = 0;
puart_t->header = 0;
puart_t->tailer = 0;
}
}
队列示意图
header每增加多少count也对应增加多少个,用于记录存入对了的数量,同理tailer处理了多少数据count也对应
减去多少个。
void USART2_IRQHandler(void)
{
u8 data;
if(USART_GetITStatus(USART2, USART_IT_RXNE)!=RESET){
data = USART_ReceiveData(USART2);
uart_receive_data(data, &usat_t);//uart_t 是 struct uart_struct的一个指针
USART_ClearITPendingBit(USART2, USART_IT_RXNE);
}
}
3.接收到数据的处理
要处理数据,首先双方有个协议的规定,才能明确对方想要表达的意思,这里是一个简单的协议,只是为了说明实现过程,协议如下。
0xAA -0x55 -LEN -data0 -data1 -data2 - …datan
其中LEN = data0 到 datan的个数用于标识完整的一帧数据的数量,0xAA 0x55是帧标识。
例如0xAA 0x55 0x01 0x00 一帧数据有效数据是一位,有效信息是0x00。
实际使用中需要增加校验位,每帧数据的ID标识,主ID,子ID标识帧的类型以及根据这些信息作出对应的ACK,告诉发送者正确接收到信息,否则做进一步的容错处理,这里不详细介绍这个。
3.接收数据按照协议解析处理
static void wifi_data_copy(struct uart_struct * puart_t,u8 len)
{
u8 i;
for(i=0;i<len;i++){
puart_t->buffer_temp[i]=puart_t->buffer[(puart_t->tailer+i)%UART_BUF_LEN];
//printf("-0x%02x",puart_t->buffer_temp[i]);
}
}
int uart_receive_analysis(struct uart_struct * puart_t)
{
#define LEN 4 //最小的一帧数据具有的长度
u8 i;
u16 count =puart_t->count;
u16 header=puart_t->header;
u16 tailer=puart_t->tailer;
u8 length=0;
if(count >= LEN ){
if(puart_t->buffer[(tailer+0)%UART_BUF_LEN] == 0xAA &&
puart_t->buffer[(tailer+1)%UART_BUF_LEN] == 0x55){
length = puart_t->buffer[(tailer+2)%UART_BUF_LEN]; //记录有效的长度
if(count >= length+3){ //为什么加3? 头+有效长度信息 0xAA 0x55 LEN 刚好是3
wifi_data_copy(puart_t, length+3)
/* 打印出来接收的一帧完整的数据*/
printf("\r\nuart receive=");
for(i=0;i<length+3;i++)
printf("-0x%02x",puart_t->buffer_temp[i]);
//添加你需要的功能
/*
add your code
*/
puart_t->count = puart_t->count-length-3;
puart_t->tailer = (puart_t->tailer+length+3)%UART_BUF_LEN;
return 0;
}else{
return -3;//不足一帧是继续等待,实际中可以做个超时处理
}
}else{
puart_t->count = puart_t->count-1;
puart_t->tailer = (puart_t->tailer+1)%UART_BUF_LEN;
return -2;
}
}else
return -1;
}
4.总结
本文主要介绍了串口通信中根据芯片的特性而提供的一种数据收发的处理方式,这种方式在在车载中android与stm32通信有使用到,故在这里做一个简单的总结,如有不正确的地方,请大家指正,本人QQ:278269949。