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();