硬汉嵌入式论坛

 找回密码
 立即注册
查看: 5521|回复: 9
收起左侧

[FreeRTOS教程] 第17章 FreeRTOS系统时钟节拍和时间管理

[复制链接]

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
发表于 2016-8-26 16:40:31 | 显示全部楼层 |阅读模式



第17章      FreeRTOS系统时钟节拍和时间管理


    本章节为大家讲解FreeRTOS操作系统的系统时钟节拍和时间管理函数,其中时间管理函数是FreeRTOS的基本函数,初学者务必要掌握。
    本章教程配套的例子含Cortex-M3内核的STM32F103和Cortex-M4内核的STM32F407以及F429。
17.1 FreeRTOS的时钟节拍
17.2 FreeRTOS的时间管理
17.3 实验例程说明
17.4      总结



17.1  FreeRTOS的时钟节拍

    任何操作系统都需要提供一个时钟节拍,以供系统处理诸如延时、超时等与时间相关的事件。
    时钟节拍是特定的周期性中断,这个中断可以看做是系统心跳。中断之间的时间间隔取决于不同的应用,一般是1ms – 100ms。时钟的节拍中断使得内核可以将任务延迟若干个时钟节拍,以及当任务等待事件发生时,提供等待超时等依据。时钟节拍率越快,系统的额外开销就越大。
    对于Cortex-M3内核的STM32F103和Cortex-M4内核的STM32F407以及F429,教程配套的例子都是用滴答定时器来实现系统时钟节拍的。
    注:滴答定时器Systick
      SysTick定时器被捆绑在NVIC中,用于产生SysTick异常(异常号:15),滴答定时器是一个24位的递减计数器,支持中断。使用比较简单,专门用于给操作系统提供时钟节拍。
    FreeRTOS的系统时钟节拍可以在配置文件FreeRTOSConfig.h里面设置:
                       #define configTICK_RATE_HZ                     ( ( TickType_t ) 1000 )
如上所示的宏定义配置表示系统时钟节拍是1KHz,即1ms。
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-8-26 16:50:48 | 显示全部楼层
17.2 FreeRTOS的时间管理


    时间管理功能是FreeRTOS操作系统里面最基本的功能,同时也是必须要掌握好的。

17.2.1 时间延迟


    FreeRTOS中的时间延迟函数主要有以下两个作用:
1、为周期性执行的任务提供延迟。
2、对于抢占式调度器,让高优先级任务可以通过时间延迟函数释放CPU使用权,从而让低优先级任务可以得到执行。
下面我们通过如下的框图来说明一下延迟函数对任务运行状态的影响,让大家有一个形象的认识。
17.1.JPG

运行条件:
(1)仅对任务Task1的运行状态做说明。
(2)调度器支持时间片调度和抢占式调度。
运行过程描述如下:
(1)起初任务Task1处于运行态,调用vTaskDelay函数后进入到阻塞状态,也就是blocked状态。
(2)vTaskDelay函数设置的延迟时间到,由于任务Task1不是当前就绪的最高优先级任务,所以不能进入到运行状态,只能进入到就绪状态,也就是ready状态。
(3)一段时间后,调度器发现任务Task1是当前就绪的最高优先级任务,从而任务从就绪态切换到运行态。
(4)由于时间片调度,任务Task1由运行态切换到就绪态。

上面就是一个简单的任务运行状态的切换过程。

17.2.2 FreeRTOS的时间相关函数


    FreeRTOS时间相关的函数主要有以下4个:
(1)vTaskDelay ()
(2)vTaskDelayUntil ()
(3)xTaskGetTickCount()
(4)xTaskGetTickCountFromISR()
下面我们对这4个函数依次进行说明:

17.2.3 函数vTaskDelay


关于这个函数的讲解及其使用方法可以看FreeRTOS在线版手册:
17.2.jpg

这里也对此函数进行下介绍。
函数原型:
  1. void vTaskDelay(
  2.      const TickType_t xTicksToDelay ); /* 延迟时间长度 */
复制代码
函数描述:
函数vTaskDelay用于任务的延迟。
(1)参数xTicksToDelay用于设置延迟的时钟节拍个数,范围1- 0xFFFFFFFF。延迟时间的最大值在portmacro.h文件里面有定义:
      typedefuint32_t TickType_t;
      #defineportMAX_DELAY     ( TickType_t )0xffffffffUL
      即延迟时间的范围是:1- 0xFFFFFFFF
使用举例:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: vTaskLED
  4. *    功能说明: LED闪烁
  5. *    形    参: pvParameters 是在创建该任务时传递的形参
  6. *    返 回 值: 无
  7. *   优 先 级: 2
  8. *********************************************************************************************************
  9. */
  10. static void vTaskLED(void *pvParameters)
  11. {
  12.     while(1)
  13.     {
  14.         bsp_LedToggle(2);
  15.         vTaskDelay(200);
  16.     }
  17. }
复制代码

17.2.4 函数vTaskDelayUntil


关于这个函数的讲解及其使用方法可以看FreeRTOS在线版手册:
17.3.jpg

这里也对此函数进行下介绍。
函数原型:
  1. void vTaskDelayUntil( TickType_t *pxPreviousWakeTime,    /* 存储任务上次处于非阻塞状态时刻的变量地址 */
  2.                       const TickType_t xTimeIncrement ); /* 周期性延迟时间 */
复制代码
函数描述:
函数vTaskDelayUntil用于周期性延迟。
(1)第1个参数,存储任务上次处于非阻塞状态时刻的变量地址。
(2)第2个参数,周期性延迟时间。
使用这个函数要注意以下问题:
1.     使用此函数需要在FreeRTOSConfig.h配置文件中配置如下宏定义为1
       #defineINCLUDE_vTaskDelayUntil     1
2.     用户要注意此函数跟vTaskDelay的区别,本章17.2.7小节详细讲解。
使用举例:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: vTaskLED
  4. *    功能说明: LED闪烁
  5. *    形    参: pvParameters 是在创建该任务时传递的形参
  6. *    返 回 值: 无
  7. *   优 先 级: 2
  8. *********************************************************************************************************
  9. */
  10. static void vTaskLED(void *pvParameters)
  11. {
  12.      TickType_t xLastWakeTime;
  13.      const TickType_t xFrequency = 200;
  14.      /* 获取当前的系统时间 */
  15.     xLastWakeTime = xTaskGetTickCount();
  16.    
  17.     while(1)
  18.     {
  19.          bsp_LedToggle(2);
  20.          /* vTaskDelayUntil是绝对延迟,vTaskDelay是相对延迟。*/
  21.         vTaskDelayUntil(&xLastWakeTime, xFrequency);
  22.     }
  23. }
复制代码

17.2.5 函数xTaskGetTickCount


关于这个函数的讲解及其使用方法可以看FreeRTOS在线版手册:
17.4.jpg

这里也对此函数进行下介绍。
函数原型:
  1. volatile TickType_t xTaskGetTickCount( void );
复制代码
函数描述:
函数xTaskGetTickCount用于获取系统当前运行的时钟节拍数。
使用这个函数要注意以下问题:
1. 此函数用于在任务代码里面调用,如果在中断服务程序里面调用的话,需要使用函数
       xTaskGetTickCountFromISR,这两个函数切不可混用。
