既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新
需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)
参数 | 功能 |
---|---|
Task Name | 任务名称,保存在 TCB 结构体中,设置时自己起名字 |
Priority | 任务优先级,任务的调度等级,根据自己创建任务的紧急程度设定比如通信任务不能被打断,可以设计较高优先级 |
Stack Size(Words) | 设定给任务分配的内存大小,单位是字,对于32位单片机来说占4个字节 |
Entry Function | 任务实体,即任务的运行函数名 |
Code Generation | 代码生成模式As weak: 产生一个用 __weak 修饰的弱定义任务函数,用户可自己在进行定义;As external: 产生一个外部引用的任务函数,用户需要自己定义该函数;Default: 产生一个默认格式的任务函数,用户需要在该函数内实现自己的功能 |
Parameter: | 传入的参数,保持默认就行 |
Allocation: | 内存分配方式Static: 静态方式是直接在RAM占据一个静态空间Dynamic:动态方则是在初始配置的内存池大小数组中动态申请、释放空间 |
设置完成后点击OK,配置就完成了,之后生成代码,使用 MDK 进一步配置任务的具体信息
在生成的代码中,我们打开 freertos.c 文件可以在代码中看到任务的配置信息
在 freertos.c 文件的末尾部分,我们可以看到生成的任务实体
任务实体本身就是一个死循环函数,循环执行程序代码,但循环体代码里面必须要有延时函数,释放当前任务对 MCU 的控制权,使其他低优先级可以执行,此外,关于任务,CubeMX 提供了一系列的用户调用接口函数,具体如下
函数 | 功能 |
---|---|
osThreadNew | 创建新任务 |
*osThreadGetName | 获取任务名称 |
osThreadGetId | 获取当前任务的控制块(TCB) |
osThreadGetState | 获取当前任务的运行状态 |
osThreadGetStackSize | 获取任务的堆栈大小 |
osThreadGetStackSpace | 获取任务剩余的堆栈大小 |
osThreadSetPriority | 设定任务优先级 |
osThreadGetPriority | 获取任务优先级 |
osThreadYield | 切换控制权给下一个任务 |
osThreadSuspend | 挂起任务 |
osThreadResume | 恢复任务(挂起多少次恢复多少次) |
osThreadDetach | 分离任务,方便任务结束进行回收 |
osThreadJoin | 等待指定的任务停止 |
osThreadExit | 停止当前任务 |
osThreadTerminate | 停止指定任务 |
osThreadGetCount | 获取激活的任务数量 |
osThreadEnumerate | 列举激活的任务 |
4.2 CubeMX 下队列的创建与配置
队列,又称为消息队列,用于任务间的数据通信,传输数据,在操作系统里面,直接使用全局变量传输数据十分危险,看似正常运行,但不知道啥时候就会因为寄存器或者内存等等原因引起崩溃,所以引入消息,队列的概念,任务发送数据到队列,需要接受消息的任务挂起在队列的挂起列表,等待消息的到来,CubeMX 创建队列的步骤如下:
先点击 Add 添加队列
队列配置参数介绍
参数 | 功能 |
---|---|
Queue Name | 队列名称(自己设定) |
Queue Size | 消息队列大小 |
Item Size | 队列传输类型,保持默认16 位就行 |
Allocation | 队列内存的分配方式Static: 静态方式是直接在RAM占据一个静态空间Dynamic:动态方则是在初始配置的内存池大小数组中动态申请、释放空间 |
配置需要的参数后,点击OK,然后生成代码
生成代码后,我们可以在 freertos.c 中系统初始话函数中看到队列的初始化
初始化函数会在一开始被调用,对 FreeRTOS 系统和内核对象进行初始化,初始化后系统就可以进行调度和使用内核对象,CubeMX 生成的代码自动将创建的内核对象放到初始化函数内,所以我们在任务和中断中直接使用就可以,队列的 FreeRTOS API 接口在CubeMX 内再次进行了封装,使用更加简单,使用方式如下:
我们使用的 CMSIS 2.0 版本,所以在任务文件中包含调用声明头文件
#include "cmsis\_os2.h"
在队列头文件内我们可以在 600 多行的位置找到有关队列的 API 函数声明:
下面介绍一下队列有关接口的函数接口:
函数 | 功能 |
---|---|
osMessageQueueNew | 创建并初始化一个新的队列 |
osMessageQueueGetName | 获取队列的名字 |
osMessageQueuePut | 发送一条消息到队列 |
osMessageQueueGet | 从队列等待一条消息 |
osMessageQueueGetCapacity | 获取队列传输消息的峰值 |
osMessageQueueGetMsgSize | 获取队列使用内存池的最大峰值 |
osMessageQueueGetCount | 获取队列的消息数量 |
osMessageQueueGetSpace | 获取队列剩余的可用空槽 |
osMessageQueueReset | 清空队列 |
osMessageQueueDelete | 删除队列 |
以上的API接口有其对应的传入参数,具体使用方式需要在翻源码的注释,这里我选常用的来介绍一下:
消息队列常用的是插入与获取消息,初始化系统已经帮助我们完成,在初始化的时候会获取一个队列的句柄,之后对队列的操作都是围绕这个句柄展开,比如上面的代码中,句柄就是 myQueue01Handle
,我们发送一个消息到这个队列,就是调用发送函数,对句柄进行操作,先看一下发送消息的函数原型
osStatus\_t osMessageQueuePut (osMessageQueueId\_t mq_id, const void \*msg_ptr, uint8\_t msg_prio, uint32\_t timeout);
参数的功能
参数 | 功能 |
---|---|
mq_id | 传入队列的句柄 |
*msg_ptr | 指向需要发送的消息内容的指针 |
msg_prio | 本次发送消息的优先级(目前API未加入功能) |
timeout | 发送消息的超时时间(设置为0代表一直等待发送成功) |
osStatus_t(返回值) | 返回执行结果 |
返回值的可能
错误 | 含义 |
---|---|
osOK | 执行正常 |
osError | 系统错误 |
osErrorTimeout | 执行超时 |
osErrorResource | 资源不可用 |
osErrorParameter | 参数无效 |
osErrorNoMemory | 内存不足 |
osErrorISR | 不允许在中断调用 |
osStatusReserved | 防止编译器优化项,不需要管他 |
所以我们发送一个消息到队列,函数用法如下:
void StartTask02(void \*argument)
{
/\* USER CODE BEGIN StartTask02 \*/
osStatus\_t result;
uint8\_t dat[]="666\r\n";
/\* Infinite loop \*/
for(;;)
{
result= osMessageQueuePut(myQueue01Handle,dat,1,0);
if(result == osOK)
{
//发送成功
}else
{
//发送失败
}
osDelay(1);
}
/\* USER CODE END StartTask02 \*/
}
发送消息的优先级暂时无用,CubeMX 对 FreeRTOS 的支持还不完善,发送消息里面的优先级未使用到,并且入队方式使用的是发送到队列尾部,没有从头部插入的方式,有需求可以 通过包含 queue.h 文件,调用 FreeRTOS 的官方代码,或者自己修改 生成代码的 API 接口结合优先级使用队列的向前插入和向后插入,丰富系统功能!
除了发送消息到队列,接受队列的消息 API 接口也经常用到,函数原型如下
osStatus\_t osMessageQueueGet (osMessageQueueId\_t mq_id, void \*msg_ptr, uint8\_t \*msg_prio, uint32\_t timeout);
参数的功能
参数 | 功能 |
---|---|
mq_id | 接受队列的句柄 |
*msg_ptr | 用于接受消息内容的指针 |
msg_prio | 存放接受消息的优先级(目前API未加入功能) |
timeout | 接受消息的超时时间(设置为10代表,当前任务挂起在挂起列表,直到接收成功时恢复,或者10个TICK等待周期到达然后任务强行恢复,不再等待,为0则是不等待,等待期间任务挂起在内核对象的挂起队列) |
osStatus_t(返回值) | 返回执行结果 |
函数用法
void StartTask02(void \*argument)
{
/\* USER CODE BEGIN StartTask02 \*/
osStatus\_t result;
uint8\_t dat[10]={};
uint8\_t \*pro;
/\* Infinite loop \*/
for(;;)
{
result= osMessageQueueGet(myQueue01Handle,dat,pro,10);
if(result == osOK)
{
//接受成功
}else
{
//接受失败
}
osDelay(1);
}
/\* USER CODE END StartTask02 \*/
}
注意:FreeRTOS 中获取和发送消息的 API 接口函数分为任务中调用和中断中调用,CubeMX 代码接口将两者整合了,调用时自动判断调用环境是在 ISR 还是正常运行环境中
五、创建定时器和信号量
5.1 CubeMX下定时器的创建和配置
软件定时器本质上就是设置一段时间,当设置的时间到达之后就执行指定的功能函数,调用的这个函数叫做回调函数。回调函数的两次执行间隔叫做定时器的定时周期,简而言之,当定时器的定时周期到了以后就会执行回调函数,下面介绍一下 CubeMX 中开启定时器的方法:
在 CubeMX 里面按下面步骤添加定时器
然后配置具体参数,参数的功能如下:
参数 | 功能 |
---|---|
Timer Name | 设置定时器的名称 |
Callback | 设定定时器的回调函数体 |
Type | 设定定时器的执行类型osTimerPeriodic 定时器周期执行回调函数osTimerOnce 定时器只执行一次回调函数 |
Code Generation Option | 代码生成模式As weak: 产生一个用 __weak 修饰的弱定义任务函数,用户可自己在进行定义;As external: 产生一个外部引用的任务函数,用户需要自己定义该函数;Default: 产生一个默认格式的任务函数,用户需要在该函数内实现自己的功能 |
Parameter | 传入参数,保持默认NULL就行 |
Allocation | 软件定时器内存的分配方式,一般使用动态Static: 静态方式是直接在RAM占据一个静态空间Dynamic:动态方则是在初始配置的内存池大小数组中动态申请、释放空间 |
参数配置完成后,生成代码,我们可以在 freertos.c 文件里面看到定时器创建后获得的句柄,以及生成的回调函数:
有了句柄,我们就可以调用 cmsis_os2.c 里面的定时器接口函数对定时器进行操作,先看一下 CubeMX 提供的定时器接口函数及其功能
函数 | 功能 |
---|---|
osTimerNew | 新建定时器,返回定时器控制句柄 |
osTimerGetName | 获取定时器名称 |
osTimerStart | 设置定时器周期,启动定时器 |
osTimerStop | 停止定时器 |
osTimerIsRunning | 检测定时器是否在运行 |
osTimerDelete | 删除定时器 |
其中常用的接口是定时器的启动和停止
定时器启动: osTimerStart
,函数原型
osStatus\_t osTimerStart (osTimerId\_t timer_id, uint32\_t ticks);
参数介绍:
参数 | 功能 |
---|---|
timer_id | 需要启动的定时器句柄 |
ticks | 设置定时器的运行周期 |
此处的 ticks 设定的数字是定时器两次调用回调函数的周期数目,每个 tick 是一个心跳时钟的长度
使用例程:
void StartTask02(void \*argument)
{
/\* USER CODE BEGIN StartTask02 \*/
osStatus\_t result;
uint8\_t dat[10]={0};
uint8\_t \*pro;
result= osTimerStart(myTimer01Handle,10);
if(result == osOK)
{
//启动成功
}else
{
//启动失败
}
/\* Infinite loop \*/
for(;;)
{
osDelay(10);
}
/\* USER CODE END StartTask02 \*/
}
按照例程启动定时器,定时器会以 10个tick 的周期,调用回调函数
回调函数不要放阻塞函数,程序尽可能短
定时器启动: osTimerStop
,函数原型
osStatus\_t osTimerStop (osTimerId\_t timer_id);
参数只有一个,就是定时器的控制句柄,传入即可停止定时器,例程如下
void StartTask02(void \*argument)
{
/\* USER CODE BEGIN StartTask02 \*/
osStatus\_t result;
uint8\_t dat[10]={0};
uint8\_t \*pro;
result= osTimerStop(myTimer01Handle);
if(result == osOK)
{
//停止成功
}else
{
//停止失败
}
/\* Infinite loop \*/
for(;;)
{
osDelay(10);
}
/\* USER CODE END StartTask02 \*/
}
软件定时器是由软件定时器维护任务进行维护,检测各个定时器的状态,进行处理,回调回调函数,软件定时器维护任务的参数配置在前面的 Config 就已经提到过
5.2 CubeMX下信号量的创建和配置
信号量是 RTOS 的一个内核对象,该对象有一个队列表示该信号量拥有的信号数目,任何任务都可以对这个信号数目进行获取和释放,获取时信号-1,释放时信号+1,为0时不能继续获取,此时有任务想要继续获取信号量的话,任务会挂起在该内核对象的挂起列表,等到信号可以获取时进行恢复,根据这个特性,信号量常用于控制对共享资源的访问和任务同步,下面介绍一下 CubeMX 下信号量的配置:
点开配置页面,可以看到有两个信号量添加页面,其中 Binary Semaphores 是二值信号量,Counting Semaphores 是计数信号量,二进制信号量,仅有一个队列或者说 token,用于同步一个操作;计数信号量则拥有多个 tokens,可用于同步多个操作,或者管理有限资源
二值信号量创建:
点击 Add,配置参数
参数介绍
参数 | 功能 |
---|---|
Semaphore Name | 信号量名称 |
Allocation | 内存分配方式,一般使用动态Static: 静态方式是直接在RAM占据一个静态空间Dynamic:动态方则是在初始配置的内存池大小数组中动态申请、释放空间 |
计数信号量:
点击 Add,配置参数
参数介绍
参数 | 功能 |
---|---|
Semaphore Name | 信号量名称 |
Count | 计数信号量的最大数目 |
Allocation | 内存分配方式,一般使用动态Static: 静态方式是直接在RAM占据一个静态空间Dynamic:动态方则是在初始配置的内存池大小数组中动态申请、释放空间 |
配置完成后我们生成代码,在 freertos.c 的初始化代码中可以看到信号量被创建,并且返回了信号量的控制句柄
下面介绍一下 CubeMX 提供的信号量操作函数接口:
函数 | 功能 |
---|---|
osSemaphoreNew | 创建新的信号量 |
*osSemaphoreGetName | 获取信号量的名称 |
osSemaphoreAcquire | 获取信号量 |
osSemaphoreRelease | 释放信号量 |
osSemaphoreGetCount | 获取当前可用信号量的数目 |
osSemaphoreDelete | 删除信号量 |
其中常用的函数有获取和释放信号量,下面介绍一下这两个函数的参数和使用方式
获取信号量 osSemaphoreAcquire
函数原型
osStatus\_t osSemaphoreAcquire (osSemaphoreId\_t semaphore_id, uint32\_t timeout);
参数介绍
参数 | 功能 |
---|---|
semaphore_id | 传入要获取信号量的控制句柄 |
timeout | 获取等待时间(等待期间任务挂起在内核对象的挂起队列) |
使用例程
void StartDefaultTask(void \*argument)
{
/\* USER CODE BEGIN StartDefaultTask \*/
osStatus\_t result;
/\* Infinite loop \*/
for(;;)
{
result = osSemaphoreAcquire(myBinarySem01Handle,10);
if(result == osOK)
{
//获取成功
}else
{
//获取失败
}
osDelay(1);
}
/\* USER CODE END StartDefaultTask \*/
}
释放信号量 osSemaphoreRelease
函数原型
osStatus\_t osSemaphoreRelease (osSemaphoreId\_t semaphore_id);
参数 | 功能 |
---|---|
semaphore_id | 传入要释放的信号量控制句柄 |
使用例程
void StartDefaultTask(void \*argument)
{
/\* USER CODE BEGIN StartDefaultTask \*/
osStatus\_t result;
/\* Infinite loop \*/
for(;;)
{
result = osSemaphoreRelease(myBinarySem01Handle);
if(result == osOK)
{
//释放成功
}else
{
//释放失败
}
osDelay(1);
}
/\* USER CODE END StartDefaultTask \*/
}
二值信号量和计数信号量的操作基本一致,没用区别,只是用有的信号队列最大数目不同而已
同时注意信号量在使用过程中会出现优先级反转的Bug,使用时需要注意
六、创建互斥量
6.1 CubeMX下互斥量的创建和配置
互斥量其实就是一个拥有优先级继承的二值信号量,互斥信号量适合用于那些需要互斥访问的应用中,在互斥访问中互斥信号量相当于一个钥匙,当任务想要使用资源的时候就必须先获得这个钥匙,当使用完资源以后就必须归还这个钥匙,这样其他的任务就可以拿着这个钥匙去使用资源,与信号量不同的是,互斥量的释放必须由获取他的任务进行释放,如果不释放,可能会造成死锁
死锁就是两个任务获取对方拥有的锁,各自进入挂起列表,无法释放互斥锁
下面介绍一下 CubeMX 下互斥量的配置,在配置界面我们可用看到两个互斥量配置界面,上面的是普通互斥量,其获取只能获取一次,重复获取是无效的,而第二个则是递归互斥量,递归互斥信号量可以获取多次,但对应的也要释放多次才能让出使用权,比如我获取3次,任务要释放3次才能释放该互斥量的使用权
使用互斥量,需要点击 Add 然后配置参数
参数介绍:
参数 | 功能 |
---|---|
Mutex Name | 互斥量名称 |
Allocation | 内存分配方式,一般使用动态Static: 静态方式是直接在RAM占据一个静态空间Dynamic:动态方则是在初始配置的内存池大小数组中动态申请、释放空间 |
递归互斥信号量的配置方式与其相同,包括配置参数也相同,两者只是在用法上有些许区别,添加方式如下:
添加配置完成后,点击生成代码,在 freertos.c 文件中我们可以看到互斥量初始化完成,并且生成了对应的控制句柄
CubeMX 提供的 API 接口函数如下
函数 | 功能 |
---|---|
osMutexNew | 创建互斥量 |
*osMutexGetName | 获取互斥量名称 |
osMutexAcquire | 任务获取互斥量 |
osMutexRelease | 任务释放互斥量 |
osMutexGetOwner | 获取互斥量的拥有任务的任务 TCB |
osMutexDelete | 删除互斥量 |
主要使用到的还是互斥量的获取与释放,下面分析一下这两个函数:
获取互斥量 osMutexAcquire
函数原型
osStatus\_t osMutexAcquire (osMutexId\_t mutex_id, uint32\_t timeout);
参数介绍:
参数 | 功能 |
---|---|
mutex_id | 互斥量控制句柄 |
timeout | 获取互斥量时的等待时间(等待期间任务挂起在内核对象的挂起队列) |
使用方式
void StartTask02(void \*argument)
{
/\* USER CODE BEGIN StartTask02 \*/
osStatus\_t result;
result= osMutexAcquire(myMutex01Handle,10);
if(result == osOK)
{
//获取成功
}else
{
//获取失败
}
/\* Infinite loop \*/
for(;;)
{
osDelay(10);
}
/\* USER CODE END StartTask02 \*/
}
释放互斥量 osMutexRelease
函数原型
osStatus\_t osMutexRelease (osMutexId\_t mutex_id);
参数介绍:
参数 | 功能 |
---|---|
mutex_id | 互斥量控制句柄 |
使用方式
void StartTask02(void \*argument)
{
/\* USER CODE BEGIN StartTask02 \*/
osStatus\_t result;
result= osMutexRelease(myMutex01Handle);
if(result == osOK)
{
//释放成功
}else
{
//释放失败
}
/\* Infinite loop \*/
for(;;)
{
osDelay(10);
}
/\* USER CODE END StartTask02 \*/
}
使用方式和信号量基本相同,因为互斥量本质上就是信号量的一种
七、创建事件标志组
7.1 CubeMX下事件的创建和配置
任务间的同步除了信号量还有时间标志组,信号的同步通常是一对一的同步,有的时候系统需要多对一的同步,比如同时满足5个按键按下时,任务启动,如果使用信号会很占据资源,所以 RTOS 引入了事件标志组来满足这一需求,下面我们看一下 CubeMX 内事件标志组的配置方法:
点击 Add 创建事件标志组
配置介绍
参数 | 功能 |
---|---|
Event flags Name | 事件标志组名称 |
Allocation | 内存分配方式,一般使用动态Static: 静态方式是直接在RAM占据一个静态空间Dynamic:动态方则是在初始配置的内存池大小数组中动态申请、释放空间 |
配置完成后,生成代码,在系统初始化内,看有没有生成事件标志组控制句柄,可以看到句柄创建完成
CubeMX 提供的配置事件标志组的接口 API 如下:
函数 | 功能 |
---|---|
osEventFlagsNew | 创建事件标志组 |
*osEventFlagsGetName | 获取事件标志组名称 |
osEventFlagsSet | 设置事件标志组 |
osEventFlagsClear | 清除事件标志组 |
osEventFlagsGet | 获取当前事件组标志信息 |
osEventFlagsWait | 等待事件标志组触发 |
osEventFlagsDelete | 删除事件标志组 |
常用的 API 接口是设置事件标志组以及等待事件标志组的触发,下面我们分析一下这两个 API
在了解 API 前我们需要简单了解一下事件的触发原理:首先事件标志组的数据类型为 EventGroupHandle_t,事件标志组中的所有事件位都存储在一个无符号的 EventBits_t 类型的变量中,当 configUSE_16_BIT_TICKS 为 1 的时候事件标志组可以存储 8 个事件位,当 configUSE_16_BIT_TICKS 为 0 的时候事件标志组存储 24个事件位,每个事件位其实就是一个0或者1数字,就像下面的24位组成一个事件标志组
我们在使用事件API接口函数前需要先定义我们需要的触发事件位,比如添加如下的代码
#define event1 1<<1 //事件1
#define event2 1<<2 //事件2
编写好触发事件后,我们在看如何使用 API 接口
设置事件标志 osEventFlagsSet
函数原型
uint32\_t osEventFlagsSet (osEventFlagsId\_t ef_id, uint32\_t flags);
参数介绍:
参数 | 功能 |
---|---|
ef_id | 事件标志组控制句柄 |
flags | 事件位 |
使用方式:设置事件1和事件2
void StartDefaultTask(void \*argument)
{
/\* USER CODE BEGIN StartDefaultTask \*/
osStatus\_t result;
/\* Infinite loop \*/
for(;;)
{
result = osEventFlagsSet(myEvent01Handle,event1);
if(result == osOK)
{
//事件1设置成功
}else
{
//事件1设置失败
}
result = osEventFlagsSet(myEvent01Handle,event2);
if(result == osOK)
{
//事件2设置成功
}else
{
//事件2设置失败
}
osDelay(1);
}
/\* USER CODE END StartDefaultTask \*/
}
等待事件标志 osEventFlagsWait
函数原型
uint32\_t osEventFlagsWait (osEventFlagsId\_t ef_id, uint32\_t flags, uint32\_t options, uint32\_t timeout);
参数介绍:
参数 | 功能 |
---|---|
ef_id | 事件标志组控制句柄 |
flags | 等待的事件位 |
options | 等待事件位的操作osFlagsWaitAny :等待的事件位有任意一个等到就恢复任务osFlagsWaitAll:等待的事件位全部等到才恢复任务 osFlagsNoClear:等待成功后不清楚所等待的标志位(默认清除) |
timeout | 等待事件组的等待时间(等待期间任务挂起在内核对象的挂起队列) |
使用例子:同时等待事件1和事件2,且等待到不清除
void StartDefaultTask(void \*argument)
{
/\* USER CODE BEGIN StartDefaultTask \*/
osStatus\_t result;
/\* Infinite loop \*/
for(;;)
{
result = osEventFlagsWait(myEvent01Handle,event1|event2,osFlagsWaitAll|osFlagsNoClear,10);
if(result == osOK)
{
//等待成功
}else
{
//等待失败
}
osDelay(1);
}
/\* USER CODE END StartDefaultTask \*/
}
八、用户常量
User Constants 用于添加用户常量,将不变的量转化为常量保存,可以节省 RAM 资源空间,因为常量和变量的保存位置不同,详细了解可以参考这篇文章:C语言:内存四区
九、任务通知
FreeRTOS 的每个任务都有一个 32 位的通知值,任务控制块中的成员变量 ulNotifiedValue 就是这个通知值。任务通知是一个事件,假如某个任务通知的接收任务因为等待任务通知而阻塞的话,向这个接收任务发送任务通知以后就会解除这个任务的阻塞状态,CubeMX内没有提供相关的配置项,但在其生成的 FreeRTOS 接口里面有相关函数进行配置,函数位置如下:
接口函数功能:
函数 | 功能 |
---|---|
osThreadFlagsSet | 设置任务的通知标志 |
osThreadFlagsClear | 清除任务通知 |
osThreadFlagsGet | 获取任务标志 |
osThreadFlagsWait | 等待特定的任务标志 |
常用的两个 API 就是设置任务通知和等待任务通知函数
设置通知 osThreadFlagsSet
函数原型
uint32\_t osThreadFlagsSet (osThreadId\_t thread_id, uint32\_t flags);
![img](https://img-blog.csdnimg.cn/img_convert/aeb9c13eb68ed0a5de0cc72d26c5f02b.png)
![img](https://img-blog.csdnimg.cn/img_convert/ee1341b190b52f8ea0ff07ebdb5c06fd.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新**
**需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**
edValue 就是这个通知值。任务通知是一个事件,假如某个任务通知的接收任务因为等待任务通知而阻塞的话,向这个接收任务发送任务通知以后就会解除这个任务的阻塞状态,CubeMX内没有提供相关的配置项,但在其生成的 FreeRTOS 接口里面有相关函数进行配置,函数位置如下:
![1](https://img-blog.csdnimg.cn/8542744bd5cb45f4877b012f70237529.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBASmVja1h1NjY2,size_20,color_FFFFFF,t_70,g_se,x_16)
接口函数功能:
| 函数 | 功能 |
| --- | --- |
| osThreadFlagsSet | 设置任务的通知标志 |
| osThreadFlagsClear | 清除任务通知 |
| osThreadFlagsGet | 获取任务标志 |
| osThreadFlagsWait | 等待特定的任务标志 |
常用的两个 API 就是设置任务通知和等待任务通知函数
**设置通知 osThreadFlagsSet**
函数原型
uint32_t osThreadFlagsSet (osThreadId_t thread_id, uint32_t flags);
[外链图片转存中…(img-zjYdwjtH-1715864965218)]
[外链图片转存中…(img-beeGCPL1-1715864965218)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新
需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)