33 freertos任务通知--代替消息队列(任务邮箱)-中断

三十三、 freertos任务通知–代替消息队列(任务邮箱)-中断

main.c:

/**
**************************************************************************************************/
#include 
#include //标准C库文件,定义了各种类型的范围
#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);
/**********************End**************************************/



#include "FreeRTOSConfig.h"
/* FreeRTOS头文件 */
#include "FreeRTOS.h"
#include "task.h"
#include "event_groups.h"//事件头文件
#include "queue.h"//队列头文件
#include "semphr.h"//信号量头文件
#include "timers.h"//软件定时器头文件

/**************************** 任务句柄 ********************************/

static xTaskHandle LED_TaskHandle=NULL;
static xTaskHandle KEY_TaskHandle=NULL;
	
/*************************** 宏定义 ************************************/

#define TASK_STACK_SIZE 32//每个任务的栈大小



/* Sets up system hardware 
**********************************************************************
  * @ 函数名  : BSP_Init
  * @ 功能说明: 板级外设初始化,所有板子上的初始化均可放在这个函数里面
  * @ 参数    :   
  * @ 返回值  : 无
*********************************************************************/
static void prvSetupHardware(void)
{

	SystemCoreClockUpdate();

	DEBUGINIT();
	led_Init() ;	
	Key_INIT();
	MRT_Init();
	DEBUGOUT("%u MHz\n",SystemCoreClock/1000000);
	Board_UARTPutSTR("build date: " __DATE__ " build time: " __TIME__ "\n");

}

/**********************************************************************
 * @ 函数名 :  
 * @ 功能说明:  接收发送通知
 * @ 参数 :
 * @ 返回值 : 无
 ********************************************************************/
static void LED_Task(void* parameter)
{
	BaseType_t xReturn=pdTRUE;
 	u32	r_event=0;//接收事件
	
	const TickType_t xMaxBlockTime = pdMS_TO_TICKS(500); /* 设置最大等待时间为 500ms */
	while(1)
	{

		/*
			第一个参数 ulBitsToClearOnEntry 的作用(函数执行前):
				ulNotifiedValue &= ~ulBitsToClearOnEntry
				简单的说就是参数 ulBitsToClearOnEntry 那个位是 1,那么 ulNotifiedValue的那个位就会被清零。
				这里 ulBitsToClearOnEntry = 0x00000000 就是函数执行前保留所有位。
		
			第二个参数 ulBitsToClearOnExit 的作用(函数退出前):
					ulNotifiedValue &= ~ulBitsToClearOnExit
				简单的说就是参数 ulBitsToClearOnEntry 那个位是 1,那么 ulNotifiedValue的那个位就会被清零。
				这里 ulBitsToClearOnExit = 0xFFFFFFFF 就是函数退出前清楚所有位。
			注: ulNotifiedValue 表示任务 LED_Task 的任务控制块里面的变量,用来做消息邮箱数据的存取。
		*/
		/*获取一个任务通知,没有获取到一直等待 */
		xReturn=xTaskNotifyWait(0x0,//进入函数的时候不清除任务 bit
								0xFFFFFFFF,//退出函数的时候清除所有的 bitR
								&r_event,// 保存 ulNotifiedValue 到变量  
								xMaxBlockTime);/* 最大允许延迟时间 */
		/* 此函数只会返回 pdPASS */
		if(pdTRUE ==xReturn)
		{
			 printf("接收到消息邮箱数据 ulValue = %d\r\n", r_event);
		
		}			
		else
			Board_LED_Toggle(1);
		
//		vTaskDelay(200);
	}
}


/**********************************************************************
 * @ 函数名 :   
 * @ 功能说明: 发送任务
 * @ 参数 :
 * @ 返回值 : 无
 ********************************************************************/
static void KEY_Task(void* parameter)
{
//	BaseType_t xReturn =pdPASS;
	
	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:
				{
					/* K1键按下 */
//					printf ( "KEY1 被按下\n" );
					printf("K1键按下,启动单次定时器中断,100ms后在定时器中断给任务 LED_Task 发送消息邮箱数据 覆盖\r\n");
					bsp_HardTimer(3,10, (void*)TIM_CallBack1);
					
					Board_LED_Toggle(6);
					
				}break;
				case 2:
				{
					 /* K2键按下 */
//					printf ( "KEY2 被按下\n" );
					printf("K2键按下,启动单次定时器中断,500ms后在定时器中断给任务 LED_Task 发送消息邮箱数据 非覆盖\r\n");
					bsp_HardTimer(2, 2,(void*)TIM_CallBack2);
					
					
					Board_LED_Toggle(5);
					
				}break;
				case 3:
				{
					 /* K3键按下*/
					 
 					
				}break;
				default:break;
			}
			key2=0;
		}
			
	}
}

