前言
此文为鸿蒙系统开发笔记【基于小熊派HarmonyOS】的后续
以下学习笔记均来自bearpi,具体安装软件以及学习视频请查看
链接: 小熊派开源社区/BearPi-HM Nano
本篇内容涉及解释功能调用函数
目录
5.3. 信号量
5.3.1. 概念
- 信号量(Semaphore)是一种实现任务间通信的机制,实现任务之间同步或临界资源的互斥访问。常用于协助一组相互竞争的任务来访问临界资源。
- 在多任务系统中,各任务之间需要同步或互斥实现临界资源的保护,信号量功能可以为用户提供这方面的支持。
- 通常一个信号量的计数值用于对应有效的资源数,表示剩下的可被占用的互斥资源数。其值的含义分两种情况:
1)0,表示没有积累下来的Post信号量操作,且有可能有在此信号量上阻塞的任务。
2)正值,表示有一个或多个Post信号量操作。 - 以同步为目的的信号量和以互斥为目的的信号量在使用有如下不同:
1)用作互斥时,信号量创建后记数是满的,在需要使用临界资源时,先取信号量,使其变空,这样其他任务需要使用临界资源时就会因为无法取到信号量而阻塞,从而保证了临界资源的安全。
2)用作同步时,信号量在创建后被置为空,任务1取信号量而阻塞,任务2在某种条件发生后,释放信号量,于是任务1得以进入READY或RUNNING态,从而达到了两个任务间的同步。
5.3.2. 运作原理
1、信号量初始化,为配置的N个信号量申请内存(N值可以由用户自行配置,受内存限制),并把所有的信号量初始化成未使用,并加入到未使用链表中供系统使用。
2、信号量创建,从未使用的信号量链表中获取一个信号量资源,并设定初值。
3、信号量申请,若其计数器值大于0,则直接减1返回成功。否则任务阻塞,等待其它任务释放该信号量,等待的超时时间可设定。当任务被一个信号量阻塞时,将该任务挂到信号量等待任务队列的队尾。
4、信号量释放,若没有任务等待该信号量,则直接将计数器加1返回。否则唤醒该信号量等待任务队列上的第一个任务。
5、信号量删除,将正在使用的信号量置为未使用信号量,并挂回到未使用链表。
6、信号量允许多个任务在同一时刻访问同一资源,但会限制同一时刻访问此资源的最大任务数目。访问同一资源的任务数达到该资源的最大数量时,会阻塞其他试图获取该资源的任务,直到有任务释放该信号量。
5.3.2.1. 信号量运作示意图:
公共资源有四个任务数,信号量都分别被线程1、2、3、4获取后,此时此资源就会锁定而不让线程5进入,线程5及后面的线程都进入阻塞模式,当线程1工作完成而释放出信号量,线程5立即获得信号而得到执行。如此往复。
5.3.3. 实现信号量功能
5.3.3.1. 常用功能
/*创建并初始化信号量对象。*/
osSemaphoreId_t osSemaphoreNew(uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr)
参数: max_count– 表示可以申请的最大可用令牌数量。 initial_count– 表示可用令牌的初始数量。 attr– 指示指向信号量属性的指针。不使用此参数。
返回: 返回信号量 ID;如果发生错误,则返回 NULL。
/*获取信号量对象的令牌。*/
//令牌可以理解为信号量控制的访问权限。当一个线程成功地获取信号量,我们可以说它获取了一个令牌。
osStatus_t osSemaphoreAcquire(osSemaphoreId_t semaphore_id, uint32_t timeout)
参数: semaphore_id– 表示信号量 ID,这是使用 osSemaphoreNew 获取的。 timeout– 表示超时持续时间。
返回: 返回 CMSIS-RTOS 运行结果。
/*释放信号量对象的标记。*/
osStatus_t osSemaphoreRelease(osSemaphoreId_t semaphore_id)
参数: semaphore_id– 表示信号量 ID,这是使用 osSemaphoreNew 获取的。
返回: 返回 CMSIS-RTOS 运行结果。
/*获取信号量对象的可用标记数。*/
uint32_t osSemaphoreGetCount(osSemaphoreId_t semaphore_id)
参数: semaphore_id– 表示信号量 ID,这是使用 osSemaphoreNew 获取的。
返回: 返回可用令牌的数目。
/*删除信号量对象。*/
osStatus_t osSemaphoreDelete(osSemaphoreId_t semaphore_id)
参数: semaphore_id– 表示信号量 ID,这是使用 osSemaphoreNew 获取的。
返回: 返回 CMSIS-RTOS 运行结果。
5.4. 事件管理
- 事件是一种实现任务间通信的机制,可用于实现任务间的同步,但事件通信只能是事件类型的通信,无数据传输。一个任务可以等待多个事件的发生:可以是任意一个事件发生时唤醒任务进行事件处理;也可以是几个事件都发生后才唤醒任务进行事件处理。事件集合用32位无符号整型变量来表示,每一位代表一个事件。
- 多任务环境下,任务之间往往需要同步操作。事件可以提供一对多、多对多的同步操作。一对多同步模型:一个任务等待多个事件的触发;多对多同步模型:多个任务等待多个事件的触发。
- 任务可以通过创建事件控制块来实现对事件的触发和等待操作。LiteOS的事件仅用于任务间的同步.
5.4.1. 运作机制
5.4.2. 实现事件功能
5.4.2.1. 常用功能
/*创建并初始化事件标志对象。*/
osEventFlagsId_t osEventFlagsNew(const osEventFlagsAttr_t *attr)
参数: attr– 指示指向事件标志属性的指针。不使用此参数。
返回: 返回事件标志 ID;如果发生错误,则返回 NULL。
/*获取事件标志对象的名称。*/
const char *osEventFlagsGetName(osEventFlagsId_t ef_id)
参数: ef_id– 指示事件标志 ID,这是使用 osEventFlagsNew 获取的。
返回: 返回事件标志名称;如果发生错误,则返回 NULL。
/*设置事件标志。*/
uint32_t osEventFlagsSet(osEventFlagsId_t ef_id, uint32_t flags)
参数: ef_id– 指示事件标志 ID,这是使用 osEventFlagsNew 获取的。 flags– 指示要设置的事件标志。
返回: 返回事件标志;如果发生错误,则返回 osFlagsErrorParameter。
/*清除事件标志。*/
uint32_t osEventFlagsClear(osEventFlagsId_t ef_id, uint32_t flags)
参数: ef_id– 指示事件标志 ID,这是使用 osEventFlagsNew 获取的。 flags– 指示要清除的事件标志。
返回: 返回事件标志;如果发生错误,则返回 osFlagsErrorParameter。
/*获取事件标志。*/
uint32_t osEventFlagsGet(osEventFlagsId_t ef_id)
参数: ef_id– 指示事件标志 ID,这是使用 osEventFlagsNew 获取的。
返回: 返回触发的事件标志。
/*等待事件标志触发。*/
uint32_t osEventFlagsWait(osEventFlagsId_t ef_id, uint32_t flags, uint32_t options, uint32_t timeout)
参数: ef_id– 指示事件标志 ID,这是使用 osEventFlagsNew 获取的。 flags– 指示要触发的事件标志。 options– 指示要触发的事件标志的配置。 timeout– 表示超时持续时间。
返回: 返回触发的事件标志;如果发生错误,则返回错误值。
/*删除事件标志对象。*/
osStatus_t osEventFlagsDelete(osEventFlagsId_t ef_id)
参数: ef_id– 指示事件标志 ID,这是使用 osEventFlagsNew 获取的。
返回: 返回 CMSIS-RTOS 运行结果。
5.5. 互斥锁
5.5.1. 基本概念
1、互斥锁又称互斥型信号量,是一种特殊的二值性信号量,用于实现对共享资源的独占式处理。
2、任意时刻互斥锁的状态只有两种:开锁或闭锁。
3、当有任务持有时,互斥锁处于闭锁状态,这个任务获得该互斥锁的所有权。
4、当该任务释放时,该互斥锁被开锁,任务失去该互斥锁的所有权。
5、当一个任务持有互斥锁时,其他任务将不能再对该互斥锁进行开锁或持有。
6、多任务环境下往往存在多个任务竞争同一共享资源的应用场景,互斥锁可被用于对共享资源的保护从而实现独占式访问。另外,互斥锁可以解决信号量存在的优先级翻转问题。
LiteOS提供的互斥锁具有如下特点:
通过优先级继承算法,解决优先级翻转问题。
5.5.2. 运作机制
- 多任务环境下会存在多个任务访问同一公共资源的场景,而有些公共资源是非共享的,需要任务进行独占式处理。互 斥锁怎样来避免这种冲突呢?
- 用互斥锁处理非共享资源的同步访问时,如果有任务访问该资源,则互斥锁为加锁状态。此时其他任务如果想访问这 个公共资源则会被阻塞,直到互斥锁被持有该锁的任务释放后,其他任务才能重新访问该公共资源,此时互斥锁再次上锁, 如此确保同一时刻只有一个任务正在访问这个公共资源,保证了公共资源操作的完整性。
5.5.3. 互斥锁功能
/*创建并初始化互斥锁。*/
osMutexId_t osMutexNew(const osMutexAttr_t *attr)
参数: attr– 指示指向互斥锁属性的指针。不使用此参数。
返回: 返回互斥锁 ID;如果发生错误,则返回 NULL。
/*获取互斥锁。*/
osStatus_t osMutexAcquire(osMutexId_t mutex_id, uint32_t timeout)
参数: mutex_id– 表示使用 osMutexNew 获取的互斥 ID。 timeout– 表示超时持续时间。
返回: 返回 CMSIS-RTOS 运行结果。
/*释放互斥锁。*/
osStatus_t osMutexRelease(osMutexId_t mutex_id)
参数: mutex_id– 表示使用 osMutexNew 获取的互斥 ID。
返回: 返回 CMSIS-RTOS 运行结果。
/*获取当前获取的互斥锁的线程 ID。*/
osThreadId_t osMutexGetOwner(osMutexId_t mutex_id)
参数: mutex_id– 表示使用 osMutexNew 获取的互斥 ID。
返回: 返回线程 ID。
/*删除互斥锁。*/
osStatus_t osMutexDelete(osMutexId_t mutex_id)
参数: mutex_id– 表示使用 osMutexNew 获取的互斥 ID。
返回: 返回 CMSIS-RTOS 运行结果。
5.6. 消息队列
5.6.1. 基本概念
消息队列,是一种常用于任务间通信的数据结构,实现了接收来自任务或中断的不固定长度的消息,并根据不同的接口选 择传递消息是否存放在自己空间。任务能够从队列里面读取消息,当队列中的消息是空时,挂起读取任务;当队列中有新 消息时,挂起的读取任务被唤醒并处理新消息。
用户在处理业务时,消息队列提供了异步处理机制,允许将一个消息放入队列,但并不立即处理它,同时队列还能起到缓 冲消息作用。
LiteOS中使用队列数据结构实现任务异步通信工作,具有如下特性:
- 消息以先进先出方式排队,支持异步读写工作方式。
- 读队列和写队列都支持超时机制。
- 发送消息类型由通信双方约定,可以允许不同长度(不超过队列节点最大值)消息。
- 一个任务能够从任意一个消息队列接收和发送消息。
- 多个任务能够从同一个消息队列接收和发送消息。
- 当队列使用结束后,如果是动态申请的内存,需要通过释放内存函数回收。
5.6.2. 运作机制
- 创建队列时,根据用户传入队列长度和消息节点大小来开辟相应的内存空间以供该队列使用,返回队列ID。
- 在队列控制块中维护一个消息头节点位置Head和一个消息尾节点位置Tail来表示当前队列中消息存储情况。Head表示队列中被占用消息的起始位置。Tail表示队列中被空闲消息的起始位置。刚创建时Head和Tail均指向队列起始位置。
- 写队列时,根据Tail找到被占用消息节点末尾的空闲节点作为数据写入对象。
- 读队列时,根据Head找到最先写入队列中的消息节点进行读取。
- 删除队列时,根据传入的队列ID寻找到对应的队列,把队列状态置为未使用,释放原队列所占的空间,对应的队列控制头置为初始状态。
5.6.3. 队列功能
/*创建并初始化消息队列。*/
osMessageQueueId_t osMessageQueueNew(uint32_t msg_count, uint32_t msg_size,const osMessageQueueAttr_t *attr)
参数: msg_count– 指示消息队列中的消息数。 msg_size– 指示消息队列中消息的大小。 attr– 指示指向消息队列属性的指针。不使用此参数。
返回: 返回消息队列 ID;如果发生错误,则返回 NULL。
/*发送消息。*/
osStatus_t osMessageQueuePut(osMessageQueueId_t mq_id, const void *msg_ptr, uint8_t msg_prio, uint32_t timeout)
参数: mq_id– 指示消息队列 ID,该 ID 是使用 osMessageQueueNew 获取的。 msg_ptr– 指示指向缓冲区的指针,用于存储要放置在消息队列中的消息。 msg_prio– 指示要放置在消息队列中的消息的优先级。 timeout– 表示超时持续时间。
返回: 返回 CMSIS-RTOS 运行结果。
/*获取消息队列中的消息。*/
osStatus_t osMessageQueueGet(osMessageQueueId_t mq_id, void *msg_ptr, uint8_t *msg_prio, uint32_t timeout)
参数: mq_id– 指示消息队列 ID,该 ID 是使用 osMessageQueueNew 获取的。 msg_ptr– 指示指向缓冲区的指针,用于存储要从消息队列中检索的消息。 msg_prio– 指示指向缓冲区的指针,用于存储要从消息队列中检索的消息的优先级。此参数可以设置为 NULL。 timeout– 表示超时持续时间。
返回: 返回 CMSIS-RTOS 运行结果。
/*获取消息队列中可放置的最大消息数。*/
uint32_t osMessageQueueGetCapacity(osMessageQueueId_t mq_id)
参数: mq_id– 指示消息队列 ID,该 ID 是使用 osMessageQueueNew 获取的。
返回: 返回最大数字
/*获取消息队列中可放置的消息的最大大小。*/
uint32_t osMessageQueueGetMsgSize(osMessageQueueId_t mq_id)
参数: mq_id– 指示消息队列 ID,该 ID 是使用 osMessageQueueNew 获取的。
返回: 返回最大消息大小。
/*获取消息队列中排队的消息数。*/
uint32_t osMessageQueueGetCount(osMessageQueueId_t mq_id)
参数: mq_id– 指示消息队列 ID,该 ID 是使用 osMessageQueueNew 获取的。
返回: 返回排队的消息数。
/*获取消息队列中消息的可用槽数。*/
uint32_t osMessageQueueGetSpace(osMessageQueueId_t mq_id)
参数: mq_id– 指示消息队列 ID,该 ID 是使用 osMessageQueueNew 获取的。
返回: 返回消息的可用插槽数。
/*删除消息队列。*/
osStatus_t osMessageQueueDelete(osMessageQueueId_t mq_id)
参数: mq_id– 指示消息队列 ID,该 ID 是使用 osMessageQueueNew 获取的。
返回: 返回 CMSIS-RTOS 运行结果。
6. GPIO
以下功能均来自wifiiot_gpio.h:
这个.h中包含声明GPIO接口函数,这些功能用于初始化GPIO。
wifiiot_gpio_ex.h:
这个.h中包含声明扩展的GPIO接口函数,这些功能用于设置GPIO拉力和驱动器强度。
6.1. GPIO引脚
6.2. GPIO中断
wifiiot_gpio.h中包含声明GPIO中断相关函数。
7. PWM
API功能来自wifiiot_pwm.h
7.1. 常用接口
//枚举 PWM 端口。
typedef enum {
/**脉宽调制0 */
WIFI_IOT_PWM_PORT_PWM0 = 0,
/**脉宽调制1 */
WIFI_IOT_PWM_PORT_PWM1 = 1,
/**脉宽调制2 */
WIFI_IOT_PWM_PORT_PWM2 = 2,
/**脉宽调制3 */
WIFI_IOT_PWM_PORT_PWM3 = 3,
/**脉宽调制4 */
WIFI_IOT_PWM_PORT_PWM4 = 4,
/**脉宽调制5 */
WIFI_IOT_PWM_PORT_PWM5 = 5,
/**最大值 */
WIFI_IOT_PWM_PORT_MAX
}WifiIlotPwmPort;
//枚举 PWM 时钟源
typedef enum {
/**160 MHz工作时钟 */
WIFI_IOT_PWM_CLK_160M,
/**24 MHz 或 40 MHz 外部晶振 */
WIFI_IOT_PWM_CLK_XTAL,
/**最大值 */
WIFI_IOT_PWM_CLK_MAX
}WifiIotPwmClkSource;
//初始化 PWM 设备。
unsigned int PwmInit(WifiIotPwmPort port)
参数: port– 表示 PWM 端口号。
返回: 如果操作成功则返回{@link WIFI_IOT_SUCCESS};
*否则返回 {@link wifiiot_errno.h} 中定义的错误代码
//取消初始化 PWM 设备。
unsigned int PwmDeinit(WifiIotPwmPort port)
参数: port– 表示 PWM 端口号。
返回: 如果操作成功则返回{@link WIFI_IOT_SUCCESS};
*否则返回 {@link wifiiot_errno.h} 中定义的错误代码
//根据输入参数输出 PWM 信号。
//该功能根据配置的分频倍数和占空比从指定端口输出 PWM 信号。
unsigned int PwmStart(WifiIotPwmPort port, unsigned short duty, unsigned short freq)
参数: port– 表示 PWM 端口号。 duty– 表示 PWM 占空比。 freq– 表示频分倍数。
//停止 PWM 信号输出。
unsigned int PwmStop(WifiIotPwmPort port)
参数: port– 表示 PWM 端口号。
8. ADC
8.1. 功能
unsigned int AdcRead(WifiIotAdcChannelIndex channel, unsigned short *data, WifiIotAdcEquModelSel equModel,WifiIotAdcCurBais curBais, unsigned short rstCnt);
//枚举 ADC 通道索引。
typedef enum {
/**通道0 */
WIFI_IOT_ADC_CHANNEL_0,
/**通道1 */
WIFI_IOT_ADC_CHANNEL_1,
/**通道2 */
WIFI_IOT_ADC_CHANNEL_2,
/**通道3 */
WIFI_IOT_ADC_CHANNEL_3,
/**通道 4 */
WIFI_IOT_ADC_CHANNEL_4,
/**通道 5 */
WIFI_IOT_ADC_CHANNEL_5,
/**通道 6 */
WIFI_IOT_ADC_CHANNEL_6,
/**频道 7 */
WIFI_IOT_ADC_CHANNEL_7,
/**按钮值 */
WIFI_IOT_ADC_CHANNEL_BUTT,
}WifiIotAdcChannelIndex;
//枚举模拟电源控制模式。
typedef enum {
/**默认控制 */
WIFI_IOT_ADC_CUR_BAIS_DEFAULT,
/**自动控制 */
WIFI_IOT_ADC_CUR_BAIS_AUTO,
/**手动控制(AVDD = 1.8V)*/
WIFI_IOT_ADC_CUR_BAIS_1P8V,
/**手动控制(AVDD = 3.3V)*/
WIFI_IOT_ADC_CUR_BAIS_3P3V,
/**按钮值 */
WIFI_IOT_ADC_CUR_BAIS_BUTT,
WifiIotAdcCurBais;
typedef enum {
/** One-equation model */
WIFI_IOT_ADC_EQU_MODEL_1,
/** Two-equation model */
WIFI_IOT_ADC_EQU_MODEL_2,
/** Four-equation model */
WIFI_IOT_ADC_EQU_MODEL_4,
/** Eight-equation model */
WIFI_IOT_ADC_EQU_MODEL_8,
/** Button value */
WIFI_IOT_ADC_EQU_MODEL_BUTT,
} WifiIotAdcEquModelSel;