硬汉嵌入式论坛

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

[FreeRTOS教程] 第13章 FreeRTOS任务优先级修改及其分配方案

[复制链接]

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
发表于 2016-8-22 14:28:08 | 显示全部楼层 |阅读模式



第13章     FreeRTOS任务优先级修改及其分配方案


    本章节主要为大家讲解FreeRTOS任务优先级设置的注意事项、任务优先级的分配方案及其相关的一个例子,内容相对比较简单。
    本章教程配套的例子含Cortex-M3内核的STM32F103和Cortex-M4内核的STM32F407以及F429。
13.1 任务优先级说明
13.2 任务优先级分配方案
13.3 中断优先级和任务优先级的区别
13.4 任务优先级修改
13.5 任务优先级获取
13.6 实验例程说明
13.7      总结


13.1  任务优先级说明

    下面对FreeRTOS优先级相关的几个重要知识点进行下说明,这些知识点在以后的使用中务必要掌握牢固。
u FreeRTOS中任务的最高优先级是通过FreeRTOSConfig.h文件中的configMAX_PRIORITIES进行配置的,用户实际可以使用的优先级范围是0到configMAX_PRIORITIES– 1。比如我们配置此宏定义为5,那么用户可以使用的优先级号是0,1,2,3,4,不包含5,对于这一点,初学者要特别的注意。
u 用户配置任务的优先级数值越小,那么此任务的优先级越低,空闲任务的优先级是0。
u 建议用户配置宏定义configMAX_PRIORITIES的最大值不要超过32,即用户任务可以使用的优先级范围是0到31。因为对于CM内核的移植文件,用户任务的优先级不是大于等于32的话,portmacro.h文件中的宏定义configUSE_PORT_OPTIMISED_TASK_SELECTION会优化优先级列表中要执行的最高优先级任务的获取算法(对于CM内核的移植文件,此宏定义默认是使能的,当然,用户也可以在FreeRTOSConfig.h文件中进行配置)。相比通用的最高优先级任务获取算法,这两种方式的对比如下:
    Ø 通用方式,没有优化---配置宏定义configUSE_PORT_OPTIMISED_TASK_SELECTION为0:
        2 所有平台的移植文件都可以配置为0,因为这是通用方式。
        2 纯C编写,比专用方式效率低。
        2 可用的优先级数量不限制。
    Ø 专用方式,进行优化---配置宏定义configUSE_PORT_OPTIMISED_TASK_SELECTION为为1:
        2 部分平台支持。
        2 这些平台架构有专用的汇编指令,比如CLZ(Count Leading Zeros)指令,通过这些指令可以加速算法执行速度。
        2 比通用方式高效。
        2 有最大优先级数限制,通常限制为32个。
u 如果用户在FreeRTOSConfig.h文件中配置宏定义configUSE_TIME_SLICING为1,或者没有配置此宏定义,时间片调度都是使能的。另外,只要芯片资源允许,可以配置任意多个同优先级任务。
    (备注:没有定义configUSE_TIME_SLICING,也能使用时间片调度是因为此宏定义默认已经在FreeRTOS.h文件中使能)
u FreeRTOS中处于运行状态的任务永远是当前能够运行的最高优先级任务。下一章节讲解调度器,大家会对这个知识点有一个全面的认识。
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-8-22 14:30:10 | 显示全部楼层
13.2 任务优先级分配方案


    对于初学者,有时候会纠结任务优先级设置为多少合适,因为任务优先级设置多少是没有标准的。对于这个问题,我们这里为大家推荐一个标准,任务优先级设置推荐方式如下图13.1所示:
13.1.JPG
图13.1 任务优先级分配方案

