- 简述:
- 信号量(Semaphore)是一种实现任务间通信的机制,可实现任务之间同步或临界资源的互斥访问
- 信号量像一种上锁机制,必须有相应的钥匙才能继续执行
- 信号量不具备传递数据的功能
- 分类:
- 二进制信号量:
- 信号量资源释放:1
- 信号量资源获取:0
- 最大可以信号量个数为1
- 计数型信号量:
- 多个任务访问共享资源
- 比如某一信号量初始化值为10,那么只有前10个请求该信号量的任务可以使用共享资源
- 后续任务要等待前10个任务释放掉信号量
- 有任务请求信号量的时候,信号量的值就会减1,直到减为0
- ---------释放------------------,---------------------加1,直接定义的初始值;
- 二进制信号量:
- 信号量函数
- OSSemCreate(); 创建一个信号量
- OSSemDel(); 删除一个信号量
- OSSemPend(); 等待一个信号量
- OSSemPend()Abort(); 取消等待
- OSSemPost(); 释放一个信号量
- OSSemSet(); 强制设置一个信号量的值
- 常用函数:创建、释放、等待
- 二进制信号量例程:
- 创建
//创建信号量 OSSemCreate((OS_SEM *)&SemOfKey, //指向消息队列的指针 (CPU_CHAR *)"SemOfKey", //信号量的名字 (OS_SEM_CTR )0, //指示事件发生,0事件没有发生 (OS_ERR *)&err); //返回错误类型
- 发布
/************************************************** * 函数名: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 } }
- 等待
/************************************************** * 函数名: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 ) ); } } }
- 创建
- 计数信号量例程:
- 创建
//创建信号量 OSSemCreate((OS_SEM *)&SemOfKey, //指向消息队列的指针 (CPU_CHAR *)"SemOfKey", //信号量的名字 (OS_SEM_CTR )5, //现有资源数目 (OS_ERR *)&err); //返回错误类型
- 发布
//创建信号量 OSSemCreate((OS_SEM *)&SemOfKey, //指向消息队列的指针 (CPU_CHAR *)"SemOfKey", //信号量的名字 (OS_SEM_CTR )5, //现有资源数目 (OS_ERR *)&err); //返回错误类型
- 等待
/************************************************** * 函数名: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(); } } }
- 创建
- 下载验证
- 二进值信号量
- 计数信号量
- 二进值信号量
- 总结
- 信号量访问资源不会导致中断延迟
- 推荐将信号量用于I/O端口的保护,而不是内存地址
- 避免信号量过度使用
- 信号量会导致一种严重的问题:优先级反转
- 参考资料:
- 正点原子《STM32F767 UCOS开发手册》
- 野火《uC/OS-III内核应用与开发》
- 《嵌入式实时操作系统 uC/OS-III原理及应用(第二版)》
- 官方源码
- 硬件平台:
- 正点原子阿波罗F767
- 软件平台:
- MDK5.2.5
- 库版本:
- TM32Cube_FW_F7_V1.4.0
- uC/OS-III版本
- UCOSIII 3.04
【5】uC/OS-III应用开发————>信号量(STM32F767)
最新推荐文章于 2025-04-24 14:54:04 发布