2020征文-開發板 基于鴻蒙Hi3861平臺的HarmonyOS Device開發體驗
https://harmonyos.51cto.com/#zz
"剩蛋老人"哼著”金顧拜“來了HarmonyOS Device 開發體驗
大家好,我是不務正業的非著名 Copy 攻城獅,此篇應是 Copy 攻城獅 2020 年最后一個”Hello,World“--基于 Harmony OS 的 Hi3861 開發板進行物聯網應用開發實戰。Copy 攻城獅的“Hello World”之路從來都不是一帆風順的,此次嘗試開(拷)發(貝)物聯網應用也走了不少彎路,最后終于跑通了蜂鳴器版的《Jingle Bells》.
環境搭建篇
編程界有個傳承了幾十年的”規矩“--入門先從環境搭建開始,有的時候環境搭建比較簡單,比如學習 HTML 編程,有瀏覽器就行;有時候又比較繁瑣,比如 React Native 開發,需要安裝 NodeJS、Python、Java、Android SDK……而 HarmonyOS Device 開發屬于后者,環境搭建比較繁瑣,比如需要 Linux 系統進行編譯,燒錄到設備時又需要用到 Windows。如果您還想體驗 Wifi 模組或者“碰一碰”等其他功能,還需要提供熱點及其他設備。HarmonyOS 官方提供了詳細的環境搭建文檔以及 Hi3861 開發板介紹理論上跟著文檔走一遍就能正常運行“Hello,HarmonyOS Device”。

盡管如此,不過每個人的開發習慣或者工具口味不一樣,因此在實際搭建環境的時候還是會和官方文檔有些不一樣的地方。由于手頭有點乞丐版的云主機資源,因此我選擇將他們派上用場,用 Linux 的云主機作為編譯機,在本地的 Window 10 電腦上安裝 SFTP Drive 將 Linux 云主機掛載到本機,使得燒錄的時候能直接讀取到 Linux 上的文件;通過 VSCode 的 Remote SSH 擴展以及 HUAWEI DevEco Device Tool 擴展來開發調試代碼,此外通過某大佬分享的 sscom 串口調試工具進行更加便捷的調試。如果您恰好和我一樣的情況,或者您也想嘗試一下我的搭建思路,那我們就開始吧!
1. Windows 環境(開發、調試、燒錄)
在 Windows 上,因為涉及到開發調試,因此我們需要安裝 VS Code 及擴展(也就是插件)、SFTP Drive(燒錄時用來直接訪問 Linux 上的文件)、CH341SER.EXE(USB 轉串口驅動)、sscom(可選,方面連接串口調試)。我這邊本地已經安裝了 VS Code 就不過多贅述,相信大家都安裝了,從我接觸過的幾個軟硬件開發教程都推薦安裝 VS Code,真香!
1.1 Remote - SSH和 SFTP Drive
可能大家會有疑問,這兩個玩意都是訪問遠程主機上文件的,裝一個就行了吧?剛開始我也有同樣的想法,后來在實操中發現:如果只安裝 Remote - SSSH,燒錄配置時無法讀取遠程文件;如果只安裝 SFTP Drive,在編輯代碼時訪問遠程文件非常慢;在座的給位大佬有好的方案的話一定要傳授一下哦。我這里安裝的是 Remote - SSH,如果您想體驗更多的功能,可以直接安裝 Remote Development,Remote 系列是巨硬公司針對遠程開發而開發的擴展。安裝完 Remote - SSH 之后,為了免密碼登錄 Linux(有風險需謹慎),我們需要操作一下 SSH 密鑰配置。

