|
| 1 | +# 凹语言重新点亮 Arduino nano 33 |
| 2 | + |
| 3 | +- 时间:2024-09-22 |
| 4 | +- 撰稿:凹语言 开发组 |
| 5 | +- 转载请注明原文链接:[https://wa-lang.org/smalltalk/st0052.html](https://wa-lang.org/smalltalk/st0052.html) |
| 6 | + |
| 7 | +--- |
| 8 | + |
| 9 | +凹语言是国内 Gopher 发起的纯社区构建的开源国产编程语言项目。凹语言最初在2022年底增加了对Arduino-wasm平台的支持,后来在2023年底因为聚焦MVP开发临时去掉了Arduino目标的支持。最近在下个发布的v0.17.0版本中将恢复对Arduino nano 33开发版的支持,相对于之前的版本现在的凹语言特性更加丰富。 |
| 10 | + |
| 11 | +- 例子代码:[https://gitee.com/wa-lang/wa/tree/master/waroot/examples/arduino](https://gitee.com/wa-lang/wa/tree/master/waroot/examples/arduino) |
| 12 | +- 安装凹语言版本:`go install wa-lang.org/master` |
| 13 | + |
| 14 | +## 1. Arduino-wasm 是什么 |
| 15 | + |
| 16 | +Wasm3 是一个高性能的 WebAssembly 解释器,而 Arduino-wasm 则是 Wasm3 针对 Arduino 的定制版本。Wasm3 最小的硬件依赖是 ~64Kb Flash 和 ~10Kb RAM。 |
| 17 | + |
| 18 | +Github 仓库:[https://github.com/wasm3/wasm3-arduino](https://github.com/wasm3/wasm3-arduino) |
| 19 | + |
| 20 | +下面是 Wasm3 运行在 iOS 的截图: |
| 21 | + |
| 22 | + |
| 23 | + |
| 24 | +Arduino-wasm 则是运行在 Arduino Nano 33 等开发板上的 Wasm3。 |
| 25 | + |
| 26 | + |
| 27 | +## 2. Arduino Nano 33 开发板介绍 |
| 28 | + |
| 29 | +Arduino Nano 33,是 Arduino Nano 的高配版本,是一款基于 nRF52840 SoC ARM 32 位处理器的微型开发板。其中 Arduino Nano BLE Sense 其主控芯片集成了蓝牙低功耗(BLE)。NANO 33 BLE 不仅保留了与经典款 NANO 同样的尺寸与管脚,且在此基础上配有多种高性能传感器等,当然最重要的是满足了 Arduino-wasm 的最低硬件要求。 |
| 30 | + |
| 31 | + |
| 32 | + |
| 33 | +目前(2024年底),淘宝的价格大约在200元以内。 |
| 34 | + |
| 35 | +## 3. 编写 Arduino 的闪灯例子 |
| 36 | + |
| 37 | +首先用`wa init`生成一个arduino例子: |
| 38 | + |
| 39 | +``` |
| 40 | +$ wa init -arduino |
| 41 | +$ cd hello/ |
| 42 | +$ tree |
| 43 | +. |
| 44 | +├── README. |
| 45 | +├── src |
| 46 | +│ └── main.wa |
| 47 | +└── wa.mod |
| 48 | +``` |
| 49 | + |
| 50 | +其中 `main.wa` 内容如下: |
| 51 | + |
| 52 | +```wa |
| 53 | +// 版权 @2024 arduino 作者。保留所有权利。 |
| 54 | +
|
| 55 | +import "syscall/arduino" |
| 56 | +
|
| 57 | +global LED = arduino.GetPinLED() |
| 58 | +
|
| 59 | +func init { |
| 60 | + arduino.PinMode(LED, 1) |
| 61 | + arduino.Print("凹语言(Wa)/Arduino is running ...\n") |
| 62 | + arduino.Print("https://wa-lang.org\n") |
| 63 | +
|
| 64 | + for { |
| 65 | + arduino.DigitalWrite(LED, arduino.HIGH) |
| 66 | + arduino.Delay(100) |
| 67 | + arduino.DigitalWrite(LED, arduino.LOW) |
| 68 | + arduino.Delay(900) |
| 69 | + } |
| 70 | +} |
| 71 | +``` |
| 72 | + |
| 73 | +代码逻辑比较简单,只是换成了凹语言来写。我们直接使用了 `syscall/arduino` 包来使用 Arduino 的功能。 |
| 74 | + |
| 75 | + |
| 76 | +## 4. `syscall/arduino` 包介绍 |
| 77 | + |
| 78 | +让我们看看 [`syscall/arduino` 包的代码](https://gitee.com/wa-lang/wa/tree/master/waroot/src/syscall/arduino): |
| 79 | + |
| 80 | +```wa |
| 81 | +// 版权 @2022 凹语言 作者。保留所有权利。 |
| 82 | +
|
| 83 | +const ( |
| 84 | + LOW :i32 = 0 |
| 85 | + HIGH :i32 = 1 |
| 86 | +
|
| 87 | + INPUT :i32 = 0 |
| 88 | + OUTPUT :i32 = 1 |
| 89 | + INPUT_PULLUP :i32 = 2 |
| 90 | +) |
| 91 | +
|
| 92 | +#wa:import arduino millis |
| 93 | +func Millis() => i32 |
| 94 | +
|
| 95 | +#wa:import arduino delay |
| 96 | +func Delay(ms: i32) |
| 97 | +
|
| 98 | +#wa:import arduino pinMode |
| 99 | +func PinMode(pin, mode: i32) |
| 100 | +
|
| 101 | +#wa:import arduino digitalWrite |
| 102 | +func DigitalWrite(pin, value: i32) |
| 103 | +
|
| 104 | +#wa:import arduino getPinLED |
| 105 | +func GetPinLED() => i32 |
| 106 | +
|
| 107 | +#wa:import arduino print |
| 108 | +func PrintRawString(ptr: i32, len: i32) |
| 109 | +
|
| 110 | +func Print(s: string) { |
| 111 | + print(s) |
| 112 | +} |
| 113 | +
|
| 114 | +func Println(s: string) { |
| 115 | + println(s) |
| 116 | +} |
| 117 | +``` |
| 118 | + |
| 119 | +主要是将常用的函数通过 WASM 方式导入到了代码空间,大部分函数并不在凹语言中实现。 |
| 120 | + |
| 121 | +## 5. 编译到 Arduino-wasm 平台 |
| 122 | + |
| 123 | +可以通过`wa build`命令构建程序: |
| 124 | + |
| 125 | +``` |
| 126 | +$ wa build |
| 127 | +$ tree |
| 128 | +. |
| 129 | +├── README.md |
| 130 | +├── output |
| 131 | +│ ├── arduino |
| 132 | +│ │ ├── app.wasm.h |
| 133 | +│ │ └── arduino.ino |
| 134 | +│ ├── hello.wasm |
| 135 | +│ └── hello.wat |
| 136 | +├── src |
| 137 | +│ └── main.wa |
| 138 | +└── wa.mod |
| 139 | +``` |
| 140 | + |
| 141 | +output目录存放编译的结果,`output/arduino/arduino.ino`是Arduino工程文件,`output/arduino/app.wasm.h`是`output/hello.wasm`文件对应的数据数组。 |
| 142 | + |
| 143 | +```c |
| 144 | +// Auto Generate by Wa language. See https://wa-lang.org |
| 145 | + |
| 146 | +unsigned int app_wasm_len = 4608; |
| 147 | + |
| 148 | +unsigned char app_wasm[] = { |
| 149 | + 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x37, |
| 150 | + |
| 151 | + 0x03, 0x24, 0x74, 0x30, 0x17, 0x00, 0x18, 0x00, |
| 152 | +}; |
| 153 | +``` |
| 154 | + |
| 155 | +然后 Arduino 工程就可以通过 `#include "app.wasm.h"` 方式引用这个 WASM 程序,最终和 Wasm3 一起编译。 |
| 156 | + |
| 157 | +## 6. Arduino 平台胶水代码初探 |
| 158 | + |
| 159 | +最终还需要一个 `arduino.ino` 代码(其实就是针对 Arduino 简化的 C++ 程序)。代码结构如下: |
| 160 | + |
| 161 | +```c |
| 162 | +#include <wasm3.h> |
| 163 | +#include <m3_env.h> |
| 164 | + |
| 165 | +// 定义 WASM 和 本地栈大小 |
| 166 | +#define WASM_STACK_SLOTS 1024 |
| 167 | +#define NATIVE_STACK_SIZE (32*1024) |
| 168 | + |
| 169 | +// WASM 最大内存限制, 一般不得超过 64KB 大小 |
| 170 | +#define WASM_MEMORY_LIMIT (32*1024) |
| 171 | + |
| 172 | +// 导入 凹语言 生成的 WASM 文件对应的二进制头文件 |
| 173 | +#include "app.wasm.h" |
| 174 | +``` |
| 175 | + |
| 176 | +开头保护 Wasm3 和 WASM 程序对应的头文件,同时定义以下栈的大小。 |
| 177 | + |
| 178 | +然后看看代码主体结构: |
| 179 | + |
| 180 | +```cpp |
| 181 | +// 执行 WASM 的函数 |
| 182 | +void wasm_task(void*) { ... } |
| 183 | + |
| 184 | +// setup 作为 main 函数用户 |
| 185 | +void setup() { |
| 186 | + // 串口初始化 |
| 187 | + Serial.begin(115200); |
| 188 | + delay(100); |
| 189 | + |
| 190 | + // 等待串口初始化完成, 必须是 USB 串口 |
| 191 | + while(!Serial) {} |
| 192 | + |
| 193 | + // 阻塞执行 wasm 程序, 不会返回 |
| 194 | + wasm_task(NULL); |
| 195 | +} |
| 196 | + |
| 197 | +// 该函数不会被执行 |
| 198 | +// 定义该函数只是为了确保 Arduino 编译通过 |
| 199 | +void loop() { |
| 200 | + delay(100); |
| 201 | +} |
| 202 | +``` |
| 203 | +
|
| 204 | +Arduino 的常规代码只有 setup 和 loop 两个函数。不过这里只用到了 setup 函数。在 setup 函数中首先初始化串口(方便打印调试信息),最后调用 `wasm_task` 执行凹语言写的亮灯代码,其中会加载 WASM 模块并执行。`wasm_task` 看起来是一个比较复杂的程序,不过核心逻辑和普通的 WASM 执行流程类似,细节可以下次文章再展开。 |
| 205 | +
|
| 206 | +总体来说,以上这些胶水代码是相对固定的。后面会自动生成全部这些代码,同时去掉对外部其他工具的依赖。目标是生成的 Arduino 工程文件可以直接打开构建。 |
| 207 | +
|
| 208 | +## 7. Arduino 构建 & 执行 |
| 209 | +
|
| 210 | +如果是第一次使用 Arduino Nano 33 开发板,打开 IDE 后会提示安装必要的工具。然后需要在库管理菜单手动安装 Wasm3 包: |
| 211 | +
|
| 212 | + |
| 213 | +
|
| 214 | +然后编译后上传的效果: |
| 215 | +
|
| 216 | + |
| 217 | +
|
| 218 | +执行的效果,除了可以看到 LED 闪烁,串口还可以看到输出信息: |
| 219 | +
|
| 220 | + |
| 221 | +
|
| 222 | +一切正常! |
| 223 | +
|
| 224 | +## 9. 总结展望 |
| 225 | +
|
| 226 | +目前流行 Arduino 单片机的配置还是比较低的,可能难以运行 WASM 程序。不过可以乐观估计 Arduino Nano 33 将会很快普及。而且,Wasm3 不仅仅可以支持 Arduino,还可以支持树莓派 Pico(淘宝价格30元)。因此,从长远看 WASM 是一个兼具灵活性和性价比的可选方案。 |
0 commit comments