【5】uC/OS-III应用开发————>信号量(STM32F767)

本文深入讲解了信号量机制,包括二进制信号量和计数型信号量的概念、使用场景和编程实例。信号量用于任务间通信,实现资源的同步访问和互斥,通过创建、发布和等待信号量,确保多任务环境下资源的安全访问。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. 简述:
    1. 信号量(Semaphore)是一种实现任务间通信的机制,可实现任务之间同步或临界资源的互斥访问
    2. 信号量像一种上锁机制,必须有相应的钥匙才能继续执行
    3. 信号量不具备传递数据的功能
  2. 分类:
    1. 二进制信号量:
      1. 信号量资源释放:1
      2. 信号量资源获取:0
      3. 最大可以信号量个数为1
    2. 计数型信号量:
      1. 多个任务访问共享资源
      2. 比如某一信号量初始化值为10,那么只有前10个请求该信号量的任务可以使用共享资源
      3. 后续任务要等待前10个任务释放掉信号量
      4. 有任务请求信号量的时候,信号量的值就会减1,直到减为0
      5. ---------释放------------------,---------------------加1,直接定义的初始值;
  3. 信号量函数
    1. OSSemCreate(); 创建一个信号量
    2. OSSemDel(); 删除一个信号量
    3. OSSemPend(); 等待一个信号量
    4. OSSemPend()Abort(); 取消等待
    5. OSSemPost(); 释放一个信号量
    6. OSSemSet(); 强制设置一个信号量的值
    7. 常用函数:创建、释放、等待
  4. 二进制信号量例程:
    1. 创建
          //创建信号量
          OSSemCreate((OS_SEM        *)&SemOfKey,                                 //指向消息队列的指针
                    (CPU_CHAR      *)"SemOfKey",                                  //信号量的名字
                    (OS_SEM_CTR     )0,                                           //指示事件发生,0事件没有发生
                    (OS_ERR        *)&err);                                       //返回错误类型

       

    2. 发布
      /**************************************************
       * 函数名:static void AppTaskKey(void *p_arg)
       * 描述  :按键检测
       * 输入  :无
       * 输出  :无
       * 返回  :无 
       * 调用  :内部调用 
       **************************************************/
      static void AppTaskKey(void *p_arg)
      {
          OS_ERR err;
          
          uint8_t KeyValue;
      
          (void)p_arg;
          
          for(;;)
          {
              KeyValue = BSP_KEY_Scan(0);
              if(KeyValue == Key_WkUP_PA0_Value)
              {
                  OSSemPost((OS_SEM   *)&SemOfKey,        //发布SemOfKey
                            (OS_OPT    )OS_OPT_POST_ALL,  //发布给所有等待任务
                            (OS_ERR   *)&err);            //返回错误类型
              }
              OSTimeDlyHMSM(0,0,0,10,OS_OPT_TIME_PERIODIC,&err);   //延时10ms
          }
      }

       

    3. 等待
      /**************************************************
       * 函数名:static void AppTaskUsart(void *p_arg)
       * 描述  :串口打印
       * 输入  :无
       * 输出  :无
       * 返回  :无 
       * 调用  :内部调用 
       **************************************************/
      static void AppTaskUsart(void *p_arg)
      {
          OS_ERR err;
          CPU_TS ts_sem_post,ts_sem_get;
          CPU_INT32U cpu_clk_freq;
          
          (void)p_arg;
          
          cpu_clk_freq = HAL_RCC_GetHCLKFreq();
          
          for(;;)
          {
              OSSemPend((OS_SEM       *)&SemOfKey,            //等待该信号量被发布
                        (OS_TICK       )0,                    //无期限等待
                        (OS_OPT        )OS_OPT_PEND_BLOCKING, //如果没有信号量可以就等待
                        (CPU_TS       *)&ts_sem_post,         //获取信号量最后一次被发布的时间戳
                        (OS_ERR       *)&err);                //返回错误类型
              
              ts_sem_get = OS_TS_GET();   //获取解除等待时的时间戳
      
              if(err == OS_ERR_NONE) //消息接收成功
              {
      			printf ( "\r\n发布信号量的时间戳是%d", ts_sem_post );
      			printf ( "\r\n解除等待状态的时间戳是%d", ts_sem_get );
      			printf ( "\r\n接收到信号量与发布信号量的时间相差%dus\r\n", 
      			        ( ts_sem_get - ts_sem_post ) / ( cpu_clk_freq / 1000000 ) );
              }
          }
      }

       

  5. 计数信号量例程:
    1. 创建
          //创建信号量
          OSSemCreate((OS_SEM        *)&SemOfKey,                                 //指向消息队列的指针
                    (CPU_CHAR      *)"SemOfKey",                                  //信号量的名字
                    (OS_SEM_CTR     )5,                                           //现有资源数目
                    (OS_ERR        *)&err);                                       //返回错误类型

       

    2. 发布
          //创建信号量
          OSSemCreate((OS_SEM        *)&SemOfKey,                                 //指向消息队列的指针
                    (CPU_CHAR      *)"SemOfKey",                                  //信号量的名字
                    (OS_SEM_CTR     )5,                                           //现有资源数目
                    (OS_ERR        *)&err);                                       //返回错误类型

       

    3. 等待
      /**************************************************
       * 函数名:static void AppTaskUsart(void *p_arg)
       * 描述  :串口打印
       * 输入  :无
       * 输出  :无
       * 返回  :无 
       * 调用  :内部调用 
       **************************************************/
      static void AppTaskUsart(void *p_arg)
      {
          OS_ERR err;
          uint8_t KeyValue;
          OS_SEM_CTR ctr;
          
          CPU_SR_ALLOC();
          
          (void)p_arg;
          
          for(;;)
          {
              KeyValue = BSP_KEY_Scan(0);
              if(KeyValue == Key0_PH3_Value)
              {
                  ctr = OSSemPend((OS_SEM       *)&SemOfKey,            //等待该信号量被发布
                                  (OS_TICK       )0,                    //无期限等待
                                  (OS_OPT        )OS_OPT_PEND_NON_BLOCKING, //如果没有信号量可用不等待
                                  (CPU_TS       *)0,                    //不获取时间戳
                                  (OS_ERR       *)&err);                //返回错误类型   
                  
                  OS_CRITICAL_ENTER();
      
                  if(err == OS_ERR_NONE) //消息接收成功
                  {
                      printf ( "\r\nKEY0被按下:成功申请到停车位,剩下%d个停车位。\r\n", ctr );
                  }
                  else if(err == OS_ERR_PEND_WOULD_BLOCK)
                  {
                      printf ( "\r\nKEY0被按下:不好意思,现在停车场已满,请等待!\r\n" );
                  }
                  
                  OS_CRITICAL_EXIT();
              }
          }
      }
      

       

  6. 下载验证
    1. 二进值信号量
    2. 计数信号量
  7. 总结
    1. 信号量访问资源不会导致中断延迟
    2. 推荐将信号量用于I/O端口的保护,而不是内存地址
    3. 避免信号量过度使用
    4. 信号量会导致一种严重的问题:优先级反转
  8. 参考资料:
    1. 正点原子《STM32F767 UCOS开发手册》
    2. 野火《uC/OS-III内核应用与开发》
    3. 《嵌入式实时操作系统 uC/OS-III原理及应用(第二版)》
    4. 官方源码
  9. 硬件平台:
    1. 正点原子阿波罗F767
  10. 软件平台:
    1. MDK5.2.5
  11. 库版本:
    1. TM32Cube_FW_F7_V1.4.0
  12. uC/OS-III版本
    1. UCOSIII 3.04
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值