在 VSCode 的 Remote 擴展和 SFTP Drive 中先通過賬號密碼訪問遠程主機,確保能正常訪問到 Linux 主機中的代碼和文件。
SSH 密鑰配置的時候,我們可以在遠程主機上生成密鑰,也可以在本機生成密鑰,最終將配置關聯就可以。我們這里采用的是 Windows 機使用 PowerShell 執行`ssh-keygen`生成密鑰到文件`C:\Users\您的用戶名\.ssh\id_rsa`(私鑰),同時會生成文件`C:\Users\您的用戶名\.ssh\id_rsa.pub`(公鑰),通過 SFTP Drive 拷貝公鑰到遠程主機的`~/.ssh`目錄,在 VSCode 中連接遠程主機執行命令`cat id_rsa.pub >> authorized_keys`追加到 authorized_keys 中,由于我本機已經有了公鑰私鑰,直接拿來用即可。
此步需注意的是:
- cd ~/.ssh
- cat id_rsa.pub >> authorized_keys #追加公鑰
- sudo chmod 600 authorized_keys
- sudo chmod 700 ~/.ssh #文件及文件夾加權限
- sudo vim /etc/ssh/sshd_config #準備修改sshd配置
- # PubkeyAuthentication yes 確保此處注釋放開
- sudo service sshd restart #重啟sshd
完事之后關閉 VSCode 再打開,不出意外再連接遠程主機就不需要輸入訪問密碼了,徹底告別每次連接都要輸密碼的煩惱。
1.2 HUAWEI DevEco Device Tool 及依賴安裝
HUAWEI DevEco Device Tool可以理解為是 HarmonyOS Device 的開發工具,“HarmonyOS 智能設備一站式集成開發環境,支持 HarmonyOS 組件按需定制、一鍵編譯和燒錄、可視化調試、分布式能力集成等,幫助開發者高效開發和創新新硬件”。
官網:https://device.harmonyos.com/cn/ide,目前只支持 Windows,這也是為什么我們需要用到 Windows 本機的原因!另外 HUAWEI DevEco Device Tool 沒有上架到 VSCode 擴展市場,只能通過**從 VSIX 安裝**的方式進行安裝,也就是說我們需要解壓從官網下載的安裝包,另外將`.vsix`文件后綴修改為`.zip`解壓有驚喜哦 -- 在 DevEcoDeviceTool/extension/deveco/tool 您能得到 HiBurn.exe ,這個程序就可以用來燒錄(相當于不使用 VSCode 的擴展在程序中配置燒錄參數直接燒錄)。

根據官方文檔的指引,我們還需要:
- - 安裝 Node.js(盡量別裝最新的)
- - 安裝 JDK
- - 安裝 hpm
- - 安裝 VSCode C/C++擴展
- - 安裝 CH341SER.EXE
- - 安裝 Jlink 工具(可選,V6.54c 及以上版本)
- - 安裝 hcc_riscv32(這個我沒裝成功,所以調試全靠手打)
鑒于前期跑過“Hello, HarmonyOS”(因此才獲得的開發板),大部分環境我都有,不過在安裝 Jlink 工具的時候卡了很久,主要是網絡的問題,導致下載的文件不全,好在想方設法終于下好了,又在安裝 hcc_riscv32 時卡住了,幸好不是關鍵,索性放棄!……費了九牛二虎之力,終于完成 Windows 部分的環境搭建,可以直接燒錄別人編譯好的程序了!

2. Linux 環境(編譯)
相比 Windows 環境,HarmonyOS Device Linux 的環境搭建顯得微不足道,跟著文檔走一遍就完事了。不過,經過實操,如果您是 Ubuntu 18.04,我更加推薦潤和許老師的文檔--Harmony OS 開發指南——源碼下載和編譯。如果您和我一樣還想嘗試一下在 CentOS 上搭建環境,那就推薦鴻蒙社區的文章--在 CentOS 中安裝鴻蒙 LiteOS 編譯環境-海思 Hi3861,同樣的也只取我需要的--我只需要編譯部分的環境搭建。我的云主機操作系統是 CentOS 7.6 64 位,和博主的大同小異,按照文章中的命令行逐個敲完再去編譯就一把過。

