硬汉嵌入式论坛

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

[FreeRTOS教程] 第18章 FreeRTOS事件标志组

[复制链接]

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
发表于 2016-8-27 15:40:04 | 显示全部楼层 |阅读模式



第18章      FreeRTOS事件标志组


    前面的章节我们已经讲解了任务管理和时间管理,从本章节开始讲解任务间的通信和同步机制。首先讲解任务间的通信和同步机制之一,事件标志组。
    本章教程配套的例子含Cortex-M3内核的STM32F103和Cortex-M4内核的STM32F407以及F429。
18.1 事件标志组
18.2 事件标志组API函数
18.3 实验例程说明(任务间通信)
18.4 实验例程说明(中断方式通信)
18.5      总结


18.1 事件标志组


18.1.1  为什么要使用事件标志

    事件标志组是实现多任务同步的有效机制之一。也许有不理解的初学者会问采用事件标志组多麻烦,搞个全局变量不是更简单?其实不然,在裸机编程时,使用全局变量的确比较方便,但是在加上RTOS后就是另一种情况了。使用全局变量相比事件标志组主要有如下三个问题:
1、使用事件标志组可以让RTOS内核有效地管理任务,而全局变量是无法做到的,任务的超时等机制需要用户自己去实现。
2、使用了全局变量就要防止多任务的访问冲突,而使用事件标志组则处理好了这个问题,用户无需担心。
3、使用事件标志组可以有效地解决中断服务程序和任务之间的同步问题。

18.1.2 FreeRTOS任务间事件标志组的实现

    任务间事件标志组的实现是指各个任务之间使用事件标志组实现任务的通信或者同步机制。
    下面我们来说说FreeRTOS中事件标志的实现,根据用户在FreeRTOSConfig.h文件中的配置:
1、#define configUSE_16_BIT_TICKS                1
          配置宏定义configUSE_16_BIT_TICKS为1时,每创建一个事件标志组,用户可以使用的事件标志是8个。
2、#define configUSE_16_BIT_TICKS                0
          配置宏定义configUSE_16_BIT_TICKS为0时,每创建一个事件标志组,用户可以使用的事件标志是24个。

    上面说的8个和24个事件标志应该怎么理解呢?其实就是定义了一个16位变量,仅使用了低8bit或者定义了一个32位变量,仅使用了低24bit。每一个bit用0和1两种状态来代表事件标志。反映到FreeRTOS上就是将事件标志存储到了EventBits_t类型的变量中,这个变量又是怎么回事呢?定义如下:
  1. /*
  2. * The type that holds event bits always matches TickType_t - therefore the
  3. * number of bits it holds is set by configUSE_16_BIT_TICKS (16 bits if set to 1,
  4. * 32 bits if set to 0.
  5. *
  6. * \defgroup EventBits_t EventBits_t
  7. * \ingroup EventGroup
  8. */
  9. typedef TickType_t EventBits_t;
复制代码
进一步跟踪TickType_t的数据类型,定义如下:
  1. #if( configUSE_16_BIT_TICKS == 1 )
  2.      typedef uint16_t TickType_t;
  3.      #define portMAX_DELAY ( TickType_t ) 0xffff
  4. #else
  5.      typedef uint32_t TickType_t;
  6.      #define portMAX_DELAY ( TickType_t ) 0xffffffffUL
  7.      /* 32-bit tick type on a 32-bit architecture, so reads of the tick count do
  8.      not need to be guarded with a critical section. */
  9.      #define portTICK_TYPE_IS_ATOMIC 1
  10. #endif
复制代码
由上面定义可以看出,TickType_t数据类型可以是16位数或者32位数,这样就跟上面刚刚说的configUSE_16_BIT_TICKS  宏定义呼应上了。教程配套的例子都是配置宏定义configUSE_16_BIT_TICKS0,即用户每创建一个事件标志组,有24个标志可以设置。如下图所示,这里仅使用bit0bit1bit2
18.1.jpg

注意:后面的讲解中,默认全是创建一个事件标志,支持24个事件标志设置。
下面我们通过如下的框图来说明一下FreeRTOS事件标志的实现,让大家有一个形象的认识。
18.2.JPG

运行条件:
(1)创建2个任务:Task1Task2
运行过程描述如下:
(1)任务Task1运行过程中调用函数xEventGroupWaitBits,等待事件标志位被设置,任务Task1由运行态进入到阻塞态。
(2)任务Task2设置Task1等待的事件标志,任务Task1由阻塞态进入到就绪态,在调度器的作用下由就绪态又进入到运行态。

上面就是一个简单的FreeRTOS任务间事件标志通信过程。

18.1.3 FreeRTOS中断方式事件标志组的实现

    FreeRTOS中断方式事件标志组的实现是指中断函数和FreeRTOS任务之间使用事件标志。下面我们通过如下的框图来说明一下FreeRTOS事件标志的实现,让大家有一个形象的认识。
18.3.JPG

运行条件:
(1)创建一个任务和一个串口接收中断
运行过程描述如下:
(1)任务Task1运行过程中调用函数xEventGroupWaitBits,等待事件标志位被设置,任务Task1由运行态进入到阻塞态。
(2)Task1阻塞的情况下,串口接收到数据进入到了串口中断服务程序,在串口中断服务程序中设置Task1等待的事件标志,任务Task1由阻塞态进入到就绪态,在调度器的作用下由就绪态又进入到运行态。
上面就是一个简单的FreeRTOS中断方式事件标志通信过程。实际应用中,中断方式的消息机制要注意以下四个问题:
(1)中断函数的执行时间越短越好,防止其它低于这个中断优先级的异常不能得到及时响应。
(2)实际应用中,建议不要在中断中实现消息处理,用户可以在中断服务程序里面发送消息通知任务,在任务中实现消息处理,这样可以有效地保证中断服务程序的实时响应。同时此任务也需要设置为高优先级,以便退出中断函数后任务可以得到及时执行。
(3)中断服务程序中一定要调用专用于中断的事件标志设置函数,即以FromISR结尾的函数。
(4)在操作系统中实现中断服务程序与裸机编程的区别。
         A.   如果FreeRTOS工程的中断函数中没有调用FreeRTOS的事件标志组API函数,与裸机编程是一样的。
         B.   如果FreeRTOS工程的中断函数中调用了FreeRTOS的事件标志组的API函数,退出的时候要检测是否有高优先级任务就绪,如果有就绪的,需要在退出中断后进行任务切换,这点跟裸机编程稍有区别,详见18.4小节实验例程说明(中断方式):
         C.   另外强烈推荐用户将Cortex-M3内核的STM32F103Cortex-M4内核的STM32F407F429NVIC优先级分组设置为4,即:NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);这样中断优先级的管理将非常方便。
         D.   用户要在FreeRTOS多任务开启前就设置好优先级分组,一旦设置好切记不可再修改。
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-8-27 15:47:53 | 显示全部楼层
18.2 事件标志组API函数


    使用如下11个函数可以实现FreeRTOS的事件标志组:
xEventGroupCreate()
xEventGroupCreateStatic()
vEventGroupDelete()
xEventGroupWaitBits()
xEventGroupSetBits()
xEventGroupSetBitsFromISR()
xEventGroupClearBits()
xEventGroupClearBitsFromISR()
xEventGroupGetBits()
xEventGroupGetBitsFromISR()
xEventGroupSync()
    关于这11个函数的讲解及其使用方法可以看FreeRTOS在线版手册:
18.4.jpg

这里我们重点的说以下4个函数:
    xEventGroupCreate()
    xEventGroupWaitBits()
    xEventGroupSetBits()
    xEventGroupSetBitsFromISR()
因为本章节配套的例子使用的是这4个函数。

18.2.1 函数xEventGroupCreate


函数原型:
  1. EventGroupHandle_t xEventGroupCreate( void );
复制代码
函数描述:
函数xEventGroupCreate用于创建事件标志组。
(1)返回值,如果创建成功,此函数返回事件标志组的句柄,如果FreeRTOSConfig.h文件中定义的heap空间不足会返回NULL
      #defineconfigTOTAL_HEAP_SIZE       ( ( size_t ) (17 * 1024 ) )
使用举例:
  1. static EventGroupHandle_t xCreatedEventGroup = NULL;
  2. /*
  3. *********************************************************************************************************
  4. *    函 数 名: AppObjCreate
  5. *    功能说明: 创建任务通信机制
  6. *    形    参: 无
  7. *    返 回 值: 无
  8. *********************************************************************************************************
  9. */
  10. static void AppObjCreate (void)
  11. {
  12.      /* 创建事件标志组 */
  13.      xCreatedEventGroup = xEventGroupCreate();
  14.    
  15.      if(xCreatedEventGroup == NULL)
  16.     {
  17.         /* 没有创建成功,用户可以在这里加入创建失败的处理机制 */
  18.     }
  19. }
复制代码

18.2.2 函数xEventGroupSetBits


函数原型:
  1. EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,  /* 事件标志组句柄 */
  2.                                 const EventBits_t uxBitsToSet ); /* 事件标志位设置 */
复制代码
函数描述:
函数xEventGroupSetBits用于设置指定的事件标志位为1。
    (1)第1个参数是事件标志组句柄。
    (2)第2个参数表示24个可设置的事件标志位,EventBits_t是定义的32位变量(详解18.1.2小节说明),低24位用于事件标志设置。变量uxBitsToSet的低24位的某个位设置为1,那么被设置的事件标志组的相应位就设置为1。变量uxBitsToSet设置为0的位对事件标志相应位没有影响。比如设置变量uxBitsToSet = 0x0003就表示将事件标志的位0和位1设置为1,其余位没有变化。
    (3)返回当前的事件标志组数值。
使用这个函数要注意以下问题:
1.     使用前一定要保证事件标志组已经通过函数xEventGroupCreate创建了。
2.     此函数是用于任务代码中调用的,故不可以在中断服务程序中调用此函数,中断服务程序中使用的是   xEventGroupSetBitsFromISR
3.     用户通过参数uxBitsToSet设置的标志位并不一定会保留到此函数的返回值中,下面举两种情况:
     a.     调用此函数的过程中,其它高优先级的任务就绪了,并且也修改了事件标志,此函数返回的事件标志位会发生变化。
     b.    调用此函数的任务是一个低优先级任务,通过此函数设置了事件标志后,让一个等待此事件标志的高优先级任务就绪了,会立即切换到高优先级任务去执行,相应的事件标志位会被函数xEventGroupWaitBits清除掉,等从高优先级任务返回到低优先级任务后,函数xEventGroupSetBits的返回值已经被修改。
