安富莱电子 www.armfly.com
安富莱_STM32-V5开发板_FreeRTOS教程(V1.0)
进入和退出临界区使用的时候一定要保证成对使用
将 bsp.h 文件里面的宏定义:#define USE_FreeRTOS 1
/* 开关全局中断的宏 */
#define ENABLE_INT() __set_PRIMASK(0) /* 使能全局中断 */
#define DISABLE_INT() __set_PRIMASK(1) /* 禁止全局中断 */
修改为如下的形式:
#if USE_FreeRTOS == 1
#include "FreeRTOS.h"
#include "task.h"
#define DISABLE_INT() taskENTER_CRITICAL()
#define ENABLE_INT() taskEXIT_CRITICAL()
#else
/* 开关全局中断的宏 */
#define ENABLE_INT() __set_PRIMASK(0) /* 使能全局中断 */
#define DISABLE_INT() __set_PRIMASK(1) /* 禁止全局中断 */
#endif
/*
*********************************************************************************************************
*程序里单次定时器中断,50ms 后在定时器中断将任务 vTaskLED 恢复。
*1. printf 函数的多任务调用通过任务代码中临界段的进入和退出函数taskENTER_CRITICAL()和 taskEXIT_CRITICAL()实现互斥效果。
*2.中断服务程序中临界段的调用通过函数 portSET_INTERRUPT_MASK_FROM_ISR()和portCLEAR_INTERRUPT_MASK_FROM_ISR()实现保护。
*3.临界区解释:
* 代码的临界段也称为临界区,指处理时不可分割的代码。一旦这部分代码开始执行,则不允许任何中断打入。为确保临界段代码的执行不被中断,在进入临界段之前必须关中断,而临界段 代码执行完后,要立即开中断。
*4. (1)本实验通过如下两个函数可以实现任务代码中临界段的进入和退出,支持嵌套调用
* taskENTER_CRITICAL(); 进入临界区
* 临界区代码
* taskEXIT_CRITICAL(); 退出临界区
*
* (2)本实验通过如下两个函数可以实现中断服务程序中临界段的进入和退出,支持嵌套调用
* UBaseType_t uxSavedInterruptStatus;
* uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); 进入临界区
* 临界区代码
* portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); 退出临界区
*
* (3)通过如下两个函数实现开关中断,注意,关闭了中断也就关闭了任务的调度,不支持嵌套调用:
* taskDISABLE_INTERRUPTS(); 关闭中断
* 防止被中断打断的代码
* taskENABLE_INTERRUPTS(); 打开中断
*
* (4)临界区设置和开关中断的区别。
* 临界区设置里面也有开关中断操作的,并且支持开关中断的嵌套使用,而单纯的开关
* 中断操作是不能够嵌套使用的,比如下面:
* void FunctionA()
* {
* taskDISABLE_INTERRUPTS(); 关闭中断
* FunctionB(); 调用函数B
* FunctionC(); 调用函数C
* taskENABLE_INTERRUPTS(); 打开中断
* }
*
* void FunctionB()
* {
* taskDISABLE_INTERRUPTS(); 关闭中断
* 代码
* taskENABLE_INTERRUPTS(); 打开中断
* }
* 工程中调用了FunctionA就会出现执行完FunctionB后中断被打开的情况,此时
* FunctionC将不被保护了。
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* 函 数 名: vTaskLED
* 功能说明: LED闪烁和串口打印
* 形 参: pvParameters 是在创建该任务时传递的形参
* 返 回 值: 无
* 优 先 级: 2
*********************************************************************************************************
*/
static void vTaskLED(void *pvParameters)
{
while(1)
{
taskENTER_CRITICAL(); /* 进入临界区 */
printf("任务vTaskLED正在运行\r\n");
taskEXIT_CRITICAL(); /* 退出临界区 */
bsp_LedToggle(2);
vTaskDelay(500);
}
}
硬件外设的初始化添加:
bsp_InitHardTimer(); /* 初始化 TIM2 定时器 */
定时器中断回调函数中:
/*
*********************************************************************************************************
* 函 数 名: TIM_CallBack1
* 功能说明: 定时器中断的回调函数,此函数被bsp_StartHardTimer所调用。
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
static void TIM_CallBack1(void)
{
BaseType_t xYieldRequired;
UBaseType_t uxSavedInterruptStatus;
uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); /* 进入临界区 */
{
/* 用户可以在这里添加临界段代码,我们这里暂时未用到 */
}
portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); /* 退出临界区 */
/* 恢复挂起任务 */
xYieldRequired = xTaskResumeFromISR(xHandleTaskLED);
/* 退出中断后是否需要执行任务切换 */
if( xYieldRequired == pdTRUE )
{
portYIELD_FROM_ISR(xYieldRequired);
}
}
网友评论