老話說得好:"If I have seen further, it is by standing upon the shoulders of giants",于是我結合許老師和社區文章完成了 HarmonyOS 在 CentOS 上的編譯環境搭建。
2.1 源碼獲取(其中的一種方法)
- ```bash
- # 配置repo工具
- mkdir ~/bin/
- # sudo apt install curl # 如果沒有curl命令需要先下載
- curl https://gitee.com/oschina/repo/raw/fork_flow/repo-py3 > ~/bin/repo
- chmod +x ~/bin/repo
- echo 'export PATH=~/bin:$PATH' >> ~/.bashrc
- source ~/.bashrc
- ```
- ```bash
- # 下載Harmony OS源碼
- mkdir -p ~/harmonyos/openharmony && cd ~/harmonyos/openharmony
- sudo apt install --no-install-recommends git python # repo工具本身是python腳本,它會調用git命令下載單個代碼倉
- # 開始前需要配置`user.name`和`user.email`,如果沒有配置,使用如下命令進行配置:
- # git config --global user.name "yourname"
- # git config --global user.email "your-email-address"
- repo init -u https://gitee.com/openharmony/manifest.git -b master --no-repo-verify
- repo sync -c # 以后每天同步遠程倉的修改,只需要執行這一條命令即可
- ```
2.2 安裝編譯基礎環境
依賴 Python 3.7+ 以及SCons安裝,我這里通過自行編譯安裝的 Python 3.9.0。
- ```bash
- # 下載Python源碼包
- wget https://www.python.org/ftp/python/3.9.0/Python-3.9.0.tgz
- # 解壓源碼包
- tar -xzvf Python-3.9.0.tgz
- # 安裝依賴
- yum groupinstall -y "Development tools"
- yum install -y openssl-devel
- yum install -y libffi libffi-devel
- yum install -y bzip2-devel
- yum install -y sqlite-devel
- yum install -y readline-devel
- yum install -y libuuid-devel
- yum install -y uuid-devel
- yum install -y xz-devel
- yum install -y gdbm-devel
- yum install -y tk-devel
- # 配置編譯
- cd Python-3.9.0
- ./configure --prefix=/usr/local/python3
- # 編譯Python
- make -j8 && make install
- # 創建軟鏈接
- ln -s /usr/local/python3/bin/python3 /usr/bin/python3
- ln -s /usr/local/python3/bin/pip3 /usr/bin/pip3
- # 驗證
- python3 --version
- pip3 --version
- # 安裝編譯時需依賴的Python 3組件
- pip3 install setuptools
- pip3 install kconfiglib
- pip3 install pycryptodome
- pip3 install six --upgrade --ignore-installed six
- pip3 install ecdsa
- ```
- ```bash
- # 下載SCons源碼包
- wget http://prdownloads.sourceforge.net/scons/scons-4.0.1.tar.gz
- # 解壓源碼包
- tar -xzvf scons-4.0.1.tar.gz
- # 安裝
- cd SCons-4.0.1/
- python3 setup.py install
- # 創建軟鏈接
- ln -s /usr/local/python3/bin/scons /usr/bin/scons
- ```
2.3 安裝編譯工具環境
我們需要用到的編譯工具有交叉編譯器 gcc_riscv32、 產生 ninja 編譯腳本的 gn、執行 ninja 編譯腳本的 ninja,雖然我并不知道她們是怎么工作的,但我堅信“Just Do IT”!
- ```bash
- # 下載交叉編譯工具
- wget https://repo.huaweicloud.com/harmonyos/compiler/gcc_riscv32/7.3.0/linux/gcc_riscv32-linux-7.3.0.tar.gz
- # 解壓工具鏈
- tar -xvf gcc_riscv32-linux-7.3.0.tar.gz
- # 安裝交叉編譯工具
- mv gcc_riscv32 /usr/local/ # 按照個人喜好存放
- vi /etc/profile # 將環境變量配置進來export PATH=/usr/local/gcc_riscv32/bin:$PATH
- # 如果已存在PATH,需將:/usr/local/gcc_riscv32/bin:$PATH 追加到PATH
- source /etc/profile
- # 如果還是不生效,請嘗試加到全局變量 vim ~/.bashrc 我這邊就醬
- # 驗證
- cd
- riscv32-unknown-elf-gcc --version
- ```
- ```bash
- # 下載gn工具源碼包
- wget https://repo.huaweicloud.com/harmonyos/compiler/gn/1523/linux/gn.1523.tar
- # 解壓
- tar -xvf gn.1523.tar
- # 安裝
- mv gn /usr/local/
- ln -s /usr/local/gn/gn /usr/bin/gn
- # 驗證
- gn --version
- ```
- ```bash
- # 下載ninja
- wget https://repo.huaweicloud.com/harmonyos/compiler/ninja/1.9.0/linux/ninja.1.9.0.tar
- # 解壓
- tar -xvf ninja.1.9.0.tar
- # 安裝
- mv ninja /usr/local/
- ln -s /usr/local/ninja/ninja /usr/bin/ninja
- # 驗證
- ninja --version
- ```
2.4 編譯測試
通過簡單而又繁瑣的 Ctrl C 和 Ctrl V 我們終于完成了 HarmonyOS Device 用于編譯的 Linux 環境搭建。我已經迫不及待地想編譯一次試試:
- ```bash
- cd /root/harmonyos/openharmony
- python3 build.py wifiiot
- ```
至此,完整的 HarmonyOS Device 環境算是搭建完畢,我們可以開始編寫自己的程序進行編譯、燒錄了。接下來,我們嘗試從 Hi3861 套件的一些基本功能中了解 HarmonyOS Device 的開發調試。
開發調試篇
具體的文檔和教程請參考 HarmonyOS 官方文檔以及廠商的開源教程如 HiHope 的《Harmony OS 物聯網應用開發實戰》配套視頻和代碼倉庫、BearPi 的《HM Nano 鴻蒙·季 發布》配套視頻及代碼倉庫。我們使用的是 HiHope 出品的 WI-FI IoT Hi3861 套件,涵蓋了一個核心板(Hi3861 WLAN 模組)和七個擴展模塊(交通燈板、炫彩燈板、OLED 板、NFC 板、機器人擴展板),包含了豐富的外設接口如 I2C(The Inter Integrated Circuit)、PWM(Pulse Width Modulation)、GPIO(General Purpose Input/Output)和多路 ADC(Analog to Digital Converter)等等,可玩性非常高。鴻蒙社區也有很多牛人創造了超多創意玩法,比如通過蜂鳴器演奏樂曲、通過 OLED 播放視頻、俄羅斯方塊小游戲、控制大疆無人機……您是不是也想來一套?接下來,請跟隨 Copy 攻城獅本大獅一起探索一下 HarmonyOS Devic 開發調試吧!
3.1 從點燈開始
如果您留意到 HarmonyOS Device 官方文檔中關于 Hi3861 的示例程序,除了“Hello,World”和 WLAN 模組聯網,在設備開發章節還提供了一個 LED 外設控制的 Demo,通過調用 HarmonyOS 的 NDK 接口,實現對 GPIO 控制,達到 LED 閃爍的效果,也就是我們常說的“點燈”。源代碼在我們下載的目錄中:harmonyos/openharmony/applications/sample/wifi-iot/app/iothardware/led_example.c。
在 Copy 代碼之前,大概了解一下源碼的目錄:
- ├── applications # 應用程序樣例,包括wifi-iot,camera等
- │ └── sample
- │ ├──── camera # 攝像頭類產品
- │ └──── wifi-iot # WIFI連接類產品
- ├── base # 基礎軟件服務子系統集&硬件服務子系統集
- ├── build # 組件化編譯、構建和配置腳本
- │ └── lite
- ├── build.py # 編譯腳本文件
- ├── device # qemu模擬不同內核運行在不同的單板
- ├── docs # OpenHarmony開發者文檔
- ├── domains # 增強軟件服務子系統集
- │ └── iot
- ├── drivers # 驅動子系統
- │ ├── hdf
- │ └── liteos
- ├── foundation # 系統基礎能力子系統集
- ├── kernel # 內核子系統
- ├── out # 編譯輸出
- │ └── wifiiot # python3 build.py wifiiot的產物
- ├── prebuilts # 編譯器及工具鏈子系統
- ├── test # 測試子系統
- ├── third_party # 開源第三方組件
- ├── utils # 常用的工具集
- └── vendor # 廠商提供的軟件
- ├── hisi
- └── huawei
再看看我們的開發目錄`applications/sample/wifi-iot`:
- ├── app
- │ ├── BUILD.gn # 入口
- │ ├── demolink # Hello,World
- │ │ ├── BUILD.gn
- │ │ └── helloworld.c
- │ ├── iothardware # 點燈Demo
- │ │ ├── BUILD.gn
- │ │ └── led_example.c
- │ ├── samgr # 服務框架子系統管理系統功能
- │ │ ├── bootstrap_example.c
- │ │ ├── broadcast_example.c
- │ │ ├── BUILD.gn
- │ │ ├── example.h
- │ │ ├── feature_example.c
- │ │ ├── maintenance_example.c
- │ │ ├── service_example.c
- │ │ ├── service_recovery_example.c
- │ │ ├── specified_task_example.c
- │ │ └── task_example.c
- │ └── startup # 啟動配置
- │ └── BUILD.gn
- └── LICENSE # 許可證
根據現有的代碼,要想完成“點燈”實踐,我們只需在 VSCode Remote 中修改入口文件`BUILD.gn`:
- import("//build/lite/config/component/lite_component.gni")
- lite_component("app") {
- features = [
- "iothardware:led_example"
- ]
- }
然后新開一個 VSCode 窗口進行 DevEco Device Tool 配置及燒錄,燒錄完畢通過串口工具能查看開發板的輸出,再 Reset 開發板之后,伴隨著節奏聲,LED 燈一閃一閃,有點轉向燈的趕腳,按下左邊按鈕時提示閃爍。

