OpenHarmony轻量系统开发【4】编写第一个程序、启动流程分析

news2024/12/23 9:56:07

摘要:本文简单介绍如何编写第一个hello world程序,以及程序是被执行的

适合群体:适用于Hi3861开发板,启动流程分析

4.1编写第一个程序

编写一个hello world程序比较简单,可以参考官网:

https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/quick-start/quickstart-lite-steps-hi3861-application-framework.md

本文在这里做下总结:

(1)确定目录结构。

开发者编写业务时,务必先在./applications/sample/wifi-iot/app路径下新建一个目录(或一套目录结构),用于存放业务源码文件。

例如:在app下新增业务my_first_app,其中hello_world.c为业务代码,BUILD.gn为编译脚本,具体规划目录结构如下:

.
└── applications
    └── sample
        └── wifi-iot
            └── app
                │── my_first_app
                │  │── hello_world.c
                │  └── BUILD.gn
                └── BUILD.gn

(2)编写业务代码。

在hello_world.c中新建业务入口函数HelloWorld,并实现业务逻辑。并在代码最下方,使用 HarmonyOS启动恢复模块接口SYS_RUN()启动业务。(SYS_RUN定义在ohos_init.h文件中)

#include <stdio.h>
#include "ohos_init.h"
#include "ohos_types.h"

void HelloWorld(void)
{
    printf("___________>>>>>>>>>>>>>>>>>>>> [DEMO] Hello world.\n");
}
SYS_RUN(HelloWorld);

(3)编写用于将业务构建成静态库的BUILD.gn文件。

如步骤1所述,BUILD.gn文件由三部分内容(目标、源文件、头文件路径)构成,需由开发者完成填写。以my_first_app为例,需要创建./applications/sample/wifi-iot/app/my_first_app/BUILD.gn,并完如下配置。

static_library("myapp") {
    sources = [
        "hello_world.c"
    ]
    include_dirs = [
        "//utils/native/lite/include"
    ]
}

static_library中指定业务模块的编译结果,为静态库文件libmyapp.a,开发者根据实际情况完成填写。

sources中指定静态库.a所依赖的.c文件及其路径,若路径中包含"//“则表示绝对路径(此处为代码根路径),若不包含”//"则表示相对路径。

include_dirs中指定source所需要依赖的.h文件路径。

(4)编写模块BUILD.gn文件,指定需参与构建的特性模块。

配置./applications/sample/wifi-iot/app/BUILD.gn文件,在features字段中增加索引,使目标模块参与编译。features字段指定业务模块的路径和目标,以my_first_app举例,features字段配置如下。

import("//build/lite/config/component/lite_component.gni")

lite_component("app") {
    features = [
        "my_first_app:myapp",
    ]

}

my_first_app是相对路径,指向./applications/sample/wifi-iot/app/my_first_app/BUILD.gn。

myapp是目标,指向./applications/sample/wifi-iot/app/my_first_app/BUILD.gn中的static_library(“myapp”)。

4.2 Hi3861相关代码结构

目前hi3861用的是liteos-m内核,但是目前hi3681的liteos-m被芯片rom化了,固化在芯片内部了。所以在harmonyOS代码是找不到hi3861的内核部分。

但是这样不妨碍我们去理清hi3861的其他代码结构。

hi3861平台配置文件位于:

vendor\hisilicon\hispark_pegasus\config.json

可以看到该配置文件有很多内容,

第一段这里指定了产品名称、版本、使用的内核类型

下面这里都是子系统:

其中我们重点关注这几个模块:

(1)applications:应用子系统

路径:applications/sample/wifi-iot/app

作用:这个路径下存放了hi3681编写的应用程序代码,例如我们刚刚写得hello world 代码就放在这个路径下。

(2)iot_hardware:硬件驱动子系统

头文件路径: base\iot_hardware\peripheral\interfaces\kits

具体代码路径,由device\board\hisilicon\hispark_pegasus\liteos_m\config.gni文件中指定:

config.gni文件内容较多,后续会一一解读

作用:存放了 hi3681 芯片相关的驱动、例如spi、gpio、uart等。

(3)xts:xts测试子系统。

这里我们先不要xts子系统,不然每次开机后,系统都要跑xts认证程序,影响我们后面测试,我们先注删除,如下:

4.3 Hi3861启动流程

由于hi3681的liteos-m被芯片rom化了,固化在芯片内部了。所以我们主要看内核启动后的第一个入口函数。

代码路径:

device\soc\hisilicon\hi3861v100\sdk_liteos\app\wifiiot_app\src\app_main.c

