功能说明
队列可以实现系统的异步转同步的消息机制,用于保证系统和谐运行。以下代码实现为方式。
这里尤其要注意在队列调用的实际使用方式。
代码示例
- 源文件
/*
* 2019-10-22
* by fzy at leshun
*
* harmony_msg.c
*/
#include <stdio.h>
#include <string.h>
#include "cmsis_os.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "harmony_msg.h"
#define HMMSG_Q_NUM 4
static QueueHandle_t HMMSG_queue[HMS_QUEUE_TYPE_NUM] = {NULL};
DTU_MSG HMMSG_Msg[HMMSG_Q_NUM];
int HMSG_init(void)
{
int ret = 0;
int i = 0;
for (i = 0; i < HMS_QUEUE_TYPE_NUM; i++)
{
HMMSG_queue[i] = xQueueCreate(HMMSG_Q_NUM, sizeof( DTU_MSG * ));
if (HMMSG_queue[i] == NULL)
{
//LSFS_DEBUG(DBG_LEVEL_ERROR, "HMMSG_queue create queue fail\r\n");
//while(1);
ret = -1;
break;
}
}
for (i = 0; i < HMMSG_Q_NUM; i++)
{
HMMSG_Msg[i].used = 0;
}
return ret;
}
int HMSG_Send_MSG(int msg_id, DTU_MSG *msg)
{
int ret = -1;
DTU_MSG *pMsg;
int i;
if (HMMSG_queue[msg_id] != NULL)
{
// find a useless space in HMMSG_Msg
taskENTER_CRITICAL();
for (i = 0; i < HMMSG_Q_NUM; i++)
{
if (HMMSG_Msg[i].used == 0)
{
HMMSG_Msg[i].used = 1;
break;
}
}
taskEXIT_CRITICAL();
if (i != HMMSG_Q_NUM) // find it
{
pMsg = &HMMSG_Msg[i];
if (msg != NULL)
{
memcpy(pMsg, msg, sizeof(DTU_MSG));
}
pMsg->msg_type = msg_id;
if( xQueueSend( HMMSG_queue[msg_id], ( void * )&pMsg, ( TickType_t ) 10 ) != pdPASS )
{
//LSFS_DEBUG(DBG_LEVEL_INFO, "LSFS_log_print send fail\r\n");
return -1;
}
ret = 0;
}
}
return ret;
}
int HMSG_Recv_MSG(int msgType, DTU_MSG *msg, int timeout)
{
int ret = -1;
DTU_MSG *p_msg = NULL;
if (xQueueReceive(HMMSG_queue[msgType], (void *)&p_msg, ( TickType_t ) timeout) == pdTRUE)
{
if (p_msg != NULL)
{
if (p_msg->cVal.cmd_type == DTU_MSGCMD_REBOOT)
{
if (msg != NULL)
{
memcpy((void *)msg, (void *)p_msg, sizeof(DTU_MSG));
ret = DTU_MSGCMD_REBOOT;
}
}
taskENTER_CRITICAL();
p_msg->used = 0;
taskEXIT_CRITICAL();
}
}
return ret;
}
- 头文件
/*
* 2019-10-22
* by fzy at leshun
*
* harmony_msg.h
*/
#ifndef __HARMONY_MSG_H__
#define __HARMONY_MSG_H__
#define HMS_QUEUE_TYPE_NUM 1 /* 消息队列通道类型个数 */
#define HMS_QUEUE_TYPE_SYS 0 /* 系统 TYPE_ID */
#ifdef __cplusplus
extern "C"
{
#endif
/* 消息类型 */
#define DTU_MSGCMD_HBT 0 /* 心跳报文 */
#define DTU_MSGCMD_CMD 1 /* 普通命令 */
#define DTU_MSGCMD_REBOOT 2 /* 要求系统重新启动 */
#define UPLOAD_MAX_LEN 256
typedef struct _DTU_MSG_Val
{
int cmd_type; /* 命令类型 */
union
{
int state; /* 心跳报文回复状态 */
int cmd; /* 管理程序下发给子模块的命令 */
int reboot_delay; /* 重启延时 ms, 0 表示立刻重启*/
struct
{
int dev_code; /* 设备号 */
char bin[UPLOAD_MAX_LEN];
unsigned int len;
unsigned int type; /* 用于记录MQTT的数据包类型 */
int app_id;
} UploadData;
}data;
}DTU_MSG_Val; /* 消息队列实际值 */
typedef struct _DTU_MSG
{
char used; /* 是否忙碌 */
int msg_type; /* 消息类型 */
DTU_MSG_Val cVal; /* 实际数据 */
}DTU_MSG;
int HMSG_init(void);
int HMSG_Send_MSG(int msg_id, DTU_MSG *msg);
int HMSG_Recv_MSG(int msgType, DTU_MSG *msg, int timeout);
#ifdef __cplusplus
}
#endif
#endif
使用方法示例: main.c
void main_task()
{
int ret;
HMSG_init();
DTU_MSG m;
while(1)
{
ret = HMSG_Recv_MSG(HMS_QUEUE_TYPE_SYS, &m, 100);
//
// 处理接收的队列消息
//
msleep(1); // 注意这个延时
}
}
void task_Send_A()
{
DTU_MSG m;
while(1)
{
if (HMSG_Send_MSG(HMS_QUEUE_TYPE_SYS, &m) != 0)
{
printf("send fail\r\n");
}
msleep(5); // 注意延时,保证发送的频率,接收函数有能力处理
}
}
void task_Send_B()
{
DTU_MSG m;
while(1)
{
if (HMSG_Send_MSG(HMS_QUEUE_TYPE_SYS, &m) != 0)
{
printf("send fail\r\n");
}
msleep(5); // 注意延时,保证发送的频率,接收函数有能力处理
}
}
注意事项
- 尤其要注意上面的延时,设计合理的接受频率和发送频率,以及优先级是保证队列正常运行的关键。
- FreeRTOS V9.0.0 下,发送任务太快,接收任务太慢时,会出现队列接收重复的现象,严重会影响业务逻辑。