Chinaunix首页 | 论坛 | 博客
  • 博客访问: 831598
  • 博文数量: 281
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2770
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-02 19:45
个人简介

邮箱:zhuimengcanyang@163.com 痴爱嵌入式技术的蜗牛

文章分类
文章存档

2020年(1)

2018年(1)

2017年(56)

2016年(72)

2015年(151)

分类: 嵌入式

2015-09-23 09:17:42

计数信号量
例12 演示了一个二值信号量被用于让任务和中断进行同步。整个执行流程可以描述为:
1. 中断产生。
2. 中断服务例程启动,给出信号量以使延迟处理任务解除阻塞。
3. 当中断服务例程退出时,延迟处理任务得到执行。延迟处理任务做的第一件事便是获取信号量。
4. 延迟处理任务完成中断事件处理后,试图再次获取信号量——如果此时信号量无效,任务将切入阻塞待等待事件发生。

在中断以相对较慢的频率发生的情况下,上面描述的流程是足够而完美的。如果在延迟处理任务完成上一个中断事件的处理之前,新的中断事件又发生了,等效于将新的事件锁存在二值信号量中,使得延迟处理任务在处理完上一个事件之后,立即就可以处理新的事件。也就是说,延迟处理任务在两次事件处理之间,不会有进入阻塞态的机会,因为信号量中锁存有一个事件,所以当xSempaphoreTake()调用时,信号量立即有效。这种情形将在下图中进行展现。
这种情形:中断要优先完成,最多只锁存一个信号量,因为这是个二值信号量,要么是1,要么是0,不能增加为2,3......

在下图中可以看到,一个二值信号量最多只可以锁存一个中断事件。在锁存的事件还未被处理之前,如果还有中断事件发生,那么后续发生的中断事件将会丢失。如果用计数信号量代替二值信号量,那么,这种丢中断的情形将可以避免。

就如同我们可以把二值信号量看作是只有一个数据单元的队列一样,计数信号量可以看作是深度大于1 的队列。任务其实对队列中存储的具体数据并不感兴趣——其只关心队列是空还是非空。

计数信号量每次被给出(Given),其队列中的另一个空间将会被使用。队列中的有效数据单元个数就是信号量的”计数(Count)”值。


一个二值信号量最多只能锁存一个中断事件



使用计数信号量对事件 “计数(Count)”

计数信号量有以下两种典型用法:
1.事件计数
在这种用法中,每次事件发生时,中断服务例程都会“给出(Give)”信号量——信号量在每次被给出时其计数值加1。延迟处理任务每处理一个任务都会”获取(Take)”一次信号量——信号量在每次被获取时其计数值减1。信号量的计数值其实就是已发生事件的数目与已处理事件的数目之间的差值。这种机制可以参考上图。
用于事件计数的计数信号量,在被创建时其计数值被初始化为0。
2.资源管理
在这种用法中,信号量的计数值用于表示可用资源的数目。一个任务要获取资源的控制权,其必须先获得信号量——使信号量的计数值减1。当计数值减至0,则表示没有可用资源。当任务利用资源完成工作后,将给出(归还)信号量——使信号量的计数值加1
用于资源管理的信号量,在创建时其计数值被初始化为可用资源总数。

函数介绍
xSemaphoreCreateCounting() API 函数
FreeRTOS 中所有种类的信号量句柄都由声明为xSemaphoreHandle 类型的变量保存。
信号量在使用前必须先被创建。使用xSemaphoreCreateCounting() API 函数来创建一个计数信号量。
函数原型:
xSemaphoreHandle xSemaphoreCreateCounting( unsigned portBASE_TYPE uxMaxCount, unsigned portBASE_TYPE uxInitialCount );

