FreeRTOS临界段和开关中断

2023-11-11

http://blog.sina.com.cn/s/blog_98ee3a930102wg5u.html

本章教程为大家讲解两个重要的概念,FreeRTOS的临界段和开关中断。

本章教程配套的例子含Cortex-M3内核的STM32F103Cortex-M4内核的STM32F407以及F429

15.1 临界段

15.2 任务代码临界段处理

15.3 中断服务程序临界段处理

15.4 开关中断的实现

15.5 BSP板级支持包中开关中断的特别处理

15.6. 实验例程说明

15.7       总结

 

 

15.1  临界段

代码的临界段也称为临界区,一旦这部分代码开始执行,则不允许任何中断打断。为确保临界段代码的执行不被中断,在进入临界段之前须关中断,而临界段代码执行完毕后,要立即开中断。

 

l  FreeRTOS临界段相关知识补充

FreeRTOS的源码中有多处临界段的地方,临界段虽然保护了关键代码的执行不被打断,但也会影响系统的实时性。比如此时某个任务正在调用系统API函数,而且此时中断正好关闭了,也就是进入到了临界区中,这个时候如果有一个紧急的中断事件被触发,这个中断就不能得到及时执行,必须等到中断开启才可以得到执行,如果关中断时间超过了紧急中断能够容忍的限度,危害是可想而知的。

 

FreeRTOS源码中就有多处临界段的处理,跟FreeRTOS一样,uCOS-IIuCOS-III源码中都是有临界段的,而RTX的源码中不存在临界段。另外,除了FreeRTOS操作系统源码所带的临界段以外,用户写应用的时候也有临界段的问题,比如以下两种:

u  读取或者修改变量(特别是用于任务间通信的全局变量)的代码,一般来说这是最常见的临界代码。

u  调用公共函数的代码,特别是不可重入的函数,如果多个任务都访问这个函数,结果是可想而知的。

总之,对于临界段要做到执行时间越短越好,否则会影响系统的实时性。

15.2 任务代码临界段处理

FreeRTOS任务代码中临界段的进入和退出主要是通过操作寄存器basepri实现的。进入临界段前操作寄存器basepri关闭了所有小于等于宏定义configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY所定义的中断优先级,这样临界段代码就不会被中断干扰到,而且实现任务切换功能的PendSV中断和滴答定时器中断是最低优先级中断,所以此任务在执行临界段代码期间是不会被其它高优先级任务打断的。退出临界段时重新操作basepri寄存器,即打开被关闭的中断这里我们不考虑不受FreeRTOS管理的更高优先级中断FreeRTOS进入和退出临界段的函数如下:

#define taskENTER_CRITICAL()         portENTER_CRITICAL()

#define taskEXIT_CRITICAL()          portEXIT_CRITICAL()

上面这两个函数是供用户调用的,其中函数taskENTER_CRITICAL是进入临界段,函数taskEXIT_CRITICAL是退出临界段。进一步跟踪宏定义的实现如下:

#define portENTER_CRITICAL()         vPortEnterCritical()

#define portEXIT_CRITICAL()          vPortExitCritical()

再进一步跟踪宏定义的实现如下:

void vPortEnterCritical( void )

{

     portDISABLE_INTERRUPTS();

     uxCriticalNesting++;

 

    

     if( uxCriticalNesting == 1 )

     {

         configASSERT( ( portNVIC_INT_CTRL_REG & portVECTACTIVE_MASK ) == 0 );

     }

}

 

 

void vPortExitCritical( void )

{

     configASSERT( uxCriticalNesting );

     uxCriticalNesting--;

     if( uxCriticalNesting == 0 )

     {

         portENABLE_INTERRUPTS();

     }

}

通过上面的两个函数vPortEnterCriticalvPortExitCritical可以看出,进入临界段和退出临界段是通过函数调用开关中断函数portENABLE_INTERRUPTSportDISABLE_INTERRUPTS实现的。细心的读者还会发现上面的这两个函数都对变量uxCriticalNesting进行了操作。这个变量比较重要,用于临界段的嵌套计数。初学的同学也许会问这里直接的开关中断不就可以了吗,为什么还要做一个嵌套计数呢?主要是因为直接的开关中断方式不支持在开关中断之间的代码里再次执行开关中断的嵌套处理,假如当前我们的代码是关闭中断的,嵌套了一个含有开关中断的临界区代码后,退出时中断就成开的了,这样就出问题了。通过嵌套计数就有效地防止了用户嵌套调用函数taskENTER_CRITICALtaskEXIT_CRITICAL时出错。

l  直接的开关中断方式不支持嵌套调用例子说明

比如下面的例子:

void FunctionA()

{

taskDISABLE_INTERRUPTS();  关闭中断

FunctionB(); 调用函数B

FunctionC(); 调用函数C

taskENABLE_INTERRUPTS();  打开中断

}

 

void FunctionB()

{

taskDISABLE_INTERRUPTS();  关闭中断

代码

taskENABLE_INTERRUPTS();  打开中断

}

