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

摘要:本文简单介绍如何编写第一个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.鸿蒙南向开发方向

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Redis中的订阅发布(三)

订阅发布 发送消息 当一个Redis客户端执行PUBLISH 命令将消息message发送给频道channel的时候&#xff0c;服务器需要执行以下 两个动作: 1.将消息message发送给channel频道的所有订阅者2.如果一个或多个模式pattern与频道channel相匹配&#xff0c;那么将消息message发送给…

开源相机管理库Aravis例程学习(二)——连续采集multiple-acquisition-main-thread

开源相机管理库Aravis例程学习&#xff08;二&#xff09;——连续采集multiple-acquisition-main-thread 简介例程代码函数说明arv_camera_set_acquisition_modearv_camera_create_streamarv_camera_get_payloadarv_buffer_newarv_stream_push_bufferarv_camera_start_acquisi…

CCleaner怎么清理软件缓存 CCleaner清理要勾选哪些 ccleanerfree下载

CCleaner软件是一款优秀的数据清理软件&#xff0c;其中没有硬盘和内存的设置&#xff0c;也不含任何广告软件&#xff0c;其出色的注册表清洁功能能够保证您的电脑更稳定运行。本文将围绕CCleaner怎么清理软件缓存&#xff0c;CCleaner清理要勾选哪些的相关内容进行介绍。 一、…

使用Hugo、Github Pages搭建自己的博客

文章目录 搭建博客框架及对比使用Hugo搭建博客使用Github Pages部署博客 搭建博客框架及对比 在众多的博客框架中&#xff0c;Hugo、Jekyll和Hexo因其出色的性能和易用性而备受推崇。 特点HugoJekyllHexo速度极高中等较高易用性高中等高&#xff08;熟悉JavaScript者&#xf…

如何应对孩子情绪化地发脾气?

你有小孩儿吗&#xff1f;是否受孩子发脾气的困扰&#xff1f;如果都没有&#xff0c;可以跳出去看看别人的文章了&#xff0c;如果有&#xff0c;可以继续往下看。 白牙有个小闺女&#xff0c;3 岁半&#xff0c;今天她看大人洗脚&#xff0c;她也想洗&#xff0c;但没来得及给…

【微信小程序——开发DAY5(黑马程序员课程)】

微信小程序——开发DAY5&#xff08;黑马程序员课程&#xff09; 使用npm包注意&#xff1a;先安装node.js安装Vant组件库使用Vant组件库定制全局主题样式API Promise化 全局数据共享&#xff08;又叫做&#xff1a;状态管理&#xff09;1.安装Mobx相关的包2.删除miniprogram.n…

音质更细腻,时尚与舒适兼备,唐麦M5耳机体验

在音乐的世界里&#xff0c;一款好的耳机就像是一位懂你的老朋友&#xff0c;它能够准确传达音乐的情感&#xff0c;让你沉浸在每一个音符中。所以无论是在通勤的路上&#xff0c;还是在健身的过程中&#xff0c;一款优质的蓝牙耳机总能为我们带来更加丰富的听觉体验。最近我最…

数据类型知识

1&#xff0c;介绍 根据数据所占的空间不同&#xff0c;把数据分为不同的数据类型 js的变量数据类型是在程序运行中&#xff0c;靠等号右边数值的值来判断的 js动态变量&#xff0c;里面的数据类型是可以变化的 2.数据类型 1.简单数据类型 程序里面&#xff0c;数字前面有…

每日OJ题_BFS解决最短路③_力扣127. 单词接龙

目录 ③力扣127. 单词接龙 解析代码 ③力扣127. 单词接龙 127. 单词接龙 难度 困难 字典 wordList 中从单词 beginWord 和 endWord 的 转换序列 是一个按下述规格形成的序列 beginWord -> s1 -> s2 -> ... -> sk&#xff1a; 每一对相邻的单词只差一个字母。…

GPT人工智能在线网页版大全

