CMSIS 2.0接口使用事件标志是实时操作系统(RTOS)中一种重要的同步机制。事件标志是一种轻量级的同步原语,用于任务间或中断服务程序(ISR)之间的通信。 每个事件标志对象可以包含多个标志位,通常最多为31个(因为第31位通常保留)。
注意事项
在使用事件标志时,需要注意避免竞态条件,确保在多任务环境中正确同步。
osEventFlagsWait函数支持超时机制,可以根据需要设置合适的超时时间。
可以在中断服务程序(ISR)中安全地调用与事件标志相关的函数,但需要注意中断嵌套和优先级问题。
通过CMSIS 2.0接口的事件标志功能,开发人员可以更加灵活地实现任务间的同步和通信,提高系统的效率和稳定性。
EventFlags API分析
osEventFlagsId_t osEventFlagsNew(const osEventFlagsAttr_t *attr)
描述:
osEventFlagsNew函数创建了一个新的事件标志对象,用于跨线程发送事件,并返回事件标志对象标识符的指针,或者在出现错误时返回NULL。可以在RTOS启动(调用 osKernelStart)之前安全地调用该函数,但不能在内核初始化 (调用 osKernelInitialize)之前调用该函数。
注意 :不能在中断服务调用该函数。
参数:
参数名 | 描述 |
attr | 事件标志属性;空:默认值. |
uint32_t osEventFlagsSet(osEventFlagsId_t ef_id,uint32_t flags)
描述:
osEventFlagsSet函数在一个由参数ef_id指定的事件标记对象中设置由参数flags指定的事件标记。
注意 :不能在中断服务调用该函数。
参数:
参数名 | 描述 |
ef_id | 事件标志由osEventFlagsNew获得的ID 。 |
flags | 指定设置的标志。 |
uint32_t osEventFlagsWait(osEventFlagsId_t ef_id,uint32_t flags,uint32_t options,uint32_t timeout)
描述:
osEventFlagsWait函数挂起当前运行线程,直到设置了由参数ef_id指定的事件对象中的任何或所有由参数flags指定的事件标志。当这些事件标志被设置,函数立即返回。否则,线程将被置于阻塞状态。
注意 :如果参数timeout设置为0,可以从中断服务例程调用。
参数:
参数名 | 描述 |
ef_id | 事件标志由osEventFlagsNew获得的ID。 |
flags | 指定要等待的标志。 |
options | 指定标记选项。 |
timeout | 超时时间,0表示不超时。 |
代码编写
修改D:\DevEcoProjects\test\src\vendor\rtplay\rt_hi3861\demo\BUILD.gn文件
# Copyright (c) 2023 Beijing HuaQing YuanJian Education Technology Co., Ltd
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import("//build/lite/config/component/lite_component.gni")
lite_component("demo") {
features = [
#"base_00_helloworld:base_helloworld_example",
#"base_01_led:base_led_example",
#"base_02_loopkey:base_loopkey_example",
#"base_03_irqkey:base_irqkey_example",
#"base_04_adc:base_adc_example",
#"base_05_pwm:base_pwm_example",
#"base_06_ssd1306:base_ssd1306_example",
#"kernel_01_task:kernel_task_example",
#"kernel_02_timer:kernel_timer_example",
"kernel_03_event:kernel_event_example",
]
}
创建D:\DevEcoProjects\test\src\vendor\rtplay\rt_hi3861\demo\kernel_03_event文件夹
文件夹中创建D:\DevEcoProjects\test\src\vendor\rtplay\rt_hi3861\demo\kernel_03_event\kernel_event_example.c文件D:\DevEcoProjects\test\src\vendor\rtplay\rt_hi3861\demo\kernel_03_event\BUILD.gn文件
# Copyright (c) 2023 Beijing HuaQing YuanJian Education Technology Co., Ltd
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
static_library("kernel_event_example") {
sources = [
"kernel_event_example.c",
]
include_dirs = [
"//utils/native/lite/include",
"//kernel/liteos_m/kal/cmsis",
]
}
/*
* Copyright (c) 2023 Beijing HuaQing YuanJian Education Technology Co., Ltd
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdio.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
osThreadId_t Task1_ID; // 任务1 ID
osThreadId_t Task2_ID; // 任务2 ID
osEventFlagsId_t event_ID; // 事件 ID
uint32_t event1_Flags = 0x00000001U; // 事件掩码 每一位代表一个事件
uint32_t event2_Flags = 0x00000002U; // 事件掩码 每一位代表一个事件
uint32_t event3_Flags = 0x00000004U; // 事件掩码 每一位代表一个事件
#define TASK_STACK_SIZE 1024
#define TASK_DELAY_TIME 1 // s
/**
* 注意: 任务延时不能使用osDelay,这个函数延时有问题
*/
/**
* @description: 任务1 用于发送事件
* @param {*}
* @return {*}
*/
void Task1(void)
{
while (1) {
printf("enter Task 1.......\n");
osEventFlagsSet(event_ID, event1_Flags); // 设置事件标记
printf("send eventFlag1.......\n");
sleep(TASK_DELAY_TIME); // 1秒
osEventFlagsSet(event_ID, event2_Flags); // 设置事件标记
printf("send eventFlag2.......\n");
sleep(TASK_DELAY_TIME); // 1秒
osEventFlagsSet(event_ID, event3_Flags); // 设置事件标记
printf("send eventFlag3.......\n");
sleep(TASK_DELAY_TIME); // 1秒
}
}
/**
* @description: 任务2 用于接受事件
* @param {*}
* @return {*}
*/
void Task2(void)
{
uint32_t flags = 0;
while (1) {
// 永远等待事件标记触发,当接收到 event1_Flags 和 event2_Flags 和 event3_Flags时才会执行printf函数
// osFlagsWaitAll :全部事件标志位接收到 osFlagsWaitAny: 任意一个事件标志位接收到
// 当只有一个事件的时候,事件的类型选择哪个都可以
flags = osEventFlagsWait(event_ID, event1_Flags | event2_Flags | event3_Flags, osFlagsWaitAll, osWaitForever);
printf("receive event is OK\n"); // 事件已经标记
}
}
/**
* @description: 初始化并创建任务
* @param {*}
* @return {*}
*/
static void kernel_event_example(void)
{
printf("Enter kernel_event_example()!\n");
event_ID = osEventFlagsNew(NULL); // 创建事件
if (event_ID != NULL) {
printf("ID = %d, Create event_ID is OK!\n", event_ID);
}
osThreadAttr_t taskOptions;
taskOptions.name = "Task1"; // 任务的名字
taskOptions.attr_bits = 0; // 属性位
taskOptions.cb_mem = NULL; // 堆空间地址
taskOptions.cb_size = 0; // 堆空间大小
taskOptions.stack_mem = NULL; // 栈空间地址
taskOptions.stack_size = TASK_STACK_SIZE; // 栈空间大小 单位:字节
taskOptions.priority = osPriorityNormal; // 任务的优先级
Task1_ID = osThreadNew((osThreadFunc_t)Task1, NULL, &taskOptions); // 创建任务1
if (Task1_ID != NULL) {
printf("ID = %d, Create Task1_ID is OK!\n", Task1_ID);
}
taskOptions.name = "Task2"; // 任务的名字
Task2_ID = osThreadNew((osThreadFunc_t)Task2, NULL, &taskOptions); // 创建任务2
if (Task2_ID != NULL) {
printf("ID = %d, Create Task2_ID is OK!\n", Task2_ID);
}
}
SYS_RUN(kernel_event_example);
使用build,编译成功后,使用upload进行烧录。