加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

【FreeRTOS操作系统教程】第29章 FreeRTOS独立看门狗监测任务执行状态

(2016-09-10 14:41:19)
标签:

fatfs

freertos

stemwin

stm32

usb

分类: FreeRTOS

第29章      FreeRTOS独立看门狗监测任务执行状态



通过前面的几个章节,我们基本已经完成了FreeRTOS所有功能的讲解,本章节为大家介绍一种使用独立看门狗监测任务执行状态的方法,借此为大家提供一种在软件或者硬件死机时,FreeRTOS系统如何保证系统复位的思路。

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

29.1 独立看门狗监测任务的实现思路

29.2 实验例程说明

29.3       总结

 

 

29.1 独立看门狗监测任务的实现思路

29.1.1  什么是独立看门狗

假设有一只饥饿的狗正在看守一座房子,而有人要闯入。如果这个强盗的同谋以2分钟的时间间隔不停的向看门狗扔肉。那么这只狗将忙于吃肉而忽视保卫工作,因此将不会犬叫。然而,如果同谋扔完了肉或者由于其它原因忘了喂肉,狗将开始犬叫,从而惊动邻居、房屋主人或者警察。

嵌入式化的独立看门狗定时器遵循同样的方法。用户需要每隔一段时间就刷新看门狗定时器,否则将导致看门狗定时器溢出。在大多数情况下,看门狗定时器的溢出将使得系统复位。即使经过仔细规划和设计,嵌入式系统也有可能由于出乎预料的问题而死机,看门狗定时器就是用来处理类似情况的,看门狗定时器可用于从这种状态恢复。

教程使用的STM32F103STM32F407STM32F429都自带独立看门狗,使用也比较简单,用户初始化好看门狗,并设置好看门狗溢出时间即可,剩下就是在溢出时间范围内及时喂狗。

下面就提供一种利用独立看门狗监测多任务的执行状态的思路。

29.1.2 多任务监测实现思路

为了保证FreeRTOS的所有用户任务都在正常的运行,我们通过独立看门狗的形式来监测,一旦发现有某个任务长时间没有执行,看门狗就会将系统复位。

【FreeRTOS操作系统教程】第29章 <wbr>FreeRTOS独立看门狗监测任务执行状态

 

运行条件:

    (1)创建5个用户任务Task1Task2Task3Task4Task5。其中Task5的优先级最高,然后依次是Task4Task3Task2Task1

    (2)任务Task1Task4定期发事件标志给任务Task5,表示任务运行正常。

  实现思路:

    (1)喂狗程序放在最高优先级的任务Task5里面,其它的4个任务都定期的向最高优先级任务发送事件标志,只有四个任务都发来了事件标志才进行喂狗。

    (2)看门狗的复位时间设置为多少合适呢?这个要根据四个任务Task1Task4的最大发送事件标志间隔来确定。假设测试发现,最大的发送事件标志时间间隔是由Task4产生的,间隔是6s,我们可以在此基础上再设置一些时间容限,把看门狗的复位时间设置为10s,也就是说,四个任务Task1Task4需要在10s内给任务Task5发送事件标志,让Task5执行喂狗操作,否则看门狗定时器溢出,从而导致系统将复位。

    (3)推荐在最高优先级任务里面实现喂狗,这样才可以保证其它低优先级任务发来了事件标志后,Task5可以及时的喂狗。如果放在一个低优先级的任务里面会存在问题,比如所有的任务都已经发送了表示自己正常运行的事件标志,但是此低优先级任务在执行喂狗程序前被其它高优先级的任务抢占了,造成不能及时喂狗,从而导致系统复位,这种误判断会使得系统不能够正常工作。

 

按照上面的实现思路,我们在开发板上面实战演练下。

29.2 实验例程说明

29.2.1 STM32F103开发板实验

配套例子:

V4-335_FreeRTOS实验_独立看门狗监测任务执行状态

实验目的:

