0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

基于STM32F407的FreeRTOS学习笔记(7)

CHANBAEK 来源:实在太懒于是不想取名 作者: 电路小白 2023-11-08 11:04 次阅读

本期在二进制信号量的基础上介绍计数信号量

01基本介绍

图片

01.什么是计数信号量

计数信号量顾名思义是用来计数的信号量,相比于二进制信号量,计数信号量的并不只有两种状态。用官方的开发者文档中的话来说,计数信号量可以看作长度大于1的队列,我们并不关心其中的内容而是关系队列是否为空。

关于队列的公众号可以参考这篇文章。

02.如何创建计数信号量

图片

官方的参考文档中提供了两种创建方式(动态和静态)我们使用动态创建方式。调用xSemaphoreCreateCounting函数

其中包含了两个参数,一个是最大计数量还有一个是初始计数量。

创建一个SemaphoreHandler_t类型的句柄变量用以接收返回值。

03.释放和获取信号量

释放和获取信号量和上一期二进制信号量的释放和获取方式一样。均是调用

xSemaphoreGive释放信号量以及调用

xSemaphoreTake获取信号量。

但是计数信号量则多了一个可以调用的函数。

图片

调用这个函数我们就可以获得计数值啦。

02代码编写

1测试流程

我们做两个实验,首先是使用一个LED函数,函数每翻转一次就向计数信号量释放一次信号。

第二个函数轮询计数信号量,当计数信号量的数量比一半多时,使另一个LED也开始进行翻转并同样释放信号量。当计数信号量到达最大数时,关闭第二个灯的翻转。

2大体思路

第一个LED灯翻转,发送信号量。定义一个轮询函数用来时刻检测信号量状况,当信号量到达一定数量时恢复LED2任务的运行,当信号量满时清空信号量列表并挂起LED2

任务的挂起与恢复可以参考这期。

3代码编写

首先是任务启动函数,在这个函数中我们要创建一个计数信号量并且启动其他的相关任务函数。

void Start_LED(void * pvParameters)
{
  taskENTER_CRITICAL();                            

  LED_SemaphoreHandler = xSemaphoreCreateCounting(20,0);//最大计数20,初始0
  if(LED_SemaphoreHandler!=NULL)
  {
    printf("Semaphore Create Successfullyrn");
  }

  xTaskCreate((TaskFunction_t        )LED_TOG,//任务函数
              (char *                )"LED_TOG",//任务名称
              (configSTACK_DEPTH_TYPE) 128,//堆栈空间128Byte
              (void*                 ) NULL,//无返回
              (UBaseType_t          ) 1,//优先级1
              (TaskHandle_t *        )&LED_TOG_Handler);//任务函数句柄

   xTaskCreate((TaskFunction_t        )LED_TOG2,//任务函数
              (char *                )"LED_TOG2",//任务名称
              (configSTACK_DEPTH_TYPE) 128,//堆栈空间128Byte
              (void*                 ) NULL,//无返回
              (UBaseType_t          ) 2,//优先级1
              (TaskHandle_t *        )&LED_TOG2_Handler);//任务函数句柄

     xTaskCreate((TaskFunction_t        )CountTest,//任务函数
              (char *                )"GetCount",//任务名称
              (configSTACK_DEPTH_TYPE) 128,//堆栈空间128Byte
              (void*                 ) NULL,//无返回
              (UBaseType_t          ) 0,//优先级1
              (TaskHandle_t *        )&GetCount_Handler);//任务函数句柄

  taskEXIT_CRITICAL();
  vTaskSuspend(LED_TOG2_Handler);
  vTaskDelete(NULL);
}

其次LED函数的内容非常简单,检测信号量是否创建(指针不为空)如果指针不为空则翻转LED,并且释放信号量。(注意第二个LED的函数不释放信号量防止释放两次信号量)

void LED_TOG(void * pvParameters)//参数为 void * pvParameters
{

  while(1)
  {
    if(LED_SemaphoreHandler!=NULL)
    {
      HAL_GPIO_TogglePin(GPIOF,GPIO_PIN_9);
      xSemaphoreGive(LED_SemaphoreHandler);
    }

    vTaskDelay(500);//延迟500ms
  }
}