使用举例:
  1. #define BIT_0 (1 << 0)
  2. #define BIT_1 (1 << 1)
  3. #define BIT_ALL (BIT_0 | BIT_1)
  4. static EventGroupHandle_t xCreatedEventGroup = NULL;
  5. /*
  6. *********************************************************************************************************
  7. *    函 数 名: vTaskTaskUserIF
  8. *    功能说明: 接口消息处理。
  9. *    形    参: pvParameters 是在创建该任务时传递的形参
  10. *    返 回 值: 无
  11. *   优 先 级: 1  (数值越小优先级越低,这个跟uCOS相反)
  12. *********************************************************************************************************
  13. */
  14. static void vTaskTaskUserIF(void *pvParameters)
  15. {
  16.      uint8_t ucKeyCode;
  17.      EventBits_t uxBits;
  18.     while(1)
  19.     {
  20.          ucKeyCode = bsp_GetKey();
  21.         
  22.          if (ucKeyCode != KEY_NONE)
  23.          {
  24.               switch (ucKeyCode)
  25.               {                 
  26.                    /* K2键按下,直接发送事件标志给任务vTaskMsgPro,设置bit0 */
  27.                    case KEY_DOWN_K2:
  28.                        /* 设置事件标志组的bit0 */
  29.                        uxBits = xEventGroupSetBits(xCreatedEventGroup, BIT_0);
  30.                        if((uxBits & BIT_0) != 0)
  31.                        {
  32.                             printf("K2键按下,事件标志的bit0被设置\\r\\n");
  33.                        }
  34.                        else
  35.                        {
  36.                             printf("K2键按下,事件标志的bit0被清除,说明任务vTaskMsgPro已经接受到bit0和
  37. bit1被设置的情况\\r\\n");
  38.                        }
  39.                        break;
  40.                      
  41.                    /* K3键按下,直接发送事件标志给任务vTaskMsgPro,设置bit1 */
  42.                    case KEY_DOWN_K3:
  43.                        /* 设置事件标志组的bit1 */
  44.                        uxBits = xEventGroupSetBits(xCreatedEventGroup, BIT_1);
  45.                        if((uxBits & BIT_1) != 0)
  46.                        {
  47.                             printf("K3键按下,事件标志的bit1被设置\\r\\n");
  48.                        }
  49.                        else
  50.                        {
  51.                             printf("K3键按下,事件标志的bit1被清除,说明任务vTaskMsgPro已经接受到bit0和
  52. bit1被设置的情况\\r\\n");
  53.                        }
  54.                        break;
  55.                   
  56.                    /* 其他的键值不处理 */
  57.                    default:                    
  58.                        break;
  59.               }
  60.          }
  61.         
  62.          vTaskDelay(20);
  63.      }
  64. }
复制代码

18.2.3 函数xEventGroupSetBitsFromISR
函数原型:
  1. BaseType_t xEventGroupSetBitsFromISR(
  2.                           EventGroupHandle_t xEventGroup,          /* 事件标志组句柄 */
  3.                           const EventBits_t uxBitsToSet,           /* 事件标志位设置 */
  4.                           BaseType_t *pxHigherPriorityTaskWoken ); /* 高优先级任务是否被唤醒的状态保存 */
复制代码
函数描述:
函数xEventGroupSetBits用于设置指定的事件标志位为1。
    (1)1个参数是事件标志组句柄。
    (2)第2个参数表示24个可设置的事件标志位,EventBits_t是定义的32位变量(详解18.1.2小节说明),低24位用于事件标志设置。变量uxBitsToSet的低24位的某个位设置为1,那么被设置的事件标志组的相应位就设置为1。变量uxBitsToSet设置为0的位对事件标志相应位没有影响。比如设置变量uxBitsToSet = 0x0003就表示将事件标志的位0和位1设置为1,其余位没有变化。
    (3) 第3个参数用于保存是否有高优先级任务准备就绪。如果函数执行完毕后,此参数的数值是pdTRUE,说明有高优先级任务要执行,否则没有。
    (4)返回值,如果消息成功发送给daemon任务(就是FreeRTOS的定时器任务)返回pdPASS,否则返回pdFAIL,另外daemon任务中的消息队列满了也会返回pdFAIL
使用这个函数要注意以下问题:
1.     使用前一定要保证事件标志已经通过函数xEventGroupCreate创建了。同时要在FreeRTOSConfig.h文件中使能如下三个宏定义:
      #define  INCLUDE_xEventGroupSetBitFromISR  1
      #define  configUSE_TIMERS                    1
      #define  INCLUDE_xTimerPendFunctionCall     1
2.     函数xEventGroupSetBitsFromISR是用于中断服务程序中调用的,故不可以在任务代码中调用此函数,任务代码中使用的是xEventGroupSetBits。
3.     函数xEventGroupSetBitsFromISR对事件标志组的操作是不确定性操作,因为不知道当前有多少个任务在等待此事件标志。而FreeRTOS不允许在中断服务程序和临界段中执行不确定性操作。为了不在中断服务程序中执行,就通过此函数给FreeRTOS的daemon任务(就是FreeRTOS的定时器任务)发送消息,在daemon任务中执行事件标志的置位操作。同时也为了不在临界段中执行此不确定操作,将临界段改成由调度锁来完成。这样不确定性操作在中断服务程序和临界段中执行的问题就都得到解决了。
4.     由于函数xEventGroupSetBitsFromISR对事件标志的置位操作是在daemon任务里面执行的,如果想让置位操作立即生效,即让等此事件标志的任务能够得到及时执行,需要设置daemon任务的优先级高于使用此事件标志组的所有其它任务。
5.     通过下面的使用举例重点一下函数xEventGroupSetBitsFromISR第三个参数的规范用法,初学者务必要注意。
使用举例:
  1. #define BIT_0 (1 << 0)
  2. #define BIT_1 (1 << 1)
  3. #define BIT_ALL (BIT_0 | BIT_1)
  4. static EventGroupHandle_t xCreatedEventGroup = NULL;
  5. /*
  6. *********************************************************************************************************
  7. *    函 数 名: TIM2_IRQHandler
  8. *    功能说明: 定时器中断。                     
  9. *    形    参: 无
  10. *    返 回 值: 无
  11. *********************************************************************************************************
  12. */
  13. static void TIM2_IRQHandler(void)
  14. {
  15.      BaseType_t xResult;
  16.      BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  17.      /* 中断消息处理,此处省略 */
  18.      ……
  19.    
  20.      /* 向任务vTaskMsgPro发送事件标志 */
  21.      xResult = xEventGroupSetBitsFromISR(xCreatedEventGroup, /* 事件标志组句柄 */
  22.                                               BIT_0 ,             /* 设置bit0 */
  23.                                               &xHigherPriorityTaskWoken );
  24.      /* 消息被成功发出 */
  25.      if( xResult != pdFAIL )
  26.      {
  27.          /* 如果xHigherPriorityTaskWoken = pdTRUE,那么退出中断后切到当前最高优先级任务执行 */
  28.          portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
  29.      }
  30. }
复制代码
18.2.4 函数xEventGroupWaitBits
函数原型:
  1. EventBits_t xEventGroupWaitBits(
  2.                        const EventGroupHandle_t xEventGroup,  /* 事件标志组句柄 */
  3.                        const EventBits_t uxBitsToWaitFor,     /* 等待被设置的事件标志位 */
  4.                        const BaseType_t xClearOnExit,         /* 选择是否清零被置位的事件标志位 */
  5.                        const BaseType_t xWaitForAllBits,      /* 选择是否等待所有标志位都被设置 */
  6.                        TickType_t xTicksToWait );             /* 设置等待时间 */
复制代码
函数描述:
函数xEventGroupWaitBits等待事件标志被设置。
1、第1个参数是事件标志组句柄。
2、第2个参数表示等待24个事件标志位中的指定标志,EventBits_t是定义的32位变量(详解18.1.2小节说明),低24位用于事件标志设置。比如设置变量uxBitsToWaitFor = 0x0003就表示等待事件标志的位0和位1设置为1。此参数切不可设置为0
3、第3个参数选择是否清除已经被置位的事件标志,如果这个参数设置为pdTRUE,且函数xEventGroupWaitBits在参数xTicksToWait设置的溢出时间内返回,那么相应被设置的事件标志位会被清零。如果这个参数设置为pdFALSE,对已经被设置的事件标志位没有影响。
4、第4个参数选择是否等待所有的标志位都被设置,如果这个参数设置为pdTRUE,要等待第2个参数uxBitsToWaitFor所指定的标志位全部被置1,函数才可以返回。当然,超出了在参数xTicksToWait设置的溢出时间也是会返回的。如果这个参数设置为pdFALSE,第2个参数uxBitsToWaitFor所指定的任何标志位被置1,函数都会返回,超出溢出时间也会返回。
5、第5个参数设置等待时间,单位时钟节拍周期。如果设置为 portMAX_DELAY,表示永久等待。
6、返回值,由于设置的时间超时或者指定的事件标志位被置1,导致函数退出时返回的事件标志组数值。
使用这个函数要注意以下问题:
1.     此函数切不可在中断服务程序中调用。
2.     这里再着重说明下这个函数的返回值,通过返回值用户可以检测是哪个事件标志位被置1了。
    (1)如果由于设置的等待时间超时,函数的返回值可会有部分事件标志位被置1
    (2)如果由于指定的事件标志位被置1而返回,并且设置了这个函数的参数xClearOnExitpdTRUE,那么此函数的返回值是清零前的事件标志组数值。
      另外,调用此函数的任务在离开阻塞状态到退出函数xEventGroupWaitBits之间这段时间,如果一个高优先级的任务抢占执行了,并且修改了事件标志位,那么此函数的返回值会跟当前的事件标志组数值不同。
使用举例:
  1. #define BIT_0 (1 << 0)
  2. #define BIT_1 (1 << 1)
  3. #define BIT_ALL (BIT_0 | BIT_1)
  4. static EventGroupHandle_t xCreatedEventGroup = NULL;
  5. /*
  6. *********************************************************************************************************
  7. *    函 数 名: vTaskMsgPro
  8. *    功能说明: 消息处理,使用函数xEventGroupWaitBits接收任务vTaskTaskUserIF发送的事件标志
  9. *    形    参: pvParameters 是在创建该任务时传递的形参
  10. *    返 回 值: 无
  11. *   优 先 级: 3
  12. *********************************************************************************************************
  13. */
  14. static void vTaskMsgPro(void *pvParameters)
  15. {
  16.      EventBits_t uxBits;
  17.      const TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS; /* 最大延迟100ms */
  18.    
  19.     while(1)
  20.     {
  21.          /* 等K2按键按下设置bit0和K3按键按下设置bit1 */
  22.          uxBits = xEventGroupWaitBits(xCreatedEventGroup, /* 事件标志组句柄 */
  23.                                           BIT_ALL,            /* 等待bit0和bit1被设置 */
  24.                                           pdTRUE,             /* 退出前bit0和bit1被清除,这里是bit0和bit1
  25. 都被设置才表示“退出”*/
  26.                                           pdTRUE,             /* 设置为pdTRUE表示等待bit1和bit0都被设置*/
  27.                                           xTicksToWait);      /* 等待延迟时间 */
  28.         
  29.          if((uxBits & BIT_ALL) == BIT_ALL)
  30.          {
  31.               /* 接收到bit1和bit0都被设置的消息 */
  32.               printf("接收到bit0和bit1都被设置的消息\\r\\n");
  33.          }
  34.          else
  35.          {
  36.               /* 超时,另外注意仅接收到一个按键按下的消息时,变量uxBits的相应bit也是被设置的 */
  37.               bsp_LedToggle(3);
  38.          }
  39.     }
  40. }
复制代码
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-8-27 16:08:40 | 显示全部楼层
18.3 实验例程说明(任务间通信)



18.3.1 STM32F103开发板实验


配套例子:
    V4-312_FreeRTOS实验_事件标志组
实验目的:
    1.     学习FreeRTOS的事件标志组。
实验内容:
    1.     K1按键按下,串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1)。
    2.     K2键按下,直接发送事件标志给任务vTaskMsgPro,设置bit0。
    3.     K3键按下,直接发送事件标志给任务vTaskMsgPro,设置bit1。
    4.     任务vTaskMsgPro只有接收到bit0和bit1都被设置了才执行串口打印消息。
    5.     各个任务实现的功能如下:
              vTaskUserIF任务   :按键消息处理。
              vTaskLED任务     :LED闪烁。
              vTaskMsgPro任务 :消息处理,使用函数xEventGroupWaitBits接收任务vTaskTaskUserIF发送的事件标志。
              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按键,串口打印):
