【鸿蒙设备开发笔记】openharmony内核开发(一),任务管理、定时器,多实例讲解

【鸿蒙设备开发笔记】openharmony内核开发(一),多实例讲解

------任务管理、定时器、实例


CMSIS-RTOS2接口

简介

CMSIS是Cortex微控制器软件接口标准,是由ARM专门针对Cortex-M系列提出的标准。

CMSIS-RTOS2是一个通用的API,它与底层的RTOS内核无关,写应用程序的程序员在用户代码中调用


简单来说,这就是一套API函数可以让开发人员直接调用,不必过多关注内核,同时转用其他芯片的时候也可以减少代码的修改


官网有很详细的介绍 :点这里
在这里插入图片描述

在鸿蒙内

鸿蒙在CMSIS-RTOS2接口中封装了LiteOS-m的内核代码

在源码中实现的目录位置:
//kernel/liteos_m/kal/cmsis/cmsis_liteos2.c

具体关系图如下显示
在这里插入图片描述
如果你需要在业务代码使用相关api,需要包含“cmsis_os2.h”

通过调用“cmsis_os2.h”中的API函数使用系统相关功能

任务管理

概念


系统

  • 任务是竞争系统资源的最小运行单元。任务可以使用或等待CPU、使用内存空间等系统资源,并独
    立于其它任务运行。
  • LiteOS的任务模块可以给用户提供多个任务,实现了任务之间的切换和通信。用户可以把注意力放在功能的实现中。
  • LiteOS中的任务是抢占式调度机制,高优先级的任务可打断低优先级任务,低优先级任务必须在高优先级任务阻塞或结束后才能得到调度,同时支持时间片轮转调度方式。
  • LiteOS的任务默认有32个优先级(0-31),最高优先级为0,最低优先级为31。

任务状态

任务状态通常分为以下四种:

  • 就绪态(Ready):该任务在就绪列表中,等待CPU运行它。
  • 运行态(Running):该任务正在执行。
  • 阻塞态(Blocked):该任务不在就绪列表中。包含任务被挂起、任务被延时、任务正在等待信号量、读写队列或者等待读写事件等。
  • 退出态(Dead):该任务运行结束,等待系统回收资源。

名词介绍

  • 任务ID:在任务创建时通过参数返回给用户,作为任务的一个非常重要的标识。
  • 任务优先级:优先级表示任务执行的优先顺序。
  • 任务入口函数:每个新任务得到调度后将执行的函数。
  • 任务控制块TCB:每一个任务都含有一个任务控制块(TCB)。TCB包含了任务上下文栈指针(stack pointer)、任务状态、任务优先级、任务ID、任务名、任务栈大小等信息。TCB可以反映出每个任务运行情况。
  • 任务栈:每一个任务都拥有一个独立的栈空间,我们称为任务栈。
  • 任务上下文:任务在运行过程中使用到的一些资源,如寄存器等,我们称为任务上下文。LiteOS在任务挂起的时候会将本任务的任务上下文信息,保存在自己的任务栈里面,以便任务恢复后,从栈空间中恢复挂起时的上下文信息,从而继续执行被挂起时被打断的代码。
  • 任务切换:任务切换包含获取就绪列表中最高优先级任务、切出任务上下文保存、切入任务上下文恢复等动作

任务状态迁移说明:

  • 就绪态→运行态:任务创建后进入就绪态,发生任务切换时,就绪列表中最高优先级的任务被执行,从而进入运行态,但此刻该任务依旧在就绪列表中。
  • 运行态→阻塞态:任务运行因挂起、读信号量等待等,在就绪列表中被删除进入阻塞。
  • 阻塞态→就绪态(阻塞态→运行态):阻塞的任务被恢复后(任务恢复、延时时间超时、读信号量超时或读到信号量等),此时被恢复的任务会被加入就绪列表,从而由阻塞态变成就绪态;此时如果被恢复任务的优先级高于正在运行任务的优先级,则会发生任务切换,将该任务由就绪态变成运行态。
  • 就绪态→阻塞态:任务也有可能在就绪态时被阻塞(挂起)。
  • 运行态→就绪态:有更高优先级任务创建或者恢复后,发生任务切换而进入就绪列表。
  • 运行态→退出态:任务运行结束,内核自动将此任务删除,此时由运行态变为退出态。
  • 阻塞态→退出态:阻塞的任务调用删除接口,任务状态由阻塞态变为退出态

创建

创建任务接口详解:

osThreadNew(osThreadFunc_t func, void * argument, const osThreadAttr_t * attr)
参数名称描述
func任务函数名称
argument作为启动参数传递给任务函数的指针(一般填NULL)
attr任务入口函数的参数列表
返回值任务ID

完整代码在鸿蒙源码中的实例代码 A1_kernal_thread