hi_void app_main(hi_void)
{
#ifdef CONFIG_FACTORY_TEST_MODE
        printf("factory test mode!\r\n");
#endif

    const hi_char* sdk_ver = hi_get_sdk_version();
    printf("sdk ver:%s\r\n", sdk_ver);
    printf("_____>>>>>>> lza %s %d\r\n", __FILE__, __LINE__);
    hi_flash_partition_table *ptable = HI_NULL;

    peripheral_init();
    peripheral_init_no_sleep();

#ifndef CONFIG_FACTORY_TEST_MODE
    hi_lpc_register_wakeup_entry(peripheral_init);
#endif

    hi_u32 ret = hi_factory_nv_init(HI_FNV_DEFAULT_ADDR, HI_NV_DEFAULT_TOTAL_SIZE, HI_NV_DEFAULT_BLOCK_SIZE);
    if (ret != HI_ERR_SUCCESS) {
        printf("factory nv init fail\r\n");
    }

    /* partion table should init after factory nv init. */
    ret = hi_flash_partition_init();
    if (ret != HI_ERR_SUCCESS) {
        printf("flash partition table init fail:0x%x \r\n", ret);
    }
    ptable = hi_get_partition_table();

    ret = hi_nv_init(ptable->table[HI_FLASH_PARTITON_NORMAL_NV].addr, ptable->table[HI_FLASH_PARTITON_NORMAL_NV].size,
        HI_NV_DEFAULT_BLOCK_SIZE);
    if (ret != HI_ERR_SUCCESS) {
        printf("nv init fail\r\n");
    }

#ifndef CONFIG_FACTORY_TEST_MODE
    hi_upg_init();
#endif

    /* if not use file system, there is no need init it */
    hi_fs_init();

    (hi_void)hi_event_init(APP_INIT_EVENT_NUM, HI_NULL);
    hi_sal_init();
    /* 此处设为TRUE后中断中看门狗复位会显示复位时PC值,但有复位不完全风险,量产版本请务必设为FALSE */
    hi_syserr_watchdog_debug(HI_FALSE);
    /* 默认记录宕机信息到FLASH,根据应用场景,可不记录,避免频繁异常宕机情况损耗FLASH寿命 */
    hi_syserr_record_crash_info(HI_TRUE);

    hi_lpc_init();
    hi_lpc_register_hw_handler(config_before_sleep, config_after_sleep);

#if defined(CONFIG_AT_COMMAND) || defined(CONFIG_FACTORY_TEST_MODE)
    ret = hi_at_init();
    if (ret == HI_ERR_SUCCESS) {
        hi_at_sys_cmd_register();
    }
#endif

    /* 如果不需要使用Histudio查看WIFI驱动运行日志等,无需初始化diag */
    /* if not use histudio for diagnostic, diag initialization is unnecessary */
    /* Shell and Diag use the same uart port, only one of them can be selected */
#ifndef CONFIG_FACTORY_TEST_MODE

#ifndef ENABLE_SHELL_DEBUG
#ifdef CONFIG_DIAG_SUPPORT
    (hi_void)hi_diag_init();
#endif
#else
    (hi_void)hi_shell_init();
#endif

    tcpip_init(NULL, NULL);
#endif

    ret = hi_wifi_init(APP_INIT_VAP_NUM, APP_INIT_USR_NUM);
    if (ret != HISI_OK) {
        printf("wifi init failed!\n");
    } else {
        printf("wifi init success!\n");
    }
    app_demo_task_release_mem(); /* 释放系统栈内存所使用任务 */

#ifndef CONFIG_FACTORY_TEST_MODE
    app_demo_upg_init();
#ifdef CONFIG_HILINK
    ret = hilink_main();
    if (ret != HISI_OK) {
        printf("hilink init failed!\n");
    } else {
        printf("hilink init success!\n");
    }
#endif
#endif
    OHOS_Main();
}

app_main一开始打印了 SDK版本号,中间还会有一些初始化动作,最后一行会调用OHOS_Main();

该函数原型如下:

void OHOS_Main()
{
#if defined(CONFIG_AT_COMMAND) || defined(CONFIG_FACTORY_TEST_MODE)
    hi_u32 ret;
    ret = hi_at_init();
    if (ret == HI_ERR_SUCCESS) {
        hi_u32 ret2 = hi_at_register_cmd(G_OHOS_AT_FUNC_TBL, OHOS_AT_FUNC_NUM);
        if (ret2 != HI_ERR_SUCCESS) {
            printf("Register ohos failed!\n");
        }
    }
#endif
    OHOS_SystemInit();
}

最后,OHOS_SystemInit函数进行鸿蒙系统的初始化。我们进去看下初始化做了哪些动作。

路径:base\startup\bootstrap_lite\services\source\system_init.c