使用举例:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: vTaskTaskUserIF
  4. *    功能说明: 接口消息处理。
  5. *    形    参: pvParameters 是在创建该任务时传递的形参
  6. *    返 回 值: 无
  7. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
  8. *********************************************************************************************************
  9. */
  10. static void vTaskTaskUserIF(void *pvParameters)
  11. {
  12.      uint8_t ucKeyCode;
  13.      uint8_t pcWriteBuffer[500];
  14.     while(1)
  15.     {
  16.          ucKeyCode = bsp_GetKey();
  17.         
  18.          if (ucKeyCode != KEY_NONE)
  19.          {
  20.               switch (ucKeyCode)
  21.               {
  22.                   
  23.                    /* K1键按下 打印系统时钟节拍数 */
  24.                    case KEY_DOWN_K1:         
  25.                        printf("当前的系统时钟节拍数 = %d\\r\\n", xTaskGetTickCount());
  26.                        break;
  27.                   
  28.                    /* 其他的键值不处理 */
  29.                    default:                    
  30.                        break;
  31.               }
  32.          }
  33.         
  34.          vTaskDelay(20);
  35.      }
  36. }
复制代码

17.2.6 函数xTaskGetTickCountFromISR


关于这个函数的讲解及其使用方法可以看FreeRTOS在线版手册:
17.5.jpg

这里也对此函数进行下介绍。
函数原型:
  1. volatile TickType_t xTaskGetTickCountFromISR( void );
复制代码
函数描述:
函数xTaskGetTickCountFromISR用于获取系统当前运行的时钟节拍数。
使用这个函数要注意以下问题:
1. 此函数用于在中断服务程序里面调用,如果在任务里面调用的话,需要使用函数xTaskGetTickCount,这两个函数切不可混用。
使用举例:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: TIM6_IRQHandler
  4. *    功能说明: TIM6中断服务程序。
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void TIM6_IRQHandler( void )
  10. {
  11.      TickType_t xTickCount;
  12.     xTickCount = xTaskGetTickCountFromISR;
  13. }
复制代码

17.2.7 函数vTaskDelay和vTaskDelayUntil的区别


        函数vTaskDelayUntil实现的是周期性延迟,而函数vTaskDelay实现的是相对性延迟,反映到实际应用上有什么区别呢,下面就给大家举一个简单的例子。
运行条件:
(1)有一个bsp_KeyScan函数,这个函数处理时间大概耗时2ms
(2)有两个任务,一个任务Task1是用的vTaskDelay延迟,延迟10ms,另一个任务Task2是用的vTaskDelayUntil延迟,延迟10ms。
(3)不考虑任务被抢占而造成的影响。
实际运行过程效果:
Task1
          bsp_KeyScan+  vTaskDelay(10)      --->   bsp_KeyScan +  vTaskDelay(10)
          |----2ms + 10ms 为一个周期------|              |----2ms + 10ms 为一个周期----|
      这个就是相对性的含义

Task2
         bsp_KeyScan +  vTaskDelayUntil       ---------> bsp_KeyScan +  vTaskDelayUntil
               |----10ms为一个周期(2ms包含在10ms内)---|    |----10ms为一个周期------|
      这就是周期性的含义。
下面我们通过函数vTaskDelay来实现vTaskDelayUntil,大家会有一个更加全面的认识:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: vTaskMsgPro
  4. *    功能说明: 消息处理,这里是用作LED闪烁   
  5. *    形    参: pvParameters 是在创建该任务时传递的形参
  6. *    返 回 值: 无
  7. *   优 先 级: 3
  8. *********************************************************************************************************
  9. */
  10. static void vTaskMsgPro(void *pvParameters)
  11. {
  12.      TickType_t xDelay, xNextTime;
  13.      const TickType_t xFrequency = 200;
  14.    
  15.      /* 获取xFrequency个时钟节拍后的时间 */
  16.      xNextTime = xTaskGetTickCount() + xFrequency;
  17.    
  18.     while(1)
  19.     {
  20.          bsp_LedToggle(3);
  21.         
  22.          /* 用vTaskDelay实现vTaskDelayUntil() */
  23.          xDelay = xNextTime - xTaskGetTickCount();
  24.          xNextTime += xFrequency;
  25.         
  26.          if(xDelay <= xFrequency)
  27.          {
  28.               vTaskDelay(xDelay);
  29.          }
  30.      }
  31. }
复制代码
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-8-26 16:58:16 | 显示全部楼层
17.3 实验例程说明



17.3.1 STM32F103开发板实验


配套例子:
    V4-311_FreeRTOS实验_周期性延迟和相对性延迟函数
实验目的:
    1.     学习FreeRTOS的周期性延迟和相对性延迟函数。
    2.     注意相对性延迟函数vTaskDelay和周期性延迟函数vTaskDelayUntil的区别。
实验内容:
    1.     K1按键按下,串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1)。
    2.     K2键按下,串口打印系统时钟节拍数。
    3.     各个任务实现的功能如下:
              vTaskUserIF任务   :按键消息处理。
              vTaskLED任务     :LED闪烁。
              vTaskMsgPro任务 :消息处理,这里是用作LED闪烁。
              vTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
FreeRTOS的配置:
    FreeRTOSConfig.h文件中的配置如下:
  1. /* Ensure stdint is only used by the compiler, and not the assembler. */
  2. #if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
  3. #include <stdint.h>
  4. extern volatile uint32_t ulHighFrequencyTimerTicks;
  5. #endif
  6. #define configUSE_PREEMPTION         1
  7. #define configUSE_IDLE_HOOK          0
  8. #define configUSE_TICK_HOOK          0
  9. #define configCPU_CLOCK_HZ           ( ( unsigned long ) 72000000 )  
  10. #define configTICK_RATE_HZ           ( ( TickType_t ) 1000 )
  11. #define configMAX_PRIORITIES         ( 5 )
  12. #define configMINIMAL_STACK_SIZE     ( ( unsigned short ) 128 )
  13. #define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 17 * 1024 ) )
  14. #define configMAX_TASK_NAME_LEN      ( 16 )
  15. #define configUSE_TRACE_FACILITY      1
  16. #define configUSE_16_BIT_TICKS       0
  17. #define configIDLE_SHOULD_YIELD      1
  18. /* Run time and task stats gathering related definitions. */
  19. #define configGENERATE_RUN_TIME_STATS                1
  20. #define configUSE_STATS_FORMATTING_FUNCTIONS         1
  21. #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()     (ulHighFrequencyTimerTicks = 0ul)
  22. #define portGET_RUN_TIME_COUNTER_VALUE()             ulHighFrequencyTimerTicks
  23. //#define portALT_GET_RUN_TIME_COUNTER_VALUE           1
  24. /* Co-routine definitions. */
  25. #define configUSE_CO_ROUTINES            0
  26. #define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
  27. /* Set the following definitions to 1 to include the API function, or zero
  28. to exclude the API function. */
  29. #define INCLUDE_vTaskPrioritySet          1
  30. #define INCLUDE_uxTaskPriorityGet         1
  31. #define INCLUDE_vTaskDelete               1
  32. #define INCLUDE_vTaskCleanUpResources      0
  33. #define INCLUDE_vTaskSuspend              1
  34. #define INCLUDE_vTaskDelayUntil           1
  35. #define INCLUDE_vTaskDelay                1
  36. /* Cortex-M specific definitions. */
  37. #ifdef __NVIC_PRIO_BITS
  38.      /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
  39.      #define configPRIO_BITS              __NVIC_PRIO_BITS
  40. #else
  41.      #define configPRIO_BITS              4        /* 15 priority levels */
  42. #endif
  43. /* The lowest interrupt priority that can be used in a call to a "set priority"
  44. function. */
  45. #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY              0x0f
  46. /* The highest interrupt priority that can be used by any interrupt service
  47. routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL
  48. INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
  49. PRIORITY THAN THIS! (higher priorities are lower numeric values. */
  50. #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY         0x01