/*****任务创建*****/
static void Thread_example(void)
{
    osThreadAttr_t attr;

    attr.name = "thread1";  //函数名称
    attr.attr_bits = 0U;     //属性位  用来设置下面这个函数会不会被使用,0U不能使用,1U可以使用
    attr.cb_mem = NULL;//控制块的指针,目前不使用
    attr.cb_size = 0U; //控制快大小 写0U
    attr.stack_mem = NULL;//任务栈,目前不使用


    attr.stack_size = 1024 * 4;//但是任务栈大小要设置 ,一定要是8字节对齐的大小
    attr.priority = 25;//任务优先级,这里是数字越大,优先级越高
//---------将上述参数传递,并创建任务
    if (osThreadNew((osThreadFunc_t)thread1, NULL, &attr) == NULL)
    {
        printf("Falied to create thread1!\n");
    }   
 //-----------------------------
    attr.name = "thread2";//重新设置任务函数名,如果其他参数不修改,可以不改
    attr.priority = 24;//任务优先级,
//-------------------创建第二个任务
    if (osThreadNew((osThreadFunc_t)thread2, NULL, &attr) == NULL)
    {
        printf("Falied to create thread2!\n");
    }
}

APP_FEATURE_INIT(Thread_example);  //创建任务 

任务优先级一样的情况下,先创建的任务会先运行
延时期间,任务从运行态变为阻塞态

删除、挂起、恢复

删除某个任务:osThreadTerminate(osThreadId_t thread_id);
任务挂起:osThreadSuspend(osThreadId_t thread_id)
任务恢复:osThreadResume (osThreadId_t thread_id)

三个函数的的参数返回值都为:

参数名称描述
thread_id任务ID
返回值成功则返回“osOK”

任务创建实例

代码

#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"

osThreadId_t thread1id;
osThreadId_t thread2id;
/*****任务一*****/
void thread1(void)     //优先级高先执行
{
   osDelay(200U); //延时等待系统打印完毕
   printf("This is BearPi Harmony Thread1111------------\r\n");
   osDelay(10);      //延时,1函数挂起,2函数可以执行
   printf("qian duan-------------------------\r\n");   //1的优先级高,所以抢先执行,在2函数还没有打印10个就插入中间打印
   osThreadSuspend(thread1id);  //将1函数挂起,2函数又继续打印
   printf("chong xin--------------------\r\n");   //恢复后打印
   osThreadTerminate(thread1id);  //删除1

}

/*****任务二*****/
void thread2(void)   //1函数挂起后,执行
{
    osDelay(200U);  //延时等待系统打印完毕
    for (int i = 0;i<10;i++)   //打印10次,但是因为1函数延时结束,进入就绪态,而1的优先级高,所以抢先执行
    {
        printf("This is BearPi Harmony Thread22222-----------------------\r\n");
    }
    osThreadResume (thread1id);   //打印完成后,恢复1函数,1函数被恢复进入就绪态,而1的优先级高,所以抢先执行
    osThreadTerminate(thread2id);//删除2

}

/*****任务创建*****/
static void Thread_example(void)
{
    osThreadAttr_t attr;

    attr.name = "thread1";  //函数名称
    attr.attr_bits = 0U;    //属性位
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 1024 * 4;
    attr.priority = 25;
    thread1id = osThreadNew((osThreadFunc_t)thread1, NULL, &attr);
    if (thread1id == NULL)
    {
        printf("Falied to create thread1!\n");
    }   
    attr.name = "thread2";
    attr.priority = 21;
    thread2id = osThreadNew((osThreadFunc_t)thread2, NULL, &attr);
    if (thread2id == NULL)
    {
        printf("Falied to create thread2!\n");
    }
}

APP_FEATURE_INIT(Thread_example);

现象

在这里插入图片描述

解释

1任务优先级高,先执行,打印’1111111‘,

然后1任务延时挂起,2任务开始运行,打印’2222‘,

1任务延时结束进入就绪态,1任务优先级比2任务高,抢断2任务执行,打印“qian duan”,

然后1任务挂起,2任务继续打印完10个‘22222’,

结束后,1任务恢复,打印”chong xin“,

1任务删除,2任务删除,无输出了

定时器

鸿蒙提供了软件定时器


概念

软件定时器,是基于系统Tick时钟中断且由软件来模拟的定时器,当经过设定的Tick时钟计数值后会触发用户定义的回调函数。定时精度与系统Tick时钟的周期有关。

硬件定时器受硬件的限制,数量上不足以满足用户的实际需求,因此为了满足用户需求,提供更多的定时器,LiteOS操作系统提供软件定时器功能。

软件定时器扩展了定时器的数量,允许创建更多的定时业务。


