十九: freertos消息队列-中断方式
源码:
#include <stdio.h>
#include "board.h"
#include "led.h"
#include "key.h"
#include "uart.h"
#include "tim_mrt.h"
/*** System oscillator rate and clock rate on the CLKIN pin ****/
/**/const uint32_t OscRateIn = MAIN_OSC_XTAL_FREQ_HZ; /**/
/**/const uint32_t ExtRateIn = EXT_CLOCK_IN_FREQ_HZ; /**/
//系统复位
#define System_restart (LPC_SWM->PINENABLE0 = 0xffffffffUL) /**/
/***************************************************************/
static void TIM_CallBack1(void);
static void TIM_CallBack2(void);
#include "FreeRTOSConfig.h"
/* FreeRTOS头文件 */
#include "FreeRTOS.h"
#include "task.h"
#include "event_groups.h"//事件头文件
#include "queue.h"//队列头文件
/**************************** 任务句柄 ********************************/
/*
* 任务句柄是一个指针,用于指向一个任务。
*/
/* LED任务句柄 */
static TaskHandle_t LED1_Task_Handle= NULL;
static xTaskHandle KEY_Task_Handle = NULL;
#define TASK_STACK_SIZE 32
static QueueHandle_t xQueue1 = NULL;
static QueueHandle_t xQueue2 = NULL;
typedef struct Msg
{
uint8_t ucMessageID;
uint16_t usData[2];
uint32_t ulData[2];
}MSG_T;
MSG_T g_tMsg; /* 定义一个结构体用于消息队列 */
/* Sets up system hardware
**********************************************************************
* @ 函数名 : BSP_Init
* @ 功能说明: 板级外设初始化,所有板子上的初始化均可放在这个函数里面
* @ 参数 :
* @ 返回值 : 无
*********************************************************************/
static void prvSetupHardware(void)
{
SystemCoreClockUpdate();
DEBUGINIT();
led_Init() ;
Key_INIT();
MRT_Init();
Board_UARTPutSTR("build date: " __DATE__ " build time: " __TIME__ "\n");
}
/**********************************************************************
* @ 函数名 : vLED_Task0
* @ 功能说明: LED_Task任务主体,接收任务 vKEY_task 发送的消息队列数据(xQueue2)
* @ 参数 :
* @ 返回值 : 无
********************************************************************/
static void vLED1_Task (void *pvParameters)
{
MSG_T *ptMsg;
BaseType_t xResult;
const TickType_t xMaxBlockTime = pdMS_TO_TICKS(200); /* 设置最大等待时间为200ms */
while (1) {
xResult = xQueueReceive(xQueue2, /* 消息队列句柄 */
(void *)&ptMsg, /* 这里获取的是结构体的地址 */
(TickType_t)xMaxBlockTime);/* 设置阻塞时间 */
vTaskDelay(100);
if(xResult == pdPASS)
{
/* 成功接收,并通过串口将数据打印出来 */
printf("接收到消息队列数据 ptMsg->ucMessageID = %d\r\n", ptMsg->ucMessageID);
printf("接收到消息队列数据 ptMsg->ulData[0] = %d\r\n", ptMsg->ulData[0]);
printf("接收到消息队列数据 ptMsg->usData[0] = %d\r\n", ptMsg->usData[0]);
Board_LED_Toggle(0);
}
else
{
/* 超时 */
}
}
}
/*
*********************************************************************************************************
* 函 数 名: vKEY_task
* 功能说明: 按键任务
* 形 参: pvParameters 是在创建该任务时传递的形参
* 返 回 值: 无
* 优 先 级: 1 (数值越小优先级越低,这个跟uCOS相反)
*********************************************************************************************************
*/
static void vKEY_task(void* pvParameters)
{
MSG_T *ptMsg;
uint8_t pcWriteBuffer[200];
/* 初始化结构体指针 */
ptMsg = &g_tMsg;
/* 初始化数组 */
ptMsg->ucMessageID = 0;
ptMsg->ulData[0] = 0;
ptMsg->usData[0] = 0;
u8 key2=0;
while(1)
{
u8 key=0;
if(Scan_Key())
vTaskDelay(20);
else continue;
if(!Scan_Key())continue;
else
{
key=Scan_Key();
key2=key;
}
while(Scan_Key()){};//等按键抬起
if(key2)
{
switch(key2)
{
case 1:
{
printf("=================================================\r\n");
printf("任务名 任务状态 优先级 剩余栈 任务序号\r\n");
vTaskList((char *)&pcWriteBuffer);
printf("%s\r\n", pcWriteBuffer);
}break;
case 2:
{
printf("K2键按下,启动单次定时器中断,100ms后在定时器中断给任务vTaskMsgPro发送消息\r\n");
bsp_HardTimer(2,(void *)TIM_CallBack1);
}break;
case 3:
{
/* K3键按下,向xQueue2发送数据 */
printf("K3键按下,启动单次定时器中断,1s后在定时器中断给任务vTaskLED发送消息\r\n");
bsp_HardTimer(3,(void *)TIM_CallBack2);
}break;
default:break;
}
key2=0;
}
}
}
/*
*********************************************************************************************************
* 函 数 名: vTaskMsgPro
* 功能说明: 使用函数 xQueueReceive 接收任务 vKEY_task 发送的消息队列数据(xQueue1)
* 形 参: pvParameters 是在创建该任务时传递的形参
* 返 回 值: 无
* 优 先 级: 3
*********************************************************************************************************
*/
static void vTaskMsgPro(void *pvParameters)
{
BaseType_t xResult;
const TickType_t xMaxBlockTime = pdMS_TO_TICKS(300); /* 设置最大等待时间为300ms */
uint8_t ucQueueMsgValue;
while(1)
{
/* 获取K2按键按下的消息队列 */
xResult = xQueueReceive(xQueue1, /* 消息队列句柄 */
(void *)&ucQueueMsgValue, /* 存储接收到的数据到变量ucQueueMsgValue中 */
(TickType_t)xMaxBlockTime);/* 设置阻塞时间 */
if(xResult == pdPASS)
{
/* 成功接收,并通过串口将数据打印出来 */
printf("接收到消息队列数据ucQueueMsgValue = %d\r\n", ucQueueMsgValue);
Board_LED_Toggle(1);
}
else
{
/* 超时 */
}
}
}
/*
*********************************************************************************************************
* 函 数 名: AppObjCreate
* 功能说明: 创建任务通信机制
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
static void AppObjCreate (void)
{
/* 创建10个uint8_t型消息队列 */
xQueue1 = xQueueCreate(10, sizeof(uint8_t));
if( xQueue1 == 0 )
{
/* 没有创建成功,用户可以在这里加入创建失败的处理机制 */
DEBUGSTR("队列1创建失败\n");
}
/* 创建10个存储指针变量的消息队列,由于CM3/CM4内核是32位机,一个指针变量占用4个字节 */
xQueue2 = xQueueCreate(10, sizeof(struct Msg *));
if( xQueue2 == 0 )
{
/* 没有创建成功,用户可以在这里加入创建失败的处理机制 */
DEBUGSTR("队列2创建失败\n");
}
}
/***********************************************************************
* @ 函数名 : AppTaskCreate
* @ 功能说明: 为了方便管理,所有的任务创建函数都放在这个函数里面
* @ 参数 : 无
* @ 返回值 : 无
**********************************************************************/
static void AppTaskCreate()
{
BaseType_t xReturn=pdPASS;/*定义任务返回值*/
taskENTER_CRITICAL();//进入临界区,禁止中断打断
xReturn=xTaskCreate(vLED1_Task,
"vLED1_Task",
TASK_STACK_SIZE*2,
NULL,
(tskIDLE_PRIORITY + 1UL),
(TaskHandle_t *) &LED1_Task_Handle);
xReturn=xTaskCreate(vKEY_task,
"vKEY_Task",
TASK_STACK_SIZE*4,
NULL,
(tskIDLE_PRIORITY + 1UL),
(TaskHandle_t *) &KEY_Task_Handle);
xReturn=xTaskCreate(vTaskMsgPro,
"vTaskMsgPro",
TASK_STACK_SIZE*5,
NULL,
(tskIDLE_PRIORITY + 3UL),
NULL);
if(pdPASS==xReturn)
{
printf("创建LED_Task任务成功\r\n");
}
// vTaskDelete(LED1_Task_Handle);//删除AppTaskCreate任务
// vTaskDelete(UART_Task_Handle);//删除AppTaskCreate任务
taskEXIT_CRITICAL(); //退出临界区
}
/**
* @brief main routine for blinky example
* @return Function should not exit.
*/
int main(void)
{
prvSetupHardware();
Board_UARTPutSTR("LPC824 FreeRTOS 任务管理\n\r");
printf("Key按下挂起任务,Key按下恢复任务\r\n");
AppTaskCreate();
/* 创建任务通信机制 */
AppObjCreate();
vTaskStartScheduler();//任务调度
/* Loop forever */
while (1) {
printf("FreeRTOS 运行失败\n\r");
}
}
/*
*********************************************************************************************************
* 函 数 名: TIM_CallBack1和TIM_CallBack2
* 功能说明: 定时器中断的回调函数,此函数被bsp_HardTimer所调用。
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
static uint32_t g_uiCount = 0; /* 设置为全局静态变量,方便数据更新 */
static void TIM_CallBack1(void)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
g_uiCount++;
/* 向消息队列发数据 */
xQueueSendFromISR(xQueue1,
(void *)&g_uiCount,
&xHigherPriorityTaskWoken);
/* 如果xHigherPriorityTaskWoken = pdTRUE,那么退出中断后切到当前最高优先级任务执行 */
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
Board_LED_Toggle(5);
}
void TIM_CallBack2(void)
{
MSG_T *ptMsg;
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/* 初始化结构体指针 */
ptMsg = &g_tMsg;
/* 初始化数组 */
ptMsg->ucMessageID++;
ptMsg->ulData[0]++;
ptMsg->usData[0]++;
/* 向消息队列发数据 */
xQueueSendFromISR(xQueue2,
(void *)&ptMsg,
&xHigherPriorityTaskWoken);
/* 如果xHigherPriorityTaskWoken = pdTRUE,那么退出中断后切到当前最高优先级任务执行 */
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
Board_LED_Toggle(6);//亮灭1s
}
任务标志事件
- 按键任务里
按键任务里置位标志
按下按键2,100ms后向队列1里发送消息,每按一次发送的数据加1。
按下按键3,1s后向消息队列2里发数据,每按一次发送三组数据。- LED任务,接收消息队列2的数据。
- 消息任务里
两个标志同时置位后,翻转LED2。- 实验现象
按下按键2,LED1状态翻转。按下按键3,LED2状态翻转。- 函数:
xQueueCreate(); xQueueReceive(); xQueueSend(); xQueueSendFromISR(); portYIELD_FROM_ISR();