/***********************************************************************
  * @ 函数名  : AppTaskCreate
  * @ 功能说明: 为了方便管理,所有的任务创建函数都放在这个函数里面
  * @ 参数    : 无  
  * @ 返回值  : 无
  **********************************************************************/
static void AppTaskCreate(void)
{
	BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */
	taskENTER_CRITICAL();//进入临界区,禁止中断打断
	
	xReturn = xTaskCreate(	 LED_Task,
							"LED_Task",
							TASK_STACK_SIZE*6,
							NULL,
							2,
							&LED_TaskHandle);
	if (pdPASS == xReturn)
		printf("创建 Receive1_Task 任务成功!\r\n");
	

	xReturn = xTaskCreate(	 KEY_Task,
							"KEY_Task",
							TASK_STACK_SIZE*6,
							NULL,
							1,
							&KEY_TaskHandle);
	if (pdPASS == xReturn)
		printf("创建 Send_Task 任务成功!\r\n");

	taskEXIT_CRITICAL(); //退出临界区	

}

/**
 * @brief	main routine for blinky example
 * @return	Function should not exit.
 */
int main(void)
{
	
	prvSetupHardware();
	Board_UARTPutSTR("LPC824 FreeRTOS 任务通知任务间通信 \n");

	

	AppTaskCreate();

	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;

	xTaskNotifyFromISR(LED_TaskHandle,/* 目标任务 *///这里是句柄,不是函数名,不然会进入硬件错误
			           g_uiCount++,           /* 发送数据 */
			           eSetValueWithOverwrite,/* 如果目标任务上次的数据还没有处理,上次的数据会被覆盖 */
	                   &xHigherPriorityTaskWoken);

	/* 如果 xHigherPriorityTaskWoken = pdTRUE,那么退出中断后切到当前最高优先级任务执行 */
	if(pdTRUE ==xHigherPriorityTaskWoken)
		portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
	
	Board_LED_Toggle(3);
}

static void TIM_CallBack2(void)
{
	BaseType_t xHigherPriorityTaskWoken = pdFALSE;
	
	/* 通过此函数的返回值可以判断是否发送成功,这里没有做判断 */
	xTaskNotifyFromISR(LED_TaskHandle,/* 目标任务 *///这里是句柄,不是函数名,不然会进入硬件错误
			           g_uiCount++,              /* 发送数据 */
			           eSetValueWithoutOverwrite,/* 如果目标任务上次的数据还没有处理,上次的数据不会被覆盖 */
	                   &xHigherPriorityTaskWoken);

	/* 如果 xHigherPriorityTaskWoken = pdTRUE,那么退出中断后切到当前最高优先级任务执行 */
	if(pdTRUE ==xHigherPriorityTaskWoken)
		portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
	
	Board_LED_Toggle(4);
}


void HardFault_Handler(void)
{
	printf("硬件错误中断\n");
	while(1)
	{

	}
}

tim_mrt.h:

#ifndef _TIM_MRT_H_
#define _TIM_MRT_H_

void MRT_Init(void);
void setupMRT(uint8_t ch, MRT_MODE_T mode, uint32_t rate);
void bsp_HardTimer(u8 ch,uint32_t frequency_Hz, void * _pCallBack);

#endif

tim_mrt.c:

/*
 * 	注意,MRT定时器有4个独立通道,但共用中断号10。
 */
#include "board.h"
#include "tim_mrt.h"
/*****************************************************************************
 * Private types/enumerations/variables
 ****************************************************************************/

/* 保存 TIM定时中断到后执行的回调函数指针 */
static void (*s_TIM_CallBack0)(void);
static void (*s_TIM_CallBack1)(void);
static void (*s_TIM_CallBack2)(void);
static void (*s_TIM_CallBack3)(void);

 

/*****************************************************************************
 * Public types/enumerations/variables
 ****************************************************************************/

 
 
/* Interrupt fire reference counters for t0/1, t2, and t3 */
//bool Ms500;
//static uint32_t t01 , t3;
//static uint32_t t2;

/*****************************************************************************
 * Private functions
 ****************************************************************************/