软件定时器功能上支持:
⚫ 静态裁剪:能通过宏关闭软件定时器功能。
⚫ 软件定时器创建。
⚫ 软件定时器启动。
⚫ 软件定时器停止。
⚫ 软件定时器删除。
⚫ 软件定时器剩余Tick数获取。


软件定时器使用了系统的一个队列和一个任务资源,软件定时器的触发遵循队列规则,先进先出

定时时间短的定时器总是比定时时间长的靠近队列头,满足优先被触发的准则。短的定时器将优先触发

软件定时器以Tick为基本计时单位,当用户创建并启动一个软件定时器时,Huawei LiteOS会根据当前系统Tick时间及用户设置的定时间隔确定该定时器的到期Tick时间,并将该定时器控制结构挂入计时全局链表。

当Tick中断到来时,在Tick中断处理函数中扫描软件定时器的计时全局链表,看是否有定时器超时,若有则将超时的定时器记录下来。

Tick中断处理函数结束后,软件定时器任务(优先级为最高)被唤醒,在该任务中调用之前记录下来的定时器的超时回调函数。


定时器使用

创建定时器:osTimerNew (osTimerFunc_t func, osTimerType_t type, void *argument, const osTimerAttr_t *attr);
参数名称描述
osTimerFunc_t func定时器回调函数名
osTimerType_t type定时器类型可选:单次(osTimerOnce)还是循环(osTimerPeriodic)
void *argument给回调函数的参数
const osTimerAttr_t *attr定时器属性,一般不设置 填NULL
返回值定时器ID
启动定时器:osTimerStart (osTimerId_t timer_id, uint32_t ticks);
参数名称描述
osTimerId_t timer_id定时器ID
uint32_t ticks超时时间
返回值启动成功返回“osOK”

软件定时器以Tick为基本计时单位,在Hi2861内 1U = 10ms,100U = 1s。

停止定时器:osTimerStop (osTimerId_t timer_id);
除定时器:osTimerDelete (osTimerId_t timer_id);

以上两个函数皆为

参数名称描述
osTimerId_t timer_id定时器ID
返回值启动成功返回“osOK”

单次定时器在超时后会自动停止,若再次去操作停止函数会停止失败(返回的不是osOK),但是程序还是会继续运行

无论定时器启动还是停止的可以调用删除定时器,这两个都会返回是否停止/删除成功,成功返回“osOK”

定时器实例

代码

#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"

uint32_t exec1, exec2;

/***** 定时器1 回调函数 *****/
void Timer1_Callback(void *arg)
{
    (void)arg;
    printf("This is BearPi Harmony Timer1_Callback!\r\n");
}

/***** 定时器2 回调函数 *****/
void Timer2_Callback(void *arg)
{
    (void)arg;
    printf("This is BearPi Harmony Timer2_Callback!\r\n");
}

/***** 定时器创建 *****/
static void Timer_example(void)
{
    osTimerId_t id1, id2;
    uint32_t timerDelay;
    osStatus_t status;

    exec1 = 1U;
    id1 = osTimerNew(Timer1_Callback, osTimerOnce, &exec1, NULL);//创建定时器
    if (id1 != NULL)
    {

        // Hi3861 1U=10ms,100U=1S
        timerDelay = 100U;

        status = osTimerStart(id1, timerDelay);  //启动定时器
        if (status != osOK)
        {
            // Timer could not be started
        }
    }
    osDelay(200U);   //延时2s
    status = osTimerStop(id1);   //定时器关闭
    
    if(status != osOK)
    {
        printf("Stop timer failed \r\n");

    }
    else 
    {
        printf("Stop timer succse \r\n");
    }
    status = osTimerStart(id1, timerDelay);
    if (status != osOK)
    { 
       printf("start timer failed \r\n");
    }
    else 
    {
        printf("start timer succse \r\n");
    }
    osDelay(200U);

    status = osTimerDelete(id1);
    if(status != osOK)
    {
    printf("delete Timer1 failed\r\n");
    }
    else
    {
    printf("delete Timer1 success\r\n");
    }

    exec2 = 1U;
    id2 = osTimerNew(Timer2_Callback, osTimerPeriodic, &exec2, NULL);
    if (id2 != NULL)
    {

        // Hi3861 1U=10ms,300U=3S
        timerDelay = 300U;

        status = osTimerStart(id2, timerDelay);
        if (status != osOK)
        {
            // Timer could not be started
        }
    }
}

APP_FEATURE_INIT(Timer_example);

现象

在这里插入图片描述

说明

定时器开启定时1s,且是单次定时器
而我们在两秒后关闭定时器,这个时候定时器已经定时结束,自动退出了
所以定时器关闭失败,而定时器2正常运行

  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GuanFuXinCSDN

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值