C语言—队列处理消息机制
使用背景介绍
嵌入式开发中,经常使用触发flag标志位去处理很多事件,最典型的就是中断触发类型,flag置位。然后主程序轮询检查flag状态,如果检测flag置位条件满足,则进行下一步的操作,比如说中断读取串口数据操作。
通用处理情况
中断回调函数处理如下,将触发标志置1
rt_err_t rz_uart1_recv_callback(rt_device_t dev, rt_size_t size)
{
.......
recv_flag = 1;
.......
}
应用处理处理,判断触发标志是否满足,
if (recv_flag) {
recv_flag = 0;
.......
}
这种处理方式适合通用处理方法,优点是程序简单,缺点是程序接口不好,要注意标志位清除。
如果多种类型的触发标志,那么要定义很多的flag去识别,这样对程序开发很不友好!
采用队列方式存储事件消息
队列使用RT-Thread自带的数据接口 RingBuffer 其实就是先进先出(FIFO)的循环缓冲区。把一段线性的存储空间当作一个环形的存储空间使用,可以提高存储空间的利用率。
具体的使用说明,参考这位博友的文章,写的很清楚。
ringbuffer使用
设计思路
-
将所有触发的标志位类型作为事件消息,入队操作,保证每个触发事件类型有且唯一。
-
出队获取对应的事件消息,判断是否对应的触发类型。
这样设计的好处利于系统的耦合性及健壮性。
中断程序修改如下:
msg_put(MSG_TYPE_RECV_DATA); /* 相当于 recv_flag = 1; 入队操作*/
应用程序修改:
msg_put(&msg_code); /* recv_flag = 0,出队操作 */
if (MSG_TYPE_RECV_DATA == msg_code ) {
........
}
源文件程序
使用LW_OOPC框架,使用面向对象思想进行模块封装。
#ifndef __RZ_MSG_H
#define __RZ_MSG_H
#include <rtthread.h>
#include "lw_oopc.h"
#include <stdbool.h>
#include <rtdevice.h>
#define RING_BUFFER_LEN 10 /* 消息个数 */
typedef enum rz_msg_type_def {
MSG_TYPE_NONE = 0x00,
MSG_TYPE_RECV_RH172DATA,
MSG_TYPE_MAX,
}rz_msg_type_t;
typedef struct rz_msg_t rz_msg_t;
CLASS(rz_msg_t)
{
struct rt_ringbuffer *rb ;
bool (*msg_init)(rz_msg_t *t);
bool (*msg_put)(rz_msg_t *t,uint8_t msg_code);
bool (*msg_get)(rz_msg_t *t,uint8_t *msg_code);
};
bool rz_msg_init(void);
rz_msg_t * rz_msg_obj_get(void);
#endif
#include "rz_msg.h"
static rz_msg_t prz_msg_obj;
rz_msg_t * rz_msg_obj_get(void)
{
return &prz_msg_obj;
}
static bool msg_init(rz_msg_t *t)
{
t->rb = rt_ringbuffer_create(RING_BUFFER_LEN);
if (NULL == t->rb) {
rt_kprintf("can't create ringbffer");
return false;
}
return true;
}
static bool msg_put(rz_msg_t *t,uint8_t msg_code)
{
if(0 == rt_ringbuffer_put(t->rb,&msg_code,1)){
return false;
}
return true;
}
static bool msg_get(rz_msg_t *t,uint8_t* msg_code)
{
if(0 == rt_ringbuffer_get(t->rb,msg_code,1)){
return false;
}
return true;
}
CTOR(rz_msg_t)
FUNCTION_SETTING(msg_get, msg_get);
FUNCTION_SETTING(msg_put, msg_put);
FUNCTION_SETTING(msg_init, msg_init);
END_CTOR
bool rz_msg_init(void)
{
rz_msg_t * t = rz_msg_obj_get();
rz_msg_t_ctor(t);
return t->msg_init(t);
}