18.5.jpg

上面截图中打印出来的任务状态字母B, R, D, S对应如下含义:
    #definetskBLOCKED_CHAR          ( 'B' )  任务阻塞
    #definetskREADY_CHAR           ( 'R' ) 任务就绪
    #definetskDELETED_CHAR           ( 'D' )  任务删除
    #definetskSUSPENDED_CHAR   ( 'S' ) 任务挂起
使用事件标志组要包含的头文件:
使用FreeRTOS的事件标志组要包含头文件#include "event_groups.h",这个头文件在includes.h文件中进行了包含,具体如下:
  1. /*
  2. *********************************************************************************************************
  3. *                                           OS
  4. *********************************************************************************************************
  5. */
  6. #include "FreeRTOS.h"
  7. #include "task.h"
  8. #include "queue.h"
  9. #include "croutine.h"
  10. #include "semphr.h"
  11. #include "event_groups.h"
复制代码

程序设计:
任务栈大小分配:
    vTaskUserIF任务   :2048字节
    vTaskLED任务     :2048字节
    vTaskMsgPro任务 :2048字节
    vTaskStart任务    :2048字节
    任务栈空间是在任务创建的时候从FreeRTOSConfig.h文件中定义的heap空间中申请的
    #defineconfigTOTAL_HEAP_SIZE        ( ( size_t )( 17 * 1024 ) )
系统栈大小分配:
18.6.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.      AppObjCreate();
  35.    
  36.     /* 启动调度,开始执行任务 */
  37.     vTaskStartScheduler();
  38.      /*
  39.        如果系统正常启动是不会运行到这里的,运行到这里极有可能是用于定时器任务或者空闲任务的
  40.        heap空间不足造成创建失败,此要加大FreeRTOSConfig.h文件中定义的heap大小:
  41.        #define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 17 * 1024 ) )
  42.      */
  43.      while(1);
  44. }
复制代码

硬件外设初始化
    硬件外设的初始化是在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. *    函 数 名: AppObjCreate
  4. *    功能说明: 创建任务通信机制
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void AppObjCreate (void)
  10. {
  11.      /* 创建事件标志组 */
  12.      xCreatedEventGroup = xEventGroupCreate();
  13.    
  14.      if(xCreatedEventGroup == NULL)
  15.     {
  16.         /* 没有创建成功,用户可以在这里加入创建失败的处理机制 */
  17.     }
  18. }
复制代码

四个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.      EventBits_t uxBits;
  15.     while(1)
  16.     {
  17.          ucKeyCode = bsp_GetKey();
  18.         
  19.          if (ucKeyCode != KEY_NONE)
  20.          {
  21.               switch (ucKeyCode)
  22.               {
  23.                    /* K1键按下 打印任务执行情况 */
  24.                    case KEY_DOWN_K1:         
  25.                        printf("=================================================\\r\\n");
  26.                        printf("任务名      任务状态 优先级   剩余栈 任务序号\\r\\n");
  27.                        vTaskList((char *)&pcWriteBuffer);
  28.                        printf("%s\\r\\n", pcWriteBuffer);
  29.                   
  30.                        printf("\\r\\n任务名       运行计数         使用率\\r\\n");
  31.                        vTaskGetRunTimeStats((char *)&pcWriteBuffer);
  32.                        printf("%s\\r\\n", pcWriteBuffer);
  33.                        break;
  34.                   
  35.                    /* K2键按下,直接发送事件标志给任务vTaskMsgPro,设置bit0 */
  36.                    case KEY_DOWN_K2:
  37.                        /* 设置事件标志组的bit0 */
  38.                        uxBits = xEventGroupSetBits(xCreatedEventGroup, BIT_0);
  39.                        if((uxBits & BIT_0) != 0)
  40.                        {
  41.                             printf("K2键按下,事件标志的bit0被设置\\r\\n");
  42.                        }
  43.                        else
  44.                        {
  45.                             printf("K2键按下,事件标志的bit0被清除,说明任务vTaskMsgPro已经接受到bit0和
  46. bit1被设置的情况\\r\\n");
  47.                        }
  48.                        break;
  49.                      
  50.                    /* K3键按下,直接发送事件标志给任务vTaskMsgPro,设置bit1 */
  51.                    case KEY_DOWN_K3:
  52.                        /* 设置事件标志组的bit1 */
  53.                        uxBits = xEventGroupSetBits(xCreatedEventGroup, BIT_1);
  54.                        if((uxBits & BIT_1) != 0)
  55.                        {
  56.                             printf("K3键按下,事件标志的bit1被设置\\r\\n");
  57.                        }
  58.                        else
  59.                        {
  60.                             printf("K3键按下,事件标志的bit1被清除,说明任务vTaskMsgPro已经接受到bit0和
  61. bit1被设置的情况\\r\\n");
  62.                        }
  63.                        break;
  64.                   
  65.                    /* 其他的键值不处理 */
  66.                    default:                    
  67.                        break;
  68.               }
  69.          }
  70.         
  71.          vTaskDelay(20);
  72.      }
  73. }
  74. /*
  75. *********************************************************************************************************
  76. *    函 数 名: vTaskLED
  77. *    功能说明: LED闪烁
  78. *    形    参: pvParameters 是在创建该任务时传递的形参
  79. *    返 回 值: 无
  80. *   优 先 级: 2
  81. *********************************************************************************************************
  82. */
  83. static void vTaskLED(void *pvParameters)
  84. {
  85.      TickType_t xLastWakeTime;
  86.      const TickType_t xFrequency = 200;
  87.      /* 获取当前的系统时间 */
  88.     xLastWakeTime = xTaskGetTickCount();
  89.    
  90.     while(1)
  91.     {
  92.          bsp_LedToggle(2);
  93.         
  94.          /* vTaskDelayUntil是绝对延迟,vTaskDelay是相对延迟。*/
  95.         vTaskDelayUntil(&xLastWakeTime, xFrequency);
  96.     }
  97. }
  98. /*
  99. *********************************************************************************************************
  100. *    函 数 名: vTaskMsgPro
  101. *    功能说明: 消息处理,使用函数xEventGroupWaitBits接收任务vTaskTaskUserIF发送的事件标志
  102. *    形    参: pvParameters 是在创建该任务时传递的形参
  103. *    返 回 值: 无
  104. *   优 先 级: 3
  105. *********************************************************************************************************
  106. */
  107. static void vTaskMsgPro(void *pvParameters)
  108. {
  109.      EventBits_t uxBits;
  110.      const TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS; /* 最大延迟100ms */
  111.    
  112.     while(1)
  113.     {
  114.          /* 等K2按键按下设置bit0和K3按键按下设置bit1 */
  115.          uxBits = xEventGroupWaitBits(xCreatedEventGroup, /* 事件标志组句柄 */
  116.                                           BIT_ALL,            /* 等待bit0和bit1被设置 */
  117.                                           pdTRUE,             /* 退出前bit0和bit1被清除,这里是bit0和bit1
  118. 都被设置才表示“退出”*/
  119.                                           pdTRUE,             /* 设置为pdTRUE表示等待bit1和bit0都被设置*/
  120.                                           xTicksToWait);      /* 等待延迟时间 */
  121.         
  122.          if((uxBits & BIT_ALL) == BIT_ALL)
  123.          {
  124.               /* 接收到bit1和bit0都被设置的消息 */
  125.               printf("接收到bit0和bit1都被设置的消息\\r\\n");
  126.          }
  127.          else
  128.          {
  129.               /* 超时,另外注意仅接收到一个按键按下的消息时,变量uxBits的相应bit也是被设置的 */
  130.               bsp_LedToggle(3);
  131.          }
  132.     }
  133. }
  134. /*
  135. *********************************************************************************************************
  136. *    函 数 名: vTaskStart
  137. *    功能说明: 启动任务,也就是最高优先级任务,这里用作按键扫描。
  138. *    形    参: pvParameters 是在创建该任务时传递的形参
  139. *    返 回 值: 无
  140. *   优 先 级: 4
  141. *********************************************************************************************************
  142. */
  143. static void vTaskStart(void *pvParameters)
  144. {
  145.     while(1)
  146.     {
  147.          /* 按键扫描 */
  148.          bsp_KeyScan();
  149.         vTaskDelay(10);
  150.     }
  151. }
复制代码
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-8-27 16:15:56 | 显示全部楼层
18.3.2   STM32F407开发板实验


配套例子:
    V5-312_FreeRTOS实验_事件标志组
实验目的:
     1.     学习FreeRTOS的事件标志组。
实验内容:
    1.     K1按键按下,串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1)。
    2.     K2键按下,直接发送事件标志给任务vTaskMsgPro,设置bit0。
    3.     K3键按下,直接发送事件标志给任务vTaskMsgPro,设置bit1。
    4.     任务vTaskMsgPro只有接收到bit0和bit1都被设置了才执行串口打印消息。
    5.     各个任务实现的功能如下:
              vTaskUserIF任务   :按键消息处理。
              vTaskLED任务     :LED闪烁。
              vTaskMsgPro任务 :消息处理,使用函数xEventGroupWaitBits接收任务vTaskTaskUserIF发送的事件标志。
              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按键,串口打印):