复制代码
几个重要选项说明:
1、#define configUSE_PREEMPTION        1
          使能抢占式调度器
2、#define configCPU_CLOCK_HZ      ( ( unsigned long ) 72000000 )   
          系统主频72MHz。
3、#define configTICK_RATE_HZ              ( ( TickType_t ) 1000 )
          系统时钟节拍1KHz,即1ms。
4、#define configMAX_PRIORITIES          ( 5 )
          定义可供用户使用的最大优先级数,如果这个定义的是5,那么用户可以使用的优先级号是0,1,2,3,4,不包含5,对于这一点,初学者要特别的注意。
5、#define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 17 * 1024 ) )
          定义堆大小,FreeRTOS内核,用户动态内存申请,任务栈等都需要用这个空间。
6、configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY          0x01
          定义受FreeRTOS管理的最高优先级中断。简单的说就是允许用户在这个中断服务程序里面调用FreeRTOS的API的最高优先级。为了进一步说明这个宏定义的的作用,解释如下:
     (1)使用CM内核的MCU,官方强烈建议将NVIC的优先级分组配置为全抢占式优先级,全部配置为抢占式优先级的好处就是方便管理。
     (2)对于STM32来说,设置NVIC的优先级分组为4时,NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4)就是全部配置为抢占式优先级。又因为STM32的优先级设置仅使用CM内核8bit中的高4bit,即只能区分2^4 = 16种优先级。因此当优先级分组设置为4的时候可供用户选择抢占式优先级为015,共16个优先级,配置为0表示最高优先级,配置为15表示最低优先级,不存在子优先级。
     (3)这里配置configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY0x01表示用户可以在抢占式优先级为115的中断里面调用FreeRTOSAPI函数,抢占式优先级为0的中断里面是不允许调用的。
      更多关于这个参数说明请参看第12章。
FreeRTOS任务调试信息(按K1按键,串口打印):
17.6.jpg

上面截图中打印出来的任务状态字母B, R, D, S对应如下含义:
      #definetskBLOCKED_CHAR          ( 'B' )  任务阻塞
      #definetskREADY_CHAR           ( 'R' ) 任务就绪
      #definetskDELETED_CHAR           ( 'D' )  任务删除
      #definetskSUSPENDED_CHAR   ( 'S' ) 任务挂起
程序设计:
任务栈大小分配:
      vTaskUserIF任务   :2048字节
      vTaskLED任务     :2048字节
      vTaskMsgPro任务 :2048字节
      vTaskStart任务    :2048字节
      任务栈空间是在任务创建的时候从FreeRTOSConfig.h文件中定义的heap空间中申请的
      #defineconfigTOTAL_HEAP_SIZE        ( ( size_t )( 17 * 1024 ) )
系统栈大小分配:
17.7.jpg

FreeROTS初始化:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: main
  4. *    功能说明: 标准c程序入口。
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. int main(void)
  10. {
  11.      /*
  12.        在启动调度前,为了防止初始化STM32外设时有中断服务程序执行,这里禁止全局中断(除了NMI和HardFault)。
  13.        这样做的好处是:
  14.        1. 防止执行的中断服务程序中有FreeRTOS的API函数。
  15.        2. 保证系统正常启动,不受别的中断影响。
  16.        3. 关于是否关闭全局中断,大家根据自己的实际情况设置即可。
  17.        在移植文件port.c中的函数prvStartFirstTask中会重新开启全局中断。通过指令cpsie i开启,__set_PRIMASK(1)
  18.        和cpsie i是等效的。
  19.      */
  20.      __set_PRIMASK(1);
  21.    
  22.      /* 硬件初始化 */
  23.      bsp_Init();
  24.    
  25.      /* 1. 初始化一个定时器中断,精度高于滴答定时器中断,这样才可以获得准确的系统信息 仅供调试目的,实际项
  26.            目中不要使用,因为这个功能比较影响系统实时性。
  27.         2. 为了正确获取FreeRTOS的调试信息,可以考虑将上面的关闭中断指令__set_PRIMASK(1); 注释掉。
  28.      */
  29.      vSetupSysInfoTest();
  30.    
  31.      /* 创建任务 */
  32.      AppTaskCreate();
  33.    
  34.     /* 启动调度,开始执行任务 */
  35.     vTaskStartScheduler();
  36.      /*
  37.        如果系统正常启动是不会运行到这里的,运行到这里极有可能是用于定时器任务或者空闲任务的
  38.        heap空间不足造成创建失败,此要加大FreeRTOSConfig.h文件中定义的heap大小:
  39.        #define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 17 * 1024 ) )
  40.      */
  41.      while(1);
  42. }
复制代码


硬件外设初始化
    硬件外设的初始化是在bsp.c文件实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: bsp_Init
  4. *    功能说明: 初始化硬件设备。只需要调用一次。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。
  5. *             全局变量。
  6. *    形    参: 无
  7. *    返 回 值: 无
  8. *********************************************************************************************************
  9. */
  10. void bsp_Init(void)
  11. {
  12.      /*
  13.          由于ST固件库的启动文件已经执行了CPU系统时钟的初始化,所以不必再次重复配置系统时钟。
  14.          启动文件配置了CPU主时钟频率、内部Flash访问速度和可选的外部SRAM FSMC初始化。
  15.          系统时钟缺省配置为72MHz,如果需要更改,可以修改 system_stm32f10x.c 文件
  16.      */
  17.    
  18.      /* 优先级分组设置为4,可配置0-15级抢占式优先级,0级子优先级,即不存在子优先级。*/     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
  19.      bsp_InitUart();    /* 初始化串口 */
  20.      bsp_InitLed();     /* 初始LED指示灯端口 */
  21.      bsp_InitKey();     /* 初始化按键 */
  22. }
复制代码


FreeRTOS任务创建:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskCreate
  4. *    功能说明: 创建应用任务
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void AppTaskCreate (void)
  10. {
  11.     xTaskCreate( vTaskTaskUserIF,   /* 任务函数  */
  12.                  "vTaskUserIF",     /* 任务名    */
  13.                  512,               /* 任务栈大小,单位word,也就是4字节 */
  14.                  NULL,              /* 任务参数  */
  15.                  1,                 /* 任务优先级*/
  16.                  &xHandleTaskUserIF );  /* 任务句柄  */
  17.    
  18.    
  19.      xTaskCreate( vTaskLED,           /* 任务函数  */
  20.                  "vTaskLED",         /* 任务名    */
  21.                  512,                /* 任务栈大小,单位word,也就是4字节 */
  22.                  NULL,               /* 任务参数  */
  23.                  2,                  /* 任务优先级*/
  24.                  &xHandleTaskLED ); /* 任务句柄  */
  25.    
  26.      xTaskCreate( vTaskMsgPro,            /* 任务函数  */
  27.                  "vTaskMsgPro",           /* 任务名    */
  28.                  512,                     /* 任务栈大小,单位word,也就是4字节 */
  29.                  NULL,                    /* 任务参数  */
  30.                  3,                       /* 任务优先级*/
  31.                  &xHandleTaskMsgPro );  /* 任务句柄  */
  32.    
  33.    
  34.      xTaskCreate( vTaskStart,             /* 任务函数  */
  35.                  "vTaskStart",            /* 任务名    */
  36.                  512,                     /* 任务栈大小,单位word,也就是4字节 */
  37.                  NULL,                    /* 任务参数  */
  38.                  4,                       /* 任务优先级*/
  39.                  &xHandleTaskStart );   /* 任务句柄  */
  40. }
