以下内容主要注重应用,对源码不做分析,对源码有兴趣的可参考官方具体文档,相关链接:https://doc.micrium.com/display/ucos/
开发环境:TrueSTUDIO
单片机:STM32F103VET6(HAL库)
一、创建一个消息队列,OSQCreate()
在使用消息队列之前,需要先创建消息队列(或简单地说一个队列)。创建队列是通过调用OSQCreate()并向它传递两个参数来完成的:一个指向一个数组的指针,这个数组将保存消息和这个数组的大小。这个数组必须声明为一个指向void的指针数组,如下所示:
void * MyArrayOfMsg(大小);
你需要将MyArrayOfMsg[]的地址以及这个数组的大小传递给OSQCreate()。如果消息队列最初为空则它不包含任何消息。函数原型为:
1、OS_EVENT *OSQCreate (
void
**start, INT16U size)。
- start是指向一个数组的指针,这个数组将保存消息;
- size是指向数组的大小;
- 返回与队列相关联的指向事件控制块的指针。
二、发送一个消息到消息队列(FIFO 先进先出原则),OSQPost()
将一个消息存到消息队列,函数原型为:
1、INT8U OSQPost (OS_EVENT *pevent,
void
*msg)。
- pevent是消息队列相关联的指向事件控制块的指针;
- msg是指向您希望存入消息队列的消息的指针(发送的不能是空指针,由于队列发送的消息是地址,被发送的消息最好是全局变量);
- 返回值是错误类型。
三、发送一个消息到消息队列(LIFO 后进先出原则),OSQPostFront()
将一个消息存到消息队列,函数原型为:
1、INT8U OSQPostFront (OS_EVENT *pevent,
void
*msg)
- pevent是消息队列相关联的指向事件控制块的指针;
- msg是指向您希望存入消息队列的消息的指针(发送的不能是空指针,由于队列发送的消息是地址,被发送的消息最好是全局变量);
- 返回值是错误类型。
四、从一个消息队列中等待一个消息,OSQPend()
等待一个消息到达消息队列,函数原型为:
1、void
*OSQPend (OS_EVENT *pevent, INT16U timeout, INT8U *err)
- pevent是消息队列相关联的指向事件控制块的指针;
- timeout等待时长(如果是0将一直等下去,直到消息队列中有消息);
- err错误类型;
- 返回值是消息队列中收到的消息指针。
五、示例代码(非中断方式)
1、定义一个消息队列事件指针和消息队列的存储单元(存储单元存储的是数据的指针):
/* 定义一个消息队列事件指针 */ OS_EVENT *MessageQ; /* 定义消息队列的空间大小 */ void *MessageStorage[10];
2、创建消息队列:
/* 创建消息队列, 含10个存储单元(存储的内容是指针不是数据) */ MessageQ = OSQCreate(&MessageStorage[0], 10);
3、在一个任务中发送两种不同的值的地址到消息邮箱:
static void AppTask1(void *p_arg) { INT16U value1 = 1, value2 = 2; (void)p_arg; while(1) { if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET) { /* 发送消息到消息队列 */ OSQPost(MessageQ, (void *)&value1); } if(HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13) == GPIO_PIN_SET) { /* 发送消息到消息队列 */ OSQPost(MessageQ, (void *)&value2); } OSTimeDlyHMSM(0, 0, 0, 100); } }
4、在一个任务中接收消息队列中的消息:
static void AppTask2(void *p_arg) { INT8U err; INT16U r_value; (void)p_arg; while(1) { /* 等待消息队列获取到消息 */ r_value = *(INT16U *)OSQPend(MessageQ, 0, &err); if(err == OS_ERR_NONE) { if(r_value == 1) { HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0); } else if(r_value ==2) { HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5); } } } }
六、示例代码(中断方式)
1、定义消息队列事件指针和消息队列的存储单元(存储单元存储的是数据的指针):
/* 定义两个消息队列事件湿疹 */ OS_EVENT *MessageQ1; OS_EVENT *MessageQ2; /* 定义消息队列的存储单元 */ void *MessageStorage1[10]; void *MessageStorage2[10];
2、创建消息队列:
/* 创建消息队列,含10个存储单元 */ MessageQ1 = OSQCreate(&MessageStorage1[0], 10); MessageQ2 = OSQCreate(&MessageStorage2[0], 10);
3、中断函数中进行针对μC/OS系统的处理:
/** * @brief This function handles EXTI line0 interrupt. */ void EXTI0_IRQHandler(void) { #if uCOS_EN == 1 #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0u; #endif OS_ENTER_CRITICAL(); OSIntEnter(); OS_EXIT_CRITICAL(); #endif HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0); #if uCOS_EN == 1 OSIntExit(); #endif } /** * @brief This function handles EXTI line[15:10] interrupts. */ void EXTI15_10_IRQHandler(void) { #if uCOS_EN == 1 #if OS_CRITICAL_METHOD == 3u /* Allocate storage for CPU status register */ OS_CPU_SR cpu_sr = 0u; #endif OS_ENTER_CRITICAL(); OSIntEnter(); OS_EXIT_CRITICAL(); #endif HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_13); #if uCOS_EN == 1 OSIntExit(); #endif }
4、在中断的回调函数中发送消息,针对不同端口引脚被触发发送不同的消息:
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if(GPIO_Pin == GPIO_PIN_0) { OSQPost(MessageQ1, (void *)&value_u8); } if(GPIO_Pin == GPIO_PIN_13) { OSQPost(MessageQ2, (void *)&value_u16); } }
5、创建两个任务分别去接收中断发出的邮箱消息:
static void AppTaskLed1(void *p_arg) { INT8U err; INT8U r_value; (void)p_arg; while(1) { /* 从消息队列中获取消息 */ r_value = *(INT8U *)OSQPend(MessageQ1, 0, &err); if(err == OS_ERR_NONE) { if(r_value == 1) { HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_5); } } } } static void AppTaskLed2(void *p_arg) { INT8U err; INT16U r_value; (void)p_arg; while(1) { /* 从消息队列中获取消息 */ r_value = *(INT16U *)OSQPend(MessageQ2, 0, &err); if(err == OS_ERR_NONE) { if(r_value == 2) { HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0); } } } }
#endif