18.7.jpg
上面截图中打印出来的任务状态字母B, R, D, S对应如下含义:

    #definetskBLOCKED_CHAR          ( 'B' )  任务阻塞
    #definetskREADY_CHAR           ( 'R' ) 任务就绪
    #definetskDELETED_CHAR           ( 'D' )  任务删除
    #definetskSUSPENDED_CHAR   ( 'S' ) 任务挂起
使用事件标志组要包含的头文件:
使用FreeRTOS的事件标志组要包含头文件#include "event_groups.h",这个头文件在includes.h文件中进行了包含,具体如下:
  1. /*
  2. *********************************************************************************************************
  3. *                                           OS
  4. *********************************************************************************************************
  5. */
  6. #include "FreeRTOS.h"
  7. #include "task.h"
  8. #include "queue.h"
  9. #include "croutine.h"
  10. #include "semphr.h"
  11. #include "event_groups.h"
复制代码

程序设计:
任务栈大小分配:
    vTaskUserIF任务   :2048字节
    vTaskLED任务     :2048字节
    vTaskMsgPro任务 :2048字节
    vTaskStart任务    :2048字节
    任务栈空间是在任务创建的时候从FreeRTOSConfig.h文件中定义的heap空间中申请的
    #defineconfigTOTAL_HEAP_SIZE        ( ( size_t )( 30 * 1024 ) )
系统栈大小分配:
18.8.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.      AppObjCreate();
  36.     /* 启动调度,开始执行任务 */
  37.     vTaskStartScheduler();
  38.      /*
  39.        如果系统正常启动是不会运行到这里的,运行到这里极有可能是用于定时器任务或者空闲任务的
  40.        heap空间不足造成创建失败,此要加大FreeRTOSConfig.h文件中定义的heap大小:
  41.        #define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 17 * 1024 ) )
  42.      */
  43.      while(1);
  44. }
复制代码

硬件外设初始化
    硬件外设的初始化是在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. *    函 数 名: AppObjCreate
  4. *    功能说明: 创建任务通信机制
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void AppObjCreate (void)
  10. {
  11.      /* 创建事件标志组 */
  12.      xCreatedEventGroup = xEventGroupCreate();
  13.    
  14.      if(xCreatedEventGroup == NULL)
  15.     {
  16.         /* 没有创建成功,用户可以在这里加入创建失败的处理机制 */
  17.     }
  18. }
复制代码

四个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.      EventBits_t uxBits;
  15.     while(1)
  16.     {
  17.          ucKeyCode = bsp_GetKey();
  18.         
  19.          if (ucKeyCode != KEY_NONE)
  20.          {
  21.               switch (ucKeyCode)
  22.               {
  23.                    /* K1键按下 打印任务执行情况 */
  24.                    case KEY_DOWN_K1:         
  25.                        printf("=================================================\\r\\n");
  26.                        printf("任务名      任务状态 优先级   剩余栈 任务序号\\r\\n");
  27.                        vTaskList((char *)&pcWriteBuffer);
  28.                        printf("%s\\r\\n", pcWriteBuffer);
  29.                   
  30.                        printf("\\r\\n任务名       运行计数         使用率\\r\\n");
  31.                        vTaskGetRunTimeStats((char *)&pcWriteBuffer);
  32.                        printf("%s\\r\\n", pcWriteBuffer);
  33.                        break;
  34.                   
  35.                    /* K2键按下,直接发送事件标志给任务vTaskMsgPro,设置bit0 */
  36.                    case KEY_DOWN_K2:
  37.                        /* 设置事件标志组的bit0 */
  38.                        uxBits = xEventGroupSetBits(xCreatedEventGroup, BIT_0);
  39.                        if((uxBits & BIT_0) != 0)
  40.                        {
  41.                             printf("K2键按下,事件标志的bit0被设置\\r\\n");
  42.                        }
  43.                        else
  44.                        {
  45.                             printf("K2键按下,事件标志的bit0被清除,说明任务vTaskMsgPro已经接受到bit0和
  46. bit1被设置的情况\\r\\n");
  47.                        }
  48.                        break;
  49.                      
  50.                    /* K3键按下,直接发送事件标志给任务vTaskMsgPro,设置bit1 */
  51.                    case KEY_DOWN_K3:
  52.                        /* 设置事件标志组的bit1 */
  53.                        uxBits = xEventGroupSetBits(xCreatedEventGroup, BIT_1);
  54.                        if((uxBits & BIT_1) != 0)
  55.                        {
  56.                             printf("K3键按下,事件标志的bit1被设置\\r\\n");
  57.                        }
  58.                        else
  59.                        {
  60.                             printf("K3键按下,事件标志的bit1被清除,说明任务vTaskMsgPro已经接受到bit0和
  61. bit1被设置的情况\\r\\n");
  62.                        }
  63.                        break;
  64.                   
  65.                    /* 其他的键值不处理 */
  66.                    default:                    
  67.                        break;
  68.               }
  69.          }
  70.         
  71.          vTaskDelay(20);
  72.      }
  73. }
  74. /*
  75. *********************************************************************************************************
  76. *    函 数 名: vTaskLED
  77. *    功能说明: LED闪烁
  78. *    形    参: pvParameters 是在创建该任务时传递的形参
  79. *    返 回 值: 无
  80. *   优 先 级: 2
  81. *********************************************************************************************************
  82. */
  83. static void vTaskLED(void *pvParameters)
  84. {
  85.      TickType_t xLastWakeTime;
  86.      const TickType_t xFrequency = 200;
  87.      /* 获取当前的系统时间 */
  88.     xLastWakeTime = xTaskGetTickCount();
  89.    
  90.     while(1)
  91.     {
  92.          bsp_LedToggle(2);
  93.         
  94.          /* vTaskDelayUntil是绝对延迟,vTaskDelay是相对延迟。*/
  95.         vTaskDelayUntil(&xLastWakeTime, xFrequency);
  96.     }
  97. }
  98. /*
  99. *********************************************************************************************************
  100. *    函 数 名: vTaskMsgPro
  101. *    功能说明: 消息处理,使用函数xEventGroupWaitBits接收任务vTaskTaskUserIF发送的事件标志
  102. *    形    参: pvParameters 是在创建该任务时传递的形参
  103. *    返 回 值: 无
  104. *   优 先 级: 3
  105. *********************************************************************************************************
  106. */
  107. static void vTaskMsgPro(void *pvParameters)
  108. {
  109.      EventBits_t uxBits;
  110.      const TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS; /* 最大延迟100ms */
  111.    
  112.     while(1)
  113.     {
  114.           /* 等K2按键按下设置bit0和K3按键按下设置bit1 */
  115.          uxBits = xEventGroupWaitBits(xCreatedEventGroup, /* 事件标志组句柄 */
  116.                                           BIT_ALL,            /* 等待bit0和bit1被设置 */
  117.                                           pdTRUE,             /* 退出前bit0和bit1被清除,这里是bit0和bit1
  118. 都被设置才表示“退出”*/
  119.                                           pdTRUE,             /* 设置为pdTRUE表示等待bit1和bit0都被设置*/
  120.                                           xTicksToWait);      /* 等待延迟时间 */
  121.         
  122.          if((uxBits & BIT_ALL) == BIT_ALL)
  123.          {
  124.               /* 接收到bit1和bit0都被设置的消息 */
  125.               printf("接收到bit0和bit1都被设置的消息\\r\\n");
  126.          }
  127.          else
  128.          {
  129.               /* 超时,另外注意仅接收到一个按键按下的消息时,变量uxBits的相应bit也是被设置的 */
  130.               bsp_LedToggle(3);
  131.          }
  132.     }
  133. }
  134. /*
  135. *********************************************************************************************************
  136. *    函 数 名: vTaskStart
  137. *    功能说明: 启动任务,也就是最高优先级任务,这里用作按键扫描。
  138. *    形    参: pvParameters 是在创建该任务时传递的形参
  139. *    返 回 值: 无
  140. *   优 先 级: 4
  141. *********************************************************************************************************
  142. */
  143. static void vTaskStart(void *pvParameters)
  144. {
  145.     while(1)
  146.     {
  147.          /* 按键扫描 */
  148.          bsp_KeyScan();
  149.         vTaskDelay(10);
  150.     }
  151. }
复制代码
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-8-27 16:22:25 | 显示全部楼层
18.3.3   STM32F429开发板实验


配套例子:
    V6-312_FreeRTOS实验_事件标志组
实验目的:
    1.     学习FreeRTOS的事件标志组。
实验内容:
    1.     K1按键按下,串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1)。
    2.      K2键按下,直接发送事件标志给任务vTaskMsgPro,设置bit0。
    3.      K3键按下,直接发送事件标志给任务vTaskMsgPro,设置bit1。
    4.     任务vTaskMsgPro只有接收到bit0和bit1都被设置了才执行串口打印消息。
    5.      各个任务实现的功能如下:
              vTaskUserIF任务   :按键消息处理。
              vTaskLED任务     :LED闪烁。
              vTaskMsgPro任务 :消息处理,使用函数xEventGroupWaitBits接收任务vTaskTaskUserIF发送的事件标志。
              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按键,串口打印):
18.9.jpg

上面截图中打印出来的任务状态字母B, R, D, S对应如下含义:
    #definetskBLOCKED_CHAR          ( 'B' )  任务阻塞
    #definetskREADY_CHAR           ( 'R' ) 任务就绪
    #definetskDELETED_CHAR           ( 'D' )  任务删除
    #definetskSUSPENDED_CHAR   ( 'S' ) 任务挂起
使用事件标志组要包含的头文件:
使用FreeRTOS的事件标志组要包含头文件#include "event_groups.h",这个头文件在includes.h文件中进行了包含,具体如下:
  1. /*
  2. *********************************************************************************************************
  3. *                                           OS
  4. *********************************************************************************************************
  5. */
  6. #include "FreeRTOS.h"
  7. #include "task.h"
  8. #include "queue.h"
  9. #include "croutine.h"
  10. #include "semphr.h"
  11. #include "event_groups.h"
复制代码

程序设计:
任务栈大小分配:
    vTaskUserIF任务   :2048字节
    vTaskLED任务     :2048字节
    vTaskMsgPro任务 :2048字节
    vTaskStart任务    :2048字节
    任务栈空间是在任务创建的时候从FreeRTOSConfig.h文件中定义的heap空间中申请的
    #defineconfigTOTAL_HEAP_SIZE        ( ( size_t )( 30 * 1024 ) )
系统栈大小分配:
18.10.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.      AppObjCreate();
  36.     /* 启动调度,开始执行任务 */
  37.     vTaskStartScheduler();
  38.      /*
  39.        如果系统正常启动是不会运行到这里的,运行到这里极有可能是用于定时器任务或者空闲任务的
  40.        heap空间不足造成创建失败,此要加大FreeRTOSConfig.h文件中定义的heap大小:
  41.        #define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 17 * 1024 ) )
  42.      */
  43.      while(1);
  44. }
