C语言指针应用:串口接收缓存中完整帧数据获取

在嵌入式开发中,我们经常需要处理串口接收到的数据,串口与外设交互过程中,一般都遵循一定的通讯协议,一条完整的数据帧,无论数据内容,数据长度如何变化,都有固定的帧头和帧尾,串口接收我们一般设置为固定长度的缓存,因此可能存在串口接收到一包缓存数据中包含多个数据帧,对这些数据帧解析和处理,必须完整的找到这些数据帧,并且不丢帧,这是我们平时在处理串口缓存中要注意的问题。
为保证不丢数据,一般都会设置一个数据队列来缓存串口数据,并及时对队列数据进行处理,确保队列不溢出。考虑队列的可移植性,不在队列弹出过程中对数据进行处理,而是及时将队列数据弹出到一个数组中,然后进行处理,这里就用到了文章标题所说的指针,下面详细说明。
数组中的所有数据有可能包含多个数据帧,串口接收处理函数的两个参数为缓存数组和数组长度,这里我们分别设置一个头指针和一个尾指针,分别去指向数组中数据帧的帧头和帧尾,for循环用来移动指针寻找帧头和帧尾,完成一帧数据后,调用帧数据处理,头尾指针指向帧尾下个字节,继续寻找下一帧数据,源代码如下:

帧头:0xEE,帧尾:0xFF,0xFC,0xFF,0xFF
uint8_t uartRecvDataAnalyze( uint8_t *pucBuf, uint16_t ilen)
{
uint8_t *ph = pucBuf, *pt = pucBuf; //头、尾指针都指向pucBuf起始位置
uint16_t i;
//找到完整的数据帧并处理
for ( i = 0; i < ilen; i++)
{
if(*ph != 0xEE) //找帧头位置
{
ph++;
pt = ph;
continue; //没找到就继续
}
pt++;
if(*pt == 0xFF && *(pt + 1) == 0xFC && *(pt + 2) == 0xFF && *(pt + 3) == 0xFF) //帧尾
{
pt += 4; //尾指针指向帧尾下一个字节
i += 4; //计数跳过帧尾
ProcessMessage((PCTRL_MSG)ph, pt - ph); //处理数据帧
ph = pt; //头尾指针均指向帧尾下一个字节,继续寻找下一帧
}
}
return 0;
}
具体处理方式可参考注释。可见在利用了指针后,短短几行代码,便可以实现数据缓存中多帧数据的获取和处理,非常强大。
如有相似应用,可替换帧头、帧尾和数据处理函数,修改响应的指针偏移量便可移植使用。

  • 1
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的示例代码,实现了持续接收数据缓存,以及按照先进先出的顺序从缓存提取数据到buffer: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <pthread.h> #define BUFFER_SIZE 10 // 缓存大小 #define DATA_SIZE 20 // 数据长度 // 缓存结构体 struct buffer { char data[BUFFER_SIZE][DATA_SIZE]; // 数据缓存 int head; // 缓存指针 int tail; // 缓存指针 pthread_mutex_t mutex; // 互斥锁 pthread_cond_t cond; // 条件变量 }; // 初始化缓存 void buffer_init(struct buffer *buf) { buf->head = 0; buf->tail = 0; pthread_mutex_init(&buf->mutex, NULL); pthread_cond_init(&buf->cond, NULL); } // 往缓存添加数据 void buffer_put(struct buffer *buf, const char *data) { pthread_mutex_lock(&buf->mutex); // 如果缓存已满,等待空余位置 while ((buf->tail + 1) % BUFFER_SIZE == buf->head) { pthread_cond_wait(&buf->cond, &buf->mutex); } // 添加数据 strcpy(buf->data[buf->tail], data); buf->tail = (buf->tail + 1) % BUFFER_SIZE; pthread_cond_signal(&buf->cond); // 通知等待读取的线程 pthread_mutex_unlock(&buf->mutex); } // 从缓存取出数据 void buffer_get(struct buffer *buf, char *data) { pthread_mutex_lock(&buf->mutex); // 如果缓存为空,等待有数据可读 while (buf->head == buf->tail) { pthread_cond_wait(&buf->cond, &buf->mutex); } // 取出数据 strcpy(data, buf->data[buf->head]); buf->head = (buf->head + 1) % BUFFER_SIZE; pthread_cond_signal(&buf->cond); // 通知等待写入的线程 pthread_mutex_unlock(&buf->mutex); } // 线程函数,模拟数据接收 void *receive_thread(void *arg) { struct buffer *buf = (struct buffer *)arg; char data[DATA_SIZE]; int count = 0; while (1) { sprintf(data, "data-%d", count++); buffer_put(buf, data); // 添加数据缓存 usleep(10000); // 模拟10ms延迟 } return NULL; } int main() { struct buffer buf; char data[DATA_SIZE]; buffer_init(&buf); // 初始化缓存 pthread_t tid; pthread_create(&tid, NULL, receive_thread, &buf); // 创建数据接收线程 while (1) { buffer_get(&buf, data); // 从缓存取出数据 printf("%s\n", data); } return 0; } ``` 该程序使用了一个结构体来表示缓存,其包含了一个字符数组用于存储数据,以及两个指针 head 和 tail 分别指向缓存的头和尾。当数据接收线程往缓存添加数据时,tail 指针指向的位置就是新添加的数据的位置,添加完数据后 tail 指针向后移动一位。当主线程从缓存取出数据时,head 指针指向的位置就是要取出的数据的位置,取出数据后 head 指针向后移动一位。如果 head 和 tail 指针相等,说明缓存为空。 为了实现先进先出的顺序,我们使用了互斥锁和条件变量来保证线程间的同步。当缓存已满时,数据接收线程会等待条件变量,直到有空余位置;当缓存为空时,主线程会等待条件变量,直到有数据可读。每次添加或取出数据后,都会通过条件变量通知等待的线程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值