LiteOS内核
这次学习鸿蒙,主要了解封装后的接口函数及其如何调用。
CMSIS是Cortex微控制器软件接口标准(Cortex Microcontroller Software Interface Standard)是ARM和一些编译器厂家以及半导体厂家共同遵循的一套标准,是由ARM专门针对Cortex-M系列提出的标准。在该标准的约定下, ARM和芯片厂商会提供一些通用的API接口来访问Cortex内核以及一些专用外设,以减少更换芯片以及开发工具等移植工作所带来的金钱以及时间上的消耗。
CMSIS-RTOS2(CMSIS-RTOS API Version 2)是Arm® Cortex®-M 处理器的通用的RTOS接口。为需要RTOS功能的软件组件提供了标准化的API。
CMSIS-RTOS2是一个通用的API,它与底层的RTOS内核无关,写应用程序的程序员在用户代码中调用CMSIS-RTOS2 API函数,可以更方便地将应用程序从一个RTOS到另一个RTOS,使用CMSIS-RTOS2 API的中间件也可以避免很多不必要的移植工作。
鸿蒙在CMSIS RTOS2 接口中封装了 LiteOS-m 的内核代码
CMSIS RTOS2 实现 :// kernel/liteos_m /kal /cmsis /cmsis_liteos2.c
鸿蒙与CMSIS接口的关系
使用时,包含cmsis_os2.h头文件。
从系统角度看,可把任务等同于线程。可把任务管理等同于多线程管理。Lite OS的任务默认有32个优先级(0-31),最低为0,最高为31。其他的可参考之前文章。
就绪态->运行态: 任务创建后进入就绪态,发生任务切换时,就绪列表中最高优先级的任务被执行,从而进入运行态, 但此刻该任务依旧在就绪列表中 。
运行态->阻塞态: 任务运行因挂起 、 读信号量等待等,在就绪列表中被删除进入阻塞 。
阻塞态->就绪态(阻塞态->运行态): 阻塞的任务被恢复后(任务恢复 、延时时间超时、读信号量超时或读到信号量等),此时被恢复的任务会被加入就绪列表,从而由阻塞态变成就绪态;此时如果被恢复任务的优先级高于正在运行任务的优先级,则会发生任务切换,将该任务由就绪态变成运行态 。
**就绪态->阻塞态:**任务也有可能在就绪态时被阻塞(挂起) 。
运行态->就绪态: 有更高优先级任务创建或者恢复后,发生任务切换而进入就绪列表 。
运行态->退出态: 任务运行结束 内核自动将此任务删除,此时由运行态变为退出态 。
阻塞态->退出态: 阻塞的任务调用删除接口,任务状态由阻塞态变为退出态 。
接口名 | 功能描述 |
---|---|
osThreadNew | 创建任务 |
osThreadTerminate | 删除任务(非自身) |
osThreadSuspend | 任务挂起 |
osThreadResume | 任务恢复 |
创建任务:
osThreadNew (osThreadFunc_t func,void * argument,const osThreadAttr_t * attr)
描述:
函数osThreadNew通过将线程添加到活动线程列表并将其设置为就绪状态来启动线程函数。线程函数的参数使用参数指针*argument传递。当创建的thread函数的优先级高于当前运行的线程时,创建的thread函数立即启动并成为新的运行线程。线程属性是用参数指针attr定义的。属性包括线程优先级、堆栈大小或内存分配的设置。可以在RTOS启动(调用osKernelStart)之前安全地调用该函数,但不能在内核初始化 (调用 osKernelInitialize)之前调用该函数。
注意 :不能在中断服务调用该函数
参数:
名字 | 描述 |
---|---|
func | 线程函数. |
argument | 作为启动参数传递给线程函数的指针 |
attr | 线程属性 |
删除某个任务:
osThreadTerminate( osThreadId_t thread_id)'
任务挂起:
osThreadSuspend(osThreadId_t thread_id)
任务恢复:
osThreadResume(osThreadId_t thread_id)
Gitee页面
页面的实验结果截图应该是错的,自己学习操作一下就好。
软件定时器,是基于系统Tick 时钟中断且由软件来模拟的定时器,当经过设定的 Tick 时钟计数值后会触发用户定义的回调函数。定时精度与系统 Tick 时钟的周期有关。
硬件定时器受硬件的限制,数量上不足以满足用户的实际需求,因此为了满足用户需求,提供更多的定时器, LiteOS 操作系统提供软件定时器功能。
软件定时器扩展了定时器的数量,允许创建更多的定时业务。
软件定时器功能上支持:
软件定时器使用了系统的一个队列和一个任务资源,软件定时器的触发遵循队列规则,先进先出。定时时间短的定时器总是比定时时间长的靠近队列头,满足优先被触发的准则。
软件定时器以Tick 为基本计时单位,当用户创建并启动一个软件定时器时, Huawei LiteOS 会根据当前系统 Tick 时间及用户设置的定时间隔确定该定时器的到期 Tick 时间,并将该定时器控制结构挂入计时全局链表。
当Tick 中断到来时,在 Tick 中断处理函数中扫描软件定时器的计时全局链表,看是否有定时器超时,若有则将超时的定时器记录下来。
Tick中断处理函数结束后,软件定时器任务(优先级为最高)被唤醒,在该任务中调用之前记录下来的定时器的超时回调函数。
接口名 | 功能描述 |
---|---|
osTimerNew | 创建定时器 |
osTimerStart | 启动定时器 |
osTimerStop | 停止定时器 |
osTimerDelete | 删除定时器 |
创建定时器:
osTimerNew (osTimerFunc_t func, osTimerType_t type, void * argument, const osTimerAttr_t *attr)
描述:
函数osTimerNew创建一个一次性或周期性计时器,并将其与一个带参数的回调函数相关联。计时器在osTimerStart启动之前一直处于停止状态。可以在RTOS启动(调用osKernelStart)之前安全地调用该函数,但不能在内核初始化 (调用 osKernelInitialize)之前调用该函数。
注意 :不能在中断服务调用该函数
参数:
名字 | 描述 |
---|---|
func | 函数指针指向回调函数. |
type | 定时器类型,osTimerOnce表示单次定时器,osTimerPeriodic周期表示周期性定时器. |
argument | 定时器回调函数的参数 |
attr | 计时器属性 |
启动定时器:
osTimerStart (osTimerId_t timer_id, uint 32 _t ticks)
描述:
函数osTimerStart启动或重新启动指定参数timer_id的计时器。参数ticks指定计时器的计数值。
注意 :不能在中断服务调用该函数
参数:
名字 | 描述 |
---|---|
timer_id | 由osTimerNew获得的计时器ID. |
ticks | 时间滴答计时器的值. |
停止定时器:
osTimerStop (osTimerId_t timer_id)
删除定时器:
osTimerDelete (osTimerId_t timer_id)
Gitee页面
在Timer_example函数中,通过osTimerNew()函数创建了回调函数为Timer1_Callback的定时器1,并通过osTimerStart()函数将该定时器设置为100个tick,因为hi3861默认10ms为一个tick,所以100个tick正好为1S钟,1S计时到后会触发Timer1_Callback()函数并打印日志。定时器2也同理为3S触发Timer2_Callback()函数并打印日志.
参照前言的文章。
接口名 | 功能描述 |
---|---|
osSemaphoreNew | 创建信号量 |
osSemaphoreAcquire | 获取信号量 |
osSemaphoreRelease | 释放信号量 |
osSemaphoreDelete | 删除信号量 |
创建信号量
osSemaphoreId_t osSemaphoreNew(uint32_t max_count,uint32_t initial_count,const osSemaphoreAttr_t *attr)
互斥锁是一种特殊的二值信号量,用于实现对共享资源的独占处理。任意时刻互斥锁的状态只有两种:开锁或闭锁。当有 任务持有时 互斥锁处于闭锁状态,这个任务获得该互斥锁的所有权。当该 任务释放时 该互斥锁被开锁,任务失去该互斥锁的所有权 。互斥锁可以解决信号量存在的优先级翻转问题 。
互斥锁运行机制与信号量类似。
接口名 | 功能描述 |
---|---|
osMutexNew | 创建互斥锁 |
osMutexAcquire | 获取互斥锁 |
osMutexRelease | 释放互斥锁 |
osMutexDelete | 删除互斥锁 |
创建信号量
osMutexId_t osMutexNew(const osMutexAttr_t *attr)
事件是一种实现任务间通信的机制,可用于实现任务间的同步,但事件通信只能是事件类型的通信,无数据传输。一个任务可以等待多个事件的发生:可以是任意一个事件发生时唤醒任务进行事件处理;也可以是几个事件都发生后才唤醒任务进行事件处理。事件集合用 32 位无符号整型变量来表示,每一位代表一个事件。
多任务环境下,任务之间往往需要同步操作。事件可以提供一对多、多对多的同步操作。一对多同步模型:一个任务等待多个事件的触发;多对多同步模型:多个任务等待多个事件的触发。
任务可以通过创建事件控制块来实现对事件的触发和等待操作。
LiteOS 的事件仅用于任务间的同步,
读事件时,可以根据入参事件掩码类型uwEventMask 读取事件的单个或者多个事件类型。事件读取成功后,如果设置 LOS_WAITMODE_CLR 会清除已读取到的事件类型,反之不会清除已读到的事件类型,需显式清除。可以通过入参选择读取模式,读取事件掩码类型中所有事件还是读取事件掩码类型中任意事件。
写事件时,对指定事件写入指定的事件类型,可以一次同时写多个事件类型。写事件会触发任务调度。
清除事件时,根据入参事件和待清除的事件类型,对事件对应位进行清 0 操作。
接口名 | 功能描述 |
---|---|
osEventFlagsNew | 创建事件标记对象 |
osEventFlagsSet | 设置事件标记 |
osEventFlagsWait | 等待事件标记触发 |
osEventFlagsDelete | 删除事件标记对象 |
创建事件标记对象
osEventFlagsId_t osEventFlagsNew(const osEventFlagsAttr_t *attr)
描述:
osEventFlagsNew函数创建了一个新的事件标志对象,用于跨线程发送事件,并返回事件标志对象标识符的指针,或者在出现错误时返回NULL。可以在RTOS启动(调用osKernelStart)之前安全地调用该函数,但不能在内核初始化 (调用 osKernelInitialize)之前调用该函数。
设置事件标记
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指定的事件标志。当这些事件标志被设置,函数立即返回。否则,线程将被置于阻塞状态。
参数:
名字 | 描述 |
---|---|
ef_id | 事件标志由osEventFlagsNew获得的ID. |
flags | 指定要等待的标志. |
options | 指定标记选项. |
timeout | 超时时间,0表示不超时 |
Gitee页面
在Event_example函数中,通过osEventFlagsNew()函数创建了事件标记ID,Thread_EventReceiver()函数中通过osEventFlagsWait()函数一直将线程置于阻塞状态,等待事件标记。在Thread_EventSender()函数中通过osEventFlagsSet()函数每隔1S设置的标志,实现任务间的同步。
消息队列
是一种常用于任务间通信的数据结构。实现了接收来自任务或中断的不固定长度的消息,并根据不同的接口选择传递消息是否存放在自己空间 。 任务能够从队列里面读取消息,当队列中的消息是空时,挂起读取任务;当队列中有新消息时,挂起的读取任务被唤醒并处理新消息 。
用户在处理业务时,消息队列提供了异步处理机制,允许将一个消息放入队列,但并不立即处理它,同时队列还能起到缓冲消息作用 。
LiteOS中使用队列数据结构实现任务异步通信工作。具有如下特性:
创建队列时根据用户传入队列长度和消息节点大小来开辟相应的内存空间以供该队列使用 返回队列 ID。
在队列控制块中维护一个消息头节点位置Head 和一个消息尾节点位置 Tail 来表示当前队列中消息存储情况。Head 表示队列中被占用消息的起始位置。Tail 表示队列中被空闲消息的起始位置。刚创建时 Head 和 Tail 均指向队列起始位置。
写队列时根据 Tail 找到被占用消息节点末尾的空闲节点作为数据写入对象 。
读队列时根据 Head 找到最先写入队列中的消息节点进行读取 。
删除队列时根据传入的队列 ID 寻找到对应的队列,把队列状态置为未使用,释放原队列所占的空间,对应的队列控制头置为初始状态。
接口名 | 功能描述 |
---|---|
osMessageQueueNew | 创建消息队列 |
osMessageQueuePut | 发送消息 |
osMessageQueueGet | 获取消息 |
osMessageQueueDelete | 删除消息队列 |
创建消息队列
osMessageQueueId_t osMessageQueueNew(uint32_t msg_count,uint32_t msg_size,const osMessageQueueAttr_t *attr)
描述:
函数osMessageQueueNew创建并初始化一个消息队列对象。该函数返回消息队列对象标识符,如果出现错误则返回NULL,可以在RTOS启动(调用osKernelStart)之前安全地调用该函数,但不能在内核初始化 (调用 osKernelInitialize)之前调用该函数。
参数:
名字 | 描述 |
---|---|
msg_count | 队列中的最大消息数. |
msg_size | 最大消息大小(以字节为单位). |
attr | 消息队列属性;空:默认值. |
发送消息
osStatus_t osMessageQueuePut(osMessageQueueId_t mq_id,const void *msg_ptr,uint8_t msg_prio,uint32_t timeout)
描述:
函数osMessageQueuePut将msg_ptr指向的消息放入参数mq_id指定的消息队列中。
参数:
名字 | 描述 |
---|---|
mq_id | 由osMessageQueueNew获得的消息队列ID. |
msg_ptr | 要发送的消息. |
msg_prio | 消息优先级. |
timeout | 超时值. |
获取消息
osStatus_t osMessageQueueGet(osMessageQueueId_t mq_id,void *msg_ptr,uint8_t *msg_prio,uint32_t timeout)
描述:
函数osMessageQueueGet从参数mq_id指定的消息队列中检索消息,并将其保存到参数msg_ptr所指向的缓冲区中。
参数:
名字 | 描述 |
---|---|
mq_id | 由osMessageQueueNew获得的消息队列ID. |
msg_ptr | 要发送的消息. |
msg_prio | 消息优先级. |
timeout | 超时值. |
Gitee页面
在Message_example函数中,通过osMessageQueueNew()函数创建了消息队列ID,Thread_MsgQueue1()函数中通过osMessageQueuePut()函数向消息队列中发送消息。在Thread_MsgQueue2()函数中通过osMessageQueueGet()函数读取消息队列中的消息比打印出来。
之前学习的时候,没有太了解事件和消息队列,这两个应该是OS独有的功能。可做深入了解。