void OHOS_SystemInit(void)
{

    MODULE_INIT(bsp);

    MODULE_INIT(device);

    MODULE_INIT(core);

    SYS_INIT(service);

    SYS_INIT(feature);

    MODULE_INIT(run);

    SAMGR_Bootstrap();

} 

我们可以看到主要是初始化了 一些相关模块、系统,包括有bsp、device(设备)。其中最终的是MODULE_INIT(run);

它负责调用了,所有run段的代码,那么run段的代码是哪些呢?

事实上就是我们前面application中使用SYS_RUN() 宏设置的函数名。

还记得我们前面写的hello world应用程序吗?

#include "ohos_init.h"
#include "ohos_types.h"

void HelloWorld(void)
{
    printf("[DEMO] Hello world.\n");
}

SYS_RUN(HelloWorld);

也就是说所有用SYS_RUN() 宏设置的函数都会在使用MODULE_INIT(run); 的时候被调用。

为了验证这一点,我们可以加一些打印信息,如下:

我们重新编译后烧录。打开串口查看打印信息,如下:

可以看到在27行之后,就打印 hello world的信息。符合预期。

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:

如何快速入门:https://qr21.cn/FV7h05

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

鸿蒙开发面试真题(含参考答案):https://qr18.cn/F781PH

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH

1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1597873.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【位运算 贪心】2835. 使子序列的和等于目标的最少操作次数

算法可以发掘本质&#xff0c;如&#xff1a; 一&#xff0c;若干师傅和徒弟互有好感&#xff0c;有好感的师徒可以结对学习。师傅和徒弟都只能参加一个对子。如何让对子最多。 二&#xff0c;有无限多1X2和2X1的骨牌&#xff0c;某个棋盘若干格子坏了&#xff0c;如何在没有坏…

粤嵌—2024/3/21—Pow(x,n)

代码实现&#xff1a; 方法一&#xff1a;常规解法——超时 double myPow(double x, int n) {if (n 0) {return 1.0;}if (x 1.0) {return x;}double num x;if (n > 0) {for (int i 1; i < n; i) {num num * x;}} else {n -n;for (int i 1; i < n; i) {num num…

Java编译期注解处理器AbstractProcessor使用

我们接触的注解主要分为以下两类 运行时注解&#xff1a;通过反射在运行时动态处理注解的逻辑编译时注解&#xff1a;通过注解处理器在编译期动态处理相关逻辑 编译期注解我们常用的有Lombok&#xff0c;在class文件中自动生成get和set方法 解编译期处理流程最关键的一个类就…

springMVC理解

springMVC是一种思想&#xff0c;将软件划分为&#xff0c;模型Model&#xff0c;视图View&#xff0c;控制器Controller。 MVC的工作原理&#xff1a;用户通过前端视图页面&#xff0c;发送请求到服务器&#xff0c;在服务器中请求被Controller接收&#xff0c;Controller调用…

JVM之JVM栈的详细解析

Java 栈 Java 虚拟机栈&#xff1a;Java Virtual Machine Stacks&#xff0c;每个线程运行时所需要的内存 每个方法被执行时&#xff0c;都会在虚拟机栈中创建一个栈帧 stack frame&#xff08;一个方法一个栈帧&#xff09; Java 虚拟机规范允许 Java 栈的大小是动态的或者是…

数据可视化基础与应用-04-seaborn库人口普查分析--如何做人口年龄层结构金字塔

总结 本系列是数据可视化基础与应用的第04篇seaborn&#xff0c;是seaborn从入门到精通系列第3篇。本系列主要介绍基于seaborn实现数据可视化。 参考 参考:我分享了一个项目给你《seaborn篇人口普查分析–如何做人口年龄层结构金字塔》&#xff0c;快来看看吧 数据集地址 h…

系统架构最佳实践 -- 供应链系统架构

供应链系统是现代企业管理中不可或缺的一部分&#xff0c;它涉及到从原材料采购到产品销售的整个生产流程。一个高效的供应链系统可以帮助企业实现成本控制、库存优化和客户满意度提升等目标。在本文中&#xff0c;我们将讨论供应链系统的设计与实践。 一、供应链系统设计 业务…

112 arcpy 发布 mxd地图文件 到 arcgis服务器 为 地图服务

前言 此文档主要是记录一下 最近的一次机遇 arcpy 来发布 地图文件到 arcgis服务器 上面 arcpy 主要是来自于 ArcGIS_Desktop_105_154030.zip 安装之后会在 python 的安装目录 安装另外的一份带 arcgis 的 python 环境, 然后 本文相关类库 也是基于 这个 arcpy 的 python 环境…

python 判断变量是数字型还是字符型

