[C] 纯文本查看 复制代码
#include "main.h"
#ifdef TEST_MESSAGEQUEUE
#include <string.h>
#include "cmsis_os2.h"
#include "ucos3_os2.h"
/* 线程控制块与栈 */
static uint8_t producer_cb[sizeof(os_ucos3_thread_t)];
static uint8_t consumer_cb[sizeof(os_ucos3_thread_t)];
static CPU_STK producer_stack[512 / sizeof(CPU_STK)];
static CPU_STK consumer_stack[512 / sizeof(CPU_STK)];
/* 消息队列 */
/* 消息的结构 */
typedef struct {
uint8_t value; // 改成 uint8_t, uint16_t, uint32_t 进行测试(已通过)
char info[14]; // 更改为任意大小进行测试(已通过)
} msg_t; // (当value类型为 uint16_t 时, 工程使用时尽量保证 sizeof(msg_t) 2字节对齐,测试阶段任意指定
// (当value类型为 uint32_t 时, 工程使用时尽量保证 sizeof(msg_t) 4字节对齐,测试阶段任意指定
/* 消息队列的容量 */
#define MESSAGE_QUEUE_CAPACITY 8
#define MESSAGE_SIZE sizeof(msg_t)
/* 这里需要额外定义一个 (sizeof(void*) * MESSAGE_QUEUE_CAPACITY) 大小的空间:
因为ucOS3的邮箱传递的是指针, 这个空间就是指针邮箱的静态存储空间 */
__align(8)
static uint8_t mq_cb[sizeof(os_ucos3_message_queue_t) + (sizeof(void*) * MESSAGE_QUEUE_CAPACITY)];
/* 存储消息的静态空间 */
//__align(8) // 找个办法测试不对齐
static uint8_t mq_mem[MESSAGE_SIZE * MESSAGE_QUEUE_CAPACITY];
/* CMSIS 对象句柄 */
static osThreadId_t producer_id;
static osThreadId_t consumer_id;
static osMessageQueueId_t mq_id;
static void producer_thread(void *argument) {
(void)argument;
osStatus_t state;
msg_t msg_write;
memset(&msg_write, 0, sizeof(msg_write));
for (;;) {
msg_write.value += 1000;
state = osMessageQueuePut(mq_id, &msg_write, 0, osWaitForever);
if (state == osOK) {
osDelay(50);
}
/* 消息发送失败, 错误指示灯闪烁 */
else {
osThreadSuspend(consumer_id);
for (;;) {
LED_1(0);
osDelay(50);
LED_1(1);
osDelay(200);
}
}
}
}
static void consumer_thread(void *argument) {
(void)argument;
int led_state;
osStatus_t state;
msg_t msg_read;
msg_t msg_should_read;
memset(&msg_read, 0, sizeof(msg_read));
memset(&msg_should_read, 0, sizeof(msg_should_read));
for (;;) {
state = osMessageQueueGet(mq_id, &msg_read, NULL, osWaitForever);
/* 注意以下的比较判断不能直接使用: msg_read.value == msg_should_read.value + 1000
* 因为比如当 value 类型为 uint8_t 时,右边的表达式是会超过 255 的,
* 至少应该写 msg_read.value == (msg_should_read.value + 1000) & 0xFF。
* 但是当 value 类型为 uint8_t 时,又要改成 & 0xFFFF 了。
* 因此直接用下面的通用比较方式
*/
msg_should_read.value += 1000;
if (state == osOK && msg_read.value == msg_should_read.value) {
LED_0(led_state);
led_state = !led_state;
}
/* 消息接收失败, 错误指示灯闪烁 */
else {
osThreadSuspend(producer_id);
for (;;) {
LED_1(0);
osDelay(50);
LED_1(1);
osDelay(50);
}
}
}
}
void app_main(void) {
osKernelInitialize();
/* 消息队列 (静态消息存储) */
const osMessageQueueAttr_t mq_attr = {
.name = "queue",
.cb_mem = mq_cb,
.cb_size = sizeof(mq_cb),
.mq_mem = mq_mem,
.mq_size = sizeof(mq_mem),
};
mq_id = osMessageQueueNew(MESSAGE_QUEUE_CAPACITY, MESSAGE_SIZE, &mq_attr);
/* 线程 */
const osThreadAttr_t producer_attr = {
.name = "producer",
.cb_mem = producer_cb,
.cb_size = sizeof(producer_cb),
.stack_mem = producer_stack,
.stack_size = sizeof(producer_stack),
.priority = osPriorityNormal,
};
const osThreadAttr_t consumer_attr = {
.name = "consumer",
.cb_mem = consumer_cb,
.cb_size = sizeof(consumer_cb),
.stack_mem = consumer_stack,
.stack_size = sizeof(consumer_stack),
.priority = osPriorityAboveNormal,
};
producer_id = osThreadNew(producer_thread, NULL, &producer_attr);
consumer_id = osThreadNew(consumer_thread, NULL, &consumer_attr);
(void)producer_id;
(void)consumer_id;
osKernelStart();
}
#endif /* #ifdef TEST_MESSAGEQUEUE */