复制代码


四个FreeRTOS任务的实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: vTaskTaskUserIF
  4. *    功能说明: 接口消息处理。
  5. *    形    参: pvParameters 是在创建该任务时传递的形参
  6. *    返 回 值: 无
  7. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
  8. *********************************************************************************************************
  9. */
  10. static void vTaskTaskUserIF(void *pvParameters)
  11. {
  12.      uint8_t ucKeyCode;
  13.      uint8_t pcWriteBuffer[500];
  14.     while(1)
  15.     {
  16.          ucKeyCode = bsp_GetKey();
  17.         
  18.          if (ucKeyCode != KEY_NONE)
  19.          {
  20.               switch (ucKeyCode)
  21.               {
  22.                    /* K1键按下 打印任务执行情况 */
  23.                    case KEY_DOWN_K1:         
  24.                        printf("=================================================\\r\\n");
  25.                        printf("任务名      任务状态 优先级   剩余栈 任务序号\\r\\n");
  26.                        vTaskList((char *)&pcWriteBuffer);
  27.                        printf("%s\\r\\n", pcWriteBuffer);
  28.                   
  29.                        printf("\\r\\n任务名       运行计数         使用率\\r\\n");
  30.                        vTaskGetRunTimeStats((char *)&pcWriteBuffer);
  31.                        printf("%s\\r\\n", pcWriteBuffer);
  32.                        break;
  33.                   
  34.                    /* K2键按下 打印系统时钟节拍数 */
  35.                    case KEY_DOWN_K2:         
  36.                        printf("当前的系统时钟节拍数 = %d\\r\\n", xTaskGetTickCount());
  37.                        break;
  38.                   
  39.                    /* 其他的键值不处理 */
  40.                    default:                    
  41.                         break;
  42.               }
  43.          }
  44.         
  45.          vTaskDelay(20);
  46.      }
  47. }
  48. /*
  49. *********************************************************************************************************
  50. *    函 数 名: vTaskLED
  51. *    功能说明: LED闪烁
  52. *    形    参: pvParameters 是在创建该任务时传递的形参
  53. *    返 回 值: 无
  54. *   优 先 级: 2
  55. *********************************************************************************************************
  56. */
  57. static void vTaskLED(void *pvParameters)
  58. {
  59.      TickType_t xLastWakeTime;
  60.      const TickType_t xFrequency = 200;
  61.      /* 获取当前的系统时间 */
  62.     xLastWakeTime = xTaskGetTickCount();
  63.    
  64.     while(1)
  65.     {
  66.          bsp_LedToggle(2);
  67.         
  68.          /* vTaskDelayUntil是绝对延迟,vTaskDelay是相对延迟。*/
  69.         vTaskDelayUntil(&xLastWakeTime, xFrequency);
  70.     }
  71. }
  72. /*
  73. *********************************************************************************************************
  74. *    函 数 名: vTaskMsgPro
  75. *    功能说明: 消息处理,这里是用作LED闪烁   
  76. *    形    参: pvParameters 是在创建该任务时传递的形参
  77. *    返 回 值: 无
  78. *   优 先 级: 3
  79. *********************************************************************************************************
  80. */
  81. static void vTaskMsgPro(void *pvParameters)
  82. {
  83.      TickType_t xDelay, xNextTime;
  84.      const TickType_t xFrequency = 200;
  85.    
  86.      /* 获取xFrequency个时钟节拍后的时间 */
  87.      xNextTime = xTaskGetTickCount() + xFrequency;
  88.    
  89.     while(1)
  90.     {
  91.          bsp_LedToggle(3);
  92.         
  93.          /* 用vTaskDelay实现vTaskDelayUntil() */
  94.          xDelay = xNextTime - xTaskGetTickCount();
  95.          xNextTime += xFrequency;
  96.         
  97.          if(xDelay <= xFrequency)
  98.          {
  99.               vTaskDelay(xDelay);
  100.          }
  101.      }
  102. }
  103. /*
  104. *********************************************************************************************************
  105. *    函 数 名: vTaskStart
  106. *    功能说明: 启动任务,也就是最高优先级任务,这里用作按键扫描。
  107. *    形    参: pvParameters 是在创建该任务时传递的形参
  108. *    返 回 值: 无
  109. *   优 先 级: 4
  110. *********************************************************************************************************
  111. */
  112. static void vTaskStart(void *pvParameters)
  113. {
  114.     while(1)
  115.     {
  116.          /* 按键扫描 */
  117.          bsp_KeyScan();
  118.         vTaskDelay(10);
  119.     }
  120. }
复制代码
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-8-26 17:03:32 | 显示全部楼层
17.3.2   STM32F407开发板实验


配套例子:
    V5-311_FreeRTOS实验_周期性延迟和相对性延迟函数
实验目的:
    1.     学习FreeRTOS的周期性延迟和相对性延迟函数。
    2.     注意相对性延迟函数vTaskDelay和周期性延迟函数vTaskDelayUntil的区别。
实验内容:
    1.     K1按键按下,串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1)。
    2.     K2键按下,串口打印系统时钟节拍数。
    3.     各个任务实现的功能如下:
              vTaskUserIF任务   :按键消息处理。
              vTaskLED任务     :LED闪烁。
              vTaskMsgPro任务 :消息处理,这里是用作LED闪烁。
              vTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。

FreeRTOS的配置:
    FreeRTOSConfig.h文件中的配置如下:
  1. /* Ensure stdint is only used by the compiler, and not the assembler. */
  2. #if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
  3. #include <stdint.h>
  4. extern volatile uint32_t ulHighFrequencyTimerTicks;
  5. /* Ensure stdint is only used by the compiler, and not the assembler. */
  6. #if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
  7. #include <stdint.h>
  8. extern volatile uint32_t ulHighFrequencyTimerTicks;
  9. #endif
  10. #define configUSE_PREEMPTION         1
  11. #define configUSE_IDLE_HOOK          0
  12. #define configUSE_TICK_HOOK          0
  13. #define configCPU_CLOCK_HZ           ( ( unsigned long ) 168000000 )
  14. #define configTICK_RATE_HZ           ( ( TickType_t ) 1000 )
  15. #define configMAX_PRIORITIES         ( 5 )
  16. #define configMINIMAL_STACK_SIZE     ( ( unsigned short ) 128 )
  17. #define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 30 * 1024 ) )
  18. #define configMAX_TASK_NAME_LEN      ( 16 )
  19. #define configUSE_TRACE_FACILITY      1
  20. #define configUSE_16_BIT_TICKS       0
  21. #define configIDLE_SHOULD_YIELD      1
  22. /* Run time and task stats gathering related definitions. */
  23. #define configGENERATE_RUN_TIME_STATS                1
  24. #define configUSE_STATS_FORMATTING_FUNCTIONS         1
  25. #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()     (ulHighFrequencyTimerTicks = 0ul)
  26. #define portGET_RUN_TIME_COUNTER_VALUE()             ulHighFrequencyTimerTicks
  27. //#define portALT_GET_RUN_TIME_COUNTER_VALUE           1
  28. /* Co-routine definitions. */
  29. #define configUSE_CO_ROUTINES             0
  30. #define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
  31. /* Set the following definitions to 1 to include the API function, or zero
  32. to exclude the API function. */
  33. #define INCLUDE_vTaskPrioritySet     1
  34. #define INCLUDE_uxTaskPriorityGet         1
  35. #define INCLUDE_vTaskDelete               1
  36. #define INCLUDE_vTaskCleanUpResources 0
  37. #define INCLUDE_vTaskSuspend              1
  38. #define INCLUDE_vTaskDelayUntil           1
  39. #define INCLUDE_vTaskDelay                1
  40. /* Cortex-M specific definitions. */
  41. #ifdef __NVIC_PRIO_BITS
  42.      /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
  43.      #define configPRIO_BITS              __NVIC_PRIO_BITS
  44. #else
  45.      #define configPRIO_BITS              4        /* 15 priority levels */
  46. #endif
  47. /* The lowest interrupt priority that can be used in a call to a "set priority"
  48. function. */
  49. #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY              0x0f
  50. /* The highest interrupt priority that can be used by any interrupt service
  51. routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL
  52. INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
  53. PRIORITY THAN THIS! (higher priorities are lower numeric values. */
  54. #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY    0x01
