19 freertos消息队列-中断方式

十九: 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

}

任务标志事件

  1. 按键任务里
    按键任务里置位标志
    按下按键2,100ms后向队列1里发送消息,每按一次发送的数据加1。
    按下按键3,1s后向消息队列2里发数据,每按一次发送三组数据。
  2. LED任务,接收消息队列2的数据。
  3. 消息任务里
    两个标志同时置位后,翻转LED2。
  4. 实验现象
    按下按键2,LED1状态翻转。按下按键3,LED2状态翻转。
  5. 函数:
   	 xQueueCreate();
     xQueueReceive();
     xQueueSend();
     xQueueSendFromISR();
     portYIELD_FROM_ISR();
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FreeRTOS是一个开源的实时操作系统内核,被广泛应用于嵌入式系统中。ESP32是一款具有双核处理器和Wi-Fi功能的芯片,通过使用ESP-IDF开发框架可以进行软件开发。在ESP32-IDF开发中,使用FreeRTOS消息队列可以实现不同任务之间的通信。 在ESP32开发中,可以通过中断服务程序(Interrupt Service Routine,ISR)来发送消息到消息队列,并在任务中通过接收方法响应。 首先,我们需要创建一个全局的消息队列句柄,可以使用xQueueCreate函数来创建一个消息队列。例如,可以使用以下代码创建一个大小为10的消息队列: xQueueHandle messageQueue = xQueueCreate(10, sizeof(int)); 然后,在中断服务程序中,可以使用xQueueSendFromISR方法将消息发送到消息队列中。例如,可以使用以下代码将一个整数值发送到消息队列中: int value = 100; xQueueSendFromISR(messageQueue, &value, NULL); 在任务中,可以使用xQueueReceive方法从消息队列中接收消息并进行响应。例如,可以使用以下代码从消息队列中接收一个整数值并打印出来: int receivedValue; xQueueReceive(messageQueue, &receivedValue, portMAX_DELAY); printf("Received value: %d\n", receivedValue); 需要注意的是,在接收消息时,可以通过指定第三个参数来设置等待时间。例如,使用portMAX_DELAY表示无限等待,即直到接收到消息为止。 通过以上步骤,我们可以实现在ESP32开发中使用FreeRTOS消息队列进行中断服务消息发送与响应。这种方式可以实现不同任务之间的通信和同步,提高系统的并发性和实时性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值