工程中调用了FunctionA就会出现执行完FunctionB后中断被打开的情况,此时FunctionC

不被保护了。

 

接下来继续说明开关中断的实现,我们要打破砂锅问到底:

#define portDISABLE_INTERRUPTS()          vPortRaiseBASEPRI()

#define portENABLE_INTERRUPTS()           vPortSetBASEPRI( 0 )

函数vPortRaiseBASEPRIvPortSetBASEPRI的源码实现如下:

static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI )

{

     __asm

     {

        

         msr basepri, ulBASEPRI

     }

}

 

 

static portFORCE_INLINE void vPortRaiseBASEPRI( void )

{

uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;

 

     __asm

     {

         

         msr basepri, ulNewBASEPRI

         dsb

         isb

     }

}

经过这么多次的宏定义后,终于来到了最终的原始函数。FreeRTOS的这种层层调用宏定义的方法在带来便利操作的同时,却让用户在分析源码的时候非常不方便。

通过上面的源码实现可以看出,FreeRTOS的开关全局中断是通过操作寄存器basepri实现的,关于这个寄存器,我们已经在第12章进行了详细的讲解,这里不再赘述。

使用举例:

使用的时候一定要保证成对使用

 

static void vTaskLED(void *pvParameters)

{

     TickType_t xLastWakeTime;

     const TickType_t xFrequency = 200;

 

    

    xLastWakeTime = xTaskGetTickCount();

    

    while(1)

    {

            

         taskENTER_CRITICAL();

         printf("任务vTaskLED正在运行\r\n");

            

         taskEXIT_CRITICAL();

         bsp_LedToggle(2);

         bsp_LedToggle(3);

        

       

        vTaskDelayUntil(&xLastWakeTime, xFrequency);

    }

}

嵌套使用举例:

void FunctionB()

{

     taskENTER_CRITICAL()

     临界段代码

     taskEXIT_CRITICAL();

 

}

 

void FunctionA()

{

     taskENTER_CRITICAL(); 

FunctionB();            

FunctionC();               

     taskEXIT_CRITICAL();   

}

15.3 中断服务程序临界段处理

与任务代码里临界段的处理方式类似,中断服务程序里面临界段的处理也有一对开关中断函数。

#define taskENTER_CRITICAL_FROM_ISR()     portSET_INTERRUPT_MASK_FROM_ISR()

#define taskEXIT_CRITICAL_FROM_ISR( x )   portCLEAR_INTERRUPT_MASK_FROM_ISR( x )

进一步跟踪宏定义的实现如下:

#define portSET_INTERRUPT_MASK_FROM_ISR()      ulPortRaiseBASEPRI()

#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x)   vPortSetBASEPRI(x)

再进一步跟踪宏定义的实现如下:

static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI )

{

     __asm

     {

        

         msr basepri, ulBASEPRI

     }

}

 

static portFORCE_INLINE uint32_t ulPortRaiseBASEPRI( void )

{

uint32_t ulReturn, ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;

 

     __asm

     {

        

         mrs ulReturn, basepri

         msr basepri, ulNewBASEPRI

         dsb

         isb

     }

 

     return ulReturn;

}

通过上面的源码可以看出,中断服务程序里面的临界段代码的开关中断也是通过寄存器basepri实现的。

初学的同学也许会问,这里怎么没有中断嵌套计数了呢?是的,这里换了另外一种实现方法,通过保存和恢复寄存器basepri的数值就可以实现嵌套使用。如果大家研究过uCOS-II或者III的源码,跟这里的实现方式是一样的,具体看下面的使用举例。

使用举例:

使用的时候一定要保证成对使用

 

void TIM6_DAC_IRQHandler( void )

{

UBaseType_t uxSavedInterruptStatus;

 

uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();

     临界区代码

portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );

 

}

嵌套使用举例:

void FunctionB()

{

UBaseType_t uxSavedInterruptStatus;

 

uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();

     临界区代码

portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );

}

 

 

 

void TIM6_DAC_IRQHandler( void )

{

UBaseType_t uxSavedInterruptStatus;

 

uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();

FunctionB(); 

FunctionC();     

portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );

}

15.4开关中断的实现

FreeRTOS也专门提供了一组开关中断函数,实现比较简单,其实就是前面15.2小节里面临界段进入和退出函数的精简版本,主要区别是不支持中断嵌套。具体实现如下:

#define taskDISABLE_INTERRUPTS()   portDISABLE_INTERRUPTS()

#define taskENABLE_INTERRUPTS()    portENABLE_INTERRUPTS()

进一步跟踪宏定义的实现如下:

#define portDISABLE_INTERRUPTS()          vPortRaiseBASEPRI()

#define portENABLE_INTERRUPTS()           vPortSetBASEPRI( 0 )

函数vPortRaiseBASEPRIvPortSetBASEPRI的源码实现如下:

static portFORCE_INLINE void vPortSetBASEPRI( uint32_t ulBASEPRI )