复制代码
几个重要选项说明:
1、#define configUSE_PREEMPTION        1
          使能抢占式调度器
2、#define configCPU_CLOCK_HZ      ( ( unsigned long ) 168000000 )
          系统主频168MHz。
3、#define configTICK_RATE_HZ              ( ( TickType_t ) 1000 )
         系统时钟节拍1KHz,即1ms。
4、#define configMAX_PRIORITIES          ( 5 )
          定义可供用户使用的最大优先级数,如果这个定义的是5,那么用户可以使用的优先级号是0,1,2,3,4,不包含5,对于这一点,初学者要特别的注意。
5、#define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 30 * 1024 ) )
          定义堆大小,FreeRTOS内核,用户动态内存申请,任务栈等都需要用这个空间。
6、configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY          0x01
          定义受FreeRTOS管理的最高优先级中断。简单的说就是允许用户在这个中断服务程序里面调用FreeRTOS的API的最高优先级。为了进一步说明这个宏定义的的作用,解释如下:
    (1)使用CM内核的MCU,官方强烈建议将NVIC的优先级分组配置为全抢占式优先级,全部配置为抢占式优先级的好处就是方便管理。
    (2)对于STM32来说,设置NVIC的优先级分组为4时,NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4)就是全部配置为抢占式优先级。又因为STM32的优先级设置仅使用CM内核8bit中的高4bit,即只能区分2^4 = 16种优先级。因此当优先级分组设置为4的时候可供用户选择抢占式优先级为015,共16个优先级,配置为0表示最高优先级,配置为15表示最低优先级,不存在子优先级。
     (3)这里配置configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY0x01表示用户可以在抢占式优先级为115的中断里面调用FreeRTOSAPI函数,抢占式优先级为0的中断里面是不允许调用的。
    更多关于这个参数说明请参看第12章。
FreeRTOS任务调试信息(按K1按键,串口打印):
17.8.jpg

上面截图中打印出来的任务状态字母B, R, D, S对应如下含义:
    #definetskBLOCKED_CHAR          ( 'B' )  任务阻塞
    #definetskREADY_CHAR           ( 'R' ) 任务就绪
    #definetskDELETED_CHAR           ( 'D' )  任务删除
    #definetskSUSPENDED_CHAR   ( 'S' ) 任务挂起
程序设计:
任务栈大小分配:
    vTaskUserIF任务   :2048字节
    vTaskLED任务     :2048字节
    vTaskMsgPro任务 :2048字节
    vTaskStart任务    :2048字节
    任务栈空间是在任务创建的时候从FreeRTOSConfig.h文件中定义的heap空间中申请的
     #defineconfigTOTAL_HEAP_SIZE        ( ( size_t )( 30 * 1024 ) )
系统栈大小分配:
17.9.jpg

FreeROTS初始化:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: main
  4. *    功能说明: 标准c程序入口。
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. int main(void)
  10. {
  11.      /*
  12.        在启动调度前,为了防止初始化STM32外设时有中断服务程序执行,这里禁止全局中断(除了NMI和HardFault)。
  13.        这样做的好处是:
  14.        1. 防止执行的中断服务程序中有FreeRTOS的API函数。
  15.        2. 保证系统正常启动,不受别的中断影响。
  16.        3. 关于是否关闭全局中断,大家根据自己的实际情况设置即可。
  17.        在移植文件port.c中的函数prvStartFirstTask中会重新开启全局中断。通过指令cpsie i开启,__set_PRIMASK(1)
  18.        和cpsie i是等效的。
  19.      */
  20.      __set_PRIMASK(1);
  21.    
  22.      /* 硬件初始化 */
  23.      bsp_Init();
  24.    
  25.      /* 1. 初始化一个定时器中断,精度高于滴答定时器中断,这样才可以获得准确的系统信息 仅供调试目的,实际项
  26.            目中不要使用,因为这个功能比较影响系统实时性。
  27.         2. 为了正确获取FreeRTOS的调试信息,可以考虑将上面的关闭中断指令__set_PRIMASK(1); 注释掉。
  28.      */
  29.      vSetupSysInfoTest();
  30.    
  31.      /* 创建任务 */
  32.      AppTaskCreate();
  33.    
  34.     /* 启动调度,开始执行任务 */
  35.     vTaskStartScheduler();
  36.      /*
  37.        如果系统正常启动是不会运行到这里的,运行到这里极有可能是用于定时器任务或者空闲任务的
  38.        heap空间不足造成创建失败,此要加大FreeRTOSConfig.h文件中定义的heap大小:
  39.        #define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 17 * 1024 ) )
  40.      */
  41.      while(1);
  42. }
复制代码
硬件外设初始化
    硬件外设的初始化是在bsp.c文件实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: bsp_Init
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void bsp_Init(void)
  10. {
  11.      /*
  12.          由于ST固件库的启动文件已经执行了CPU系统时钟的初始化,所以不必再次重复配置系统时钟。
  13.          启动文件配置了CPU主时钟频率、内部Flash访问速度和可选的外部SRAM FSMC初始化。
  14.          系统时钟缺省配置为168MHz,如果需要更改,可以修改 system_stm32f4xx.c 文件
  15.      */
  16.      /* 优先级分组设置为4,可配置0-15级抢占式优先级,0级子优先级,即不存在子优先级。*/
  17.      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
  18.      bsp_InitUart();    /* 初始化串口 */
  19.      bsp_InitKey();     /* 初始化按键变量 */
  20.      bsp_InitLed();     /* 初始LED指示灯端口 */
  21. }
复制代码
FreeRTOS任务创建:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskCreate
  4. *    功能说明: 创建应用任务
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void AppTaskCreate (void)
  10. {
  11.     xTaskCreate( vTaskTaskUserIF,   /* 任务函数  */
  12.                  "vTaskUserIF",     /* 任务名    */
  13.                  512,               /* 任务栈大小,单位word,也就是4字节 */
  14.                  NULL,              /* 任务参数  */
  15.                  1,                 /* 任务优先级*/
  16.                  &xHandleTaskUserIF );  /* 任务句柄  */
  17.    
  18.    
  19.      xTaskCreate( vTaskLED,           /* 任务函数  */
  20.                  "vTaskLED",         /* 任务名    */
  21.                  512,                /* 任务栈大小,单位word,也就是4字节 */
  22.                  NULL,               /* 任务参数  */
  23.                  2,                  /* 任务优先级*/
  24.                  &xHandleTaskLED ); /* 任务句柄  */
  25.    
  26.      xTaskCreate( vTaskMsgPro,            /* 任务函数  */
  27.                  "vTaskMsgPro",           /* 任务名    */
  28.                  512,                     /* 任务栈大小,单位word,也就是4字节 */
  29.                  NULL,                    /* 任务参数  */
  30.                  3,                       /* 任务优先级*/
  31.                  &xHandleTaskMsgPro );  /* 任务句柄  */
  32.    
  33.    
  34.      xTaskCreate( vTaskStart,             /* 任务函数  */
  35.                  "vTaskStart",            /* 任务名    */
  36.                  512,                     /* 任务栈大小,单位word,也就是4字节 */
  37.                  NULL,                    /* 任务参数  */
  38.                  4,                       /* 任务优先级*/
  39.                  &xHandleTaskStart );   /* 任务句柄  */
  40. }