python如何判断数据类型&#xff1f;方法如下&#xff1a; 使用type()函数&#xff1a; import types type(x) is types.IntType # 判断是否int 类型 type(x) is types.StringType #是否string类型可以不用记住types.StringType&#xff0c;即&#xff1a; import types type(…

Ubuntu 22.04安装中文输入法

1. 安装 sudo apt install fcitx5 2. 管理已安装的语言 Setting->Region & Language->Manage Installed Language 在下图中点击“安装”&#xff0c;之后需要等一会 选择Fcitx 5 3. 添加输入法 Setting->Keyboard 点击chinese 选择你想要的输入法 重启一下&a…

安全中级-初开始

一、网络基础 重要点&#xff1a;TTL值&#xff08;防环&#xff0c;linux64.Windows128 &#xff09;&#xff0c;IP数据包包头格式字节&#xff08;20&#xff09; 标识标志偏移量起到什么作用&#xff08;数据超过1500会分片&#xff09; wireshack抓包会有一个MSS&#x…

R语言 并行计算makeCluster报错

问题&#xff1a;使用parallel包进行并行计算&#xff0c; cl <- makeCluster(detectCores()) 出现以下问题&#xff1a; 解决方式&#xff1a;用makeClusterPSOCK命令代替即可 library("future") cl <- makeClusterPSOCK(124, revtunnel TRUE, outfile &…

基于51单片机的智能小车

一、安装 二、电机模块 1.L9110S电机控制器接线 实物接线&#xff1a; 2.L9110前后左右控制小车 2.1分文件编写 2.2使用串口发送以及使用中断优化 中断&#xff1a; 2.3增加蓝牙控制 2.4设置点动的效果 2.5软件调速的原理&#xff08;参考PWM波&#xff09; 原理&#xff1a…

OpenHarmony轻量系统开发【6】驱动之ADC按键

摘要&#xff1a;本文简单介绍如何操作ADC去读取电压&#xff0c;并且实现开发板上3个ADC按键检测的功能 适合群体&#xff1a;适用于润和Hi3861开发板&#xff0c;L0轻量系统驱动开发 文中所有代码仓库&#xff1a;https://gitee.com/qidiyun/hihope-3861-smart-home-kit 6…

libVLC Ubuntu编译详解

1.简介 有时候&#xff0c;windows上开发不满足项目需求&#xff0c;需要移植到linux上&#xff0c;不得不自行编译libvlc&#xff0c;编译libvlc相对而言稍微麻烦一点。 我使用的操作系统&#xff1a;Ubuntu20.04 查看系统命令lsb_release -a libvlc版本&#xff1a; 3.0.1…

cookie与session及其区别

一、cookie 1. 为什么需要cookie&#xff1f; web程序使用HTTP协议进行传输&#xff0c;而HTTP协议是无状态的协议&#xff08;即对事务处理无记忆性&#xff0c;如果后续处理需要使用前面的信息&#xff0c;只能重传&#xff0c;导致每次连接传送的数据量增大&#xff09;。c…

Spring配置类解析与Bean扫描过程源码分析

文章目录 一、注册ConfigurationClassPostProcessor二、postProcessBeanDefinitionRegistry方法1、processConfigBeanDefinitions方法2、流程梳理3、postProcessBeanFactory方法 后记 一、注册ConfigurationClassPostProcessor Spring启动之前&#xff0c;构造AnnotatedBeanDe…

1046: 链栈基本操作的实现

解法&#xff1a;学习版看刚开始的文章 #include<iostream> #include<stack> using namespace std; #define int long long signed main() {int n, a, k;stack<int> sk;cin >> n;while (n--) {cin >> a;sk.push(a);}cin >> k;if (k >…

YOLOV5检测界面搭建+bug解决

目录 一、环境搭建 二、界面运行bug解决 三、界面 先给出Github链接&#xff1a;https://github.com/Javacr/PyQt5-YOLOv5 大佬链接&#xff1a;大佬 一、环境搭建 下载完项目后&#xff0c;需要配置环境&#xff1a; conda create -n yolov5_pyqt5 python3.8 conda act…

【洛谷 P8802】[蓝桥杯 2022 国 B] 出差 题解(带权无向图+单源最短路+Dijkstra算法+链式前向星+最小堆)

[蓝桥杯 2022 国 B] 出差 题目描述 A \mathrm{A} A 国有 N N N 个城市&#xff0c;编号为 1 … N 1 \ldots N 1…N 小明是编号为 1 1 1 的城市中一家公司的员工&#xff0c;今天突然接到了上级通知需要去编号为 N N N 的城市出差。 由于疫情原因&#xff0c;很多直达的交…