{

     __asm

     {

        

         msr basepri, ulBASEPRI

     }

}

 

 

static portFORCE_INLINE void vPortRaiseBASEPRI( void )

{

uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;

 

     __asm

     {

         

         msr basepri, ulNewBASEPRI

         dsb

         isb

     }

}

从上面的源码可以看出,FreeRTOS的全局中断开关是通过操作寄存器basepri实现的,关于这个寄存器,我们已经在第12章进行了详细的讲解,这里不再赘述。

使用举例:

使用的时候一定要保证成对使用

 

static void vTaskLED(void *pvParameters)

{

     TickType_t xLastWakeTime;

     const TickType_t xFrequency = 200;

 

    

    xLastWakeTime = xTaskGetTickCount();

    

    while(1)

    {

              

         taskDISABLE_INTERRUPTS();

         printf("任务vTaskLED正在运行\r\n");

              

          taskENABLE_INTERRUPTS();

         bsp_LedToggle(2);

         bsp_LedToggle(3);

        

       

        vTaskDelayUntil(&xLastWakeTime, xFrequency);

    }

}

15.5BSP板级支持包中开关中断的特别处理

前面为大家讲解了FreeRTOS临界段的处理方法和开关中断方法,加上了FreeRTOS操作系统后,我们实际编写的外设驱动又该怎么修改呢?因为外设驱动编写时,有些地方有用到开关中断操作,这里以此教程配套的STM32F103F407F429开发板为例进行说明,这三种开发板的外设驱动的编写架构都是统一的,用户只需将bsp.h文件里面的宏定义:

 

#define ENABLE_INT()   __set_PRIMASK(0)  

#define DISABLE_INT()  __set_PRIMASK(1)  

修改为如下的形式:

#define  USE_FreeRTOS      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

u  #define  USE_FreeRTOS      1

将中断开关设置改成了条件编译的形式,这样在使用裸机或者使用FreeRTOS时,切换自如。此宏定义配置为1表示使用FreeRTOS的开关中断API函数,配置为0表示使用裸机的方式开关中断。

u  采用taskENTER_CRITICAL()taskEXIT_CRITICAL()实现开关中断

因为BSP驱动包的源码基本没有在中断里面进行开关中断,都是在中断以外,所以开关中断是采用的任务代码里面临界段的处理函数,而且支持嵌套调用。

大家写的工程代码也可以采用类似的方案,方便裸机和FreeRTOS的切换,或者采用其它适合自己的方案。另外要注意,因为FreeRTOS存在不受其控制的更高优先级中断,用户需要根据实际情况进行特别处理,可以不采用FreeRTOS的开关中断函数,而是直接使用__set_PRIMASK实现全局中断的开关。

15.6实验例程说明

15.6.1STM32F103开发板实验

配套例子:

V4-309_FreeRTOS实验_临界段和开关中断

实验目的:

1.     学习FreeRTOS的临界段和开关中断设置

实验内容:

1.     K1按键按下,串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1)。

2.     K2按键按下,挂起任务vTaskLED

3.     K3按键按下,启动单次定时器中断,50ms后在定时器中断将任务vTaskLED恢复。

4.     本实验printf函数的多任务调用通过任务代码中临界段的进入和退出函数taskENTER_CRITICAL()taskEXIT_CRITICAL()实现互斥效果。

5.     本实验中断服务程序中临界段的调用通过函数portSET_INTERRUPT_MASK_FROM_ISR()portCLEAR_INTERRUPT_MASK_FROM_ISR()实现保护。

6.     各个任务实现的功能如下:

              vTaskUserIF任务   :按键消息处理。

              vTaskLED任务     LED闪烁和串口打印。

              vTaskMsgPro任务 :消息处理,这里是用作LED闪烁和串口打印。

              vTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。

FreeRTOS的配置:

FreeRTOSConfig.h文件中的配置如下:

 

#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)

 #include

 extern volatile uint32_t ulHighFrequencyTimerTicks;

#endif

 

#define configUSE_PREEMPTION         1

#define configUSE_IDLE_HOOK          0

#define configUSE_TICK_HOOK          0

#define configCPU_CLOCK_HZ           ( ( unsigned long ) 72000000 )  

#define configTICK_RATE_HZ           ( ( TickType_t ) 1000 )

#define configMAX_PRIORITIES         ( 5 )

#define configMINIMAL_STACK_SIZE     ( ( unsigned short ) 128 )

#define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 17 * 1024 ) )

#define configMAX_TASK_NAME_LEN      ( 16 )

#define configUSE_TRACE_FACILITY      1

#define configUSE_16_BIT_TICKS       0

#define configIDLE_SHOULD_YIELD      1

 

 

#define configGENERATE_RUN_TIME_STATS                1

#define configUSE_STATS_FORMATTING_FUNCTIONS         1

#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()     (ulHighFrequencyTimerTicks = 0ul)

#define portGET_RUN_TIME_COUNTER_VALUE()             ulHighFrequencyTimerTicks

