|
|
|
本篇关键词:时钟周期、机器周期、指令周期、
|
|
|
|
|
|
|
|
[![](https://gitee.com/weharmonyos/resources/raw/master/index/05.png)](http://weharmonyos.com/blog/05.html)
|
|
|
|
|
|
|
|
|
|
|
|
[下载 >> 离线文档.鸿蒙内核源码分析(百篇博客分析.挖透鸿蒙内核).pdf](http://weharmonyos.com/resources/pdf/鸿蒙内核源码分析(百篇博客分析.挖透鸿蒙内核).zip)
|
|
|
|
|
|
|
|
基础知识相关篇为:
|
|
|
|
|
|
|
|
* [v01.12 鸿蒙内核源码分析(双向链表) | 谁是内核最重要结构体](http://weharmonyos.com/blog/01.html)
|
|
|
|
* [v02.01 鸿蒙内核源码分析(内核概念) | 名不正则言不顺](http://weharmonyos.com/blog/02.html)
|
|
|
|
* [v03.02 鸿蒙内核源码分析(源码结构) | 宏观尺度看内核结构](http://weharmonyos.com/blog/03.html)
|
|
|
|
* [v04.01 鸿蒙内核源码分析(地址空间) | 内核如何看待空间](http://weharmonyos.com/blog/04.html)
|
|
|
|
* [v05.03 鸿蒙内核源码分析(计时单位) | 内核如何看待时间](http://weharmonyos.com/blog/05.html)
|
|
|
|
* [v06.01 鸿蒙内核源码分析(宏的使用) | 为什么被翻译成了宏 ](http://weharmonyos.com/blog/06.html)
|
|
|
|
* [v07.01 鸿蒙内核源码分析(钩子框架) | 万物皆可HOOK ](http://weharmonyos.com/blog/07.html)
|
|
|
|
* [v08.04 鸿蒙内核源码分析(位图管理) | 一分钱被掰成八半使用](http://weharmonyos.com/blog/08.html)
|
|
|
|
* [v09.01 鸿蒙内核源码分析(POSIX) | 操作系统界的话事人 ](http://weharmonyos.com/blog/09.html)
|
|
|
|
* [v10.01 鸿蒙内核源码分析(main函数) | 要走了无数码农的第一次 ](http://weharmonyos.com/blog/10.html)
|
|
|
|
|
|
|
|
|
|
|
|
### 什么是时间
|
|
|
|
* 施教授说时间就是运动。地球围绕太阳公转一圈叫一年,地球自转一圈叫一天,地球自转了365天才围绕太阳转完了一圈,所以一年等于365天。这些可都是运动啊,
|
|
|
|
|
|
|
|
### 本篇说清楚时间概念
|
|
|
|
|
|
|
|
时间概念太重要了,在鸿蒙内核又是如何管理和使用时间的呢?
|
|
|
|
|
|
|
|
时间管理以系统时钟 `g_sysClock` 为基础,给应用程序提供所有和时间有关的服务。
|
|
|
|
|
|
|
|
* 用户以秒、毫秒为单位计时。
|
|
|
|
* 操作系统以Tick为单位计时,这个认识很重要。 每秒的tick大小很大程度上决定了内核调度的次数多少。
|
|
|
|
* 当用户需要对系统进行操作时,例如任务挂起、延时等,此时需要时间管理模块对Tick和秒/毫秒进行转换。
|
|
|
|
|
|
|
|
熟悉两个概念:
|
|
|
|
|
|
|
|
* Cycle(周期):系统最小的计时单位。Cycle的时长由系统主时钟频率决定,系统主时钟频率就是每秒钟的Cycle数。
|
|
|
|
* Tick(节拍):Tick是操作系统的基本时间单位,由用户配置的每秒Tick数决定,可大可小。
|
|
|
|
|
|
|
|
怎么去理解他们之间的关系呢?看几个宏定义就清楚了。
|
|
|
|
|
|
|
|
```c
|
|
|
|
#ifndef OS_SYS_CLOCK //HZ:是每秒中的周期性变动重复次数的计量
|
|
|
|
#define OS_SYS_CLOCK (get_bus_clk()) //系统主时钟频率 例如:50000000 即20纳秒震动一次
|
|
|
|
#endif
|
|
|
|
#ifndef LOSCFG_BASE_CORE_TICK_PER_SECOND
|
|
|
|
#define LOSCFG_BASE_CORE_TICK_PER_SECOND 100 //每秒Tick数,意味着正常情况下每秒100次检查
|
|
|
|
#endif
|
|
|
|
#define OS_CYCLE_PER_TICK (g_sysClock / LOSCFG_BASE_CORE_TICK_PER_SECOND) //每个tick多少机器周期
|
|
|
|
```
|
|
|
|
**时钟周期(振荡周期)**
|
|
|
|
|
|
|
|
在鸿蒙`g_sysClock`表示时钟周期,是CPU的赫兹,也就是上面说的`Cycle`,这是固定不变的,由硬件晶振的频率决定的。
|
|
|
|
`OsMain`是内核运行的第一个C函数,首个子函数就是 `osRegister`,完成对`g_sysClock`的赋值
|
|
|
|
|
|
|
|
```c
|
|
|
|
LITE_OS_SEC_TEXT_INIT VOID osRegister(VOID)
|
|
|
|
{
|
|
|
|
g_sysClock = OS_SYS_CLOCK; //获取CPU HZ
|
|
|
|
g_tickPerSecond = LOSCFG_BASE_CORE_TICK_PER_SECOND;//每秒节拍数 默认100 即一个tick = 10ms
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
```
|
|
|
|
**CPU周期也叫(机器周期)**
|
|
|
|
|
|
|
|
在鸿蒙宏`OS_CYCLE_PER_TICK`表示机器周期,`Tick`由用户根据实际情况配置。
|
|
|
|
例如:主频为1G的CPU,其振荡周期为: 1吉赫 (GHz 109 Hz) = 1 000 000 000 Hz
|
|
|
|
当Tick为100时,则1 000 000 000/100 = 10000000 ,即一个tick内可产生1千万个CPU周期。CPU就是用这1千万个周期去执行指令的。
|
|
|
|
|
|
|
|
**指令周期**
|
|
|
|
|
|
|
|
指令周期是执行一条指令所需要的时间,一般由若干个机器周期组成。指令不同,所需的机器周期数也不同。
|
|
|
|
对于一些简单的的单字节指令,在取指令周期中,指令取出到指令寄存器后,立即译码执行,不再需要其它的机器周期。
|
|
|
|
对于一些比较复杂的指令,例如转移指令、乘法指令,则需要两个或者两个以上的机器周期。
|
|
|
|
通常含一个机器周期的指令称为单周期指令,包含两个机器周期的指令称为双周期指令。
|
|
|
|
|
|
|
|
### Tick硬中断函数
|
|
|
|
|
|
|
|
```c
|
|
|
|
LITE_OS_SEC_BSS volatile UINT64 g_tickCount[LOSCFG_KERNEL_CORE_NUM] = {0};//tick计数器,系统一旦启动,一直在++, 为防止溢出,这是一个 UINT64 的变量
|
|
|
|
LITE_OS_SEC_DATA_INIT UINT32 g_sysClock;//系统时钟,是绝大部分部件工作的时钟源,也是其他所有外设的时钟的来源
|
|
|
|
LITE_OS_SEC_DATA_INIT UINT32 g_tickPerSecond;//每秒Tick数,鸿蒙默认是每秒100次,即:10ms
|
|
|
|
LITE_OS_SEC_BSS DOUBLE g_cycle2NsScale; //周期转纳秒级
|
|
|
|
/* spinlock for task module */
|
|
|
|
LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_tickSpin); //节拍器自旋锁
|
|
|
|
#define TICK_LOCK(state) LOS_SpinLockSave(&g_tickSpin, &(state))
|
|
|
|
/*
|
|
|
|
* Description : Tick interruption handler
|
|
|
|
*///节拍中断处理函数 ,鸿蒙默认10ms触发一次
|
|
|
|
LITE_OS_SEC_TEXT VOID OsTickHandler(VOID)
|
|
|
|
{
|
|
|
|
UINT32 intSave;
|
|
|
|
TICK_LOCK(intSave);
|
|
|
|
g_tickCount[ArchCurrCpuid()]++;//当前CPU核计数器
|
|
|
|
TICK_UNLOCK(intSave);
|
|
|
|
#ifdef LOSCFG_KERNEL_VDSO
|
|
|
|
OsUpdateVdsoTimeval();
|
|
|
|
#endif
|
|
|
|
#ifdef LOSCFG_KERNEL_TICKLESS
|
|
|
|
OsTickIrqFlagSet(OsTicklessFlagGet());
|
|
|
|
#endif
|
|
|
|
#if (LOSCFG_BASE_CORE_TICK_HW_TIME == YES)
|
|
|
|
HalClockIrqClear(); /* diff from every platform */
|
|
|
|
#endif
|
|
|
|
OsTimesliceCheck();//时间片检查
|
|
|
|
OsTaskScan(); /* task timeout scan *///任务扫描
|
|
|
|
#if (LOSCFG_BASE_CORE_SWTMR == YES)
|
|
|
|
OsSwtmrScan();//定时器扫描,看是否有超时的定时器
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
|
|
#if __cplusplus
|
|
|
|
}
|
|
|
|
```
|
|
|
|
**解读**
|
|
|
|
* `g_tickCount`记录每个CPU核tick的数组,每次硬中断都触发 `OsTickHandler`,每个CPU核单独计数。
|
|
|
|
* `OsTickHandler`是内核调度的动力,其中会检查任务时间片是否用完,定时器是否超时。主动delay的任务是否需要被唤醒,其本质是个硬中断,在`HalClockInit`硬时钟初始化时创建的,具体在硬中断篇中会详细讲解。
|
|
|
|
* `TICK_LOCK`是tick操作的自旋锁,宏原型`LOS_SpinLockSave`在自旋锁篇中已详细介绍。
|
|
|
|
|
|
|
|
### 功能函数
|
|
|
|
|
|
|
|
```c
|
|
|
|
#define OS_SYS_MS_PER_SECOND 1000 //一秒多少毫秒
|
|
|
|
//获取自系统启动以来的Tick数
|
|
|
|
LITE_OS_SEC_TEXT_MINOR UINT64 LOS_TickCountGet(VOID)
|
|
|
|
{
|
|
|
|
UINT32 intSave;
|
|
|
|
UINT64 tick;
|
|
|
|
/*
|
|
|
|
* use core0's tick as system's timeline,
|
|
|
|
* the tick needs to be atomic。
|
|
|
|
*/
|
|
|
|
TICK_LOCK(intSave);
|
|
|
|
tick = g_tickCount[0];//使用CPU core0作为系统的 tick数
|
|
|
|
TICK_UNLOCK(intSave);
|
|
|
|
return tick;
|
|
|
|
}
|
|
|
|
//每个Tick多少Cycle数
|
|
|
|
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_CyclePerTickGet(VOID)
|
|
|
|
{
|
|
|
|
return g_sysClock / LOSCFG_BASE_CORE_TICK_PER_SECOND;
|
|
|
|
}
|
|
|
|
//毫秒转换成Tick
|
|
|
|
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_MS2Tick(UINT32 millisec)
|
|
|
|
{
|
|
|
|
if (millisec == OS_MAX_VALUE) {
|
|
|
|
return OS_MAX_VALUE;
|
|
|
|
}
|
|
|
|
return ((UINT64)millisec * LOSCFG_BASE_CORE_TICK_PER_SECOND) / OS_SYS_MS_PER_SECOND;
|
|
|
|
}
|
|
|
|
//Tick转化为毫秒
|
|
|
|
LITE_OS_SEC_TEXT_MINOR UINT32 LOS_Tick2MS(UINT32 tick)
|
|
|
|
{
|
|
|
|
return ((UINT64)tick * OS_SYS_MS_PER_SECOND) / LOSCFG_BASE_CORE_TICK_PER_SECOND;
|
|
|
|
}
|
|
|
|
```
|
|
|
|
**说明**
|
|
|
|
* 在CPU篇中讲过,0号CPU核默认为主核,默认获取自系统启动以来的Tick数使用的是`g_tickCount[0]`
|
|
|
|
* 因每个CPU核的tick是独立计数的,所以`g_tickCount`中各值是不一样的。
|
|
|
|
* 系统的Tick数在关中断的情况下不进行计数,因为`OsTickHandler`本质是由硬中断触发的,屏蔽硬中断的情况下就不会触发`OsTickHandler`,自然也就不会有`g_tickCount[ArchCurrCpuid()]++`的计数,所以系统Tick数不能作为准确时间使用。
|
|
|
|
* 追问下,什么情况下硬中断会被屏蔽?
|
|
|
|
|
|
|
|
### 编程示例
|
|
|
|
|
|
|
|
前提条件:
|
|
|
|
* 使用每秒的Tick数LOSCFG_BASE_CORE_TICK_PER_SECOND的默认值100。
|
|
|
|
* 配好OS_SYS_CLOCK系统主时钟频率。
|
|
|
|
|
|
|
|
**时间转换**
|
|
|
|
```c
|
|
|
|
VOID Example_TransformTime(VOID)
|
|
|
|
{
|
|
|
|
UINT32 ms;
|
|
|
|
UINT32 tick;
|
|
|
|
|
|
|
|
tick = LOS_MS2Tick(10000); // 10000ms转换为tick
|
|
|
|
dprintf("tick = %d \n",tick);
|
|
|
|
ms = LOS_Tick2MS(100); // 100tick转换为ms
|
|
|
|
dprintf("ms = %d \n",ms);
|
|
|
|
}
|
|
|
|
```
|
|
|
|
**时间转换结果**
|
|
|
|
```c
|
|
|
|
tick = 1000
|
|
|
|
ms = 1000
|
|
|
|
```
|
|
|
|
|
|
|
|
**时间统计和时间延迟**
|
|
|
|
```c
|
|
|
|
LITE_OS_SEC_TEXT UINT32 LOS_TaskDelay(UINT32 tick);
|
|
|
|
VOID Example_GetTime(VOID)
|
|
|
|
{
|
|
|
|
UINT32 cyclePerTick;
|
|
|
|
UINT64 tickCount;
|
|
|
|
|
|
|
|
cyclePerTick = LOS_CyclePerTickGet();
|
|
|
|
if(0 != cyclePerTick) {
|
|
|
|
dprintf("LOS_CyclePerTickGet = %d \n", cyclePerTick);
|
|
|
|
}
|
|
|
|
tickCount = LOS_TickCountGet();
|
|
|
|
if(0 != tickCount) {
|
|
|
|
dprintf("LOS_TickCountGet = %d \n", (UINT32)tickCount);
|
|
|
|
}
|
|
|
|
LOS_TaskDelay(200);//延迟200个tick
|
|
|
|
tickCount = LOS_TickCountGet();
|
|
|
|
if(0 != tickCount) {
|
|
|
|
dprintf("LOS_TickCountGet after delay = %d \n", (UINT32)tickCount);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
**时间统计和时间延迟结果**
|
|
|
|
```c
|
|
|
|
LOS_CyclePerTickGet = 495000 //取决于CPU的频率
|
|
|
|
LOS_TickCountGet = 1 //实际情况不一定是1的
|
|
|
|
LOS_TickCountGet after delay = 201 //实际情况不一定是201,但二者的差距会是200
|
|
|
|
```
|
|
|
|
### 百文说内核 | 抓住主脉络
|
|
|
|
|
|
|
|
* 百文相当于摸出内核的肌肉和器官系统,让人开始丰满有立体感,因是直接从注释源码起步,在加注释过程中,每每有心得处就整理,慢慢形成了以下文章。内容立足源码,常以生活场景打比方尽可能多的将内核知识点置入某种场景,具有画面感,容易理解记忆。说别人能听得懂的话很重要! 百篇博客绝不是百度教条式的在说一堆诘屈聱牙的概念,那没什么意思。更希望让内核变得栩栩如生,倍感亲切。
|
|
|
|
* 与代码需不断`debug`一样,文章内容会存在不少错漏之处,请多包涵,但会反复修正,持续更新,`v**.xx` 代表文章序号和修改的次数,精雕细琢,言简意赅,力求打造精品内容。
|
|
|
|
* 百文在 < 鸿蒙研究站 | 开源中国 | 博客园 | 51cto | csdn | 知乎 | 掘金 > 站点发布,**鸿蒙研究站 | weharmonyos** 中回复 **百文** 可方便阅读。
|
|
|
|
* ![](https://gitee.com/weharmonyos/resources/raw/master/common/cate.png)
|
|
|
|
|
|
|
|
按功能模块:
|
|
|
|
|
|
|
|
* 基础知识 >> [双向链表](http://weharmonyos.com/blog/01.html) | [内核概念](http://weharmonyos.com/blog/02.html) | [源码结构](http://weharmonyos.com/blog/03.html) | [地址空间](http://weharmonyos.com/blog/04.html) | [计时单位](http://weharmonyos.com/blog/05.html) | [宏的使用](http://weharmonyos.com/blog/06.html) | [钩子框架](http://weharmonyos.com/blog/07.html) | [位图管理](http://weharmonyos.com/blog/08.html) | [POSIX](http://weharmonyos.com/blog/09.html) | [main函数](http://weharmonyos.com/blog/10.html) |
|
|
|
|
* 进程管理 >> [调度故事](http://weharmonyos.com/blog/11.html) | [进程控制块](http://weharmonyos.com/blog/12.html) | [进程空间](http://weharmonyos.com/blog/13.html) | [线性区](http://weharmonyos.com/blog/14.html) | [红黑树](http://weharmonyos.com/blog/15.html) | [进程管理](http://weharmonyos.com/blog/16.html) | [Fork进程](http://weharmonyos.com/blog/17.html) | [进程回收](http://weharmonyos.com/blog/18.html) | [Shell编辑](http://weharmonyos.com/blog/19.html) | [Shell解析](http://weharmonyos.com/blog/20.html) |
|
|
|
|
* 任务管理 >> [任务控制块](http://weharmonyos.com/blog/21.html) | [并发并行](http://weharmonyos.com/blog/22.html) | [就绪队列](http://weharmonyos.com/blog/23.html) | [调度机制](http://weharmonyos.com/blog/24.html) | [任务管理](http://weharmonyos.com/blog/25.html) | [用栈方式](http://weharmonyos.com/blog/26.html) | [软件定时器](http://weharmonyos.com/blog/27.html) | [控制台](http://weharmonyos.com/blog/28.html) | [远程登录](http://weharmonyos.com/blog/29.html) | [协议栈](http://weharmonyos.com/blog/30.html) |
|
|
|
|
* 内存管理 >> [内存规则](http://weharmonyos.com/blog/31.html) | [物理内存](http://weharmonyos.com/blog/32.html) | [虚拟内存](http://weharmonyos.com/blog/33.html) | [虚实映射](http://weharmonyos.com/blog/34.html) | [页表管理](http://weharmonyos.com/blog/35.html) | [静态分配](http://weharmonyos.com/blog/36.html) | [TLFS算法](http://weharmonyos.com/blog/37.html) | [内存池管理](http://weharmonyos.com/blog/38.html) | [原子操作](http://weharmonyos.com/blog/39.html) | [圆整对齐](http://weharmonyos.com/blog/40.html) |
|
|
|
|
* 通讯机制 >> [通讯总览](http://weharmonyos.com/blog/41.html) | [自旋锁](http://weharmonyos.com/blog/42.html) | [互斥锁](http://weharmonyos.com/blog/43.html) | [快锁使用](http://weharmonyos.com/blog/44.html) | [快锁实现](http://weharmonyos.com/blog/45.html) | [读写锁](http://weharmonyos.com/blog/46.html) | [信号量](http://weharmonyos.com/blog/47.html) | [事件机制](http://weharmonyos.com/blog/48.html) | [信号生产](http://weharmonyos.com/blog/49.html) | [信号消费](http://weharmonyos.com/blog/50.html) | [消息队列](http://weharmonyos.com/blog/51.html) | [消息封装](http://weharmonyos.com/blog/52.html) | [消息映射](http://weharmonyos.com/blog/53.html) | [共享内存](http://weharmonyos.com/blog/54.html) |
|
|
|
|
* 文件系统 >> [文件概念](http://weharmonyos.com/blog/55.html) | [文件故事](http://weharmonyos.com/blog/56.html) | [索引节点](http://weharmonyos.com/blog/57.html) | [VFS](http://weharmonyos.com/blog/58.html) | [文件句柄](http://weharmonyos.com/blog/59.html) | [根文件系统](http://weharmonyos.com/blog/60.html) | [挂载机制](http://weharmonyos.com/blog/61.html) | [管道文件](http://weharmonyos.com/blog/62.html) | [文件映射](http://weharmonyos.com/blog/63.html) | [写时拷贝](http://weharmonyos.com/blog/64.html) |
|
|
|
|
* 硬件架构 >> [芯片模式](http://weharmonyos.com/blog/65.html) | [ARM架构](http://weharmonyos.com/blog/66.html) | [指令集](http://weharmonyos.com/blog/67.html) | [协处理器](http://weharmonyos.com/blog/68.html) | [工作模式](http://weharmonyos.com/blog/69.html) | [寄存器](http://weharmonyos.com/blog/70.html) | [多核管理](http://weharmonyos.com/blog/71.html) | [中断概念](http://weharmonyos.com/blog/72.html) | [中断管理](http://weharmonyos.com/blog/73.html) |
|
|
|
|
* 内核汇编 >> [编码方式](http://weharmonyos.com/blog/74.html) | [汇编基础](http://weharmonyos.com/blog/75.html) | [汇编传参](http://weharmonyos.com/blog/76.html) | [可变参数](http://weharmonyos.com/blog/77.html) | [开机启动](http://weharmonyos.com/blog/78.html) | [进程切换](http://weharmonyos.com/blog/79.html) | [任务切换](http://weharmonyos.com/blog/80.html) | [中断切换](http://weharmonyos.com/blog/81.html) | [异常接管](http://weharmonyos.com/blog/82.html) | [缺页中断](http://weharmonyos.com/blog/83.html) |
|
|
|
|
* 编译运行 >> [编译过程](http://weharmonyos.com/blog/84.html) | [编译构建](http://weharmonyos.com/blog/85.html) | [GN语法](http://weharmonyos.com/blog/86.html) | [忍者无敌](http://weharmonyos.com/blog/87.html) | [ELF格式](http://weharmonyos.com/blog/88.html) | [ELF解析](http://weharmonyos.com/blog/89.html) | [静态链接](http://weharmonyos.com/blog/90.html) | [重定位](http://weharmonyos.com/blog/91.html) | [动态链接](http://weharmonyos.com/blog/92.html) | [进程映像](http://weharmonyos.com/blog/93.html) | [应用启动](http://weharmonyos.com/blog/94.html) | [系统调用](http://weharmonyos.com/blog/95.html) | [VDSO](http://weharmonyos.com/blog/96.html) |
|
|
|
|
* 调测工具 >> [模块监控](http://weharmonyos.com/blog/97.html) | [日志跟踪](http://weharmonyos.com/blog/98.html) | [系统安全](http://weharmonyos.com/blog/99.html) | [测试用例](http://weharmonyos.com/blog/100.html) |
|
|
|
|
* 前因后果 >> [总目录](http://weharmonyos.com/blog/101.html) | [源码注释](http://weharmonyos.com/blog/102.html) | [静态站点](http://weharmonyos.com/blog/103.html) | [参考手册](http://weharmonyos.com/blog/104.html) |
|
|
|
|
|
|
|
|
### 百万注源码 | 处处扣细节
|
|
|
|
|
|
|
|
* 百万汉字注解内核目的是要看清楚其毛细血管,细胞结构,等于在拿放大镜看内核。内核并不神秘,带着问题去源码中找答案是很容易上瘾的,你会发现很多文章对一些问题的解读是错误的,或者说不深刻难以自圆其说,你会慢慢形成自己新的解读,而新的解读又会碰到新的问题,如此层层递进,滚滚向前,拿着放大镜根本不愿意放手。
|
|
|
|
* [< gitee](https://gitee.com/weharmony/kernel_liteos_a_note) | [github](https://github.com/kuangyufei/kernel_liteos_a_note) | [coding](https://weharmony.coding.net/public/harmony/kernel_liteos_a_note/git/files) | [gitcode >](https://gitcode.net/kuangyufei/kernel_liteos_a_note) 四大码仓推送 | 同步官方源码,**鸿蒙研究站 | weharmonyos** 中回复 **百万** 可方便阅读。
|
|
|
|
|
|
|
|
[![](https://gitee.com/weharmony/kernel_liteos_a_note/widgets/widget_card.svg?colors=393222,ebdfc1,fffae5,d8ca9f,393222,a28b40)](https://gitee.com/weharmony/kernel_liteos_a_note)
|
|
|
|
### 关注不迷路 | 代码即人生
|
|
|
|
|
|
|
|
![](https://gitee.com/weharmonyos/resources/raw/master/common/so1so.png)
|
|
|
|
|
|
|
|
据说喜欢点赞分享的,后来都成了大神。:)
|
|
|
|
|
|
|
|
|