复制代码

硬件外设初始化
    硬件外设的初始化是在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. *    函 数 名: AppObjCreate
  4. *    功能说明: 创建任务通信机制
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void AppObjCreate (void)
  10. {
  11.      /* 创建事件标志组 */
  12.      xCreatedEventGroup = xEventGroupCreate();
  13.    
  14.      if(xCreatedEventGroup == NULL)
  15.     {
  16.         /* 没有创建成功,用户可以在这里加入创建失败的处理机制 */
  17.     }
  18. }
复制代码

四个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.      EventBits_t uxBits;
  15.     while(1)
  16.     {
  17.          ucKeyCode = bsp_GetKey();
  18.         
  19.          if (ucKeyCode != KEY_NONE)
  20.          {
  21.               switch (ucKeyCode)
  22.               {
  23.                    /* K1键按下 打印任务执行情况 */
  24.                    case KEY_DOWN_K1:         
  25.                        printf("=================================================\\r\\n");
  26.                        printf("任务名      任务状态 优先级   剩余栈 任务序号\\r\\n");
  27.                        vTaskList((char *)&pcWriteBuffer);
  28.                        printf("%s\\r\\n", pcWriteBuffer);
  29.                   
  30.                        printf("\\r\\n任务名       运行计数         使用率\\r\\n");
  31.                        vTaskGetRunTimeStats((char *)&pcWriteBuffer);
  32.                        printf("%s\\r\\n", pcWriteBuffer);
  33.                        break;
  34.                   
  35.                    /* K2键按下,直接发送事件标志给任务vTaskMsgPro,设置bit0 */
  36.                    case KEY_DOWN_K2:
  37.                        /* 设置事件标志组的bit0 */
  38.                        uxBits = xEventGroupSetBits(xCreatedEventGroup, BIT_0);
  39.                        if((uxBits & BIT_0) != 0)
  40.                        {
  41.                             printf("K2键按下,事件标志的bit0被设置\\r\\n");
  42.                        }
  43.                        else
  44.                        {
  45.                             printf("K2键按下,事件标志的bit0被清除,说明任务vTaskMsgPro已经接受到bit0和
  46. bit1被设置的情况\\r\\n");
  47.                        }
  48.                        break;
  49.                      
  50.                    /* K3键按下,直接发送事件标志给任务vTaskMsgPro,设置bit1 */
  51.                    case KEY_DOWN_K3:
  52.                        /* 设置事件标志组的bit1 */
  53.                        uxBits = xEventGroupSetBits(xCreatedEventGroup, BIT_1);
  54.                        if((uxBits & BIT_1) != 0)
  55.                        {
  56.                             printf("K3键按下,事件标志的bit1被设置\\r\\n");
  57.                        }
  58.                        else
  59.                        {
  60.                             printf("K3键按下,事件标志的bit1被清除,说明任务vTaskMsgPro已经接受到bit0和
  61. bit1被设置的情况\\r\\n");
  62.                        }
  63.                        break;
  64.                   
  65.                    /* 其他的键值不处理 */
  66.                    default:                    
  67.                        break;
  68.               }
  69.          }
  70.         
  71.          vTaskDelay(20);
  72.      }
  73. }
  74. /*
  75. *********************************************************************************************************
  76. *    函 数 名: vTaskLED
  77. *    功能说明: LED闪烁
  78. *    形    参: pvParameters 是在创建该任务时传递的形参
  79. *    返 回 值: 无
  80. *   优 先 级: 2
  81. *********************************************************************************************************
  82. */
  83. static void vTaskLED(void *pvParameters)
  84. {
  85.      TickType_t xLastWakeTime;
  86.      const TickType_t xFrequency = 200;
  87.      /* 获取当前的系统时间 */
  88.     xLastWakeTime = xTaskGetTickCount();
  89.    
  90.     while(1)
  91.     {
  92.          bsp_LedToggle(2);
  93.         
  94.          /* vTaskDelayUntil是绝对延迟,vTaskDelay是相对延迟。*/
  95.         vTaskDelayUntil(&xLastWakeTime, xFrequency);
  96.     }
  97. }
  98. /*
  99. *********************************************************************************************************
  100. *    函 数 名: vTaskMsgPro
  101. *    功能说明: 消息处理,使用函数xEventGroupWaitBits接收任务vTaskTaskUserIF发送的事件标志
  102. *    形    参: pvParameters 是在创建该任务时传递的形参
  103. *    返 回 值: 无
  104. *   优 先 级: 3
  105. *********************************************************************************************************
  106. */
  107. static void vTaskMsgPro(void *pvParameters)
  108. {
  109.      EventBits_t uxBits;
  110.      const TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS; /* 最大延迟100ms */
  111.    
  112.     while(1)
  113.     {
  114.          /* 等K2按键按下设置bit0和K3按键按下设置bit1 */
  115.          uxBits = xEventGroupWaitBits(xCreatedEventGroup, /* 事件标志组句柄 */
  116.                                           BIT_ALL,            /* 等待bit0和bit1被设置 */
  117.                                           pdTRUE,             /* 退出前bit0和bit1被清除,这里是bit0和bit1
  118. 都被设置才表示“退出”*/
  119.                                           pdTRUE,             /* 设置为pdTRUE表示等待bit1和bit0都被设置*/
  120.                                           xTicksToWait);      /* 等待延迟时间 */
  121.         
  122.          if((uxBits & BIT_ALL) == BIT_ALL)
  123.          {
  124.               /* 接收到bit1和bit0都被设置的消息 */
  125.               printf("接收到bit0和bit1都被设置的消息\\r\\n");
  126.          }
  127.          else
  128.          {
  129.               /* 超时,另外注意仅接收到一个按键按下的消息时,变量uxBits的相应bit也是被设置的 */
  130.               bsp_LedToggle(3);
  131.          }
  132.     }
  133. }
  134. /*
  135. *********************************************************************************************************
  136. *    函 数 名: vTaskStart
  137. *    功能说明: 启动任务,也就是最高优先级任务,这里用作按键扫描。
  138. *    形    参: pvParameters 是在创建该任务时传递的形参
  139. *    返 回 值: 无
  140. *   优 先 级: 4
  141. *********************************************************************************************************
  142. */
  143. static void vTaskStart(void *pvParameters)
  144. {
  145.     while(1)
  146.     {
  147.          /* 按键扫描 */
  148.          bsp_KeyScan();
  149.         vTaskDelay(10);
  150.     }
  151. }
复制代码
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-8-27 16:45:34 | 显示全部楼层
18.4 实验例程说明(中断方式)



18.4.1 STM32F103开发板实验


配套例子:
    V4-313_FreeRTOS实验_事件标志组(中断方式)
实验目的:
    1.     学习FreeRTOS的事件标志组(中断方式)。
实验内容:
    1.     K1按键按下,串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1)。
    2.     K2键按下,启动单次定时器中断,50ms后在定时器中断给任务vTaskMsgPro发送事件标志,设置bit0。
    3.     K3键按下,启动单次定时器中断,50ms后在定时器中断给任务vTaskMsgPro发送事件标志,设置bit1。
    4.     任务vTaskMsgPro只有接收到bit0和bit1都被设置了才执行串口打印消息。
    5.     各个任务实现的功能如下:
              vTaskUserIF任务   :按键消息处理。
              vTaskLED任务     :LED闪烁。
              vTaskMsgPro任务 : 消息处理,使用函数xEventGroupWaitBits接收定时器中断的事件标志。
              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         ( 6 )
  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_xTaskResumeFromISR        1
  35. #define INCLUDE_vTaskDelayUntil           1
  36. #define INCLUDE_vTaskDelay                1
  37. #define INCLUDE_xEventGroupSetBitFromISR  1
  38. #define INCLUDE_xTimerPendFunctionCall    1
  39. /* Software timer definitions. */
  40. #define configUSE_TIMERS                    1
  41. #define configTIMER_TASK_PRIORITY         ( 5 )
  42. #define configTIMER_QUEUE_LENGTH           20
  43. #define configTIMER_TASK_STACK_DEPTH     ( configMINIMAL_STACK_SIZE * 2 )
  44. /* Cortex-M specific definitions. */
  45. #ifdef __NVIC_PRIO_BITS
  46.      /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
  47.      #define configPRIO_BITS              __NVIC_PRIO_BITS
  48. #else
  49.      #define configPRIO_BITS              4        /* 15 priority levels */
  50. #endif
  51. /* The lowest interrupt priority that can be used in a call to a "set priority"
  52. function. */
  53. #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY              0x0f
  54. /* The highest interrupt priority that can be used by any interrupt service
  55. routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL
  56. INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
  57. PRIORITY THAN THIS! (higher priorities are lower numeric values. */
  58. #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          ( 6 )
        定义可供用户使用的最大优先级数,如果这个定义的是6,那么用户可以使用的优先级号是0,1,2,3,4,5不包含6,对于这一点,初学者要特别的注意。
5、#define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 17 * 1024 ) )
        定义堆大小,FreeRTOS内核,用户动态内存申请,任务栈等都需要用这个空间。
6、使用事件标志组中的函数xEventGroupSetBitsFromISR,务必使能以下三个宏定义
    (1)#define INCLUDE_xEventGroupSetBitFromISR  1
    (2)#define INCLUDE_xTimerPendFunctionCall    1
    (3)#define configUSE_TIMERS                              1
       因为使能了FreeRTOS的定时器组任务,定时器组的其它宏定义也做一下配置,配置如下:
    (1)#define configTIMER_TASK_PRIORITY       ( 5 )
    (2)#define configTIMER_QUEUE_LENGTH       20
    (3)#define configTIMER_TASK_STACK_DEPTH      ( configMINIMAL_STACK_SIZE * 2 )
7、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按键,串口打印):
18.11.jpg

上面截图中打印出来的任务状态字母B, R, D, S对应如下含义:
    #definetskBLOCKED_CHAR          ( 'B' )  任务阻塞
    #definetskREADY_CHAR           ( 'R' ) 任务就绪
    #definetskDELETED_CHAR           ( 'D' )  任务删除
    #definetskSUSPENDED_CHAR   ( 'S' ) 任务挂起
使用事件标志组要包含的头文件:
    使用FreeRTOS的事件标志组要包含头文件#include "event_groups.h",这个头文件在includes.h文件中进行了包含,具体如下:
  1. /*
  2. *********************************************************************************************************
  3. *                                           OS
  4. *********************************************************************************************************
  5. */
  6. #include "FreeRTOS.h"
  7. #include "task.h"
  8. #include "queue.h"
  9. #include "croutine.h"
  10. #include "semphr.h"
  11. #include "event_groups.h"