為了簡化操作,我安裝了串口調試工具 sscom,因此在每次燒錄前我先在 sscom 中關閉串口,燒錄完畢之后,我就在 sscom 中打開串口,方便的點在于不必每次都輸入串口,在發送操作指令時也更加快捷。值得注意的是燒錄時一定要先關閉被占用的串口,不然會提示串口繁忙而無法正常燒錄。

這里的點燈 Demo 通過 GPIO(General-purpose input/output,通用型輸入輸出)實現,同樣的還可以實現交通燈板上的“紅黃綠”LED 及蜂鳴器的操作,我們實現蜂鳴器版的《Jingle Bells》也基于 GPIO。
3.2 走向 Copy 之路
在萬物互聯的世界里,傳感器承擔了絕大部分的數據采集工作,在 WIFI-IoTHi3861 套件中的炫彩燈板包含了光敏、人體紅外,環境檢測板包含了溫濕度傳感器、燃氣傳感器。這部分主要涉及到 ADC 和 I2C,因此我們在進行傳感器應用開發的時候,需要特別留意公共基礎庫中的`wifiiot_adc.h`和`wifiiot_i2c.h`,文件均位于openharmony/base/iot_hardware/interfaces/kits/wifiiot_lite目錄下.另外就是如果使用了外設接口編譯的時候要注意對應的配置是否已經設置正常,比如我用到了 I2C,那么在編譯配置文件`vendor\hisi\hi3861\hi3861\build\config\usr_config.mk`中,我就需要將`# CONFIG_I2C_SUPPORT is not set`修改為`CONFIG_I2C_SUPPORT=y`……當然一開始我是不知道這些“門道”的,直到我在 HarmonyOS Device 開發中又走向了 Copy 之路,這條道也許永遠難回頭。我就像這些傳感器,在既定的程序里采集“知識”……
秉著學習的態度,我直接 clone 的 HiHope 的倉庫到我的`harmonyos/openharmony`目錄中,當然,既然是 Copy,我一定會按照`LICENSE`的規則使用,萬一沒遵守也是僅個人學習使用,應該不會被“譴責”吧。請開始 Copy 吧:
- ```bash
- cd /root/harmonyos/openharmony/applications/sample/wifi-iot
- git clone https://gitee.com/hihopeorg/HarmonyOS-IoT-Application-Development.git
- mv HarmonyOS-IoT-Application-Development/* ./
- ```
于是乎,在司職前端開發的 Copy 攻城獅的票圈又多了些物聯網開發的動態,“外行看熱鬧,內行看笑話”,不過捫心自問,這樣的 Copy,我還是非常樂意嘗試--零基礎也能玩玩,真好!一頓 Copy 操作下來,我便開始嘗試編譯燒錄每一個 Demo,盡管代碼看的吃力(我是太白),但一些關鍵的代碼還是能夠勉強修改,比如“1 改為 2”……總體來說,我體驗到了動手實踐的樂趣。尤其是看到蜂鳴器版的《兩只老虎》,我瞬間想到了那年平安夜,在陌生的城市,深夜加班之后,路燈下自己的影子被拉得長長的,我和往常一樣掃了一輛共享單車,鎖開的那一瞬間,音樂響起來的……
實戰應用篇
說回我們今天的主要任務--蜂鳴器版的《Jingle Bells》。小的時候我們學過“聲音是一種波。可以被人耳識別的聲(頻率在 20 Hz~20000 Hz 之間),我們稱之為聲音”。那聲音的頻率和我們聽到的音調又有什么關系呢?剛好我找到了它--每個人都應該了解的音樂理論, 從表格中可以看出,“幾”字型方向聲音頻率逐漸增大,我們聽到的“哆唻咪”差不多是表中的“1046.50,1174.66,1318.51”。