//#define portALT_GET_RUN_TIME_COUNTER_VALUE           1

 

 

#define configUSE_CO_ROUTINES            0

#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )

 

 

 

#define INCLUDE_vTaskPrioritySet          1

#define INCLUDE_uxTaskPriorityGet         1

#define INCLUDE_vTaskDelete               1

#define INCLUDE_vTaskCleanUpResources      0

#define INCLUDE_vTaskSuspend              1

#define INCLUDE_vTaskDelayUntil           1

#define INCLUDE_vTaskDelay                1

 

 

#ifdef __NVIC_PRIO_BITS

    

     #define configPRIO_BITS              __NVIC_PRIO_BITS

#else

     #define configPRIO_BITS              4       

#endif

 

 

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY              0x0f

 

 

#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY         0x01


FreeRTOS任务调试信息(按K1按键,串口打印):

【FreeRTOS操作系统教程】第15章 <wbr>FreeRTOS临界段和开关中断

 

上面截图中打印出来的任务状态字母B, R, D, S对应如下含义:

#define tskBLOCKED_CHAR          ( 'B' )  任务阻塞

#define tskREADY_CHAR           ( 'R' )  任务就绪

#define tskDELETED_CHAR           ( 'D' )  任务删除

#define tskSUSPENDED_CHAR   ( 'S' )  任务挂起

程序设计:

u  任务栈大小分配:

vTaskUserIF任务   2048字节

vTaskLED任务     2048字节

vTaskMsgPro任务 :2048字节

vTaskStart任务    2048字节

任务栈空间是在任务创建的时候从FreeRTOSConfig.h文件中定义的heap空间中申请的

#define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 17 * 1024 ) )

u  系统栈大小分配:

【FreeRTOS操作系统教程】第15章 <wbr>FreeRTOS临界段和开关中断

 

u  FreeROTS初始化:

 

int main(void)

{

    

     __set_PRIMASK(1); 

    

    

     bsp_Init();

    

    

     vSetupSysInfoTest();

    

    

     AppTaskCreate();

    

   

    vTaskStartScheduler();

 

    

     while(1);

}

u  硬件外设初始化

硬件外设的初始化是在bsp.c文件实现:

 

void bsp_Init(void)

{

    

    

          NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

 

     bsp_InitUart();   

     bsp_InitLed();    

     bsp_InitKey();    

 

     bsp_InitHardTimer();

}

u  FreeRTOS任务创建:

 

static void AppTaskCreate (void)

{

    xTaskCreate( vTaskTaskUserIF,  

                 "vTaskUserIF",    

                 512,              

                 NULL,             

                 1,                

                 &xHandleTaskUserIF );  /* 任务句柄  */

    

    

     xTaskCreate( vTaskLED,          

                 "vTaskLED",        

                 512,               

                 NULL,              

                 2,                 

                 &xHandleTaskLED );

    

     xTaskCreate( vTaskMsgPro,           

                 "vTaskMsgPro",          

                 512,                    

                 NULL,                   

                 3,                      

                 &xHandleTaskMsgPro );  /* 任务句柄  */

    

    

     xTaskCreate( vTaskStart,            

                 "vTaskStart",           

                 512,                    

                 NULL,                   

                 4,                      

                 &xHandleTaskStart );   

}

u  四个FreeRTOS任务的实现:

 

static void vTaskTaskUserIF(void *pvParameters)

{

     uint8_t ucKeyCode;

     uint8_t pcWriteBuffer[500];

 

    while(1)

    {

         ucKeyCode = bsp_GetKey();

        

         if (ucKeyCode != KEY_NONE)

         {

              switch (ucKeyCode)

              {

                  

                   case KEY_DOWN_K1: 

                       taskENTER_CRITICAL();         

                       printf("=================================================\r\n");

                       printf("任务名      任务状态 优先级   剩余栈 任务序号\r\n");

                       vTaskList((char *)&pcWriteBuffer);

                       printf("%s\r\n", pcWriteBuffer);

                  

                       printf("\r\n任务名       运行计数         使用率\r\n");

                       vTaskGetRunTimeStats((char *)&pcWriteBuffer);

                       printf("%s\r\n", pcWriteBuffer);

                       taskEXIT_CRITICAL();    

                       break;

                  

                  

                   case KEY_DOWN_K2:

                       taskENTER_CRITICAL();   

                       printf("K2键按下,挂起任务vTaskLED\r\n");

                       taskEXIT_CRITICAL();    

                       vTaskSuspend(xHandleTaskLED);

                       break;

                  

                  

                   case KEY_DOWN_K3:

                        taskENTER_CRITICAL();                       

                       printf("K3键按下,启动单次定时器中断,50ms后在定时器中断将任务vTaskLED恢复\r\n");

                       taskEXIT_CRITICAL(); 

                       bsp_StartHardTimer(1 ,50000, (void *)TIM_CallBack1);

                       break;

 

                  

                   default:                    

                       break;

              }

         }

        

         vTaskDelay(20);

     }

}

 

 