复制代码
四个FreeRTOS任务的实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: vTaskTaskUserIF
  4. *    功能说明: 接口消息处理。
  5. *    形    参: pvParameters 是在创建该任务时传递的形参
  6. *    返 回 值: 无
  7. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
  8. *********************************************************************************************************
  9. */
  10. static void vTaskTaskUserIF(void *pvParameters)
  11. {
  12.      uint8_t ucKeyCode;
  13.      uint8_t pcWriteBuffer[500];
  14.     while(1)
  15.     {
  16.          ucKeyCode = bsp_GetKey();
  17.         
  18.          if (ucKeyCode != KEY_NONE)
  19.          {
  20.               switch (ucKeyCode)
  21.               {
  22.                    /* K1键按下 打印任务执行情况 */
  23.                    case KEY_DOWN_K1:         
  24.                        printf("=================================================\\r\\n");
  25.                        printf("任务名      任务状态 优先级   剩余栈 任务序号\\r\\n");
  26.                        vTaskList((char *)&pcWriteBuffer);
  27.                        printf("%s\\r\\n", pcWriteBuffer);
  28.                   
  29.                        printf("\\r\\n任务名       运行计数         使用率\\r\\n");
  30.                        vTaskGetRunTimeStats((char *)&pcWriteBuffer);
  31.                        printf("%s\\r\\n", pcWriteBuffer);
  32.                        break;
  33.                   
  34.                    /* K2键按下 打印系统时钟节拍数 */
  35.                    case KEY_DOWN_K2:         
  36.                        printf("当前的系统时钟节拍数 = %d\\r\\n", xTaskGetTickCount());
  37.                        break;
  38.                   
  39.                    /* 其他的键值不处理 */
  40.                    default:                     
  41.                        break;
  42.               }
  43.          }
  44.         
  45.          vTaskDelay(20);
  46.      }
  47. }
  48. /*
  49. *********************************************************************************************************
  50. *    函 数 名: vTaskLED
  51. *    功能说明: LED闪烁
  52. *    形    参: pvParameters 是在创建该任务时传递的形参
  53. *    返 回 值: 无
  54. *   优 先 级: 2
  55. *********************************************************************************************************
  56. */
  57. static void vTaskLED(void *pvParameters)
  58. {
  59.      TickType_t xLastWakeTime;
  60.      const TickType_t xFrequency = 200;
  61.      /* 获取当前的系统时间 */
  62.     xLastWakeTime = xTaskGetTickCount();
  63.    
  64.     while(1)
  65.     {
  66.          bsp_LedToggle(2);
  67.         
  68.          /* vTaskDelayUntil是绝对延迟,vTaskDelay是相对延迟。*/
  69.         vTaskDelayUntil(&xLastWakeTime, xFrequency);
  70.     }
  71. }
  72. /*
  73. *********************************************************************************************************
  74. *    函 数 名: vTaskMsgPro
  75. *    功能说明: 消息处理,这里是用作LED闪烁   
  76. *    形    参: pvParameters 是在创建该任务时传递的形参
  77. *    返 回 值: 无
  78. *   优 先 级: 3
  79. *********************************************************************************************************
  80. */
  81. static void vTaskMsgPro(void *pvParameters)
  82. {
  83.      TickType_t xDelay, xNextTime;
  84.      const TickType_t xFrequency = 200;
  85.    
  86.      /* 获取xFrequency个时钟节拍后的时间 */
  87.      xNextTime = xTaskGetTickCount() + xFrequency;
  88.    
  89.     while(1)
  90.     {
  91.          bsp_LedToggle(3);
  92.         
  93.          /* 用vTaskDelay实现vTaskDelayUntil() */
  94.          xDelay = xNextTime - xTaskGetTickCount();
  95.          xNextTime += xFrequency;
  96.         
  97.          if(xDelay <= xFrequency)
  98.          {
  99.               vTaskDelay(xDelay);
  100.          }
  101.      }
  102. }
  103. /*
  104. *********************************************************************************************************
  105. *    函 数 名: vTaskStart
  106. *    功能说明: 启动任务,也就是最高优先级任务,这里用作按键扫描。
  107. *    形    参: pvParameters 是在创建该任务时传递的形参
  108. *    返 回 值: 无
  109. *   优 先 级: 4
  110. *********************************************************************************************************
  111. */
  112. static void vTaskStart(void *pvParameters)
  113. {
  114.     while(1)
  115.     {
  116.          /* 按键扫描 */
  117.          bsp_KeyScan();
  118.         vTaskDelay(10);
  119.     }
  120. }
复制代码
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-8-26 17:08:46 | 显示全部楼层
17.3.3   STM32F429开发板实验


配套例子:
     V6-311_FreeRTOS实验_周期性延迟和相对性延迟函数
实验目的:
    1.     学习FreeRTOS的周期性延迟和相对性延迟函数。
    2.     注意相对性延迟函数vTaskDelay和周期性延迟函数vTaskDelayUntil的区别。
实验内容:
    1.     K1按键按下,串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1)。
    2.     K2键按下,串口打印系统时钟节拍数。
    3.     各个任务实现的功能如下:
              vTaskUserIF任务   :按键消息处理。
              vTaskLED任务     :LED闪烁。
              vTaskMsgPro任务 :消息处理,这里是用作LED闪烁。
              vTaskStart任务    :启动任务,也是最高优先级任务,这里实现按键扫描。
FreeRTOS的配置:
    FreeRTOSConfig.h文件中的配置如下:
  1. /* Ensure stdint is only used by the compiler, and not the assembler. */
  2. #if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
  3. #include <stdint.h>
  4. extern volatile uint32_t ulHighFrequencyTimerTicks;
  5. #endif
  6. #define configUSE_PREEMPTION         1
  7. #define configUSE_IDLE_HOOK          0
  8. #define configUSE_TICK_HOOK          0
  9. #define configCPU_CLOCK_HZ           ( ( unsigned long ) 168000000 )
  10. #define configTICK_RATE_HZ           ( ( TickType_t ) 1000 )
  11. #define configMAX_PRIORITIES         ( 5 )
  12. #define configMINIMAL_STACK_SIZE     ( ( unsigned short ) 128 )
  13. #define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 30 * 1024 ) )
  14. #define configMAX_TASK_NAME_LEN      ( 16 )
  15. #define configUSE_TRACE_FACILITY      1
  16. #define configUSE_16_BIT_TICKS       0
  17. #define configIDLE_SHOULD_YIELD      1
  18. /* Run time and task stats gathering related definitions. */
  19. #define configGENERATE_RUN_TIME_STATS                1
  20. #define configUSE_STATS_FORMATTING_FUNCTIONS         1
  21. #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()     (ulHighFrequencyTimerTicks = 0ul)
  22. #define portGET_RUN_TIME_COUNTER_VALUE()             ulHighFrequencyTimerTicks
  23. //#define portALT_GET_RUN_TIME_COUNTER_VALUE           1
  24. /* Co-routine definitions. */
  25. #define configUSE_CO_ROUTINES            0
  26. #define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
  27. /* Set the following definitions to 1 to include the API function, or zero
  28. to exclude the API function. */
  29. #define INCLUDE_vTaskPrioritySet          1
  30. #define INCLUDE_uxTaskPriorityGet         1
  31. #define INCLUDE_vTaskDelete               1
  32. #define INCLUDE_vTaskCleanUpResources      0
  33. #define INCLUDE_vTaskSuspend              1
  34. #define INCLUDE_vTaskDelayUntil           1
  35. #define INCLUDE_vTaskDelay                1
  36. /* Cortex-M specific definitions. */
  37. #ifdef __NVIC_PRIO_BITS
  38.      /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
  39.      #define configPRIO_BITS              __NVIC_PRIO_BITS
  40. #else
  41.      #define configPRIO_BITS              4        /* 15 priority levels */
  42. #endif
  43. /* The lowest interrupt priority that can be used in a call to a "set priority"
  44. function. */
  45. #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY              0x0f
  46. /* The highest interrupt priority that can be used by any interrupt service
  47. routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL
  48. INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
  49. PRIORITY THAN THIS! (higher priorities are lower numeric values. */
  50. #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY         0x01
