基于小熊派的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内核开发—事件管理

事件管理基本概念

任务间通信的机制,可实现任务间的同步,事件可提供一对多、多对多的同步操作。

事件管理运行机制

基于小熊派的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内核开发—互斥锁

互斥锁在操作系统中用于资源管理。微控制器中许多资源可以重复使用,但每次只能被一个线程使用(例如通信通道、内存和文件)。互斥锁用于保护对共享资源的访问。创建互斥锁,然后在线程之间传递(线程可以获取和释放互斥锁)。

互斥锁基本概念

互斥锁又称互斥型信号量,特殊的二值性信号量,对共享资源保护而实现独占式处理。
任务持有(闭锁)—任务释放(开锁)
可解决信号量存在的优先级翻转问题(优先级继承算法)。

互斥锁运行机制

互斥锁处理非共享资源的同步访问时,若有任务访问该资源,则互斥锁为加锁状态。其他任务访问会被阻塞,该锁任务释放,其他任务进行资源访问,再次上锁。如此确保同一时刻只有一个任务正在访问这个公共资源,保证了公共资源操作的完整性。
基于小熊派的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);
	} 
}

全文从下往上熟悉程度依次递减

上一篇:线程


下一篇:Html标签生成类