目录
概述
本文主要介绍Free RTOS中Semaphore(计数信号量)的使用方法,包括使用STM32Cube中配置FreeRTOS,并且使能Semaphore,还介绍了Free RTOS中Semaphore中相关的函数。还通过一个简单的实例,来介绍Semaphore(计数信号量)的使用方法。
1 使用STM32Cube 配置信号量
1.1 引子
笔者使用硬件平台为STM32H750,本文使用STM32CubeMX配置工程代码,并用该工具生成FreeRTOS的相关的Task和Semaphore相关的代码。关于嵌入式实时操作系统中的信号量的概念,笔者已经在其他文章中做了介绍,这里仅仅介绍如何使用FreeRTOS提供的接口,来实现功能。
1.2 STM32Cube中配置FreeRTOS
step-1: 使能FreeRTOS
step-2: 配置信号量参数,笔者配置了3个信号量
1)2个二值信号量
2)一个计数信号量
step-3:配置Task,用于测试信号量的功能,配置3个Task,每个task的优先级相互之间不同
1.3 STM32Cube生成Project
完成Semaphore和Task参数配置后,就可以点击GENERATE生成Project,完成GENERATE之后,打开工程,其项目文件结构如下:
1) 和FreeRTOS相关的代码已经被加载项目中
2) STM32Cube生成的和FreeRTOS相关的应用代码
2 cmsis_os中信号量接口函数
2.1 函数:osSemaphoreNew
函数功能: 创建并初始化一个信号量对象。
函数原型:
osSemaphoreId_t osSemaphoreNew (uint32_t max_count,
uint32_t initial_count,
const osSemaphoreAttr_t *attr);
参数介绍:
参数名称 | 描述 |
---|---|
max_count | 可用令牌的最大数量 |
initial_count | 可用令牌的初始数量 |
attr | 信号量属性; 默认值: NULL。 |
返回值:
供其他函数参考的信号量ID,如果发生错误则为NULL。
2.2 函数:osSemaphoreGetName
函数功能:获取信号量对象的名称
函数原型:
const char *osSemaphoreGetName (osSemaphoreId_t semaphore_id);
参数介绍:
参数名称 | 描述 |
---|---|
semaphore_id | 获取的信号量ID,这个ID是由osSemaphoreNew创建的 |
返回值:
状态码,表示函数的执行状态。
2.3 函数:osSemaphoreAcquire
函数功能: 获取信号量令牌,如果当前没有令牌,则超时放弃。
函数原型:
osStatus_t osSemaphoreAcquire (osSemaphoreId_t semaphore_id,
uint32_t timeout);
参数介绍:
参数名称 | 描述 |
---|---|
semaphore_id | 获取的信号量ID,这个ID是由osSemaphoreNew创建的 |
timeout | CMSIS_RTOS_TimeOutValue,如果没有超时,则为0。 |
返回值:
状态码,表示函数的执行状态
2.4 函数:osSemaphoreRelease
函数功能:释放一个信号量令牌,直到初始最大计数。
函数原型:
osStatus_t osSemaphoreRelease (osSemaphoreId_t semaphore_id);
参数介绍:
参数名称 | 描述 |
---|---|
semaphore_id | 获取的信号量ID,这个ID是由osSemaphoreNew创建的 |
返回值:
状态码,表示函数的执行状态
2.5 函数:osSemaphoreGetCount
功能介绍:获取当前信号量令牌计数。
函数原型:
uint32_t osSemaphoreGetCount (osSemaphoreId_t semaphore_id);
参数介绍:
参数名称 | 描述 |
---|---|
semaphore_id | 获取的信号量ID,这个ID是由osSemaphoreNew创建的 |
返回值:
可用令牌的数量。
2.6 函数:osSemaphoreDelete
功能介绍:删除信号量对象。
函数原型:
osStatus_t osSemaphoreDelete (osSemaphoreId_t semaphore_id);
参数介绍:
参数名称 | 描述 |
---|---|
semaphore_id | 获取的信号量ID,这个ID是由osSemaphoreNew创建的 |
返回值:
状态码,表示函数的执行状态
3 使用信号量方法
3.1 数据结构: osSemaphoreAttr_t
数据结构参数说明
参数名称 | 描述 |
---|---|
name | 信号量的名称 |
attr_bits | 属性位 |
cb_mem | 控制块存储器 |
cb_size | 为控制块提供的内存大小 |
/// Attributes structure for semaphore.
typedef struct {
const char *name; ///< name of the semaphore
uint32_t attr_bits; ///< attribute bits
void *cb_mem; ///< memory for control block
uint32_t cb_size; ///< size of provided memory for control block
} osSemaphoreAttr_t;
3.2 数据结构:StaticSemaphore_t
了解嵌入式实时操作系统中信号的相关知识,就知道每一个信号必须有一个controlBlock,其数据结构定义如下:
信号controlBlock数据结构定义如下:
3.3 数据结构:osSemaphoreId_t
在cmsis_os2.h 文件中定义了osSemaphoreId_t的数据类型为 void
4 计数信号量的使用Demo
4.1 实现功能
代码第39行:定义信号量ID句柄
代码第41行:定义控制块数据结构
代码第43~47行:初始化信号量参数簇
详细代码:
/* Definitions for myCountingSem01 */
osSemaphoreId_t myCountingSem01Handle;
osStaticSemaphoreDef_t myCountingSem01ControlBlock;
const osSemaphoreAttr_t myCountingSem01_attributes = {
.name = "myCountingSem01",
.cb_mem = &myCountingSem01ControlBlock,
.cb_size = sizeof(myCountingSem01ControlBlock),
};
代码第58行:创建信号量句柄
详细代码:
void initTask( void )
{
//myBinarySem01Handle = osSemaphoreNew(1, 1, &myBinarySem01_attributes);
/* creation of myBinarySem02 */
//myBinarySem02Handle = osSemaphoreNew(1, 1, &myBinarySem02_attributes);
/* creation of myCountingSem01 */
myCountingSem01Handle = osSemaphoreNew(3, 3, &myCountingSem01_attributes);
}
4.2 编写测试函数
代码第68行:释放计数信号量
代码第71行:获取当前的计数值
代码第85行:获取计数信号量
代码第88行:获取当前的计数值
详细代码:
void mainTask(void *argument)
{
int cnt;
osStatus_t sem_osStatus;
for(;;)
{
sem_osStatus = osSemaphoreRelease(myCountingSem01Handle);
if( sem_osStatus == osOK ){
printf("mainTask: osSemaphoreRelease \r\n");
cnt = osSemaphoreGetCount(myCountingSem01Handle);
printf("mainTask osSemaphoreGetCount: %d \r\n", cnt);
}
osDelay(30);
}
}
void monitorTask(void *argument)
{
osStatus_t sem_osStatus;
int cnt;
for(;;)
{
sem_osStatus = osSemaphoreAcquire(myCountingSem01Handle, 100);
if( sem_osStatus == osOK ){
printf("monitorTask: osSemaphoreAcquire \r\n");
cnt = osSemaphoreGetCount(myCountingSem01Handle);
printf("monitorTask osSemaphoreGetCount: %d \r\n", cnt);
}
osDelay(10);
}
}
5 测试
编译代码,然后将代码下载到板卡上,运行log如下:
根据计数信号的定义,
1)当Task获取到信号时,count值会减一
2)当Task释放到信号时,count值会加一
结论:
log 打印出来的信息符合信号量使用的要求