复制代码

几个重要选项说明:
1、#define configUSE_PREEMPTION        1
          使能抢占式调度器
2、#define configCPU_CLOCK_HZ      ( ( unsigned long ) 168000000 )
          系统主频168MHz。
3、#define configTICK_RATE_HZ              ( ( TickType_t ) 1000 )
          系统时钟节拍1KHz,即1ms。
4、#define configMAX_PRIORITIES          ( 5 )
          定义可供用户使用的最大优先级数,如果这个定义的是5,那么用户可以使用的优先级号是0,1,2,3,4,不包含5,对于这一点,初学者要特别的注意。
5、#define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 30 * 1024 ) )
           定义堆大小,FreeRTOS内核,用户动态内存申请,任务栈等都需要用这个空间。
6、configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY          0x01
          定义受FreeRTOS管理的最高优先级中断。简单的说就是允许用户在这个中断服务程序里面调用FreeRTOS的API的最高优先级。为了进一步说明这个宏定义的的作用,解释如下:
    (1)使用CM内核的MCU,官方强烈建议将NVIC的优先级分组配置为全抢占式优先级,全部配置为抢占式优先级的好处就是方便管理。
    (2)对于STM32来说,设置NVIC的优先级分组为4时,NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4)就是全部配置为抢占式优先级。又因为STM32的优先级设置仅使用CM内核8bit中的高4bit,即只能区分2^4 = 16种优先级。因此当优先级分组设置为4的时候可供用户选择抢占式优先级为015,共16个优先级,配置为0表示最高优先级,配置为15表示最低优先级,不存在子优先级。
    (3)这里配置configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY0x01表示用户可以在抢占式优先级为115的中断里面调用FreeRTOSAPI函数,抢占式优先级为0的中断里面是不允许调用的。
     更多关于这个参数说明请参看第12章。
FreeRTOS任务调试信息(按K1按键,串口打印):
17.10.jpg

上面截图中打印出来的任务状态字母B, R, D, S对应如下含义:
    #definetskBLOCKED_CHAR          ( 'B' )  任务阻塞
    #definetskREADY_CHAR           ( 'R' ) 任务就绪
    #definetskDELETED_CHAR           ( 'D' )  任务删除
    #definetskSUSPENDED_CHAR   ( 'S' ) 任务挂起
程序设计:
任务栈大小分配:
    vTaskUserIF任务   :2048字节
    vTaskLED任务     :2048字节
    vTaskMsgPro任务 :2048字节
    vTaskStart任务    :2048字节
    任务栈空间是在任务创建的时候从FreeRTOSConfig.h文件中定义的heap空间中申请的
    #defineconfigTOTAL_HEAP_SIZE        ( ( size_t )( 30 * 1024 ) )
系统栈大小分配:
17.11.jpg

FreeROTS初始化:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: main
  4. *    功能说明: 标准c程序入口。
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. int main(void)
  10. {
  11.      /*
  12.        在启动调度前,为了防止初始化STM32外设时有中断服务程序执行,这里禁止全局中断(除了NMI和HardFault)。
  13.        这样做的好处是:
  14.        1. 防止执行的中断服务程序中有FreeRTOS的API函数。
  15.        2. 保证系统正常启动,不受别的中断影响。
  16.        3. 关于是否关闭全局中断,大家根据自己的实际情况设置即可。
  17.        在移植文件port.c中的函数prvStartFirstTask中会重新开启全局中断。通过指令cpsie i开启,__set_PRIMASK(1)
  18.        和cpsie i是等效的。
  19.      */
  20.      __set_PRIMASK(1);
  21.    
  22.      /* 硬件初始化 */
  23.      bsp_Init();
  24.    
  25.      /* 1. 初始化一个定时器中断,精度高于滴答定时器中断,这样才可以获得准确的系统信息 仅供调试目的,实际项
  26.            目中不要使用,因为这个功能比较影响系统实时性。
  27.         2. 为了正确获取FreeRTOS的调试信息,可以考虑将上面的关闭中断指令__set_PRIMASK(1); 注释掉。
  28.      */
  29.      vSetupSysInfoTest();
  30.    
  31.      /* 创建任务 */
  32.      AppTaskCreate();
  33.    
  34.     /* 启动调度,开始执行任务 */
  35.     vTaskStartScheduler();
  36.      /*
  37.        如果系统正常启动是不会运行到这里的,运行到这里极有可能是用于定时器任务或者空闲任务的
  38.        heap空间不足造成创建失败,此要加大FreeRTOSConfig.h文件中定义的heap大小:
  39.        #define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 17 * 1024 ) )
  40.      */
  41.      while(1);
  42. }
复制代码

硬件外设初始化
    硬件外设的初始化是在bsp.c文件实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: bsp_Init
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void bsp_Init(void)
  10. {
  11.      /*
  12.          由于ST固件库的启动文件已经执行了CPU系统时钟的初始化,所以不必再次重复配置系统时钟。
  13.          启动文件配置了CPU主时钟频率、内部Flash访问速度和可选的外部SRAM FSMC初始化。
  14.          系统时钟缺省配置为168MHz,如果需要更改,可以修改 system_stm32f4xx.c 文件
  15.      */
  16.      /* 优先级分组设置为4,可配置0-15级抢占式优先级,0级子优先级,即不存在子优先级。*/
  17.      NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
  18.    
  19.      SystemCoreClockUpdate();    /* 根据PLL配置更新系统时钟频率变量 SystemCoreClock */
  20.      bsp_InitUart();    /* 初始化串口 */
  21.      bsp_InitKey();     /* 初始化按键变量 */
  22.      bsp_InitExtIO();   /* FMC总线上扩展了32位输出IO, 操作LED等外设必须初始化 */
  23.      bsp_InitLed();     /* 初始LED指示灯端口 */
  24. }
复制代码