1.     学习独立看门狗监测FreeRTOS任务执行状态。

实验内容:

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

2.     K2按键按下后将任务vTaskTaskUserIF延迟20s后执行,从而实现看门狗复位。

3.     看门狗监测任务执行状态说明:

(1)  设置看门狗复位时间是10s,如果10s内不喂狗系统复位。

(2)  使用事件标志组,在最高优先级任务中等待其它所有用户任务发来的事件标志,如果所有任务都发来了事件标志,那么就执行喂狗程序,如果有一个任务10s内没有发来事件标志,那么系统会被复位。

(3)  简单的说就是为了检测任务的执行状态,我们设置每个任务10s内必须发一次事件标志以此来表示任务在执行。如果10s内有一个任务没有发来消息,系统会被复位。

(4)  等待事件标志的任务: 

uxBits = xEventGroupWaitBits(xCreatedEventGroup,

TASK_BIT_ALL,

pdTRUE,

pdTRUE,

xTicksToWait);

                 其它四个发送事件标志的任务:

                 xEventGroupSetBits(xCreatedEventGroup, TASK_BIT_0);

xEventGroupSetBits(xCreatedEventGroup, TASK_BIT_1);

xEventGroupSetBits(xCreatedEventGroup, TASK_BIT_2);

xEventGroupSetBits(xCreatedEventGroup, TASK_BIT_3);

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

              vTaskUserIF任务 :按键消息处理。

              vTaskLED任务   LED闪烁

              vTaskMsgPro任务:LED闪烁。

vTaskScan 任务   : 按键扫描

              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                   

#endif

 

 

#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY              0x0f

 

 

#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY         0x01

几个重要选项说明:

u  #define configUSE_PREEMPTION        1

使能抢占式调度器

u  #define configCPU_CLOCK_HZ     ( ( unsigned long ) 72000000 )   

系统主频72MHz

u  #define configTICK_RATE_HZ              ( ( TickType_t ) 1000 )

系统时钟节拍1KHz,即1ms

u  #define configMAX_PRIORITIES          ( 5 )

定义可供用户使用的最大优先级数,如果这个定义的是5,那么用户可以使用的优先级号是0,1,2,3,4不包含5,对于这一点,初学者要特别的注意。

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

定义堆大小,FreeRTOS内核,用户动态内存申请,任务栈等都需要用这个空间。

u  configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY          0x01

定义受FreeRTOS管理的最高优先级中断。简单的说就是允许用户在这个中断服务程序里面调用FreeRTOSAPI的最高优先级。为了进一步说明这个宏定义的的作用,解释如下:

l  使用CM内核的MCU,官方强烈建议将NVIC的优先级分组配置为全抢占式优先级,全部配置为抢占式优先级的好处就是方便管理。

l  对于STM32来说,设置NVIC的优先级分组为4时,NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4)就是全部配置为抢占式优先级。又因为STM32的优先级设置仅使用CM内核8bit中的高4bit,即只能区分2^4 = 16种优先级。因此当优先级分组设置为4的时候可供用户选择抢占式优先级为015,共16个优先级,配置为0表示最高优先级,配置为15表示最低优先级,不存在子优先级。

l  这里配置configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY0x01表示用户可以在抢占式优先级为115的中断里面调用FreeRTOSAPI函数,抢占式优先级为0的中断里面是不允许调用的。

更多关于这个参数说明请参看第12章。

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

【FreeRTOS操作系统教程】第29章 <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操作系统教程】第29章 <wbr>FreeRTOS独立看门狗监测任务执行状态

 

u  FreeROTS初始化:

 

int main(void)

{

    

     __set_PRIMASK(1); 

    

    

     bsp_Init();

    

    

     vSetupSysInfoTest();

    

    

     AppTaskCreate();

 

    

     AppObjCreate();

    

   

    vTaskStartScheduler();

 

    

     while(1);

}

u  硬件外设初始化

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

 

