复习时间:貌似很遥远呀!(未定期)
基于小熊派的鸿蒙开发内核篇
- 一、CMSIS-RTOS2接口
- 二、HarmonyOS内核开发—任务管理
- 三、HarmonyOS内核开发—定时器管理
- 四、HarmonyOS内核开发—信号量
- 五、HarmonyOS内核开发—事件管理
- 六、HarmonyOS内核开发—互斥锁
- 七、HarmonyOS内核开发—消息队列
一、CMSIS-RTOS2接口
Cortex微控制器软件接口标准,Cortex-M系列的RTOS接口,为需要RTOS的软件组件提供了标准化API访问内核或外设。更多API参考:
https://arm-software.github.io/CMSIS_5/RTOS2/html/index.html
二、HarmonyOS内核开发—任务管理
三、HarmonyOS内核开发—定时器管理
定时器基本概念
是基于系统Tick时钟中断且由软件来模拟的定时器,当经过设定的Tick时钟计数值后会触发用户定义的回调函数。定时精度与系统Tick时钟的周期有关。
定时器运行机制
使用系统队列(FIFO)和任务资源,定时时间短优先被触发。
定时器创建实现
创建定时器:osTimerNew (osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr);
启动定时器:osTimerStart (osTimerId_t timer_id, uint32_t ticks);
停止定时器:osTimerStop (osTimerId_t timer_id);
删除定时器:osTimerDelete (osTimerId_t timer_id);
实验拓展
exec1 = 1U;
id1 = osTimerNew(Timer1_Callback, osTimerOnce, &exec1, NULL);
if (id1 != NULL)
{
// Hi3861 1U=10ms,100U=1S
timerDelay = 100U; //T1延时1s
status = osTimerStart(id1, timerDelay);
if (status != osOK) {
// Timer could not be started
}
}
osDelay(50U); //系统延时0.5s
status = osTimerStop(id1); //停止T1
if(status != osOK) {
printf("stop Timer1 failed\r\n");
/*停止失败(单次定时器未在延时时间内停止):
假设我在2s的时候去停止而T1只延时了1s,
其实已经停止了,这时再去停止就会停止失败*/
}
else
{
printf("stop Timer1 success\r\n");
//停止成功(0.5s停止会成功)
//单词定时器得在其运行期间去停止
}
status = osTimerStart(id1, timerDelay);
if (status != osOK) {
printf("start Timer1 failed\r\n");
}
osDelay(200U); //系统延时2s
status = osTimerDelete(id1); //删除T1,定时器运行期间前后都能停止
if(status != osOK) {
printf("delete Timer1 failed\r\n"); //删除失败
}
else
{
printf("delete Timer1 success\r\n"); //删除成功
}
四、HarmonyOS内核开发—信号量
信号量基本概念
互斥
同步
信号量运行机制
初始化
创建
申请-1(0状态无法申请)
释放+1
删除
信号量功能实现
创建互斥锁:osSemaphoreNew (uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr);
获取互斥锁:osSemaphoreAcquire (osSemaphoreId_t semaphore_id, uint32_t timeout);
释放互斥锁:osSemaphoreRelease (osSemaphoreId_t semaphore_id);
删除互斥锁:osMutexDelete (osMutexId_t mutex_id);
实验拓展
实验没太明白,聪明的人可以通过拓展实验而做出另一个实用性实验,我还没达到那个能力,确实努力可以弥补一些这方面的能力,目前也只有努力这种方法了,多看看基础如51/32等,形成嵌入式方向思考的能力和举一反三(我没有举一反三的聪明天赋只能努力多看多学优秀的人的智慧结晶)的能力。
首先创建任务(osThreadNew)《P10-任务管理》设置优先级为同级
osSemaphoreNew (uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr);
sem1 = osSemaphoreNew(4, 0, NULL);
五、HarmonyOS内核开发—事件管理
事件管理基本概念
任务间通信的机制,可实现任务间的同步,事件可提供一对多、多对多的同步操作。
事件管理运行机制
a任务:事件2、3逻辑或(osFlagsWaitAny)
b任务:事件2、5逻辑与(osFlagsWaitAll)
事件2发生,a任务唤醒
事件5发生,b任务才唤醒
事件管理功能实现
/***** 发送事件 *****/
void Thread_EventSender (void *argument)
{
(void)argument;
while (1)
{
osEventFlagsSet(evt_id, FLAGS_MSK1);
osThreadYield(); // suspend thread
osDelay(100);
}
}
/***** 接收事件 *****/
void Thread_EventReceiver (void *argument)
{
(void)argument;
uint32_t flags;
while (1)
{
flags = osEventFlagsWait(evt_id, FLAGS_MSK1, osFlagsWaitAny, osWaitForever);
printf("Receive Flags is %d\n",flags);
}
}
/***** 创建事件 *****/
static void Event_example (void)
{
evt_id = osEventFlagsNew(NULL);
if (evt_id == NULL) {
printf("Falied to create EventFlags!\n");
}
osThreadAttr_t attr;
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 1024*4;
attr.priority = 25;
attr.name = "Thread_EventSender";
if (osThreadNew(Thread_EventSender, NULL, &attr) == NULL) {
printf("Falied to create Thread_EventSender!\n");
}
attr.name = "Thread_EventReceiver";
if (osThreadNew(Thread_EventReceiver, NULL, &attr) == NULL) {
printf("Falied to create Thread_EventReceiver!\n");
}
}
实验拓展
/***** 发送事件 *****/
void Thread_EventSender(void *argument)
{
(void)argument;
while (1)
{
osEventFlagsSet(evt_id, FLAGS_MSK1);
osEventFlagsSet(evt_id, FLAGS_MSK2);
osEventFlagsSet(evt_id, FLAGS_MSK3);
//suspend thread
osThreadYield();
osDelay(100);
}
}
/***** 接收事件 *****/
void Thread_EventReceiver(void *argument)
{
(void)argument;
uint32_t flags;
while (1)
{
flags = osEventFlagsWait(evt_id, FLAGS_MSK1|FLAGS_MSK2|FLAGS_MSK3, osFlagsWaitAll, osWaitForever);
//多个事件对应一个任务
printf("Receive Flags is %d\n", flags);
}
}
六、HarmonyOS内核开发—互斥锁
互斥锁在操作系统中用于资源管理。微控制器中许多资源可以重复使用,但每次只能被一个线程使用(例如通信通道、内存和文件)。互斥锁用于保护对共享资源的访问。创建互斥锁,然后在线程之间传递(线程可以获取和释放互斥锁)。
互斥锁基本概念
互斥锁又称互斥型信号量,特殊的二值性信号量,对共享资源保护而实现独占式处理。
任务持有(闭锁)—任务释放(开锁)
可解决信号量存在的优先级翻转问题(优先级继承算法)。
互斥锁运行机制
互斥锁处理非共享资源的同步访问时,若有任务访问该资源,则互斥锁为加锁状态。其他任务访问会被阻塞,该锁任务释放,其他任务进行资源访问,再次上锁。如此确保同一时刻只有一个任务正在访问这个公共资源,保证了公共资源操作的完整性。
互斥锁功能实现
创建互斥锁:osMutexNew (const osMutexAttr_t *attr);
获取互斥锁:osMutexAcquire (osMutexId_t mutex_id, uint32_t timeout);
释放互斥锁:osMutexRelease (osMutexId_t mutex_id);
删除互斥锁:osMutexDelete (osMutexId_t mutex_id);
/***** 高优先级 *****/
void HighPrioThread(void)
{
osDelay(100U); // wait 1s until start actual work
while(1)
{
osMutexAcquire(mutex_id, osWaitForever); // try to acquire mutex
printf("HighPrioThread is runing.\r\n");
osDelay(300U);
osMutexRelease(mutex_id);
}
}
/***** 中优先级 *****/
void MidPrioThread(void)
{
osDelay(100U); // wait 1s until start actual work
while(1)
{
printf("MidPrioThread is runing.\r\n");
osDelay(100);
}
}
/***** 低优先级 *****/
void LowPrioThread(void)
{
while(1)
{
osMutexAcquire(mutex_id, osWaitForever); //申请
printf("LowPrioThread is runing.\r\n");
osDelay(300U); // block mutex for 5s
osMutexRelease(mutex_id); //释放
}
}
void Mutex_example(void)
{
osThreadAttr_t attr;
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 1024 * 4;
attr.name = "HighPrioThread";
attr.priority = 26;
if (osThreadNew((osThreadFunc_t)HighPrioThread, NULL, &attr) == NULL)
{
printf("Falied to create HighPrioThread!\n");
}
attr.name = "MidPrioThread";
attr.priority = 25;
if (osThreadNew((osThreadFunc_t)MidPrioThread, NULL, &attr) == NULL)
{
printf("Falied to create MidPrioThread!\n");
}
attr.name = "LowPrioThread";
attr.priority = 24;
if (osThreadNew((osThreadFunc_t)LowPrioThread, NULL, &attr) == NULL)
{
printf("Falied to create LowPrioThread!\n");
}
mutex_id = osMutexNew(NULL);
if (mutex_id == NULL)
{
printf("Falied to create Mutex!\n");
}
}
问:为什么LOW首先获取申请互斥锁呢?
答:高/中优先级都osDelay(100U);可以复习下《任务管理》中的时间概念和《软件定时器》
拓验拓展
void HighPrioThread(void)
{
// wait 1s until start actual work
osDelay(100U);
osStatus_t status;
while (1)
{
// try to acquire mutex
status = osMutexAcquire(mutex_id, osWaitForever);
//申请互斥锁并返回一个状态值
if(status != osOK) {
printf("acquire mutex failed\r\n");
//互斥锁申请失败
}
else
{
printf("acquire mutex success\r\n");
//互斥锁申请成功
}
printf("HighPrioThread is runing.\r\n");
osDelay(300U);
status = osMutexRelease(mutex_id);
//释放互斥锁
if(status != osOK) {
printf("release mutex failed\r\n");
//互斥锁释放失败
}
else
{
printf("release mutex success\r\n");
//互斥锁释放成功
}
}
}
void LowPrioThread(void)
{
osStatus_t status;
while (1)
{
status = osMutexAcquire(mutex_id, osWaitForever);
printf("LowPrioThread is runing.\r\n");
if(status != osOK) {
printf("acquire mutex failed\r\n");
}
else
{
printf("acquire mutex success\r\n");
}
// block mutex for 3s
osDelay(300U);
status = osMutexRelease(mutex_id);
if(status != osOK) {
printf("release mutex failed\r\n");
}
else
{
printf("release mutex success\r\n");
}
}
}
status = osMutexDelete(mutex_id);
//删除互斥锁并返回一个状态值
if(status != osOK) {
printf("delete mutex failed\r\n");
//删除互斥锁失败
}
else
{
printf("delete mutex success\r\n");
//删除互斥锁成功
}
status = osMutexDelete(mutex_id);
//再次删除互斥锁并返回一个状态值,再次删除肯定失败,因为互斥锁已经不存在
if(status != osOK) {
printf("delete mutex failed\r\n");
//删除互斥锁失败
}
else
{
printf("delete mutex success\r\n");
//删除互斥锁成功
}
七、HarmonyOS内核开发—消息队列
1、消息队列基本概念
2、消息队列运行机制
3、消息队列功能实现
创建消息队列:osMutexNew (const osMutexAttr_t *attr);
发送消息:osMutexAcquire (osMutexId_t mutex_id, uint32_t timeout);
获取消息:osMutexRelease (osMutexId_t mutex_id);
删除消息队列:osMutexDelete (osMutexId_t mutex_id);
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
//number of Message Queue Objects
#define MSGQUEUE_OBJECTS 16
typedef struct
{
//object data type
char *Buf;
uint8_t Idx;
} MSGQUEUE_OBJ_t;
MSGQUEUE_OBJ_t msg;
//message queue id
osMessageQueueId_t mid_MsgQueue;
void Thread_MsgQueue1(void *argument)
{
(void)argument;
//do some work...
msg.Buf = "Hello BearPi-HM_Nano!";
msg.Idx = 0U;
while (1)
{
//消息队列ID、消息内容、优先级、超时时间(0表示立刻)
//when timeout is 0, the function returns instantly
osMessageQueuePut(mid_MsgQueue, &msg, 0U, 0U);
//suspend thread
osThreadYield();
osDelay(100);
}
}
void Thread_MsgQueue2(void *argument)
{
(void)argument;
osStatus_t status;
while (1)
{
//Insert thread code here...
//wait for message
//消息队列ID、消息内容、优先级、超时时间
status = osMessageQueueGet(mid_MsgQueue, &msg, NULL, 0U);
if (status == osOK)
{
//msg为结构体类型
printf("Message Queue Get msg:%s\n", msg.Buf);
}
}
}
static void Message_example(void)
{
//创建并初始化一个消息队列对象,返回值为消息队列ID
mid_MsgQueue = osMessageQueueNew(MSGQUEUE_OBJECTS, 100, NULL);
if (mid_MsgQueue == NULL)
{
printf("Falied to create Message Queue!\n");
}
osThreadAttr_t attr;
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = 1024 * 10;
attr.priority = 25;
attr.name = "Thread_MsgQueue1";
if (osThreadNew(Thread_MsgQueue1, NULL, &attr) == NULL)
{
printf("Falied to create Thread_MsgQueue1!\n");
}
attr.name = "Thread_MsgQueue2";
if (osThreadNew(Thread_MsgQueue2, NULL, &attr) == NULL)
{
printf("Falied to create Thread_MsgQueue2!\n");
}
}
APP_FEATURE_INIT(Message_example);
4、实验拓展
num和count还不明白内部原理,虽能自圆其说,但感觉仍是一知半解。num是put和get才+1,而count是当前消息队列中的数量,对其内部全然不知(挖坑+1)
void Thread_MsgQueue1(void *argument)
{
(void)argument;
uint8_t num = 0;
//do some work...
msg.Buf = "Hello BearPi-HM_Nano!";
while (1)
{
msg.Idx = num;
osMessageQueuePut(mid_MsgQueue, &msg, 0U, 0U);
//消息队列内部计数(非阻塞态)
num++;
//suspend thread
osThreadYield();
osDelay(100);
}
}
void Thread_MsgQueue2(void *argument)
{
(void)argument;
osStatus_t status;
uint32_t count;
while (1)
{
//Insert thread code here...
//计数消息队列中的队列消息数量(包含阻塞量)
count = osMessageQueueGetCount(mid_MsgQueue);
printf("message queue get count: %d\r\n",count);
if(count == MSGQUEUE_OBJECTS)
{
//若满足最大消息队列数执行Delete
osMessageQueueDelete(mid_MsgQueue);
}
//wait for message
status = osMessageQueueGet(mid_MsgQueue, &msg, NULL, 0U);
if (status == osOK) {
printf("Message Queue Get msg idx:%d buf:%s\n", msg.Idx,msg.Buf);
}
osDelay(300);
}
}
全文从下往上熟悉程度依次递减