FreeRTOS任务创建:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: AppTaskCreate
  4. *    功能说明: 创建应用任务
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void AppTaskCreate (void)
  10. {
  11.     xTaskCreate( vTaskTaskUserIF,   /* 任务函数  */
  12.                  "vTaskUserIF",     /* 任务名    */
  13.                  512,               /* 任务栈大小,单位word,也就是4字节 */
  14.                  NULL,              /* 任务参数  */
  15.                  1,                 /* 任务优先级*/
  16.                  &xHandleTaskUserIF );  /* 任务句柄  */
  17.    
  18.    
  19.      xTaskCreate( vTaskLED,           /* 任务函数  */
  20.                  "vTaskLED",         /* 任务名    */
  21.                  512,                /* 任务栈大小,单位word,也就是4字节 */
  22.                  NULL,               /* 任务参数  */
  23.                  2,                  /* 任务优先级*/
  24.                  &xHandleTaskLED ); /* 任务句柄  */
  25.    
  26.      xTaskCreate( vTaskMsgPro,            /* 任务函数  */
  27.                  "vTaskMsgPro",           /* 任务名    */
  28.                  512,                     /* 任务栈大小,单位word,也就是4字节 */
  29.                  NULL,                    /* 任务参数  */
  30.                  3,                       /* 任务优先级*/
  31.                  &xHandleTaskMsgPro );  /* 任务句柄  */
  32.    
  33.    
  34.      xTaskCreate( vTaskStart,             /* 任务函数  */
  35.                  "vTaskStart",            /* 任务名    */
  36.                  512,                     /* 任务栈大小,单位word,也就是4字节 */
  37.                  NULL,                    /* 任务参数  */
  38.                  4,                       /* 任务优先级*/
  39.                  &xHandleTaskStart );   /* 任务句柄  */
  40. }
复制代码

四个FreeRTOS任务的实现:
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: vTaskTaskUserIF
  4. *    功能说明: 接口消息处理。
  5. *    形    参: pvParameters 是在创建该任务时传递的形参
  6. *    返 回 值: 无
  7. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
  8. *********************************************************************************************************
  9. */
  10. static void vTaskTaskUserIF(void *pvParameters)
  11. {
  12.      uint8_t ucKeyCode;
  13.      uint8_t pcWriteBuffer[500];
  14.     while(1)
  15.     {
  16.          ucKeyCode = bsp_GetKey();
  17.         
  18.          if (ucKeyCode != KEY_NONE)
  19.          {
  20.               switch (ucKeyCode)
  21.               {
  22.                    /* K1键按下 打印任务执行情况 */
  23.                    case KEY_DOWN_K1:         
  24.                        printf("=================================================\\r\\n");
  25.                        printf("任务名      任务状态 优先级   剩余栈 任务序号\\r\\n");
  26.                        vTaskList((char *)&pcWriteBuffer);
  27.                        printf("%s\\r\\n", pcWriteBuffer);
  28.                   
  29.                        printf("\\r\\n任务名       运行计数         使用率\\r\\n");
  30.                        vTaskGetRunTimeStats((char *)&pcWriteBuffer);
  31.                        printf("%s\\r\\n", pcWriteBuffer);
  32.                        break;
  33.                   
  34.                    /* K2键按下 打印系统时钟节拍数 */
  35.                    case KEY_DOWN_K2:         
  36.                        printf("当前的系统时钟节拍数 = %d\\r\\n", xTaskGetTickCount());
  37.                        break;
  38.                   
  39.                    /* 其他的键值不处理 */
  40.                    default:                    
  41.                        break;
  42.               }
  43.          }
  44.         
  45.          vTaskDelay(20);
  46.      }
  47. }
  48. /*
  49. *********************************************************************************************************
  50. *    函 数 名: vTaskLED
  51. *    功能说明: LED闪烁
  52. *    形    参: pvParameters 是在创建该任务时传递的形参
  53. *    返 回 值: 无
  54. *   优 先 级: 2
  55. *********************************************************************************************************
  56. */
  57. static void vTaskLED(void *pvParameters)
  58. {
  59.      TickType_t xLastWakeTime;
  60.      const TickType_t xFrequency = 200;
  61.      /* 获取当前的系统时间 */
  62.     xLastWakeTime = xTaskGetTickCount();
  63.    
  64.     while(1)
  65.     {
  66.          bsp_LedToggle(2);
  67.         
  68.          /* vTaskDelayUntil是绝对延迟,vTaskDelay是相对延迟。*/
  69.         vTaskDelayUntil(&xLastWakeTime, xFrequency);
  70.     }
  71. }
  72. /*
  73. *********************************************************************************************************
  74. *    函 数 名: vTaskMsgPro
  75. *    功能说明: 消息处理,这里是用作LED闪烁   
  76. *    形    参: pvParameters 是在创建该任务时传递的形参
  77. *    返 回 值: 无
  78. *   优 先 级: 3
  79. *********************************************************************************************************
  80. */
  81. static void vTaskMsgPro(void *pvParameters)
  82. {
  83.      TickType_t xDelay, xNextTime;
  84.      const TickType_t xFrequency = 200;
  85.    
  86.      /* 获取xFrequency个时钟节拍后的时间 */
  87.      xNextTime = xTaskGetTickCount() + xFrequency;
  88.    
  89.     while(1)
  90.     {
  91.          bsp_LedToggle(3);
  92.         
  93.          /* 用vTaskDelay实现vTaskDelayUntil() */
  94.          xDelay = xNextTime - xTaskGetTickCount();
  95.          xNextTime += xFrequency;
  96.         
  97.          if(xDelay <= xFrequency)
  98.          {
  99.               vTaskDelay(xDelay);
  100.          }
  101.      }
  102. }
  103. /*
  104. *********************************************************************************************************
  105. *    函 数 名: vTaskStart
  106. *    功能说明: 启动任务,也就是最高优先级任务,这里用作按键扫描。
  107. *    形    参: pvParameters 是在创建该任务时传递的形参
  108. *    返 回 值: 无
  109. *   优 先 级: 4
  110. *********************************************************************************************************
  111. */
  112. static void vTaskStart(void *pvParameters)
  113. {
  114.     while(1)
  115.     {
  116.          /* 按键扫描 */
  117.          bsp_KeyScan();
  118.         vTaskDelay(10);
  119.     }
  120. }
复制代码
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-8-26 17:09:18 | 显示全部楼层
17.4   总结


    本章节主要为大家讲解了FreeRTOS操作系统的时钟节拍和时间管理函数,其中时间管理函数是FreeRTOS的基本函数,初学者务必要掌握。
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

0

主题

7

回帖

7

积分

新手上路

积分
7
发表于 2016-8-29 20:18:26 | 显示全部楼层
/* 用vTaskDelay实现vTaskDelayUntil() */,任务里面的变量居然都是 静态局部的[s:146]
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106718
QQ
发表于 2016-8-29 21:46:42 | 显示全部楼层

回 zeroer1223 的帖子

zeroer1223:/* 用vTaskDelay实现vTaskDelayUntil() */,任务里面的变量居然都是 静态局部的[s:146]
(2016-08-29 20:18)
就是局部变量,没有静态,静态的话要加static,在定义的变量类型前面。
而函数前面的static是用来限制函数的作用域。
回复

使用道具 举报

0

主题

7

回帖

7

积分

新手上路

积分
7
发表于 2016-8-30 21:15:34 | 显示全部楼层

回 eric2013 的帖子

2016-08-30_210553.png
从串口数据看出 任务切换后从while函数里面开始 xNextTime 没有释放。和静态的全局变量差别在哪?(理解成普通的函数调用,应该释放的)
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106718
QQ
发表于 2016-8-31 00:59:36 | 显示全部楼层

回 zeroer1223 的帖子

zeroer1223:
从串口数据看出 任务切换后从while函数里面开始 xNextTime 没有释放。和静态的全局变量差别在哪?(理解成普通的函数调用,应该释放的) (2016-08-30 21:15) 
RTOS的任务设计就是这样的。进入任务时定义的变量是不会被释放的,用的任务栈空间。除非将此任务删除,这个任务的占用的系统Heap空间和TCB任务控制块占用的空间就被全部释放了。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-4-30 17:47 , Processed in 0.327060 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表