u IRQ任务IRQ任务是指通过中断服务程序进行触发的任务,此类任务应该设置为所有任务里面优先级最高的。
u 高优先级后台任务比如按键检测,触摸检测,USB消息处理,串口消息处理等,都可以归为这一类任务。
u 低优先级的时间片调度任务比如emWin的界面显示,LED数码管的显示等不需要实时执行的都可以归为这一类任务。实际应用中用户不必拘泥于将这些任务都设置为优先级1的同优先级任务,可以设置多个优先级,只需注意这类任务不需要高实时性。
u 空闲任务空闲任务是系统任务。
u 特别注意IRQ任务和高优先级任务必须设置为阻塞式(调用消息等待或者延迟等函数即可),只有这样,高优先级任务才会释放CPU的使用权,,从而低优先级任务才有机会得到执行。
    这里的优先级分配方案是我们推荐的一种方式,实际项目也可以不采用这种方法。调试出适合项目需求的才是最好的。
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-8-22 14:30:53 | 显示全部楼层
13.3 中断优先级和任务优先级区别


        部分初学者也容易在这两个概念上面出现问题。简单的说,这两个之间没有任何关系,不管中断的优先级是多少,中断的优先级永远高于任何任务的优先级,即任务在执行的过程中,中断来了就开始执行中断服务程序。
        另外对于STM32F103,F407和F429来说,中断优先级的数值越小,优先级越高。而FreeRTOS的任务优先级是,任务优先级数值越小,任务优先级越低。
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-8-22 14:32:24 | 显示全部楼层
13.4   任务优先级修改


    使用如下函数可以实现FreeRTOS的任务优先级修改:
u vTaskPrioritySet ()
关于这个函数的讲解及其使用方法可以看FreeRTOS在线版手册:
13.2.jpg


这里也对此函数进行下介绍。
函数原型:
  1. void vTaskPrioritySet( TaskHandle_t xTask,           /* 任务句柄 */
  2.                        UBaseType_t uxNewPriority );  /* 给任务配置的新优先级 */
复制代码
函数描述:
函数vTaskPrioritySet用于实现FreeRTOS任务优先级的修改。
u 第1个参数是任务句柄,用于区分不同的任务。
u 第2个参数是给任务配置的新优先级。
使用这个函数要注意以下问题:
1.     使用此函数需要在FreeRTOSConfig.h配置文件中配置如下宏定义为1
        #defineINCLUDE_vTaskPrioritySet      1
2.     如果第二个参数里面填的是NULL,即数值0的话,那么配置的就是当前正在执行的任务。
3.     如果被修改的任务的优先级,修改后高于正在执行的任务,将执行任务切换,切换到修改好的高优先级任务。
4.     第二个参数数值不可大于等于FreeRTOSConfig.h文件中的宏定义:
        #define configMAX_PRIORITIES 配置的数值。
使用举例:
  1. /* 任务句柄 */
  2. static TaskHandle_t xHandleTaskLED = NULL;
  3. /*
  4. *********************************************************************************************************
  5. *    函 数 名: vTaskTaskUserIF
  6. *    功能说明: 接口消息处理。
  7. *    形    参: pvParameters 是在创建该任务时传递的形参
  8. *    返 回 值: 无
  9. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
  10. *********************************************************************************************************
  11. */
  12. static void vTaskTaskUserIF(void *pvParameters)
  13. {
  14.      uint8_t ucKeyCode;
  15.     while(1)
  16.     {
  17.          ucKeyCode = bsp_GetKey();
  18.         
  19.          if (ucKeyCode != KEY_NONE)
  20.          {
  21.               switch (ucKeyCode)
  22.               {
  23.                   
  24.                    /* K2键按下 设置任务vTaskLED的优先级为1 */
  25.                    case KEY_DOWN_K2:         
  26.                        printf("K2键按下,设置任务vTaskLED的优先级为1\\r\\n");
  27.                        vTaskPrioritySet( xHandleTaskLED, 1);
  28.                        printf("K2键按下,任务vTaskLED的优先级已经设置为:%d\\r\\n",
  29. (int)uxTaskPriorityGet(xHandleTaskLED));
  30.                        break;
  31.                   
  32.                    /* K3键按下 设置任务vTaskLED的优先级为2 */
  33.                    case KEY_DOWN_K3:         
  34.                        printf("K3键按下,设置任务vTaskLED的优先级为2\\r\\n");
  35.                        vTaskPrioritySet( xHandleTaskLED, 2);
  36.                        printf("K3键按下,任务vTaskLED的优先级已经设置为:%d\\r\\n",
  37.   (int)uxTaskPriorityGet(xHandleTaskLED));
  38.                        break;
  39.                   
  40.                    /* 其他的键值不处理 */
  41.                    default:                    
  42.                        break;
  43.               }
  44.          }
  45.         
  46.          vTaskDelay(20);
  47.      }
  48. }
  49. /*
  50. *********************************************************************************************************
  51. *    函 数 名: AppTaskCreate
  52. *    功能说明: 创建应用任务
  53. *    形    参: 无
  54. *    返 回 值: 无
  55. *********************************************************************************************************
  56. */
  57. static void AppTaskCreate (void)
  58. {
  59.      xTaskCreate( vTaskLED,           /* 任务函数  */
  60.                  "vTaskLED",         /* 任务名    */
  61.                  512,                /* stack大小,单位word,也就是4字节 */
  62.                  NULL,               /* 任务参数  */
  63.                  2,                  /* 任务优先级*/
  64.                  &xHandleTaskLED ); /* 任务句柄  */
  65. }