uxMaxCount 最大计数值。
如果把计数信号量类比于队列的话,uxMaxCount 值就是队列的最大深度。
当此信号量用于对事件计数或锁存事件的话,uxMaxCount 就是可锁存事件的最大数目。
当此信号量用于对一组资源的访问进行管理的话,uxMaxCount 应当设置为所有可用资源的总数。
uxInitialCount 信号量的初始计数值。
当此信号量用于事件计数的话,uxInitialCount 应当设置为0——因为当信号量被创建时,还没有事件发生。当此信号量用于资源管理的话, uxInitialCount 应当等于uxMaxCount——因为当信号量被创建时,所有的资源都是可用的。
返回值
如果返回NULL 值,表示堆上内存空间不足,所以FreeRTOS 无法为信号量结构分配内存导致信号量创建失败。
如果返回非NULL 值,则表示信号量创建成功。此值应当被保存起来作为这个的信号量的句柄。

例子13:
       例13 用计数信号量代替二值信号量对例12 的实现进行了改进。修改main()函数调用xSemaphoreCreateCounting(),以代替对xSemaphoreCreateBinary()的调用。
注意:
只有 configUSE_COUNTING_SEMAPHORES ==1 的时候,才使能可以使用xSemaphoreCreateCounting()函数,所以在FreeRTOS.h中设置
#ifndef configUSE_COUNTING_SEMAPHORES
    #define configUSE_COUNTING_SEMAPHORES    1      // 0 改为 1,使能函数
#endif

代码实现:

