os_queue.c
1> 消息队列结构体
// 消息队列结构体
#define MsgQ_SIZE 4
typedef struct // 定义一个队列结构体
{
ushort16_t * Start; // 指向队列起始地址
ushort16_t * End; // 指向队列结束地址
ushort16_t * In; // 指向插入一条消息的地址
ushort16_t * Out; // 指向被取出的消息地址
uchar8_t Size; // 队列数组长度
uchar8_t Entries; // 已存放消息条数
ushort16_t Buffer[MsgQ_SIZE]; // 队列存储数组
} QUEUE_TypeDef;
如何实现循环队列
2> 消息队列初始化
2.1> 实例化
// 消息队列实例化
static QUEUE_TypeDef idata MsgQ;
void QUEUE_Init(void)
{
MsgQ.Start = MsgQ.Buffer; // 队列头
MsgQ.End = MsgQ.Buffer + MsgQ_SIZE - 1; // 队列尾
MsgQ.In = MsgQ.Start; // 插入点
MsgQ.Out = MsgQ.Start; // 取出点
MsgQ.Size = MsgQ_SIZE; // 队列长度,4
MsgQ.Entries = 0; // 消息条数
}
图形表示:
换个图像表示:
初始化后:
指针变量Start,In,Out都指向Buffer[0];
指针变量End指向Buffer[3]
队列长度Size,固定为4;
队列消息条数,为0;
消息内容Buffer,都为0;
2.2> 发挥想象-制作信箱
把消息队列(MsgQ)想成只能放4封信的收件箱;
3> 消息格式
3.1> 消息类型
typedef enum
{
MessageKey = 0xFF, // 按键消息类型
MessageUsart = 0xFE, // 串口消息类型
MessageInt0 = 0xFD, // 外部中断0消息类型
MessageInt1 = 0xFC, // 外部中断1消息类型
MessageTimer = 0xF0 // 最小值,不允许其他类型小于它
} MSG_TypeDef;
不同的消息类型,处理方式不同
MessgeTimer,软件定时器Timer消息类型;
软件定时器Timer消息类型需要16bit,【?】
4> 发送消息
/**
* @brief 发送消息
* @message 消息类型
* @Value 消息值, MessageTimer类型为16bit地址,其他类型下都是8bit数据
* @retval 无
*/
void QUEUE_Post(MSG_TypeDef message, ushort16_t value)
{
EnterCritical(); // 进入临界态
Assert(MsgQ.Entries <= MsgQ.Size); // 断言,判断是否满
if(message == MessageTimer) // 软件定时器器类型
*MsgQ.In = value; // 直接赋16bit地址
else // 常规消息
{
GetBit_UshortH8(*MsgQ.In) = message; // 把类型赋给高地址
GetBit_UshortL8(*MsgQ.In) = value & 0x00FF; // 把值赋值给低地址
}
MsgQ.In++; // 消息入口+1
if(MsgQ.In > MsgQ.End) // 入口越界循环
MsgQ.In = MsgQ.Start;
MsgQ.Entries++; // 消息数量+1
ExitCritical(); // 退出临界态
}
发送1条消息好比,向邮箱里投了1封信
4.2> 发挥想象-投递信件
投递信件:
5> 读取消息
5.1> 程序代码
/**
* @brief 读取消息
* @param 无
* @retval 无
*/
ushort16_t QUEUE_Pend(void)
{
short16_t message;
while(MsgQ.Entries == 0) // 等待消息
{ /* 推荐在这儿喂狗 */ };
message = *MsgQ.Out++; // 消息出口+1
MsgQ.Entries--; // 消息数量-1
if (MsgQ.Out > MsgQ.End) // 出口越界循环
MsgQ.Out = MsgQ.Start;
return(message); // 返回消息
}
指针变量【In】指向可以插入信息的地址;
指针变量【Out】指向要取的信息的地址;
5.2> 发挥想象-读取信件
6> 解析消息-main函数
int main(void)
{
ushort16_t idata msg;
uchar8_t idata msg_type;
uchar8_t idata msg_value;
// 填充初始化程序
while (1) {
msg = QUEUE_Pend(); // 读取信息
msg_type = GetMsgType(msg);
msg_value = GetMsgData(msg);
switch (msg_type) {
case MessageKey:
// 按键处理
break;
case MessageUart:
// 串口信息处理
break;
// 填充消息处理函数
default:
Function(msg); // 软件定时器消息处理
break;
}
}
}
整个流程:
Step 1> 先初始化系统;
Step 2> 进入While大循环;
Step 3> QUEUE_Pend()函数读取信息;
Step 4> switch-case根据信息类型,执行对应的处理函数;