void LED_TOG2(void * pvParameters)//参数为 void * pvParameters
{
  while(1)
  {
    if(LED_SemaphoreHandler!=NULL)
    {
      HAL_GPIO_TogglePin(GPIOF,GPIO_PIN_10);
    }
    vTaskDelay(500);
  }
}

在循环检测函数中,我们定义一个count来接收计数信号量的数量。接着当信号量大于10时我们恢复LED2函数的运行(可以多次恢复,只有一次效果)。

当信号量为20时,我们先暂停LED1函数的运行防止我们清空信号量的时候LED1又在释放信号量。之后通过不断的获取信号量来清空信号量,因为信号量本质就是队列,之后恢复他们的运行。

void CountTest(void * pvParameters)
{
  while(1)
  {
    BaseType_t count;
    if(LED_SemaphoreHandler!=NULL)
    {
      count = uxSemaphoreGetCount(LED_SemaphoreHandler);
      if(count >= 9 )
      {
        vTaskResume(LED_TOG2_Handler);//恢复函数2
      }
      if(count >= 20 )
      {
        vTaskSuspend(LED_TOG_Handler);//先挂起函数1
        while(count != 0)
        {
          xSemaphoreTake(LED_SemaphoreHandler,10);
          count = uxSemaphoreGetCount(LED_SemaphoreHandler);
        }

        vTaskResume(LED_TOG_Handler);//恢复函数1
        vTaskSuspend(LED_TOG2_Handler);//挂起函数2
      }

    }
    vTaskDelay(10);
  }
}
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 二进制
    +关注

    关注

    2

    文章

    720

    浏览量

    41344
  • 函数
    +关注

    关注

    3

    文章

    4117

    浏览量

    61545
  • FreeRTOS
    +关注

    关注

    12

    文章

    474

    浏览量

    61513
  • 信号量
    +关注

    关注

    0

    文章

    53

    浏览量

    8268