static void vTaskLED(void *pvParameters)

{

    while(1)

{

     taskENTER_CRITICAL();   

     printf("任务vTaskLED正在运行\r\n");

     taskEXIT_CRITICAL();    

     bsp_LedToggle(2);

     vTaskDelay(500);

    }

}

 

 

static void vTaskMsgPro(void *pvParameters)

{

    while(1)

{

     taskENTER_CRITICAL();  

     printf("任务vTaskMsgPro正在运行\r\n");

     taskEXIT_CRITICAL();     

     bsp_LedToggle(3);

     vTaskDelay(600);

    }

}

 

 

static void vTaskStart(void *pvParameters)

{

    while(1)

    {

        

         bsp_KeyScan();

        vTaskDelay(10);

    }

}

u  定时器中断回调函数中将任务从挂起状态恢复:

定时器中断的初始化和中断函数在bsp_timer.c 文件中实现,这个不是教程的重点,故不作介绍。 这里主要关心中断服务程序中临界段的实现方法。

 

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

     }

}

15.6.2STM32F407开发板实验

配套例子:

V5-309_FreeRTOS实验_临界段和开关中断

实验目的:

1. 学习FreeRTOS的临界段和开关中断设置

实验内容:

1.     K1按键按下,串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1)。

2.     K2按键按下,挂起任务vTaskLED

3.     K3按键按下,启动单次定时器中断,50ms后在定时器中断将任务vTaskLED恢复。

4.     本实验printf函数的多任务调用通过任务代码中临界段的进入和退出函数taskENTER_CRITICAL()taskEXIT_CRITICAL()实现互斥效果。

5.     本实验中断服务程序中临界段的调用通过函数portSET_INTERRUPT_MASK_FROM_ISR()portCLEAR_INTERRUPT_MASK_FROM_ISR()实现保护。

6.     各个任务实现的功能如下:

              vTaskUserIF任务   :按键消息处理。

              vTaskLED任务     LED闪烁和串口打印。

              vTaskMsgPro任务 :消息处理,这里是用作LED闪烁和串口打印。

              vTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。

FreeRTOS的配置:

FreeRTOSConfig.h文件中的配置如下:

 

#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)

 #include

 extern volatile uint32_t ulHighFrequencyTimerTicks;

 

 

#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)

 #include

 extern volatile uint32_t ulHighFrequencyTimerTicks;

#endif

 

#define configUSE_PREEMPTION         1

#define configUSE_IDLE_HOOK          0

#define configUSE_TICK_HOOK           0

#define configCPU_CLOCK_HZ           ( ( unsigned long ) 168000000 ) 

#define configTICK_RATE_HZ           ( ( TickType_t ) 1000 )

#define configMAX_PRIORITIES         ( 5 )

#define configMINIMAL_STACK_SIZE     ( ( unsigned short ) 128 )

#define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 30 * 1024 ) )

#define configMAX_TASK_NAME_LEN      ( 16 )

#define configUSE_TRACE_FACILITY      1

#define configUSE_16_BIT_TICKS       0

#define configIDLE_SHOULD_YIELD      1

 

 

#define configGENERATE_RUN_TIME_STATS                1

#define configUSE_STATS_FORMATTING_FUNCTIONS         1

#define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()     (ulHighFrequencyTimerTicks = 0ul)

#define portGET_RUN_TIME_COUNTER_VALUE()             ulHighFrequencyTimerTicks

//#define portALT_GET_RUN_TIME_COUNTER_VALUE           1

 

 

#define configUSE_CO_ROUTINES             0

#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )

 

 

 

#define INCLUDE_vTaskPrioritySet     1

#define INCLUDE_uxTaskPriorityGet         1

#define INCLUDE_vTaskDelete               1

#define INCLUDE_vTaskCleanUpResources 0

#define INCLUDE_vTaskSuspend              1

#define INCLUDE_vTaskDelayUntil           1

#define INCLUDE_vTaskDelay                1

 

 

#ifdef __NVIC_PRIO_BITS

    

     #define configPRIO_BITS              __NVIC_PRIO_BITS

#else

     #define configPRIO_BITS              4        

#endif

 

 

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY              0x0f

 

 

#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY    0x01


FreeRTOS任务调试信息(按K1按键,串口打印):

【FreeRTOS操作系统教程】第15章 <wbr>FreeRTOS临界段和开关中断

 

上面截图中打印出来的任务状态字母B, R, D, S对应如下含义:

#define tskBLOCKED_CHAR          ( 'B' )  任务阻塞

#define tskREADY_CHAR           ( 'R' )  任务就绪

#define tskDELETED_CHAR           ( 'D' )  任务删除

#define tskSUSPENDED_CHAR   ( 'S' )  任务挂起

程序设计:

u  任务栈大小分配:

vTaskUserIF任务   2048字节

vTaskLED任务     2048字节

vTaskMsgPro任务 :2048字节

vTaskStart任务    2048字节