平民不参与内测&#xff0c;还能使用 ChatGPT 吗&#xff1f; 自去年 ChatGPT 爆红以来&#xff0c;关于它的消息铺天盖地。如果你真的想使用它&#xff0c;途径有很多。除了官方网站外国内还有许多 ChatGPT 的镜像网站&#xff0c;其中不乏免费的 3.5 版本。虽然有些网站需要…

Spring Task 定时任务调度

一、概念 Spring Task 是 Spring 框架的一个组件&#xff0c;它为任务调度提供了支持&#xff0c;使得开发者能够创建后台任务或定期执行的任务。通过 Spring Task&#xff0c;您可以方便地在 Java 应用程序中实现定时任务&#xff0c;比如每天凌晨进行数据同步、每小时执行一…

EasyRecovery数据恢复软件2024免费版下载亲测可用(支持win7,win10)

EasyRecovery数据恢复软件是由全球著名的数据恢复公司Ontrack出品的一款专业级数据文件恢复工具。它支持恢复多种存储介质上的数据&#xff0c;包括硬盘、光盘、U盘/移动硬盘、数码相机以及Raid文件恢复等&#xff0c;能恢复的文件类型也相当丰富&#xff0c;包括文档、表格、图…

基于Springboot+Vue的Java项目-校园周边美食探索及分享平台系统开发实战(附演示视频+源码+LW)

大家好&#xff01;我是程序员一帆&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &am…

项目:仿muduo库One-Thread-One-Loop式并发服务器

文章目录 写在前面开源仓库和项目上线其他文档说明 项目背景HTTP服务器Reactor模型Reactor模型的分类 项目介绍模式设计模块划分Server模块 模块分析 补充知识Linux提供的定时器时间轮的思想通用类型any类型 Server模块Buffer模块Socket模块Channel模块Poller模块EventLoop模块…

项目——boost搜索引擎

今天我们来写一个boost搜索引擎&#xff01; &#xff08;后续如果有更新&#xff0c;这个博客也会更新&#xff09; gitee连接:boost搜索引擎: boost搜索引擎 首先我们要介绍一下我们这个项目&#xff0c;我们项目的目的是通过我们的搜索引擎能够通过关键字查找到对应的网页…

Open3D (C++) 点云投影至主成分空间

目录 一、算法原理二、代码实现三、结果展示四、相关连接Open3D (C++) 点云投影至主成分空间由CSDN点云侠原创,爬虫自重。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、算法原理 p r o j

【数据结构】树与二叉树、树与森林部分习题与算法设计例题

目录 【数据结构】树与二叉树部分习题与算法设计例题一、单选题二、算法设计题判断二叉树是否为完全二叉树求二叉树的最小深度 以及 二叉树树高 树与二叉树知识点文章: 【数据结构】树与二叉树&#xff08;递归法先序、中序、后序、层次遍历二叉树、二叉树的建立以及求树高的方…

【MySQL数据库 | 第二十四篇】Limit语句的性能问题和调优策略

前言&#xff1a; MySQL作为最流行的关系型数据库管理系统之一&#xff0c;被广泛应用于各种规模和类型的应用程序中。其强大的功能和灵活的查询语言使得开发人员能够高效地执行各种数据操作和分析。 然而&#xff0c;在处理大量数据或复杂查询时&#xff0c;一些开发人员可能…

研究生,该学单片机还是plc。?

PLC门槛相对较低&#xff0c;但是在深入学习和应用时&#xff0c;仍然有很高的技术要求。我这里有一套单片机入门教程&#xff0c;不仅包含了详细的视频 讲解&#xff0c;项目实战。如果你渴望学习单片机&#xff0c;不妨点个关注&#xff0c;给个评论222&#xff0c;私信22&am…

仿真服务器介绍及应用

仿真服务器是一种高性能的计算设备&#xff0c;专门用于运行复杂的仿真软件和处理大量的计算任务。 仿真服务器通常具备以下特点&#xff1a; 1. 高性能硬件配置&#xff1a;为了满足仿真软件对计算能力的要求&#xff0c;仿真服务器通常配备高性能的CPU、大量的内存以及高速的…