收藏 人收藏

    评论

    相关推荐

    基于STM32F407FreeRTOS学习笔记(1)

    其实从很早之前就想学实时操作系统(RTOS)了,但是一直没有时间去学,以前使用STM32单片机一直停留在逻辑开发以及前后台系统,而真正被广泛使用的则是RTOS。
    的头像 发表于 11-07 11:37 572次阅读
    基于<b class='flag-5'>STM32F407</b>的<b class='flag-5'>FreeRTOS</b><b class='flag-5'>学习</b><b class='flag-5'>笔记</b>(1)

    基于STM32F407FreeRTOS学习笔记(2)

    上一期配置完FreeRTOS的环境后,这一期记录自己关于任务创建的学习过程。
    的头像 发表于 11-07 11:39 472次阅读
    基于<b class='flag-5'>STM32F407</b>的<b class='flag-5'>FreeRTOS</b><b class='flag-5'>学习</b><b class='flag-5'>笔记</b>(2)

    基于STM32F407FreeRTOS学习笔记(3)

    上一期学习了任务的创建和删除,这一期学习任务的挂起与恢复。
    的头像 发表于 11-07 11:41 434次阅读
    基于<b class='flag-5'>STM32F407</b>的<b class='flag-5'>FreeRTOS</b><b class='flag-5'>学习</b><b class='flag-5'>笔记</b>(3)

    基于STM32F407FreeRTOS学习笔记(4)

    CPU工作的时候,各个任务运行会占用CPU的资源,在Windows系统中我们可以通过任务管理器来看各任务(进程)占用系统资源的情况。
    的头像 发表于 11-07 11:43 706次阅读
    基于<b class='flag-5'>STM32F407</b>的<b class='flag-5'>FreeRTOS</b><b class='flag-5'>学习</b><b class='flag-5'>笔记</b>(4)

    基于STM32F407FreeRTOS学习笔记(5)

    在数据结构中有一种很重要的数据结构叫做队列,其特点是数据先进先出。在FreeRTOS中也有一类队列,我们利用这类队列在FreeRTOS中实现任务与任务间的消息传递,所以也可以称之为消息队列。
    的头像 发表于 11-07 11:43 490次阅读
    基于<b class='flag-5'>STM32F407</b>的<b class='flag-5'>FreeRTOS</b><b class='flag-5'>学习</b><b class='flag-5'>笔记</b>(5)

    基于STM32F407FreeRTOS学习笔记(6)

    信号量(Semaphore)也被称为信号灯。有时被称为信号灯,是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量(来自百度百科)
    的头像 发表于 11-08 11:00 457次阅读
    基于<b class='flag-5'>STM32F407</b>的<b class='flag-5'>FreeRTOS</b><b class='flag-5'>学习</b><b class='flag-5'>笔记</b>(6)

    基于STM32F407FreeRTOS学习笔记(8)

    前面几期我们介绍过队列、二进制信号量以及计数信号量。但是在使用二进制信号量的时候会有一种优先级反转问题的出现,简而言之就是低优先级任务因为无法及时释放信号量而导致等待信号量发生的高优先级任务迟迟无法进行。
    的头像 发表于 11-08 11:07 500次阅读
    基于<b class='flag-5'>STM32F407</b>的<b class='flag-5'>FreeRTOS</b><b class='flag-5'>学习</b><b class='flag-5'>笔记</b>(8)

    基于STM32F407FreeRTOS学习笔记(9)

    在嵌入式编程中,定时器是一个非常重要且强大的功能,用来帮我们定时性的调用中断服务函数来帮助我们处理程序。定时器通常是用硬件来实现的,例如STM32F407就有8个硬件定时器。
    的头像 发表于 11-08 11:08 498次阅读
    基于<b class='flag-5'>STM32F407</b>的<b class='flag-5'>FreeRTOS</b><b class='flag-5'>学习</b><b class='flag-5'>笔记</b>(9)

    基于STM32F407FreeRTOS学习笔记(10)

    在介绍二进制信号量时曾经讲过,二进制信号量可以代替我们裸机开发中的标志位来使用。在裸机开发中我们使用标志位来表示某个事件是否发生,并且其他程序利用标记位的状态来判断程序是否可以继续进行。但是这种大量使用标记位的情况会导致代码的逻辑异常的复杂。
    的头像 发表于 11-08 11:10 445次阅读
    基于<b class='flag-5'>STM32F407</b>的<b class='flag-5'>FreeRTOS</b><b class='flag-5'>学习</b><b class='flag-5'>笔记</b>(10)

    基于STM32F407FreeRTOS学习笔记(11)

    在前面的学习中例如信号量、队列中经常会出现提示:在许多情况下,“任务通知”可以提供二进制信号量的轻量级替代方案。
    的头像 发表于 11-13 17:23 520次阅读
    基于<b class='flag-5'>STM32F407</b>的<b class='flag-5'>FreeRTOS</b><b class='flag-5'>学习</b><b class='flag-5'>笔记</b>(11)

    基于STM32F407FreeRTOS学习笔记(12)

    在上一期内容中我们简单的介绍了任务通知的几个函数以及简单的使用了任务通知来实现两个信号之间的通信。
    的头像 发表于 11-13 17:27 515次阅读
    基于<b class='flag-5'>STM32F407</b>的<b class='flag-5'>FreeRTOS</b><b class='flag-5'>学习</b><b class='flag-5'>笔记</b>(12)

    如何使用STM32F407去移植FreeRTOS

    如何使用STM32F407去移植FreeRTOS呢?有哪些操作步骤?
    发表于 10-21 09:45

    STM32F407 FreeRTOS开发指南

    参考资料:正点原子《littleVGL 开发指南》正点原子《STM32F407 FreeRTOS 开发指南》硬件平台:stm32f407开发板(或最小系统)、4.3寸TFTLCD以正点原子的例程为
    发表于 01-05 06:55

    STM32F407标准库学习笔记-GPIO

    STM32F407标准库学习笔记-GPIO头文件 gpio.h枚举-列举同一寄存器的不同选项typedef enum{ GPIO_Low_Speed = 0x00, /*!<
    发表于 11-29 15:51 46次下载
    <b class='flag-5'>STM32F407</b>标准库<b class='flag-5'>学习</b><b class='flag-5'>笔记</b>-GPIO

    STM32F407 FreeRTOS开发手册 V1.1

    STM32F407 FreeRTOS开发手册_V1.1PDF文件下载。
    发表于 07-31 11:16 48次下载