复制代码
程序设计:
任务栈大小分配:
    vTaskUserIF任务   :2048字节
    vTaskLED任务     :2048字节
    vTaskMsgPro任务 :2048字节
    vTaskStart任务    :2048字节
    任务栈空间是在任务创建的时候从FreeRTOSConfig.h文件中定义的heap空间中申请的
    #defineconfigTOTAL_HEAP_SIZE        ( ( size_t )( 17 * 1024 ) )
系统栈大小分配:
18.12.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.      AppObjCreate();
  35.    
  36.     /* 启动调度,开始执行任务 */
  37.     vTaskStartScheduler();
  38.      /*
  39.        如果系统正常启动是不会运行到这里的,运行到这里极有可能是用于定时器任务或者空闲任务的
  40.        heap空间不足造成创建失败,此要加大FreeRTOSConfig.h文件中定义的heap大小:
  41.        #define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 17 * 1024 ) )
  42.      */
  43.      while(1);
  44. }
复制代码
硬件外设初始化
    硬件外设的初始化是在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.      bsp_InitHardTimer(); /* 初始化TIM2定时器 */
  23. }
复制代码
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. *    函 数 名: AppObjCreate
  4. *    功能说明: 创建任务通信机制
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void AppObjCreate (void)
  10. {
  11.      /* 创建事件标志组 */
  12.      xCreatedEventGroup = xEventGroupCreate();
  13.    
  14.      if(xCreatedEventGroup == NULL)
  15.     {
  16.         /* 没有创建成功,用户可以在这里加入创建失败的处理机制 */
  17.     }
  18. }
复制代码
四个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键按下,启动单次定时器中断,50ms后在定时器中断给任务vTaskMsgPro发送事件标志 */
  35.                    case KEY_DOWN_K2:
  36.                        printf("K2键按下,启动单次定时器中断,50ms后在定时器中断给任务vTaskMsgPro发送事件
  37. 标志\\r\\n");
  38.                        bsp_StartHardTimer(1 ,50000, (void *)TIM_CallBack1);
  39.                        break;
  40.                   
  41.                    /* K3键按下,启动单次定时器中断,50ms后在定时器中断给任务vTaskMsgPro发送事件标志 */
  42.                    case KEY_DOWN_K3:
  43.                        printf("K3键按下,启动单次定时器中断,50ms后在定时器中断给任务vTaskMsgPro发送事件
  44. 标志\\r\\n");
  45.                        bsp_StartHardTimer(2 ,50000, (void *)TIM_CallBack2);
  46.                        break;  
  47.                    /* 其他的键值不处理 */
  48.                    default:                     
  49.                        break;
  50.               }
  51.          }
  52.         
  53.          vTaskDelay(20);
  54.      }
  55. }
  56. /*
  57. *********************************************************************************************************
  58. *    函 数 名: vTaskLED
  59. *    功能说明: LED闪烁
  60. *    形    参: pvParameters 是在创建该任务时传递的形参
  61. *    返 回 值: 无
  62. *   优 先 级: 2
  63. *********************************************************************************************************
  64. */
  65. static void vTaskLED(void *pvParameters)
  66. {
  67.      TickType_t xLastWakeTime;
  68.      const TickType_t xFrequency = 200;
  69.      /* 获取当前的系统时间 */
  70.     xLastWakeTime = xTaskGetTickCount();
  71.    
  72.     while(1)
  73.     {
  74.          bsp_LedToggle(2);
  75.         
  76.          /* vTaskDelayUntil是绝对延迟,vTaskDelay是相对延迟。*/
  77.         vTaskDelayUntil(&xLastWakeTime, xFrequency);
  78.     }
  79. }
  80. /*
  81. *********************************************************************************************************
  82. *    函 数 名: vTaskMsgPro
  83. *    功能说明: 消息处理,使用函数xEventGroupWaitBits接收定时器中断发送的事件标志  
  84. *    形    参: pvParameters 是在创建该任务时传递的形参
  85. *    返 回 值: 无
  86. *   优 先 级: 3
  87. *********************************************************************************************************
  88. */
  89. static void vTaskMsgPro(void *pvParameters)
  90. {
  91.      EventBits_t uxBits;
  92.      const TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS; /* 最大延迟100ms */
  93.    
  94.     while(1)
  95.     {
  96.          /* 等K2按键按下设置bit0和K3按键按下设置bit1 */
  97.          uxBits = xEventGroupWaitBits(xCreatedEventGroup, /* 事件标志组句柄 */
  98.                                           BIT_ALL,            /* 等待bit0和bit1被设置 */
  99.                                           pdTRUE,             /* 退出前bit0和bit1被清除 */
  100.                                           pdTRUE,             /* 设置为pdTRUE表示等待bit1和bit0都被设置*/
  101.                                           xTicksToWait);      /* 等待延迟时间 */
  102.         
  103.          if((uxBits & BIT_ALL) == BIT_ALL)
  104.          {
  105.               /* 接收到bit1和bit0都被设置的消息 */
  106.               printf("接收到bit0和bit1都被设置的消息\\r\\n");
  107.          }
  108.          else
  109.          {
  110.               /* 超时,另外注意仅接收到一个按键按下的消息时,变量uxBits的相应bit也是被设置的 */
  111.               bsp_LedToggle(3);
  112.          }
  113.     }
  114. }
  115. /*
  116. *********************************************************************************************************
  117. *    函 数 名: vTaskStart
  118. *    功能说明: 启动任务,也就是最高优先级任务,这里用作按键扫描。
  119. *    形    参: pvParameters 是在创建该任务时传递的形参
  120. *    返 回 值: 无
  121. *   优 先 级: 4
  122. *********************************************************************************************************
  123. */
  124. static void vTaskStart(void *pvParameters)
  125. {
  126.     while(1)
  127.     {
  128.         /* 按键扫描 */
  129.         bsp_KeyScan();
  130.         vTaskDelay(10);
  131.     }
  132. }
复制代码
定时器中断回调函数中给任务发送事件标志组设置消息:
    定时器中断的初始化和中断函数在bsp_timer.c 文件中实现,这个不是教程的重点,故不作介绍。 这里主要关心函数xEventGroupSetBitsFromISR在中断服务程序中的使用方法。
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: TIM_CallBack1和TIM_CallBack2
  4. *    功能说明: 定时器中断的回调函数,此函数被bsp_StartHardTimer所调用。                        
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void TIM_CallBack1(void)
  10. {
  11.      BaseType_t xResult;
  12.      BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  13.    
  14.      /* 向任务vTaskMsgPro发送事件标志 */
  15.      xResult = xEventGroupSetBitsFromISR(xCreatedEventGroup,      /* 事件标志组句柄 */
  16.                                               BIT_0 ,             /* 设置bit0 */
  17.                                               &xHigherPriorityTaskWoken );
  18.      /* 消息被成功发出 */
  19.      if( xResult != pdFAIL )
  20.      {
  21.          /* 如果xHigherPriorityTaskWoken = pdTRUE,那么退出中断后切到当前最高优先级任务执行 */
  22.          portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
  23.      }
  24. }
  25. static void TIM_CallBack2(void)
  26. {
  27.      BaseType_t xResult;
  28.      BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  29.    
  30.      /* 向任务vTaskMsgPro发送事件标志 */
  31.      xResult = xEventGroupSetBitsFromISR(xCreatedEventGroup,      /* 事件标志组句柄 */
  32.                                               BIT_1,              /* 设置bit1 */
  33.                                               &xHigherPriorityTaskWoken );
  34.      /* 消息被成功发出 */
  35.      if( xResult != pdFAIL )
  36.      {
  37.          /* 如果xHigherPriorityTaskWoken = pdTRUE,那么退出中断后切到当前最高优先级任务执行 */
  38.          portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
  39.      }
  40. }
复制代码
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-8-27 16:58:15 | 显示全部楼层
18.4.2 STM32F407开发板实验


配套例子:
     V5-313_FreeRTOS实验_事件标志组(中断方式)
实验目的:
    1.     学习FreeRTOS的事件标志组(中断方式)。
实验内容:
    1.     K1按键按下,串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1)。
    2.     K2键按下,启动单次定时器中断,50ms后在定时器中断给任务vTaskMsgPro发送事件标志,设置bit0。
    3.     K3键按下,启动单次定时器中断,50ms后在定时器中断给任务vTaskMsgPro发送事件标志,设置bit1。
    4.     任务vTaskMsgPro只有接收到bit0和bit1都被设置了才执行串口打印消息。
    5.     各个任务实现的功能如下:
              vTaskUserIF任务   :按键消息处理。
              vTaskLED任务     :LED闪烁。
              vTaskMsgPro任务 : 消息处理,使用函数xEventGroupWaitBits接收定时器中断的事件标志。
              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         ( 6 )
  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_xTaskResumeFromISR        1
  39. #define INCLUDE_vTaskDelayUntil           1
  40. #define INCLUDE_vTaskDelay                1
  41. #define INCLUDE_xEventGroupSetBitFromISR  1
  42. #define INCLUDE_xTimerPendFunctionCall    1
  43. /* Software timer definitions. */
  44. #define configUSE_TIMERS                    1
  45. #define configTIMER_TASK_PRIORITY         ( 5 )
  46. #define configTIMER_QUEUE_LENGTH           20
  47. #define configTIMER_TASK_STACK_DEPTH     ( configMINIMAL_STACK_SIZE * 2 )
  48. /* Cortex-M specific definitions. */
  49. #ifdef __NVIC_PRIO_BITS
  50.      /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
  51.      #define configPRIO_BITS              __NVIC_PRIO_BITS
  52. #else
  53.      #define configPRIO_BITS              4        /* 15 priority levels */
  54. #endif
  55. /* The lowest interrupt priority that can be used in a call to a "set priority"
  56. function. */
  57. #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY              0x0f
  58. /* The highest interrupt priority that can be used by any interrupt service
  59. routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL
  60. INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
  61. PRIORITY THAN THIS! (higher priorities are lower numeric values. */
  62. #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          ( 6 )
         定义可供用户使用的最大优先级数,如果这个定义的是6,那么用户可以使用的优先级号是0,1,2,3,4,5不包含6,对于这一点,初学者要特别的注意。
5、#define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 30 * 1024 ) )
        定义堆大小,FreeRTOS内核,用户动态内存申请,任务栈等都需要用这个空间。
6、使用事件标志组中的函数xEventGroupSetBitsFromISR,务必使能以下三个宏定义
    (1)#define INCLUDE_xEventGroupSetBitFromISR  1
    (2)#define INCLUDE_xTimerPendFunctionCall    1
    (3)#define configUSE_TIMERS                              1
       因为使能了FreeRTOS的定时器组任务,定时器组的其它宏定义也做一下配置,配置如下:
    (1)#define configTIMER_TASK_PRIORITY       ( 5 )
    (2)#define configTIMER_QUEUE_LENGTH       20
    (3)#define configTIMER_TASK_STACK_DEPTH      ( configMINIMAL_STACK_SIZE * 2 )