/*  设置定时器

参数:
ch :定时器通道(0,1,2,3)
mode :模式(单次或者循环)
rate :速率,数字越小,间隔越长。
	--	1 表示 1Hz,即1s。
	--	2 表示 2Hz,即500ms。
	--	100表示100Hz,即10ms。
*/
void setupMRT(uint8_t ch, MRT_MODE_T mode, uint32_t rate)
{
	LPC_MRT_CH_T *pMRT;
	 
	pMRT = Chip_MRT_GetRegPtr(ch); //返回定时器的指针 

									//12MHz
	Chip_MRT_SetInterval(pMRT, (Chip_Clock_GetSystemClockRate() / rate) |\
						 MRT_INTVAL_LOAD);//立即加载
 
	Chip_MRT_SetMode(pMRT, mode);
	/* Clear pending interrupt and enable timer */
	Chip_MRT_IntClear(pMRT); 
	Chip_MRT_SetEnabled(pMRT); 
}

/*****************************************************************************
 * Public functions
 ****************************************************************************/

/**
 * @brief	MRT example main function
 * @return	Status (This function will not return)
 */
void MRT_Init(void)
{
	
	Chip_MRT_Init();//启用MRT时钟,复位MET
	Chip_MRT_SetDisabled(Chip_MRT_GetRegPtr(3));//禁用定时器通道3
	Chip_MRT_SetDisabled(Chip_MRT_GetRegPtr(2));//禁用定时器通道2 
	
	NVIC_EnableIRQ(MRT_IRQn);	//启用定时器外设中断

	//通道初始化
//	setupMRT(2, MRT_MODE_REPEAT, 100); //100Hz,10ms循环
//	setupMRT(3, MRT_MODE_ONESHOT, 2); //2Hz单次,中断只发生一次,需要再次赋值。
//	setupMRT(3, MRT_MODE_REPEAT, 1); //1Hz,1s循环


}

/**
 * @brief	Handle interrupt from MRT
 * @return	Nothing
 */
void MRT_IRQHandler(void)
{
	uint32_t int_pend;

	int_pend = Chip_MRT_GetIntPending();
	Chip_MRT_ClearIntPending(int_pend);

	 //判断中断通道0和1
	if (int_pend & (MRTn_INTFLAG(0) | MRTn_INTFLAG(1))) {
		Board_LED_Set(4, true);

		s_TIM_CallBack0();
		s_TIM_CallBack1();
	}

	 //判断中断通道2
	if (int_pend & (MRTn_INTFLAG(2))) {	 

		s_TIM_CallBack2();
//		t2++;
		
	}

	 //判断中断通道3
	if (int_pend & (MRTn_INTFLAG(3))) {
		
		s_TIM_CallBack3();

	}
}

/*
*********************************************************************************************************
*	函 数 名: bsp_HardTimer
*	功能说明: 定时时间到后执行回调函数。
*	形    参: 
			ch: 多速率定时器通道(0,1,2,3)
*             _pCallBack : 定时时间到后,被执行的函数
*	返 回 值: 无
*********************************************************************************************************
*/
void bsp_HardTimer(u8 ch,uint32_t frequency_Hz, void * _pCallBack)
{
	
	switch(ch)
	{
		case 0:	{}break;
		case 1:{}break;
		case 2:
		{
			//因为函数指针赋值后才能正常运行,所以必须在调用时再初始化。
			s_TIM_CallBack2=(void (*)(void))_pCallBack;			
			setupMRT(2, MRT_MODE_ONESHOT, frequency_Hz); //单次
		}break;
		case 3:
		{
			s_TIM_CallBack3=(void (*)(void))_pCallBack;
//			setupMRT(3, MRT_MODE_REPEAT, frequency_Hz); //循环			
			setupMRT(3, MRT_MODE_ONESHOT, frequency_Hz); //单次
		}break;
		default:break;
	}
	 
	
}
/**
*END_TMI
*/

验通过函数xTaskNotifyFromISR和xTaskNotifyWait实现消息邮箱的中断方式功能。
K1键按下,启动单次定时器中断,100ms后在定时器中断给任务LED_Task发送消息邮箱数据。
K2键按下,启动单次定时器中断,500ms后在定时器中断给任务LED_Task发送消息邮箱数据。

实验现象:
key按键任务里面,当KEY1和KEY2按下后,LED任务打印出通知值。
使用函数:
发送 xTaskNotifyFromISR();
接收 xTaskNotifyWait();

你可能感兴趣的:(FreeRTOS,单片机,freertos,嵌入式软件)