任务栈空间是在任务创建的时候从FreeRTOSConfig.h文件中定义的heap空间中申请的

#define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 30 * 1024 ) )

u  系统栈大小分配:

【FreeRTOS操作系统教程】第15章 <wbr>FreeRTOS临界段和开关中断

 

u  FreeROTS初始化:

 

int main(void)

{

    

     __set_PRIMASK(1); 

    

    

     bsp_Init();

    

    

     vSetupSysInfoTest();

    

    

     AppTaskCreate();

    

   

    vTaskStartScheduler();

 

    

     while(1);

}

u  硬件外设初始化

硬件外设的初始化是在bsp.c文件实现:

 

void bsp_Init(void)

{

    

    

     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

 

     bsp_InitUart();   

     bsp_InitKey();    

     bsp_InitLed();    

 

     bsp_InitHardTimer();

}

u  FreeRTOS任务创建:

 

static void AppTaskCreate (void)

{

    xTaskCreate( vTaskTaskUserIF,  

                 "vTaskUserIF",    

                 512,              

                 NULL,             

                 1,                

                 &xHandleTaskUserIF );  /* 任务句柄  */

    

    

     xTaskCreate( vTaskLED,          

                 "vTaskLED",        

                 512,               

                 NULL,              

                 2,                 

                 &xHandleTaskLED );

    

     xTaskCreate( vTaskMsgPro,           

                 "vTaskMsgPro",          

                 512,                    

                 NULL,                   

                 3,                      

                 &xHandleTaskMsgPro );  /* 任务句柄  */

    

    

     xTaskCreate( vTaskStart,            

                 "vTaskStart",           

                 512,                    

                 NULL,                   

                 4,                      

                 &xHandleTaskStart );   

}


。。。。。。。。。



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