复制代码
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-8-22 14:42:47 | 显示全部楼层
13.5 任务优先级获取


    使用如下函数可以实现FreeRTOS的任务优先级获取:
u vTaskPriorityGet ()
关于这个函数的讲解及其使用方法可以看FreeRTOS在线版手册:
13.3.jpg

这里也对此函数进行下介绍。
函数原型:
  1. UBaseType_t uxTaskPriorityGet( TaskHandle_t xTask ); /* 任务句柄 */
复制代码
函数描述:
函数vTaskPriorityGet用于获取FreeRTOS任务优先级。
u 第1个参数是任务句柄,用于区分不同的任务。


使用这个函数要注意以下问题:
1.     使用此函数需要在FreeRTOSConfig.h配置文件中配置如下宏定义为1
      #defineINCLUDE_vTaskPriorityGet      1
2.     如果第二个参数里面填的是NULL,即数值0的话,那么获取的优先级就是当前正在执行的任务。
使用举例:
  1. /* 任务句柄 */
  2. static TaskHandle_t xHandleTaskLED = NULL;
  3. /*
  4. *********************************************************************************************************
  5. *    函 数 名: vTaskTaskUserIF
  6. *    功能说明: 接口消息处理。
  7. *    形    参: pvParameters 是在创建该任务时传递的形参
  8. *    返 回 值: 无
  9. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
  10. *********************************************************************************************************
  11. */
  12. static void vTaskTaskUserIF(void *pvParameters)
  13. {
  14.      uint8_t ucKeyCode;
  15.     while(1)
  16.     {
  17.          ucKeyCode = bsp_GetKey();
  18.         
  19.          if (ucKeyCode != KEY_NONE)
  20.          {
  21.               switch (ucKeyCode)
  22.               {
  23.                   
  24.                    /* K2键按下 设置任务vTaskLED的优先级为1 */
  25.                    case KEY_DOWN_K2:         
  26.                        printf("K2键按下,设置任务vTaskLED的优先级为1\\r\\n");
  27.                        vTaskPrioritySet( xHandleTaskLED, 1);
  28.                        printf("K2键按下,任务vTaskLED的优先级已经设置为:%d\\r\\n",
  29. (int)uxTaskPriorityGet(xHandleTaskLED));
  30.                        break;
  31.                   
  32.                    /* K3键按下 设置任务vTaskLED的优先级为2 */
  33.                    case KEY_DOWN_K3:         
  34.                        printf("K3键按下,设置任务vTaskLED的优先级为2\\r\\n");
  35.                        vTaskPrioritySet( xHandleTaskLED, 2);
  36.                        printf("K3键按下,任务vTaskLED的优先级已经设置为:%d\\r\\n",
  37.   (int)uxTaskPriorityGet(xHandleTaskLED));
  38.                        break;
  39.                   
  40.                    /* 其他的键值不处理 */
  41.                    default:                    
  42.                        break;
  43.               }
  44.          }
  45.         
  46.          vTaskDelay(20);
  47.      }
  48. }
  49. /*
  50. *********************************************************************************************************
  51. *    函 数 名: AppTaskCreate
  52. *    功能说明: 创建应用任务
  53. *    形    参: 无
  54. *    返 回 值: 无
  55. *********************************************************************************************************
  56. */
  57. static void AppTaskCreate (void)
  58. {
  59.      xTaskCreate( vTaskLED,           /* 任务函数  */
  60.                  "vTaskLED",         /* 任务名    */
  61.                  512,                /* stack大小,单位word,也就是4字节 */
  62.                  NULL,               /* 任务参数  */
  63.                  2,                  /* 任务优先级*/
  64.                  &xHandleTaskLED ); /* 任务句柄  */
  65. }