7、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按键,串口打印):
18.13.jpg

上面截图中打印出来的任务状态字母B, R, D, S对应如下含义:
    #definetskBLOCKED_CHAR          ( 'B' )  任务阻塞
    #definetskREADY_CHAR           ( 'R' ) 任务就绪
    #definetskDELETED_CHAR           ( 'D' )  任务删除
    #definetskSUSPENDED_CHAR   ( 'S' ) 任务挂起
使用事件标志组要包含的头文件:
使用FreeRTOS的事件标志组要包含头文件#include "event_groups.h",这个头文件在includes.h文件中进行了包含,具体如下:
  1. /*
  2. *********************************************************************************************************
  3. *                                           OS
  4. *********************************************************************************************************
  5. */
  6. #include "FreeRTOS.h"
  7. #include "task.h"
  8. #include "queue.h"
  9. #include "croutine.h"
  10. #include "semphr.h"
  11. #include "event_groups.h"
复制代码
程序设计:
任务栈大小分配:
    vTaskUserIF任务   :2048字节
    vTaskLED任务     :2048字节
    vTaskMsgPro任务 :2048字节
    vTaskStart任务    :2048字节
    任务栈空间是在任务创建的时候从FreeRTOSConfig.h文件中定义的heap空间中申请的
    #defineconfigTOTAL_HEAP_SIZE        ( ( size_t )( 30 * 1024 ) )
系统栈大小分配:
18.14.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.      AppObjCreate();
  35.    
  36.     /* 启动调度,开始执行任务 */
  37.     vTaskStartScheduler();
  38.      /*
  39.        如果系统正常启动是不会运行到这里的,运行到这里极有可能是用于定时器任务或者空闲任务的
  40.        heap空间不足造成创建失败,此要加大FreeRTOSConfig.h文件中定义的heap大小:
  41.        #define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 17 * 1024 ) )
  42.      */
  43.      while(1);
  44. }
复制代码


硬件外设初始化
    硬件外设的初始化是在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. bsp_InitHardTimer(); /* 初始化TIM2定时器 */
  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. *    函 数 名: AppObjCreate
  4. *    功能说明: 创建任务通信机制
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void AppObjCreate (void)
  10. {
  11.      /* 创建事件标志组 */
  12.      xCreatedEventGroup = xEventGroupCreate();
  13.    
  14.      if(xCreatedEventGroup == NULL)
  15.     {
  16.         /* 没有创建成功,用户可以在这里加入创建失败的处理机制 */
  17.     }
  18. }
复制代码
四个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键按下,启动单次定时器中断,50ms后在定时器中断给任务vTaskMsgPro发送事件标志 */
  35.                    case KEY_DOWN_K2:
  36.                        printf("K2键按下,启动单次定时器中断,50ms后在定时器中断给任务vTaskMsgPro发送事件
  37. 标志\\r\\n");
  38.                        bsp_StartHardTimer(1 ,50000, (void *)TIM_CallBack1);
  39.                        break;
  40.                   
  41.                    /* K3键按下,启动单次定时器中断,50ms后在定时器中断给任务vTaskMsgPro发送事件标志 */
  42.                    case KEY_DOWN_K3:
  43.                        printf("K3键按下,启动单次定时器中断,50ms后在定时器中断给任务vTaskMsgPro发送事件
  44. 标志\\r\\n");
  45.                        bsp_StartHardTimer(2 ,50000, (void *)TIM_CallBack2);
  46.                        break;  
  47.                    /* 其他的键值不处理 */
  48.                    default:                     
  49.                        break;
  50.               }
  51.          }
  52.         
  53.          vTaskDelay(20);
  54.      }
  55. }
  56. /*
  57. *********************************************************************************************************
  58. *    函 数 名: vTaskLED
  59. *    功能说明: LED闪烁
  60. *    形    参: pvParameters 是在创建该任务时传递的形参
  61. *    返 回 值: 无
  62. *   优 先 级: 2
  63. *********************************************************************************************************
  64. */
  65. static void vTaskLED(void *pvParameters)
  66. {
  67.      TickType_t xLastWakeTime;
  68.      const TickType_t xFrequency = 200;
  69.      /* 获取当前的系统时间 */
  70.     xLastWakeTime = xTaskGetTickCount();
  71.    
  72.     while(1)
  73.     {
  74.          bsp_LedToggle(2);
  75.         
  76.          /* vTaskDelayUntil是绝对延迟,vTaskDelay是相对延迟。*/
  77.         vTaskDelayUntil(&xLastWakeTime, xFrequency);
  78.     }
  79. }
  80. /*
  81. *********************************************************************************************************
  82. *    函 数 名: vTaskMsgPro
  83. *    功能说明: 消息处理,使用函数xEventGroupWaitBits接收定时器中断发送的事件标志  
  84. *    形    参: pvParameters 是在创建该任务时传递的形参
  85. *    返 回 值: 无
  86. *   优 先 级: 3
  87. *********************************************************************************************************
  88. */
  89. static void vTaskMsgPro(void *pvParameters)
  90. {
  91.      EventBits_t uxBits;
  92.      const TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS; /* 最大延迟100ms */
  93.    
  94.     while(1)
  95.     {
  96.          /* 等K2按键按下设置bit0和K3按键按下设置bit1 */
  97.          uxBits = xEventGroupWaitBits(xCreatedEventGroup, /* 事件标志组句柄 */
  98.                                           BIT_ALL,            /* 等待bit0和bit1被设置 */
  99.                                           pdTRUE,             /* 退出前bit0和bit1被清除 */
  100.                                           pdTRUE,             /* 设置为pdTRUE表示等待bit1和bit0都被设置*/
  101.                                           xTicksToWait);      /* 等待延迟时间 */
  102.         
  103.          if((uxBits & BIT_ALL) == BIT_ALL)
  104.          {
  105.               /* 接收到bit1和bit0都被设置的消息 */
  106.               printf("接收到bit0和bit1都被设置的消息\\r\\n");
  107.          }
  108.          else
  109.          {
  110.               /* 超时,另外注意仅接收到一个按键按下的消息时,变量uxBits的相应bit也是被设置的 */
  111.               bsp_LedToggle(3);
  112.          }
  113.     }
  114. }
  115. /*
  116. *********************************************************************************************************
  117. *    函 数 名: vTaskStart
  118. *    功能说明: 启动任务,也就是最高优先级任务,这里用作按键扫描。
  119. *    形    参: pvParameters 是在创建该任务时传递的形参
  120. *    返 回 值: 无
  121. *   优 先 级: 4
  122. *********************************************************************************************************
  123. */
  124. static void vTaskStart(void *pvParameters)
  125. {
  126.     while(1)
  127.     {
  128.         /* 按键扫描 */
  129.         bsp_KeyScan();
  130.         vTaskDelay(10);
  131.     }
  132. }
复制代码
定时器中断回调函数中给任务发送事件标志组设置消息:
    定时器中断的初始化和中断函数在bsp_timer.c 文件中实现,这个不是教程的重点,故不作介绍。 这里主要关心函数xEventGroupSetBitsFromISR在中断服务程序中的使用方法。
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: TIM_CallBack1和TIM_CallBack2
  4. *    功能说明: 定时器中断的回调函数,此函数被bsp_StartHardTimer所调用。                        
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void TIM_CallBack1(void)
  10. {
  11.      BaseType_t xResult;
  12.      BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  13.    
  14.      /* 向任务vTaskMsgPro发送事件标志 */
  15.      xResult = xEventGroupSetBitsFromISR(xCreatedEventGroup,      /* 事件标志组句柄 */
  16.                                               BIT_0 ,             /* 设置bit0 */
  17.                                               &xHigherPriorityTaskWoken );
  18.      /* 消息被成功发出 */
  19.      if( xResult != pdFAIL )
  20.      {
  21.          /* 如果xHigherPriorityTaskWoken = pdTRUE,那么退出中断后切到当前最高优先级任务执行 */
  22.          portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
  23.      }
  24. }
  25. static void TIM_CallBack2(void)
  26. {
  27.      BaseType_t xResult;
  28.      BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  29.    
  30.      /* 向任务vTaskMsgPro发送事件标志 */
  31.      xResult = xEventGroupSetBitsFromISR(xCreatedEventGroup,      /* 事件标志组句柄 */
  32.                                               BIT_1,              /* 设置bit1 */
  33.                                               &xHigherPriorityTaskWoken );
  34.      /* 消息被成功发出 */
  35.      if( xResult != pdFAIL )
  36.      {
  37.          /* 如果xHigherPriorityTaskWoken = pdTRUE,那么退出中断后切到当前最高优先级任务执行 */
  38.          portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
  39.      }
  40. }
复制代码
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-8-27 17:07:05 | 显示全部楼层
18.4.3   STM32F429开发板实验


配套例子:
    V6-313_FreeRTOS实验_事件标志组(中断方式)
实验目的:
    1.     学习FreeRTOS的事件标志组(中断方式)。
实验内容:
    1.     K1按键按下,串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1)。
    2.     K2键按下,启动单次定时器中断,50ms后在定时器中断给任务vTaskMsgPro发送事件标志,设置bit0。
    3.     K3键按下,启动单次定时器中断,50ms后在定时器中断给任务vTaskMsgPro发送事件标志,设置bit1。
    4.     任务vTaskMsgPro只有接收到bit0和bit1都被设置了才执行串口打印消息。
    5.     各个任务实现的功能如下:
              vTaskUserIF任务   :按键消息处理。
              vTaskLED任务     :LED闪烁。
              vTaskMsgPro任务 : 消息处理,使用函数xEventGroupWaitBits接收定时器中断的事件标志。
              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_xTaskResumeFromISR        1
  35. #define INCLUDE_vTaskDelayUntil           1
  36. #define INCLUDE_vTaskDelay                1
  37. #define INCLUDE_xEventGroupSetBitFromISR  1
  38. #define INCLUDE_xTimerPendFunctionCall    1
  39. /* Software timer definitions. */
  40. #define configUSE_TIMERS                    1
  41. #define configTIMER_TASK_PRIORITY         ( 5 )
  42. #define configTIMER_QUEUE_LENGTH           20
  43. #define configTIMER_TASK_STACK_DEPTH     ( configMINIMAL_STACK_SIZE * 2 )
  44. /* Cortex-M specific definitions. */
  45. #ifdef __NVIC_PRIO_BITS
  46.      /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */
  47.      #define configPRIO_BITS              __NVIC_PRIO_BITS
  48. #else
  49.      #define configPRIO_BITS              4        /* 15 priority levels */
  50. #endif
  51. /* The lowest interrupt priority that can be used in a call to a "set priority"
  52. function. */
  53. #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY              0x0f
  54. /* The highest interrupt priority that can be used by any interrupt service
  55. routine that makes calls to interrupt safe FreeRTOS API functions.  DO NOT CALL
  56. INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER
  57. PRIORITY THAN THIS! (higher priorities are lower numeric values. */
  58. #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、使用事件标志组中的函数xEventGroupSetBitsFromISR,务必使能以下三个宏定义
    (1)#define INCLUDE_xEventGroupSetBitFromISR  1
    (2)#define INCLUDE_xTimerPendFunctionCall    1
    (3)#define configUSE_TIMERS                              1
       因为使能了FreeRTOS的定时器组任务,定时器组的其它宏定义也做一下配置,配置如下:
    (1)#define configTIMER_TASK_PRIORITY       ( 5 )
    (2)#define configTIMER_QUEUE_LENGTH       20
    (3)#define configTIMER_TASK_STACK_DEPTH      ( configMINIMAL_STACK_SIZE * 2 )