void bsp_Init(void)

{

    

    

          NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

 

     bsp_InitUart();   

     bsp_InitLed();    

     bsp_InitKey();    

}

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( vTaskScan,             

                 "vTaskScan",             

                 512,                    

                 NULL,                   

                 4,                      

                 &xHandleTaskMsgPro );   

 

     xTaskCreate( vTaskStart,            

                 "vTaskStart",           

                 512,                    

                 NULL,                   

                 5,                      

                 &xHandleTaskStart );   

}

u  FreeRTOS事件标志组创建:

 

static void AppObjCreate (void)

{

    

     xCreatedEventGroup = xEventGroupCreate();

    

     if(xCreatedEventGroup == NULL)

    {

        

    }

}

u  四个FreeRTOS任务的实现:

 

static void vTaskTaskUserIF(void *pvParameters)

{

     MSG_T *ptMsg;

     uint8_t ucCount = 0;

     uint8_t ucKeyCode;

     uint8_t pcWriteBuffer[500];

 

 

static void vTaskTaskUserIF(void *pvParameters)

{

     uint8_t ucKeyCode;

     uint8_t pcWriteBuffer[500];

     const TickType_t xTicksToWait = 20000 / portTICK_PERIOD_MS;

 

    while(1)

    {

         ucKeyCode = bsp_GetKey();

        

         if (ucKeyCode != KEY_NONE)

         {

              switch (ucKeyCode)

              {

                  

                   case KEY_DOWN_K1:          

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

                       break;

                  

                  

                   case KEY_DOWN_K2:

                       printf("K2按键按下,让vTaskTaskUserIF任务延迟20s,以实现看门狗复位情况\r\n");

                       vTaskDelay(xTicksToWait);

                       break;

                  

                  

                   default:                    

                       break;

              }

         }

        

        

         xEventGroupSetBits(xCreatedEventGroup, TASK_BIT_0);

        

         vTaskDelay(20);

     }

}

 

 

static void vTaskLED(void *pvParameters)

{

     TickType_t xLastWakeTime;

     const TickType_t xFrequency = 500;

 

    

    xLastWakeTime = xTaskGetTickCount();

    

    while(1)

    {

         bsp_LedToggle(2);

         bsp_LedToggle(3);

        

         

         xEventGroupSetBits(xCreatedEventGroup, TASK_BIT_1);

        

         

        vTaskDelayUntil(&xLastWakeTime, xFrequency);

    }

}

 

 

static void vTaskMsgPro(void *pvParameters)

{

     TickType_t xLastWakeTime;

     const TickType_t xFrequency = 1000;

 

    

    xLastWakeTime = xTaskGetTickCount();

    

    while(1)

    {

         bsp_LedToggle(1);

         bsp_LedToggle(4);

        

        

         xEventGroupSetBits(xCreatedEventGroup, TASK_BIT_2);

        

         

        vTaskDelayUntil(&xLastWakeTime, xFrequency);

    }

}

 

 

static void vTaskScan(void *pvParameters)

{

    while(1)

    {

         

         bsp_KeyScan();

        

        

         xEventGroupSetBits(xCreatedEventGroup, TASK_BIT_3);

        vTaskDelay(10);

    }

}

 

 

static void vTaskStart(void *pvParameters)

{

     EventBits_t uxBits;

     const TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS;

    

    

     bsp_InitIwdg(0xC35);

    

    

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

     printf("=系统开机执行\r\n");

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

    

    while(1)

    {

        

         uxBits = xEventGroupWaitBits(xCreatedEventGroup,

                                          TASK_BIT_ALL,   

                                          pdTRUE,         

                                         pdTRUE,          

                                          xTicksToWait);  

        

         if((uxBits & TASK_BIT_ALL) == TASK_BIT_ALL)

         {

              IWDG_Feed();

              printf("五个用户任务都正常运行\r\n");

         }

         else

         {

             

             

         }

    }

}

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有