复制代码
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-8-22 14:46:48 | 显示全部楼层
13.6 实验例程说明



13.6.1 STM32F103开发板实验


配套例子:
    V4-307_FreeRTOS实验_任务优先级修改
实验目的:
    1. 学习FreeRTOS的任务优先级修改。
实验内容:
    1.     K1按键按下,串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1)。
    2.     K2按键按下,设置任务vTaskLED的优先级为1。
    3.     K3按键按下,设置任务vTaskLED的优先级为2。
    4.     各个任务实现的功能如下:
              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
复制代码
几个重要选项说明:
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 #define INCLUDE_vTaskPrioritySet                    1
      使能FreeRTOS的任务优先级修改函数vTaskPrioritySet可供用户调用。
u #define  INCLUDE_uxTaskPriorityGet   1
      使能FreeRTOS的任务优先级获取函数uxTaskPriorityGet可供用户调用。
u configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY          0x01
      定义受FreeRTOS管理的最高优先级中断。简单的说就是允许用户在这个中断服务程序里面调用FreeRTOS的API的最高优先级。为了进一步说明这个宏定义的的作用,解释如下:
    l 使用CM内核的MCU,官方强烈建议将NVIC的优先级分组配置为全抢占式优先级,全部配置为抢占式优先级的好处就是方便管理。
    l 对于STM32来说,设置NVIC的优先级分组为4时,NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4)就是全部配置为抢占式优先级。又因为STM32的优先级设置仅使用CM内核8bit中的高4bit,即只能区分2^4 = 16种优先级。因此当优先级分组设置为4的时候可供用户选择抢占式优先级为0到15,共16个优先级,配置为0表示最高优先级,配置为15表示最低优先级,不存在子优先级。
    l 这里配置configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY为0x01表示用户可以在抢占式优先级为1到15的中断里面调用FreeRTOS的API函数,抢占式优先级为0的中断里面是不允许调用的。
    更多关于这个参数说明请参看第12章。
FreeRTOS任务调试信息(按K1按键,串口打印):
13.4.jpg

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

u  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. }
复制代码
u  硬件外设初始化
    硬件外设的初始化是在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. }
复制代码
u  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. }
复制代码
u  四个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键按下 设置任务vTaskLED的优先级为1 */
  35.                    case KEY_DOWN_K2:         
  36.                        printf("K2键按下,设置任务vTaskLED的优先级为1\\r\\n");
  37.                        vTaskPrioritySet( xHandleTaskLED, 1);
  38.                        printf("K2键按下,任务vTaskLED的优先级已经设置为:%d\\r\\n",
  39. (int)uxTaskPriorityGet(xHandleTaskLED));
  40.                        break;
  41.                   
  42.                    /* K3键按下 设置任务vTaskLED的优先级为2 */
  43.                    case KEY_DOWN_K3:         
  44.                        printf("K3键按下,设置任务vTaskLED的优先级为2\\r\\n");
  45.                        vTaskPrioritySet( xHandleTaskLED, 2);
  46.                        printf("K3键按下,任务vTaskLED的优先级已经设置为:%d\\r\\n",
  47.   (int)uxTaskPriorityGet(xHandleTaskLED));
  48.                        break;
  49.                    /* 其他的键值不处理 */
  50.                    default:                    
  51.                        break;
  52.               }
  53.          }
  54.         
  55.          vTaskDelay(20);
  56.      }
  57. }
  58. /*
  59. *********************************************************************************************************
  60. *    函 数 名: vTaskLED
  61. *    功能说明: LED闪烁
  62. *    形    参: pvParameters 是在创建该任务时传递的形参
  63. *    返 回 值: 无
  64. *   优 先 级: 2
  65. *********************************************************************************************************
  66. */
  67. static void vTaskLED(void *pvParameters)
  68. {
  69.     while(1)
  70.     {
  71.          bsp_LedToggle(2);
  72.         vTaskDelay(200);
  73.     }
  74. }
  75. /*
  76. *********************************************************************************************************
  77. *    函 数 名: vTaskMsgPro
  78. *    功能说明: 消息处理,这里是用作LED闪烁   
  79. *    形    参: pvParameters 是在创建该任务时传递的形参
  80. *    返 回 值: 无
  81. *   优 先 级: 3
  82. *********************************************************************************************************
  83. */
  84. static void vTaskMsgPro(void *pvParameters)
  85. {
  86.     while(1)
  87.     {
  88.          bsp_LedToggle(3);
  89.         vTaskDelay(300);
  90.     }
  91. }
  92. /*
  93. *********************************************************************************************************
  94. *    函 数 名: vTaskStart
  95. *    功能说明: 启动任务,也就是最高优先级任务,这里用作按键扫描。
  96. *    形    参: pvParameters 是在创建该任务时传递的形参
  97. *    返 回 值: 无
  98. *   优 先 级: 4
  99. *********************************************************************************************************
  100. */
  101. static void vTaskStart(void *pvParameters)
  102. {
  103.     while(1)
  104.     {
  105.          /* 按键扫描 */
  106.          bsp_KeyScan();
  107.         vTaskDelay(10);
  108.     }
  109. }