7、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按键,串口打印):
18.15.jpg

上面截图中打印出来的任务状态字母B, R, D, S对应如下含义:
    #definetskBLOCKED_CHAR          ( 'B' )  任务阻塞
    #definetskREADY_CHAR           ( 'R' ) 任务就绪
    #definetskDELETED_CHAR           ( 'D' )  任务删除
    #definetskSUSPENDED_CHAR   ( 'S' ) 任务挂起
使用事件标志组要包含的头文件:
    使用FreeRTOS的事件标志组要包含头文件#include "event_groups.h",这个头文件在includes.h文件中进行了包含,具体如下:
  1. /*
  2. *********************************************************************************************************
  3. *                                           OS
  4. *********************************************************************************************************
  5. */
  6. #include "FreeRTOS.h"
  7. #include "task.h"
  8. #include "queue.h"
  9. #include "croutine.h"
  10. #include "semphr.h"
  11. #include "event_groups.h"
复制代码
程序设计:
任务栈大小分配:
    vTaskUserIF任务   :2048字节
    vTaskLED任务     :2048字节
    vTaskMsgPro任务 :2048字节
    vTaskStart任务    :2048字节
    任务栈空间是在任务创建的时候从FreeRTOSConfig.h文件中定义的heap空间中申请的
    #defineconfigTOTAL_HEAP_SIZE        ( ( size_t )( 30 * 1024 ) )
系统栈大小分配:
18.16.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.      AppObjCreate();
  35.    
  36.     /* 启动调度,开始执行任务 */
  37.     vTaskStartScheduler();
  38.      /*
  39.        如果系统正常启动是不会运行到这里的,运行到这里极有可能是用于定时器任务或者空闲任务的
  40.        heap空间不足造成创建失败,此要加大FreeRTOSConfig.h文件中定义的heap大小:
  41.        #define configTOTAL_HEAP_SIZE        ( ( size_t ) ( 17 * 1024 ) )
  42.      */
  43.      while(1);
  44. }
复制代码
硬件外设初始化
    硬件外设的初始化是在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. bsp_InitHardTimer(); /* 初始化TIM2定时器 */
  25. }
复制代码
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. *    函 数 名: AppObjCreate
  4. *    功能说明: 创建任务通信机制
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void AppObjCreate (void)
  10. {
  11.      /* 创建事件标志组 */
  12.      xCreatedEventGroup = xEventGroupCreate();
  13.    
  14.      if(xCreatedEventGroup == NULL)
  15.     {
  16.         /* 没有创建成功,用户可以在这里加入创建失败的处理机制 */
  17.     }
  18. }
复制代码
四个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键按下,启动单次定时器中断,50ms后在定时器中断给任务vTaskMsgPro发送事件标志 */
  35.                    case KEY_DOWN_K2:
  36.                        printf("K2键按下,启动单次定时器中断,50ms后在定时器中断给任务vTaskMsgPro发送事件
  37. 标志\\r\\n");
  38.                        bsp_StartHardTimer(1 ,50000, (void *)TIM_CallBack1);
  39.                        break;
  40.                   
  41.                    /* K3键按下,启动单次定时器中断,50ms后在定时器中断给任务vTaskMsgPro发送事件标志 */
  42.                    case KEY_DOWN_K3:
  43.                        printf("K3键按下,启动单次定时器中断,50ms后在定时器中断给任务vTaskMsgPro发送事件
  44. 标志\\r\\n");
  45.                        bsp_StartHardTimer(2 ,50000, (void *)TIM_CallBack2);
  46.                        break;  
  47.                    /* 其他的键值不处理 */
  48.                    default:                    
  49.                        break;
  50.               }
  51.          }
  52.         
  53.          vTaskDelay(20);
  54.      }
  55. }
  56. /*
  57. *********************************************************************************************************
  58. *    函 数 名: vTaskLED
  59. *    功能说明: LED闪烁
  60. *    形    参: pvParameters 是在创建该任务时传递的形参
  61. *    返 回 值: 无
  62. *   优 先 级: 2
  63. *********************************************************************************************************
  64. */
  65. static void vTaskLED(void *pvParameters)
  66. {
  67.      TickType_t xLastWakeTime;
  68.      const TickType_t xFrequency = 200;
  69.      /* 获取当前的系统时间 */
  70.     xLastWakeTime = xTaskGetTickCount();
  71.    
  72.     while(1)
  73.     {
  74.          bsp_LedToggle(2);
  75.         
  76.          /* vTaskDelayUntil是绝对延迟,vTaskDelay是相对延迟。*/
  77.         vTaskDelayUntil(&xLastWakeTime, xFrequency);
  78.     }
  79. }
  80. /*
  81. *********************************************************************************************************
  82. *    函 数 名: vTaskMsgPro
  83. *    功能说明: 消息处理,使用函数xEventGroupWaitBits接收定时器中断发送的事件标志  
  84. *    形    参: pvParameters 是在创建该任务时传递的形参
  85. *    返 回 值: 无
  86. *   优 先 级: 3
  87. *********************************************************************************************************
  88. */
  89. static void vTaskMsgPro(void *pvParameters)
  90. {
  91.      EventBits_t uxBits;
  92.      const TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS; /* 最大延迟100ms */
  93.    
  94.     while(1)
  95.     {
  96.          /* 等K2按键按下设置bit0和K3按键按下设置bit1 */
  97.          uxBits = xEventGroupWaitBits(xCreatedEventGroup, /* 事件标志组句柄 */
  98.                                           BIT_ALL,            /* 等待bit0和bit1被设置 */
  99.                                           pdTRUE,             /* 退出前bit0和bit1被清除 */
  100.                                           pdTRUE,             /* 设置为pdTRUE表示等待bit1和bit0都被设置*/
  101.                                           xTicksToWait);      /* 等待延迟时间 */
  102.         
  103.          if((uxBits & BIT_ALL) == BIT_ALL)
  104.          {
  105.               /* 接收到bit1和bit0都被设置的消息 */
  106.               printf("接收到bit0和bit1都被设置的消息\\r\\n");
  107.          }
  108.          else
  109.          {
  110.               /* 超时,另外注意仅接收到一个按键按下的消息时,变量uxBits的相应bit也是被设置的 */
  111.               bsp_LedToggle(3);
  112.          }
  113.     }
  114. }
  115. /*
  116. *********************************************************************************************************
  117. *    函 数 名: vTaskStart
  118. *    功能说明: 启动任务,也就是最高优先级任务,这里用作按键扫描。
  119. *    形    参: pvParameters 是在创建该任务时传递的形参
  120. *    返 回 值: 无
  121. *   优 先 级: 4
  122. *********************************************************************************************************
  123. */
  124. static void vTaskStart(void *pvParameters)
  125. {
  126.     while(1)
  127.     {
  128.         /* 按键扫描 */
  129.         bsp_KeyScan();
  130.         vTaskDelay(10);
  131.     }
  132. }
复制代码
定时器中断回调函数中给任务发送事件标志组设置消息:
    定时器中断的初始化和中断函数在bsp_timer.c 文件中实现,这个不是教程的重点,故不作介绍。 这里主要关心函数xEventGroupSetBitsFromISR在中断服务程序中的使用方法。
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: TIM_CallBack1和TIM_CallBack2
  4. *    功能说明: 定时器中断的回调函数,此函数被bsp_StartHardTimer所调用。                        
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void TIM_CallBack1(void)
  10. {
  11.      BaseType_t xResult;
  12.      BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  13.    
  14.      /* 向任务vTaskMsgPro发送事件标志 */
  15.      xResult = xEventGroupSetBitsFromISR(xCreatedEventGroup,      /* 事件标志组句柄 */
  16.                                               BIT_0 ,             /* 设置bit0 */
  17.                                               &xHigherPriorityTaskWoken );
  18.      /* 消息被成功发出 */
  19.      if( xResult != pdFAIL )
  20.      {
  21.          /* 如果xHigherPriorityTaskWoken = pdTRUE,那么退出中断后切到当前最高优先级任务执行 */
  22.          portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
  23.      }
  24. }
  25. static void TIM_CallBack2(void)
  26. {
  27.      BaseType_t xResult;
  28.      BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  29.    
  30.      /* 向任务vTaskMsgPro发送事件标志 */
  31.      xResult = xEventGroupSetBitsFromISR(xCreatedEventGroup,      /* 事件标志组句柄 */
  32.                                               BIT_1,              /* 设置bit1 */
  33.                                               &xHigherPriorityTaskWoken );
  34.      /* 消息被成功发出 */
  35.      if( xResult != pdFAIL )
  36.      {
  37.          /* 如果xHigherPriorityTaskWoken = pdTRUE,那么退出中断后切到当前最高优先级任务执行 */
  38.          portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
  39.      }
  40. }
复制代码
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

740

主题

1326

回帖

3546

积分

管理员

春暖花开

Rank: 9Rank: 9Rank: 9

积分
3546
QQ
 楼主| 发表于 2016-8-27 17:07:50 | 显示全部楼层
18.5  总结

    本章节为大家讲解了任务间的通信和同步机制之一,事件标志组,初学者要稍花些时间将其掌握。
努力打造安富莱高质量微信公众号:点击扫描图片关注
回复

使用道具 举报

1

主题

16

回帖

19

积分

新手上路

积分
19
发表于 2021-7-14 13:27:56 | 显示全部楼层
整个完整的freertos教程在哪里能找到呢
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106437
QQ
发表于 2021-7-15 08:17:44 | 显示全部楼层
dzc0426 发表于 2021-7-14 13:27
整个完整的freertos教程在哪里能找到呢

【安富莱】FreeRTOS操作系统教程发布,支持F103,F407和F429,配套145个例子,1200页教程
http://www.armbbs.cn/forum.php?m ... 7658&fromuid=58
(出处: 硬汉嵌入式论坛)
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-4-20 22:35 , Processed in 0.346949 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

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