一.背景
在嵌入式开发的时候,如果我们移植了操作系统,那么操作系统会带有消息队列的功能。但如果我们使用的是裸机,然后又需要到消息缓存的功能时,那么就需要自己去实现消息队列的功能了。本文章就给出了一种简便地实现消息队列的方法。
那么为什么会需要消息队列呢?
我认为主要原因是为了应对接收端接收数据快,而处理端处理数据慢而设置的缓冲吧。如果没有缓冲处理,那么很容易出现数据丢失没有处理到的情况。举个生活中的例子,现在大家的电视基本上都是网络电视了吧。有时候我们使用遥控器按的速度过快时,比如调节音量吧,我们快速连续按几次,会发现当我们停止按按键的时候,电视显示音量调节变化的动作还未结束,需要过一会才执行完我们刚才的动作,这就是电视处理器,先把我们按键的消息放到缓存队列里面,然后再一条一条慢慢取出来执行的。如果没有缓存队列,那么可能会出现我们快速按3到4次,最后只执行了一次的情况。

当然对于使用操作系统的话,消息队列的作用还可以用于各个任务之间的同步。
二.源码
上述讲了消息队列的作用,接下来给上源码。实现原理非常简单,应该没必要做过多的解释,代码量也很精简,直接阅读代码即可,大家可以根据自己的项目实际需求进行调整。
#include<stdio.h>
#include <string.h>
//消息队列数据类型
#define MAX_LEN 20
typedef struct{
unsigned *addr; //可接受数据缓存地址
unsigned buff[10]; //可接受实际数据
}message_type;
static struct
{
message_type data_buffer[MAX_LEN];
unsigned read_index; //记录接收到消息的序号(例程中未运用到)
unsigned write_index; //记录读取完消息的序号(例程中未运用到)
unsigned data_num; //记录当前队列缓存消息的数量
}g_recv_queue_t;
//消息接收(缓存入队)列函数
static void on_message_recv(message_type *rx_msg)
{
if(g_recv_queue_t.data_num < MAX_LEN){
memcpy(&g_recv_queue_t.data_buffer[g_recv_queue_t.write_index], rx_msg, sizeof(message_type));
g_recv_queue_t.data_num++;
g_recv_queue_t.write_index = (g_recv_queue_t.write_index + 1) % MAX_LEN;
}
}
//消息读取(出队列)函数
static unsigned get_msg(message_type *rx_msg)
{
if (g_recv_queue_t.data_num){
memcpy(rx_msg, &g_recv_queue_t.data_buffer[g_recv_queue_t.read_index], sizeof(message_type));
g_recv_queue_t.read_index = (g_recv_queue_t.read_index + 1) % MAX_LEN;
g_recv_queue_t.data_num--;
return 1;
}
return 0;
}
message_type message;
//指向上层接收函数的指针
void (*g_precv_func2)(message_type *rx_msg) = NULL;
//初始化消息接收函数
void copy_func2_init(void (*p_recv_data)(message_type *rx_msg))
{
g_precv_func2 = p_recv_data;
}
//某个中断里面消息接收
void XXX_IRQHandler(void)
{
//将数据存储到message消息类型变量中
//message.addr = xxx;
//...
//放入到消息队列中
g_precv_func2(&message);
}
void main(void)
{
message_type my_message;
copy_func2_init(on_message_recv);//初始化消息队列接收函数
while(1){
if(get_msg(&my_message)){//查询消息队列
//处理消息数据
}
}
}