在我所使用的 WIFI-IoT 套件中的蜂鳴器要想輸出相同的頻率,需要使用 PWM 接口來控制。根據社區大佬們的實測,通過`hi_pwm_set_clock(PWM_CLK_XTAL);`可以將時鐘源設置為晶體時鐘且時鐘頻率為 40MHz。根據 PWM 輸出的方波頻率的公式:
- f = Fcs / freq
其中,Fcs 是 PWM 時鐘源頻率,freq 是分頻倍數,取值[1~65535];

我們通過簡單的換算得出我所用的《鈴兒響叮當》簡譜中需要的音頻:
- static const uint16_t g_tuneFreqs[] = {
- 0, // 40M Hz 對應的分頻系數:
- 38223, // 1046.50 1
- 34052, // 1174.66 2
- 30338, // 1318.51 3
- 28635, // 1396.91 4
- 25510, // 1567.99 5
- 22727, // 1760.00 6
- 40495, // 987.77 7-
- 36077, // 1108.73 1+
- 51021, // 783.99 5-
- 45455 // 880.00 6-
- };
索引從 0 開始,比如"1,2,3,4,5,6"分別對應”哆來咪發嗦啦“,因此簡譜中的音符對應進來就如下圖所示了:

當然要想出色的演奏,我們還需要掌握一定的節奏,不然都是一個節拍,平平淡淡沒有跌宕起伏的感覺,怎么體現咱 Copy 攻城獅的人生歷程呢?關于節拍,我簡單做了總結,簡譜中常見的節拍有下面幾個,套用在代碼里面就是停頓時間:

整明白這些之后,開始編(kao)程(bei),其核心實踐如下:
- # 音樂處理
- static void *BeeperMusicTask(const char *arg)
- {
- (void)arg;
- printf("BeeperMusicTask start!\r\n");
- hi_pwm_set_clock(PWM_CLK_XTAL); // 設置時鐘源為晶體時鐘(40MHz,默認時鐘源160MHz)
- for (size_t i = 0; i < sizeof(g_scoreNotes)/sizeof(g_scoreNotes[0]); i++) {
- uint32_t tune = g_scoreNotes[i]; // 音符
- uint16_t freqDivisor = g_tuneFreqs[tune];
- uint32_t tuneInterval = g_scoreDurations[i] * (125*1000); // 音符時間
- printf("%d %d %d %d\r\n", tune, (40*1000*1000) / freqDivisor, freqDivisor, tuneInterval);
- PwmStart(WIFI_IOT_PWM_PORT_PWM0, freqDivisor/2, freqDivisor);
- usleep(tuneInterval);
- PwmStop(WIFI_IOT_PWM_PORT_PWM0);
- }
- return NULL;
- }
整完就是一頓編譯、燒錄,一套下來按下 Reaset 就崩出了那個似曾相識的聲音:"Jingle bells, jingle bells,ingle all the way……"
突然又一個想法冒出來了:”八音盒“是不是可以整了?服務端提供音樂數據,Hi3861的通過請求網絡獲取數據,蜂鳴器演奏,然后OLED屏顯示當前播放,再給交通燈板的按鍵加上功能,是不是齊活了~
后記
心心念念終于擼完這篇了,本來以為幾個小時就能搞定的,結果一搞就是一個周末。最近發現效率太低了,有很多文章很多題材想寫,也有很多事情要完成,卻總是發現沒時間,時間都去哪兒了?之前沒在 CentOS 上搭這套環境,知道寫文章的時候才發現同樣是 Linux,CentOS 和 Ubuntu 還是有些差異的,幸好有坑也爬出來了,關鍵在于前人的經驗分享。因此,希望此篇能給入門HarmonyOS的新人有所啟發。
B站鏈接:https://www.bilibili.com/video/BV1X64y1f7j1
https://harmonyos.51cto.com/#zz