FreeRTOS临界段和开关中断 的相关文章

  • FreeRTOS系列

    1 多任务系统 1 1 前后台系统 单片机裸机开发时 一般都是在main函数里面用while 1 做一个大循环来完成所有的处理 循环中调用相应的函数完成所需的处理 有时也需要在中断中完成一些处理 相对于多任务系统而言 这就是单人单任务系统也
  • FreeRTOS内核配置说明---FreeRTOS Kernel V10.2.1

    FreeRTOS内核是高度可定制的 使用配置文件FreeRTOSConfig h进行定制 每个FreeRTOS应用都必须包含这个头文件 用户根据实际应用来裁剪定制FreeRTOS内核 这个配置文件是针对用户程序的 而非内核 因此配置文件一般
  • FreeRTOS 软件定时器的使用

    FreeRTOS中加入了软件定时器这个功能组件 是一个可选的 不属于freeRTOS内核的功能 由定时器服务任务 其实就是一个定时器任务 来提供 软件定时器是当设定一个定时时间 当达到设定的时间之后就会执行指定的功能函数 而这个功能函数就叫
  • FreeRTOS-内核控制函数

    FreeRTOS 内核控制函数 FreeRTOS中有一些内核函数 一般来说这些内核函数在应用层不会使用 但是内核控制函数是理解FreeRTOS中断的基础 接下来我们逐一分析这些内核函数 taskYIELD 该函数的作用是进行任务切换 这是一
  • FreeRTOS软件定时器创建、复位、开始和停止(备忘)

    目录 一 简介 1 1 开发环境 1 2 摘要 二 STM32CubeIDE配置 三 创建定时器 3 1 头文件声明 3 2 工程文件定义 3 3 创建定时器 3 4 开启 复位 和关闭定时器 四 定时器回调函数 一 简介 1 1 开发环境
  • FreeRTOS简述和移植文档

    FreeRTOS简述和移植文档 文章目录 FreeRTOS简述和移植文档 1 前言 2 FreeRTOS简述 1 概述 2 实现 3 主要特色 4 支持平台 3 移植FreeRTOS 4 最后 1 前言 目前由于IOT的飞速发展 针对单片机
  • FreeRTOS系列

    1 RTOS简介 RTOS全称为 Real Time Operation System 即实时操作系统 RTOS强调的是实时性 又分为硬实时和软实时 硬实时要求在规定的时间内必须完成操作 不允许超时 而软实时里对处理过程超时的要求则没有很严
  • FreeRTOS学习笔记<中断>

    中断概念 Cortex M的NVIC最多支持240个IRQ 中断请求 1个不可屏蔽中断 NMI 1个Systick 滴答定时器 定时器中断和多个系统异常 Cortex M处理器有多个用于管中断和异常的可编程寄存器 这些寄存器大多数都在 NV
  • FreeRTOS+CubeMX系列第一篇——初识FreeRTOS

    文章目录 一 关于FreeRTOS 二 FreeRTOS的特点 三 如何在CubeMX上配置FreeRTOS 四 FreeRTOS文档资料 五 同系列博客 一 关于FreeRTOS 1 什么是FreeRTOS FreeRTOS是一个迷你的实
  • FreeRTOS_中断

    传送门 博客汇总帖 传送门 Cortex M3 中断 异常 传送门 Cortex M3笔记 基础 笔记内容参考 正点原子的FreeRTOS开发手册 cortex m3权威指南 Cortex M3和Cortex M4权威指南等 文中stm32
  • 基于HAL库的FREERTOS-----------三.队列

    一 队列简介 在实际的应用中 常常会遇到一个任务或者中断服务需要和另外一个任务进行 沟通交流 这个 沟通交流 的过程其实就是消息传递的过程 在没有操作系统的时候两个应用程序进行消息传递一般使用全局变量的方式 但是如果在使用操作系统的应用中用
  • FreeRTOS基础五:软件定时器

    软件定时器简介 软件定时器的作用 在指定的时间到来时执行指定的函数 或者以某个频率周期性地执行某个函数 被执行的函数叫做软件定时器回调函数 软件定时器由FreeRTOS内核实现 不需要硬件支持 软件定时器只有在软件定时器回调函数被调用时才需
  • freertos————互斥锁

    线程安全 多线程程序处于一个多变的环境 可访问的全局变量和堆数据随时可能被其他的线程改变 多个线程同时访问一个共享数据 可能造成严重的后果 出现问题的是之前移植了一个freemodbus的从站 多个任务访问全局变量保持寄存器区 导致最后读出
  • STM32F103移植FreeRTOS必须搞明白的系列知识---2(FreeRTOS任务优先级)

    STM32F103移植FreeRTOS必须搞明白的系列知识 1 Cortex CM3中断优先级 STM32F103移植FreeRTOS必须搞明白的系列知识 2 FreeRTOS任务优先级 STM32F103移植FreeRTOS必须搞明白的系
  • FreeRTOS之事件

    FreeRTOS之事件 声明 本人按照正点原子的FreeRTOS例程进行学习的 欢迎各位大佬指责和批评 谢谢 一 事件定义 事件 事件集 与高数上的集合意义差不多 事件啊 其实是实现任务间通信的机制 主要用于实现多任务间的同步 但是事件类型
  • FreeRTOS死机原因

    1 中断回调函数中没有使用中断级API xxFromISR 函数 xSemaphoreGiveFromISR uart busy HighterTask 正确 xSemaphoreGive uart busy 错误 2 比configMAX
  • 【FreeRTOS 事件】任务通知事件

    普通任务通知事件创建创建及运行 参阅安富莱电子demo define BIT 0 1 lt lt 0 define BIT 1 1 lt lt 1 static TaskHandle t xHandleTaskUserIF NULL sta
  • FreeRTOS轻量级同步--任务通知

    1 简介 在FreeRTOS的配置参数中的configUSE TASK NOTIFICATIONS宏打开 一般RTOS会默认打开 如图1所示 图1 notify宏开关 RTOS在创建任务时 会创建一个32位的通知值ulNotifiedVal
  • 如何更改 FreeRTOS 中任务的最大可用堆大小?

    我通过以下方式在任务中创建元素列表 l dllist pvPortMalloc sizeof dllist dlllist 有 32 字节大 我的嵌入式系统有 60kB SRAM 所以我希望系统可以轻松处理我的 200 个元素列表 我发现在
  • 当 Cortex-M3 出现硬故障时如何保留堆栈跟踪?

    使用以下设置 基于 Cortex M3 的 C gcc arm 交叉工具链 https launchpad net gcc arm embedded 使用 C 和 C FreeRtos 7 5 3 日食月神 Segger Jlink 与 J