复制代码
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-8-22 14:51:11 | 显示全部楼层
13.6.2   STM32F407开发板实验


配套例子:
    V5-307_FreeRTOS实验_任务优先级修改
实验目的:
    1. 学习FreeRTOS的任务优先级修改。
实验内容:
    1.     K1按键按下,串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1)。
    2.     K2按键按下,设置任务vTaskLED的优先级为1。
    3.     K3按键按下,设置任务vTaskLED的优先级为2。
    4.     各个任务实现的功能如下:
              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
复制代码
几个重要选项说明:
u #define configUSE_PREEMPTION        1
        使能抢占式调度器
u #define configCPU_CLOCK_HZ      ( ( unsigned long ) 168000000 )  
        系统主频168MHz。
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 ) ( 30 * 1024 ) )
        定义堆大小,FreeRTOS内核,用户动态内存申请,任务栈等都需要用这个空间。
u #define INCLUDE_vTaskPrioritySet                    1
        使能FreeRTOS的任务优先级修改函数vTaskPrioritySet可供用户调用。
u #define  INCLUDE_uxTaskPriorityGet   1
        使能FreeRTOS的任务优先级获取函数uxTaskPriorityGet可供用户调用。
u configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY          0x01
        定义受FreeRTOS管理的最高优先级中断。简单的说就是允许用户在这个中断服务程序里面调用FreeRTOS的API的最高优先级。为了进一步说明这个宏定义的的作用,解释如下:
    l 使用CM内核的MCU,官方强烈建议将NVIC的优先级分组配置为全抢占式优先级,全部配置为抢占式优先级的好处就是方便管理。
    l 对于STM32来说,设置NVIC的优先级分组为4时,NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4)就是全部配置为抢占式优先级。又因为STM32的优先级设置仅使用CM内核8bit中的高4bit,即只能区分2^4 = 16种优先级。因此当优先级分组设置为4的时候可供用户选择抢占式优先级为0到15,共16个优先级,配置为0表示最高优先级,配置为15表示最低优先级,不存在子优先级。
    l 这里配置configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY为0x01表示用户可以在抢占式优先级为1到15的中断里面调用FreeRTOS的API函数,抢占式优先级为0的中断里面是不允许调用的。
    更多关于这个参数说明请参看第12章。
FreeRTOS任务调试信息(按K1按键,串口打印):
13.6.jpg

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

u  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. }
复制代码
u  硬件外设初始化
    硬件外设的初始化是在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. }
