主题! q2 c' `; B- y7 n
( S6 e3 i T8 H3 u7 l为了让LED亮起来,编写一个小JavaScript脚本,整个过程主要通过ARM mbed C HAL函数的交互实现的。
2 B! N% \: u& l" d: e同时也适用于ARM mbed支持的其他系统。! m( \$ B; X! y! p6 {8 D
5 V n1 s- `3 C8 ]: V
前提7 F* `- z. a/ `
" D6 `- w( m9 R( n& Y' j
在嵌入式MCU中添加脚本功能的原因有很多。 这次主要是想把JavaScript VM嵌入到他们现有的C固件,以便于快速定制核心业务逻辑,而不必重新包装设备。 这次我选择的嵌入式JavaScript VM是V7,这款是我和我在Cesanta的队友共同开发的。 V7库仅作为两个文件分发:V7 .c和V7 .h,你只需在项目中导入这两个文件就可以了。 V7是用可移植的C编写的,因此很容易从c++中使用。同时v7的平太是独立的,方便我们展示如何将其嵌入到ARM mbed项目中,以及如何在STM32F4设备上构建它,当然它也可以用于其他系统。
& [$ F6 h" v0 _$ ]# z+ V8 ?9 z9 Q$ n, F( ]- H y( `, [, t# I
下面是完整的源代码:
" F6 i& C, v9 G* Z2 e! N( h7 P* c e. e7 j; K
#include "mbed.h"
5 G. ?' u5 _9 S" G" g# c#include "v7.h" % X i& P4 [' u1 o9 R
?2 m; @) T& {) Q7 FDigitalOut led_green(LED1); 8 v# q- H1 T0 I2 w
- K3 j8 N1 x: w) \3 E
enum v7_err js_set_led(struct v7 *v7, v7_val_t *res) { ) Q! W1 ]& H& P" Z$ d$ E+ V% X0 k# T
led_green = !v7_get_bool(v7, v7_arg(v7, 0)); , B) h$ A' h. U9 R
return V7_OK; - [2 [% z& y; S: Q. m' i7 G4 ?
} $ C* P0 [; ~( K5 ]! v
T& N& w8 @3 Tenum v7_err js_wait(struct v7 *v7, v7_val_t *res) {
/ Z2 o) b; i+ V5 W5 g7 y wait(v7_get_double(v7, v7_arg(v7, 0))); F! ], O% h- z6 b; ~# M2 i
return V7_OK;
' B# E! R5 A- \: ?/ f# `5 o+ d( b}
) y) X' ?3 Z- D0 N* x5 A ) G& w$ r8 W6 Z
int main() {
) R+ p0 g* \- m+ V2 Z/ T F struct v7 *v7 = v7_create(); ) N8 k: `6 {" F d& N( }& W
v7_set_method(v7, v7_get_global(v7), "setLed", &js_set_led);
4 }6 @6 e/ [( F O% k+ o v7_set_method(v7, v7_get_global(v7), "wait", &js_wait); % a8 [, D: x& Y$ y0 x$ ?
v7_exec(v7,
# `5 J7 ]; s" ~4 N! k "while(true) {" \ / A: a6 t5 h8 y- B, ?
" setLed(false);" \ " n* l; P0 O! E ~; k9 T
" wait(0.5); " \ 1 {) T/ X5 ?, E, ^, o6 z
" setLed(true);" \ 2 U% x" x5 V9 ^
你可以直接在ARM mbed在线编译器或命令行工具中复制这个代码,打开:http://developer.mbed.org/teams ... javascript_blinker/ 我们将逐步展示如何安装以及注意事项。
/ B6 Y$ A% a5 ]6 p8 j3 J
/ j; ~: p' g- J先看看如果没有脚本的话会是什么样子:4 W4 F o; e, R
#include "mbed.h" . ^. u" h1 O" C7 k' ]5 b. y
+ {4 `4 P4 v: U1 b1 A
DigitalOut led_green(LED1);
y; k6 ~" g- |( r: y8 t 7 F/ X- M: \$ r) y4 B
int main() { 2 B- e5 P; S; ]' U& @3 z
while(true) {
. t: h( f; ]8 _5 R2 u3 T: @+ f led_green = false;# H7 g3 p" i5 j1 y3 a
wait(0.2);9 M9 N9 x. u, w, i# {' y4 W
led_green = true;6 E4 k( b+ s* W; N* w
wait(0.8);- j1 _4 ?+ ~" z: P/ B' ~
}0 L' i6 q; [! D8 ~; a z- |
} 0 {+ ]1 h( s9 n+ T, y+ P
可以在mbed在线编译器中编译这段代码,或者也可以使用mbed-cli工具。) l, ~- c' a; T* E4 V9 M* O: H
! T6 j# E! ^- @8 D& D0 P
进入JavaScript让我们首先添加V7库。2 }) s5 w: p' D. h# S" |5 g( [' F
8 r0 i o: \, M2 n' J6 a! ?我已经将v7.c和v7.h文件打包在mbed代码库中,这样更方便。/ Q. J( `7 i0 _. r
2 C8 R: B/ H8 X$ W' [; G* j( n
: B* `( r% Q# E. e/ Z( _& _9 D
0 k( h6 l' \ { ~
或者,如果直接使用命令行工具:
' f3 @- r( K# z" Z
# v0 m# h" p, @ O. S4 Z. z1 t( n1 X& \& ]# J
现在,库已经被构建到固件中,但还需要它的数据头:
; I' j2 J/ q ^& \; l1 A$ }3 B* x9 ~! z1 N% V5 a5 V; m
然后,在主函数中创建一个虚拟机的实例:
+ E% `6 I9 K) O5 Y4 jstruct v7 *v7 = v7_create();
/ y. K, R0 X1 w2 P# ]' E: o# k这个v7变量保存整个VM状态,在调用v7 API函数时需要传递,那如何运行脚本?
' R" [* b5 b( M ?/ p* p6 u/ cv7_exec(v7, "print('hello from javascript')", NULL);
$ \7 L/ |! k4 e( Vv7_exec的最后一个参数用于获取JavaScript表达式的结果。这点我们容易忘记。$ x/ G: q1 r" |& ~/ V% K# K
! g% \0 T4 a' }- q5 Q! j4 ^0 I N& OJavaScript和设备 5 X/ W+ g1 e" ^& T
* F$ p9 L* R- [. I现在部份JavaScript代码已经成功运行了! 但是,我们如何让JavaScript代码在设备上做一些有用的事情呢?V7只是一个通用的JS VM库,它不知道任何关于你的嵌入式板,它的API等。 让我们先写一个简单的JS脚本,使用两个简单的函数,我们要从我们的设备的SDK导出:
- }* N3 B2 y# m7 F$ F$ ]- s# }, [# N
while(true) {
: l5 T9 L) \4 W2 U2 K setLed(false);
; c0 t. S& }' \9 ^' D5 ], L6 f wait(0.2);& q) L' b& U5 L5 o! a4 D
setLed(true);
- ]% ?6 n: j- {, z7 E wait(0.8);4 e4 u1 Z, @* T
}
6 o9 W+ z5 i- K) n我们可以使用v7_exec内联调用它,或者从闪存上的文件加载它,或者从网络下载它:4 k1 E. z9 c* @$ |. b( \: m9 d
: f* \* ^0 K2 \% \v7_exec(v7, , R' t* V* f* r
"while(true) {" \ # _* ]3 ~/ f1 L0 T6 F0 U6 `! c
" setLed(false);" \
7 y/ {. c7 l" l* l8 ` " wait(0.2); " \
4 s7 m( M9 ]: g6 O6 o/ f " setLed(true);" \ ( K7 q1 F( r2 P2 x
" wait(0.8); " \ 3 p* r# D8 h& T- s7 X# v. ~
"}",
|- d7 X6 C9 H NULL);
) e5 q+ V- T, P. F2 o! E现在注册几个函数使他可以与SDK进行交互:v7_set_method(v7, v7_get_global(v7), "setLed", &js_set_led);
- Y1 T T- L) r G jv7_set_method(v7, v7_get_global(v7), "wait", &js_wait);
" J) q ?( N5 L4 s- C; Q5 M这段代码注册了两个全局JavaScript函数setLed和wait,可以像调用本地函数一样从脚本中调用它们。
8 ]3 L8 D% u/ s$ {$ w它们的实现是用c语言编写的。让我们仔细看看js_wait是如何实现的,看看它是如何工作的:
5 _7 C. d0 V9 W% C, a
+ ]. I- f/ N! l2 j. oenum v7_err js_wait(struct v7 *v7, v7_val_t *res) {
6 a, P: o, s" U1 ?* G6 k wait(v7_get_double(v7, v7_arg(v7, 0))); * u9 b, Q g2 s7 P. L
return V7_OK; 0 e/ A! Y S, h
} , L3 w) y+ s- [8 f' T
v7_arg(v7,0):获取传递给wait()的第一个参数。它返回一个v7_val_t值,该值表示一个通用JavaScript值。 ; w( p2 R+ ^9 s1 D' m& T+ U
r* e8 M! r2 x# Y( r' K1 c' Qv7_get_double(v7, val):从v7_val_t中提取C双浮点值6 \6 }# t* R% Q7 ^' @7 R
' M$ U' p8 ? ?( u# h( E/ E
一个物联网固件开发框架。支持单片机:ESP32, ESP8266, CC3220, CC3200, STM32F4, STM32L4, STM32F7。亚马逊AWS物联网、微软Azure、谷歌物联网核心集成。用C或JavaScript编写的代码。——阅读更多 http://mongoose-os.com
3 d( F* G. ?. X; Q$ z0 G+ v& Z
! h% }. M" }8 J. K9 x1 X) ?; Q+ l
mongoose-os-master.zip
(2.2 MB, 下载次数: 16)
|