關於本文
在【8. ESP8266使用Mongoose-os初體驗(使用bh1750傳感器)】一文中,介紹過在mongoose-os中利用javascript(mjs)進行bh1750數據讀取的方法。腳本語言的靈活和非編譯解釋執行的特點表現的很鮮明,代碼少,開發便利,這也是nodeMCU和各種腳本iot平臺繁榮、大行其道的原因之一。
但是作爲mongoose-os這樣一個iot系統而言,mjs只是爲提高效率、原型開發而加入的javascript的語法糖。其核心部分依然是C實現來主導,甚至mjs中的大量接口都是通過直接ffi映射C接口而來。當然,用mjs完全可以做開發(簡單),但知其然也要知其所以然,複雜的應用、新設備的支持,用C來進行開發底層,或者功能接口映射到mjs是更自然的做法。這也就是官方所說【Advanced JavaScript】開發。
舉例而言,mongoose-os對傳感器的支持有限,官方的只有bme280等寥寥數種,對於不支持、不常見的傳感器而言,用戶必須自己進行驅動的開發。
本文以bh1750光度傳感器爲例(主要還是簡單),簡單介紹mongoose-os下,
開發環境的配置,I2C驅動的開發示例,以及mjs的導出和使用。
(bh1750的I2C接口很簡單,只有用mjs也足以勝任,本文目的爲介紹開發步驟和注意點)
1.開發環境的配置
mongoose-os雖說是opensource的,但利益驅動使然,其牢牢控制住了開發中的每一個步驟。
從空工程建立、依賴庫下載,編譯、固件刷入,都需要用其mos工具,除下載固件外,都必須在其雲端完成。
環境在linux和windows上均可運行,編譯、固件寫入的入口均爲官方的mos程序。
(本文的環境爲win+git bash+mos.exe)
-
空工程創建
從github上下載工程模板,並重新命名爲bh1750-appgit clone https://github.com/mongoose-os-apps/empty bh1750-app
文件列表如下:
./build
./fs ->文件系統(可視爲mos中看到的device Files),後面做成的mjs文件將置於此目錄
./fs/index.html
./LICENSE
./mos.yml ->配置文件
./README.md
./src
./src/main.c ->C實現代碼
2.代碼實現介紹
bh1750使用I2C接口,因此需要根據bh1750的datesheet,增加數據訪問接口(即驅動實現)。
另外bh1750支持1次測量、連續測量 + L分辨率和2種H分辨率等多種組合模式,
這裏簡便起見,驅動部分只實現了 連續 H 分辨率模式,並直接實現於src/main.c。如果實現完整的、標準的驅動,應當與main.c分離實現。
-
修改src/main.c文件實現驅動
src/main.c
#include "mgos.h" #include <stdint.h> #include <stddef.h> #include <mgos_i2c.h> #include <mgos_system.h> int32_t bh1750_init() { // 獲取i2c總線實例 struct mgos_i2c* i2c = mgos_i2c_get_global(); if (NULL == i2c) { LOG(LL_INFO, ("Could not get i2c global instance")); return -1; } // 通電 int8_t cmd = 0x01; bool ok = mgos_i2c_write(i2c, 0x23, &cmd, 1, true); // dh1750默認地址爲0x23(沒有寄存器) if( !ok ) { return -2; } // 設置連續 H 分辨率模式 cmd = 0x10; ok = mgos_i2c_write(i2c, 0x23, &cmd, 1, true); // dh1750默認地址爲0x23(沒有寄存器) return ok ? 0 : -3; } int32_t bh1750_read() { // 獲取i2c總線實例 struct mgos_i2c* i2c = mgos_i2c_get_global(); if (NULL == i2c) { LOG(LL_INFO, ("Could not get i2c global instance")); return -1; } uint16_t data = 0; uint16_t lux = 0; // 連續 H 分辨率的數據讀取 // bh1750默認地址爲0x23,沒有寄存器,直接從總線上讀 bool ok = mgos_i2c_read(i2c, 0x23, &data, 2, true); if( ok ) { // 數據爲2字節,收到的第1字節爲高位,第2字節爲低位 // 變換後按datesheet計算要求除1.2 ((uint8_t*)(&lux))[0] = ((uint8_t*)(&data))[1]; ((uint8_t*)(&lux))[1] = ((uint8_t*)(&data))[0]; lux /= 1.2; } return ok ? lux : -2; } // app默認初始化,如果希望沒有bh1750不啓動可在此檢測 enum mgos_app_init_result mgos_app_init(void) { LOG(LL_INFO, ("Hi there")); return MGOS_APP_INIT_SUCCESS; }
-
增加fs/api_bh1750.js文件,導出mjs接口
內容如下:聲明ffi接口,並導出無狀態的全局對象BH1750。
如果驅動支持多種模式並且能切換模式,就需要在持有狀態數據。
fs/api_bh1750.jslet BH1750 = { init : ffi('int bh1750_init()'), lux : ffi('int bh1750_read()'), };
-
增加初始腳本文件fs/init.js,在其中使用定時器打印傳感器採集的流明數據
fs/init.jsload('api_config.js'); load('api_rpc.js'); load('api_timer.js'); load('api_bh1750.js'); // 加載bh1750驅動 let ret = BH1750.init(); // bh1750初始化 print('init result:', ret); // 連續 H 分辨率模式要求120ms以上間隔 Timer.set(1000, true, function() { let lux = BH1750.lux(); // 獲取流明數據 print('lux:', lux); }, null); // 註冊mongoose-os的RPC服務 RPC.addHandler('Lux.Read', function(args) { return { value: BH1750.lux() }; });
3.編譯配置修改
修改mos.yml文件,其爲標準的YAML格式,具體格式、注意點可搜索。
author: mongoose-os
description: A Mongoose OS app skeleton
version: 1.0
libs_version: ${mos.version}
modules_version: ${mos.version}
mongoose_os_version: ${mos.version}
# Optional. List of tags for online search.
tags:
- c
# List of files / directories with C sources. No slashes at the end of dir names.
sources:
- src
# List of dirs. Files from these dirs will be copied to the device filesystem
filesystem:
- fs
#驅動的配置信息可以加入config
# config_schema:
# - ["my_app", "o", {title: "My app custom settings"}]
#默認使用i2c總線
config_schema:
- ["i2c.enable", true]
libs:
- origin: https://github.com/mongoose-os-libs/boards
- origin: https://github.com/mongoose-os-libs/ca-bundle
- origin: https://github.com/mongoose-os-libs/rpc-service-config
- origin: https://github.com/mongoose-os-libs/rpc-service-fs
- origin: https://github.com/mongoose-os-libs/rpc-uart
- origin: https://github.com/mongoose-os-libs/i2c (增加i2c庫依賴)
- origin: https://github.com/mongoose-os-libs/rpc-service-i2c (增加rpc依賴,不加也可,目的是用scan接口調試)
- origin: https://github.com/mongoose-os-libs/mjs(增加mjs依賴)
# Used by the mos tool to catch mos binaries incompatible with this file format
# 貌似日期實爲框架版本,不可隨意變更
manifest_version: 2017-09-29
3.編譯
在bh1750-app目錄下執行編譯命令行:
e:/mos.exe --verbose build --arch esp8266
建議打開-verbose選項,可看到詳細的日誌,基本流程如下:
- 連接到https://mongoose.cloud,上傳代碼,構築臨時環境
- 在雲端從github上checkout各種核心庫和依賴庫
- 在雲端環境,各種mount配置好文件環境
- 用docker容器進行真正編譯(語法錯誤會在此階段提示)
- 編譯後的用戶固件、fs固件、ESP8266的初始配置固件等打包爲zip文件置於build目錄下
優點顯而易見:一鍵編譯,依賴處理,雲端可以統一維護、調整編譯環境,
缺點也是鮮明:所有代碼上傳,毫無祕密可言;編譯細節無法得知(甚至不知道具體編譯器是什麼);必須聯網、速度很慢、訪問繁忙時無法編譯。
成功後日志的最後會有如下消息:
Success, built bh1750-app/esp8266 version 1.0 (20181007-145007).
Firmware saved to build/fw.zip
打包的Zip文件內容如下:
624K 10月 7 14:50 bh1750-app.bin
128 10月 7 14:50 esp_init_data_default_v08.bin
256K 10月 7 14:50 fs.bin
1.2K 10月 7 14:50 manifest.json
2.3K 10月 7 14:50 rboot.bin
其中,bh1750-app.bin爲C語言的固件,fs.bin爲存放mjs(包括依賴的底層mjs)的固件,manifest爲刷入配置,其餘爲樂鑫官方提供的初始固件。
4.固件刷新
在bh1750-app目錄下執行命令行如下(無須指定串口號,這點還沒有調查是如何實現的):
e:/mos.exe --verbose flash
$ e:/mos --verbose flash
Loaded bh1750-app/esp8266 version 1.0 (20181007-145007)
Using port COM3
Opening COM3 @ 115200...
Connecting to ESP8266 ROM, attempt 1 of 10...
Connected, chip: ESP8266EX
Running flasher @ 0...
Flasher is running
Flash size: 4194304, params: 0x0240 (dio,32m,40m)
Deduping...
2320 @ 0x0 -> 0
262144 @ 0x8000 -> 65536
638560 @ 0x100000 -> 474720
128 @ 0x3fc000 -> 0
Writing...
4096 @ 0x7000
65536 @ 0x11000
77824 @ 0x101000
...
200704 @ 0x163000
16384 @ 0x195000
8192 @ 0x19a000
4096 @ 0x3fb000
Wrote 548448 bytes in 32.90 seconds (130.23 KBit/sec)
Verifying...
2320 @ 0x0
4096 @ 0x7000
262144 @ 0x8000
638560 @ 0x100000
4096 @ 0x3fb000
128 @ 0x3fc000
Booting firmware...
All done!
4.接線
ESP8266是安信可的NodeMCU板(ESP12系列的話,接線相同)
BH1750(GY-302) | ESP8266(NodeMCU) |
---|---|
VCC | 3V3 |
GND | GND |
SCL | D5(Pin14) |
SDA | D6(Pin12) |
Mongoose-os上的I2C的SCL和SDA的管腳是可配置的。
因爲ESP8266沒有硬件I2C,其I2C是軟件模擬的。