复制代码
u  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. }
复制代码
u  四个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键按下 设置任务vTaskLED的优先级为1 */
  35.                    case KEY_DOWN_K2:         
  36.                        printf("K2键按下,设置任务vTaskLED的优先级为1\\r\\n");
  37.                        vTaskPrioritySet( xHandleTaskLED, 1);
  38.                        printf("K2键按下,任务vTaskLED的优先级已经设置为:%d\\r\\n",
  39. (int)uxTaskPriorityGet(xHandleTaskLED));
  40.                        break;
  41.                   
  42.                    /* K3键按下 设置任务vTaskLED的优先级为2 */
  43.                    case KEY_DOWN_K3:         
  44.                        printf("K3键按下,设置任务vTaskLED的优先级为2\\r\\n");
  45.                        vTaskPrioritySet( xHandleTaskLED, 2);
  46.                        printf("K3键按下,任务vTaskLED的优先级已经设置为:%d\\r\\n",
  47.   (int)uxTaskPriorityGet(xHandleTaskLED));
  48.                        break;
  49.                    /* 其他的键值不处理 */
  50.                    default:                    
  51.                        break;
  52.               }
  53.          }
  54.         
  55.          vTaskDelay(20);
  56.      }
  57. }
  58. /*
  59. *********************************************************************************************************
  60. *    函 数 名: vTaskLED
  61. *    功能说明: LED闪烁
  62. *    形    参: pvParameters 是在创建该任务时传递的形参
  63. *    返 回 值: 无
  64. *   优 先 级: 2
  65. *********************************************************************************************************
  66. */
  67. static void vTaskLED(void *pvParameters)
  68. {
  69.     while(1)
  70.     {
  71.          bsp_LedToggle(2);
  72.         vTaskDelay(200);
  73.     }
  74. }
  75. /*
  76. *********************************************************************************************************
  77. *    函 数 名: vTaskMsgPro
  78. *    功能说明: 消息处理,这里是用作LED闪烁   
  79. *    形    参: pvParameters 是在创建该任务时传递的形参
  80. *    返 回 值: 无
  81. *   优 先 级: 3
  82. *********************************************************************************************************
  83. */
  84. static void vTaskMsgPro(void *pvParameters)
  85. {
  86.     while(1)
  87.     {
  88.          bsp_LedToggle(3);
  89.         vTaskDelay(300);
  90.     }
  91. }
  92. /*
  93. *********************************************************************************************************
  94. *    函 数 名: vTaskStart
  95. *    功能说明: 启动任务,也就是最高优先级任务,这里用作按键扫描。
  96. *    形    参: pvParameters 是在创建该任务时传递的形参
  97. *    返 回 值: 无
  98. *   优 先 级: 4
  99. *********************************************************************************************************
  100. */
  101. static void vTaskStart(void *pvParameters)
  102. {
  103.     while(1)
  104.     {
  105.          /* 按键扫描 */
  106.          bsp_KeyScan();
  107.         vTaskDelay(10);
  108.     }
  109. }
复制代码
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-8-22 14:55:17 | 显示全部楼层
13.6.3   STM32F429开发板实验


配套例子:
    V6-307_FreeRTOS实验_任务优先级修改
实验目的:
    1. 学习FreeRTOS的任务优先级修改。
实验内容:
     1.     K1按键按下,串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1)。
    2.     K2按键按下,设置任务vTaskLED的优先级为1。
    3.     K3按键按下,设置任务vTaskLED的优先级为2。
    4.     各个任务实现的功能如下:
              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
复制代码

几个重要选项说明:
u #define configUSE_PREEMPTION        1
          使能抢占式调度器
u #define configCPU_CLOCK_HZ      ( ( unsigned long ) 168000000 )  
         系统主频168MHz。
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 ) ( 30 * 1024 ) )
          定义堆大小,FreeRTOS内核,用户动态内存申请,任务栈等都需要用这个空间。
u #define INCLUDE_vTaskPrioritySet                    1
          使能FreeRTOS的任务优先级修改函数vTaskPrioritySet可供用户调用。
u #define  INCLUDE_uxTaskPriorityGet   1
          使能FreeRTOS的任务优先级获取函数uxTaskPriorityGet可供用户调用。
u configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY          0x01
      定义受FreeRTOS管理的最高优先级中断。简单的说就是允许用户在这个中断服务程序里面调用FreeRTOS的API的最高优先级。为了进一步说明这个宏定义的的作用,解释如下:
    l 使用CM内核的MCU,官方强烈建议将NVIC的优先级分组配置为全抢占式优先级,全部配置为抢占式优先级的好处就是方便管理。
    l 对于STM32来说,设置NVIC的优先级分组为4时,NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4)就是全部配置为抢占式优先级。又因为STM32的优先级设置仅使用CM内核8bit中的高4bit,即只能区分2^4 = 16种优先级。因此当优先级分组设置为4的时候可供用户选择抢占式优先级为0到15,共16个优先级,配置为0表示最高优先级,配 置为15表示最低优先级,不存在子优先级。
     l 这里配置configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY为0x01表示用户可以在抢占式优先级为1到15的中断里面调用FreeRTOS的API函数,抢占式优先级为0的中断里面是不允许调用的。
    更多关于这个参数说明请参看第12章。
FreeRTOS任务调试信息(按K1按键,串口打印):
13.8.jpg

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

u  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. }
复制代码

u  硬件外设初始化
    硬件外设的初始化是在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. }
复制代码

u  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. }
复制代码

u  四个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键按下 设置任务vTaskLED的优先级为1 */
  35.                    case KEY_DOWN_K2:         
  36.                        printf("K2键按下,设置任务vTaskLED的优先级为1\\r\\n");
  37.                        vTaskPrioritySet( xHandleTaskLED, 1);
  38.                        printf("K2键按下,任务vTaskLED的优先级已经设置为:%d\\r\\n",
  39. (int)uxTaskPriorityGet(xHandleTaskLED));
  40.                        break;
  41.                   
  42.                    /* K3键按下 设置任务vTaskLED的优先级为2 */
  43.                    case KEY_DOWN_K3:         
  44.                        printf("K3键按下,设置任务vTaskLED的优先级为2\\r\\n");
  45.                        vTaskPrioritySet( xHandleTaskLED, 2);
  46.                        printf("K3键按下,任务vTaskLED的优先级已经设置为:%d\\r\\n",
  47.   (int)uxTaskPriorityGet(xHandleTaskLED));
  48.                        break;
  49.                    /* 其他的键值不处理 */
  50.                    default:                    
  51.                        break;
  52.               }
  53.          }
  54.         
  55.          vTaskDelay(20);
  56.      }
  57. }
  58. /*
  59. *********************************************************************************************************
  60. *    函 数 名: vTaskLED
  61. *    功能说明: LED闪烁
  62. *    形    参: pvParameters 是在创建该任务时传递的形参
  63. *    返 回 值: 无
  64. *   优 先 级: 2
  65. *********************************************************************************************************
  66. */
  67. static void vTaskLED(void *pvParameters)
  68. {
  69.     while(1)
  70.     {
  71.          bsp_LedToggle(2);
  72.         vTaskDelay(200);
  73.     }
  74. }
  75. /*
  76. *********************************************************************************************************
  77. *    函 数 名: vTaskMsgPro
  78. *    功能说明: 消息处理,这里是用作LED闪烁   
  79. *    形    参: pvParameters 是在创建该任务时传递的形参
  80. *    返 回 值: 无
  81. *   优 先 级: 3
  82. *********************************************************************************************************
  83. */
  84. static void vTaskMsgPro(void *pvParameters)
  85. {
  86.     while(1)
  87.     {
  88.          bsp_LedToggle(3);
  89.         vTaskDelay(300);
  90.     }
  91. }
  92. /*
  93. *********************************************************************************************************
  94. *    函 数 名: vTaskStart
  95. *    功能说明: 启动任务,也就是最高优先级任务,这里用作按键扫描。
  96. *    形    参: pvParameters 是在创建该任务时传递的形参
  97. *    返 回 值: 无
  98. *   优 先 级: 4
  99. *********************************************************************************************************
  100. */
  101. static void vTaskStart(void *pvParameters)
  102. {
  103.     while(1)
  104.     {
  105.          /* 按键扫描 */
  106.          bsp_KeyScan();
  107.         vTaskDelay(10);
  108.     }
  109. }
复制代码
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-8-22 14:56:10 | 显示全部楼层
13.7 总结

    本章节内容相对比较容易,重点是学习任务优先级分配方案,随着后面的学习,初学者需要慢慢积累这方面的经验。
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-4-30 19:20 , Processed in 0.326870 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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