随机推荐

  • 解决JDK版本导致JMeter无法启动问题

    最近在做一个秒杀系统练习时 需要使用JMeter进行压力测试 但是安装JMeter后 出现了以下错误 很明显是JDK的版本问题导致的 但是我又不想改变系统的JDK版本 所以可以下载高版本的JDK 无需改变系统的JDK版本 直接在bin jm
  • nginx-代理多个服务

    目录 1 主机多Ip 1 1单网卡多ip主机配置 1 2修改default conf 1 3server1 conf 1 3server2 conf 1 4测试文件 1 4重启测试 2 主机多端口 2 1server1 conf 2 2se
  • 三个不等_高中数学竞赛常用的不等式归纳(续一)

    当 时 代入 23 为减少篇幅就不在此写出完整的 23式 下同 式得 即 25 25 式正是 22 九 加权不等式 9 1若 且 则 26 26 式就是加权的均值不等式 简称加权不等式 26 式形式直接理解为 几何均值不大于算术均值 十 赫
  • 2020第八届“泰迪杯”特等奖(基于 BERT 深度语言模型的“智慧政务”文本挖掘应用)

    目录 1绪论 1 1 智慧政务 文本挖掘的意义 1 2 智慧政务 文本挖掘的目标 1 3语言智能的里程碑技术 BERT 深度语言模型介绍 1 4本文的总体框架 1 5本文主要的创新之处 2基于 BERT 模型的留言自动分类 2 1任务介绍与
  • 数据库连接池C3P0学习

    数据库连接池C3P0框架是个非常优异的开源jar 高性能的管理着数据源 这里只讨论程序本身负责数据源 不讨论容器管理 一 实现方式 C3P0有三种方式实现 1 自己动手写代码 实现数据源 例如 在类路径下配置一个属性文件 config pr
  • 1-2 继承和接口

    1 继承 关键字extends 父类中私有成员可以被继承 只是外界无法访问 父类中公共属性 方法可以被子类继承 支持单继承 多重继承 单链式继承 不支持多继承 一个类继承多个父类 子类中的方法重写必须是父类中已有的方法 重写后再次调用父类的
  • shell 自动备份 MySQL 数据库脚本

    前提 在当前的机器中 已经安装了 MySQL 并且将 MySQL 已经加入到环境当中 安装 MySQL 和配置 MySQL 环境可参考文章 CentOS 8 通过二进制安装 MySQL 需求 编写 shell 脚本 自动备份 MySQL 数
  • 插入排序和选择排序(普通排序)

    我自己的代码 更容易理解 void XuanZePaiXu int a int n int i j k for int i 0 i lt n i k i for int j i 1 j lt n j if a k gt a j k j if
  • Vue2 _ 实现拖拽功能

    老项目重构 其中有一些拖拽功能 不过用的是两个开源 JS 拖拽文件实现的效果 版本太老了 所以需要换代了 然后就查阅了能够用 Vue 来简单快速实现拖拽的功能实现方法 目录 一 HTML 拖放 二 Vue Draggable 强烈推荐 三
  • NFT.net批量生成NFT头像(汉化版+使用文档)

    本程序NFT net可用于批量快速生成NFT头像 相同风格但不尽相同 原程序由老外开发 本人将其汉化 并制作使用文档 工具参考 NFT net 一个可以批量生成NFT头像的工具 素材参考 B站up主 卡司红茶 汉化版 使用文档 本人首发 如
  • maven如何快速查找某个包哪里引入的

    描述 最近项目中遇到一个问题 有个jar包跟项目的中的代码冲突导致一些奇怪的异常 项目是maven项目 问题查找 由maven官网可知道maven的Dependency plugin就有这个问题的解决方案filtering the depe
  • Sybase的客户端工具

    虽然已经离开用Sybase的项目很久了 但今天突然有同事问我Sybase的客户端工具都用什么 我却不记得当时天天用的什么工具了 上网找了半天才找到软件的名字 在此做个小小的总结 以免以后更想不起来 以下几个工具都是当时常用的 他们各有优缺点
  • panda3d虚幻引擎--(1)

    目录 前言 阿巴阿巴 安装 调整窗口 导入环境 前言 阿巴阿巴 前几天无意间看到了一个叫做panda3d的东西 觉得挺好玩 就翻教程 发现现在中文教程似乎没有那么全面成体系 大部分都是复制粘贴过来官网的实例然后就发布出去了 看得云里雾里的
  • 网络安全与密码学

    1 网络安全威胁 破坏网络安全的一些理论方式 窃听 窃听信息 在网路通信双方直接进行窃听 插入 主动在网络连接中插入信息 可以在message中插入恶意信息 假冒 伪造 spoof 分组中的源地址 假冒客户端或服务器 劫持 通过移除 取代发
  • idea的bug导致的项目编译问题。

    项目代码报红 方法一 删掉依赖的子项目target 然后重新install子项目 本项目重新maven reimport 重新install 方法二 删掉 idea 文件夹 重新引入项目 方法三 invalidate Caches 清除缓存
  • 运算放大器的异常总结——震荡和发热

    上图中 运算放大器输出端F1是保险丝 此处的保险丝有2个作用 1 防止输出端短路 保护运放 2 保险丝本身存在电阻 防止运放震荡 对于第一条不需要过多解释 但是第二条 如果此处保险丝去除改为直通 则因为容性负载的存在 运放可能引起震荡 此外
  • 《画解数据结构》(2 - 5)- 堆 与 优先队列

    画解数据结构 2 5 堆
  • tcp业务层粘包和半包理解及处理

    tcp粘包处理 tcp是流式传输的 是安全的 可靠的 顺序的 udp是数据报协议 是不可靠的 面试中经常被问到tcp粘包是如何处理的 通过百度和自己的理解 这里做笔记记录 如果有不对 请指正 参考 https bbs csdn net to
  • Auto.js实现返回到应用首页(判断是否在应用首页)

    文章目录 前言 一 实现思路 二 实现步骤 使用与总结 前言 Auto js使用实现模拟点击过程中 有时软件并不在脚本运行页面 使得脚本运行无效 例如脚本需要在软件首页才能找到相关元素实现模拟操作 就需要判断页面状态 不是首页返回到首页 是
  • FreeRTOS临界段和开关中断

    http blog sina com cn s blog 98ee3a930102wg5u html 本章教程为大家讲解两个重要的概念 FreeRTOS的临界段和开关中断 本章教程配套的例子含Cortex M3内核的STM32F103和Co