点击(此处)折叠或打开

  1. #include "led.h"
  2. #include "key.h"
  3. #include "exti.h"
  4. #include "delay.h"
  5. #include "sys.h"
  6. #include "usart.h"

  7. // FreeRTOS head file, add here.
  8. #include "FreeRTOS.h"
  9. #include "task.h"
  10. #include "queue.h"
  11. #include "list.h"
  12. #include "portable.h"
  13. #include "FreeRTOSConfig.h"
  14. #include "semphr.h"


  15. /* declare a SemaphoreHandle_t variable, using to save queue handler. */
  16. SemaphoreHandle_t xBinarySemaphore = NULL;

  17. SemaphoreHandle_t xCountingSemaphore;


  18. void board_Init(void)
  19. {
  20.     LED_Init();    
  21.     KEY_Init();
  22.     //EXTIX_Init();
  23.     uart_init(115200);
  24.     
  25.     // interrupt initialize
  26.     //NVIC_Configuration();//
  27. }


  28. void keyScan_Task(void *pvParameters)
  29. {
  30.     char key = 0x00;
  31.     int keycnt;

  32.     while(1)
  33.     {
  34.         // add your key scan code here.
  35.         keyScan();
  36.         if((key = keyScan_readBuff()) != 0)
  37.         {
  38.             switch(key)
  39.             {
  40.                 case ( KEY_CODE + SHORT_KEY):
  41.                     printf("short key pressed, cnt: %d \r\n", keycnt++);
  42.                 
  43.                     //xSemaphoreGive(xBinarySemaphore);
  44.                 xSemaphoreGive(xCountingSemaphore);

  45.                     printf("key pressed, give semaphore \r\n");
  46.                 
  47.                 break;
  48.                 
  49.                 case ( KEY_CODE+FIRSTLONG_KEY_CODE):
  50.                     printf("long first pressed \r\n");
  51.                 break;
  52.                 
  53.                 case ( KEY_CODE+AFTERLONG_KEY_CODE):
  54.                     printf("long after pressed \r\n");
  55.                 break;
  56.             }
  57.         }
  58.         
  59.         vTaskDelay(10/portTICK_RATE_MS);
  60.     }
  61. }

  62. void LED_task(void *pvParameters)
  63. {
  64.     char state = 0;
  65.     
  66.     while(1)
  67.     {
  68.         ((state = !state) == 1) ? GREEN_ON() : GREEN_OFF();
  69.         vTaskDelay(1000 / portTICK_RATE_MS);
  70.     }
  71. }




  72. void Key_HanderFun(void *pvParameters)
  73. {
  74.     char state = 0;
  75.     
  76.     while(1)
  77.     {
  78.         //xSemaphoreTake(xBinarySemaphore, portMAX_DELAY);
  79.         xSemaphoreTake(xCountingSemaphore, portMAX_DELAY);

  80.         printf("take semaphore here \r\n");
  81.         
  82.         (state =!state) == 1 ? RED_ON() : RED_OFF();
  83.     }
  84. }



  85. int main(void)
  86. {
  87.     // board initialize.
  88.     board_Init();
  89.     printf("board initialize finish. \r\n");
  90.     
  91.     // create binary semaphore
  92.     //vSemaphoreCreateBinary(xBinarySemaphore);
  93.     
  94.     /* 创建计数信号量。这里为记录按键按下的次数,所以为计数信号量,设置最大计数值为10,初始计数值为0 */
  95.     xCountingSemaphore = xSemaphoreCreateCounting(10, 0);
  96.     
  97.     if(xCountingSemaphore != NULL)
  98.     {
  99.         xTaskCreate(Key_HanderFun, "keyHandlerTask", configMINIMAL_STACK_SIZE, NULL, 2, NULL);
  100.         xTaskCreate(keyScan_Task, "keyScanTask", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
  101.         xTaskCreate(LED_task, "LED_task", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
  102.         //xSemaphoreTake(xBinarySemaphore, 0);
  103.         
  104.         // start scheduler now
  105.         vTaskStartScheduler();
  106.     }
  107.     else
  108.     {
  109.         // semaphore create unsuccessful here. add your code.
  110.         printf("semaphore create failed \r\n");
  111.     }
  112.     
  113.     return 0;
  114. }


再改进一下代码:
增加一个定时器,定时时间到,进入定时器中断程序,在中断程序里释放计数信号量。

点击(此处)折叠或打开

  1. #include "led.h"
  2. #include "key.h"
  3. #include "exti.h"
  4. #include "delay.h"
  5. #include "sys.h"
  6. #include "usart.h"
  7. #include "timer.h"

  8. // FreeRTOS head file, add here.
  9. #include "FreeRTOS.h"
  10. #include "task.h"
  11. #include "queue.h"
  12. #include "list.h"
  13. #include "portable.h"
  14. #include "FreeRTOSConfig.h"
  15. #include "semphr.h"


  16. /* declare a SemaphoreHandle_t variable, using to save queue handler. */
  17. SemaphoreHandle_t xBinarySemaphore = NULL;

  18. SemaphoreHandle_t xCountingSemaphore;


  19. void board_Init(void)
  20. {
  21.     LED_Init();    
  22.     KEY_Init();
  23.     //EXTIX_Init();
  24.     uart_init(115200);
  25.     TIM3_Int_Init(10,7200);// 10kHZ, 1ms interrupt.
  26.     
  27.     // interrupt initialize
  28.     NVIC_Configuration();//
  29. }


  30. void keyScan_Task(void *pvParameters)
  31. {
  32.     char key = 0x00;
  33.     int keyCnt =0;
  34.     
  35.     while(1)
  36.     {
  37.         // add your key scan code here.
  38.         keyScan();
  39.         if((key = keyScan_readBuff()) != 0)
  40.         {
  41.             switch(key)
  42.             {
  43.                 case ( KEY_CODE + SHORT_KEY):
  44.                     printf("short key pressed, cnt: %d\r\n", ++keyCnt);
  45.                 
  46.                     //xSemaphoreGive(xBinarySemaphore);
  47.                 
  48.                     xSemaphoreGive(xCountingSemaphore);
  49.                     printf("key pressed, give semaphore \r\n");
  50.                 
  51.                 break;
  52.                 
  53.                 case ( KEY_CODE+FIRSTLONG_KEY_CODE):
  54.                     printf("long first pressed \r\n");
  55.                 break;
  56.                 
  57.                 case ( KEY_CODE+AFTERLONG_KEY_CODE):
  58.                     printf("long after pressed \r\n");
  59.                 break;
  60.             }
  61.         }
  62.         
  63.         vTaskDelay(10/portTICK_RATE_MS);
  64.     }
  65. }

  66. void LED_task(void *pvParameters)
  67. {
  68.     char state = 0;
  69.     
  70.     while(1)
  71.     {
  72.         ((state = !state) == 1) ? GREEN_ON() : GREEN_OFF();
  73.         vTaskDelay(1000 / portTICK_RATE_MS);
  74.     }
  75. }


  76. void Key_HanderFun(void *pvParameters)
  77. {
  78.     //char state = 0;
  79.     
  80.     while(1)
  81.     {
  82.         //xSemaphoreTake(xBinarySemaphore, portMAX_DELAY);
  83.         xSemaphoreTake(xCountingSemaphore, portMAX_DELAY);
  84.         printf("take semaphore here \r\n");
  85.         
  86.         //(state =!state) == 1 ? RED_ON() : RED_OFF();
  87.     }
  88. }



  89. int main(void)
  90. {
  91.     // board initialize.
  92.     board_Init();
  93.     printf("board initialize finish. \r\n");
  94.     
  95.     // create binary semaphore
  96.     //vSemaphoreCreateBinary(xBinarySemaphore);
  97.     
  98.     /* ???????????????°?????¨??±????????¨??????????????????×??ó????????10??????????????0 */
  99.     xCountingSemaphore = xSemaphoreCreateCounting(10, 0);
  100.     
  101.     if(xCountingSemaphore != NULL)
  102.     {
  103.         xTaskCreate(Key_HanderFun, "keyHandlerTask", configMINIMAL_STACK_SIZE, NULL, 2, NULL);
  104.         xTaskCreate(keyScan_Task, "keyScanTask", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
  105.         xTaskCreate(LED_task, "LED_task", configMINIMAL_STACK_SIZE, NULL, 1, NULL);
  106.         //xSemaphoreTake(xBinarySemaphore, 0);
  107.         
  108.         // start scheduler now
  109.         vTaskStartScheduler();
  110.     }
  111.     else
  112.     {
  113.         // semaphore create unsuccessful here. add your code.
  114.         printf("semaphore create failed \r\n");
  115.     }
  116.     
  117.     return 0;
  118. }


  119. void TIM3_IRQHandler(void) //TIM3 interrupt, 1ms
  120. {
  121.     static char state = 0;
  122.     static int cnt = 0;
  123.     static int sempCnt = 0;
  124.     BaseType_t xHigherPriorityTaskWoken = pdFALSE;
  125.  
  126.     if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //?ì?é???¨??TIM????·??ú??·?:TIM ??????
  127.     {
  128.         TIM_ClearITPendingBit(TIM3, TIM_IT_Update); //????TIMx???????????í??:TIM ??????
  129.         
  130.         if(++cnt >= 10// 10ms periodical interrupt here.
  131.         {
  132.             cnt = 0;
  133.            
  134.              // give counting semaphore here.
  135.              xSemaphoreGiveFromISR(xCountingSemaphore, &xHigherPriorityTaskWoken);
  136.              printf("give semaphore, sempCnt: %d \r\n", ++sempCnt);
  137.             ((state = !state) == 1) ? RED_ON() : RED_OFF();
  138.         }
  139.     }
  140. }


  141. void EXTI0_IRQHandler(void)
  142. {
  143.     static BaseType_t xHigherPriorityTaskWoken;
  144.     xHigherPriorityTaskWoken = pdFALSE;
  145.     
  146.     if(WK_UP == 1)
  147.     {    
  148.         // Unblock the task by releasing the semaphore.
  149.         xSemaphoreGiveFromISR(xBinarySemaphore, &xHigherPriorityTaskWoken);
  150.         printf("key pressed, give semaphore \r\n");
  151.     }
  152.     EXTI_ClearITPendingBit(EXTI_Line0);
  153. }
打印结果:非常快的打印频率。



阅读(2104) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~