TinyGo 是唯一能为嵌入式设备生成裸机二进制的 Go 工具,标准 go build 因依赖操作系统和 libc 而不可行;必须用预编译 TinyGo 二进制,main.go 需位于模块根目录且包名为 main,target 名称须精确匹配硬件,外设须显式 Configure()。

用 TinyGo 替代 go build 是唯一可行路径
标准 Go 编译器(go build)无法生成裸机二进制,它依赖操作系统和 libc,而嵌入式设备(如 ESP32、RP2040、nRF52840)没有这些。你看到的任何“Go 跑在单片机上”的案例,底层全是 tinygo build,不是 go build。试图用 go install 或 go run 会直接报错:no Go files in 或 cannot load runtime/cgo。
必须从官网下载预编译 tinygo 二进制(tinygo.org/getting-started/),或用包管理器安装:brew install tinygo(macOS)、sudo apt install tinygo(Ubuntu)。验证方式是运行 tinygo version 并确认 which tinygo 有输出。若提示 llvm-config: command not found,说明 LLVM 缺失,需补装 llvm-dev 和 libclang-dev(Linux)或 brew install llvm(macOS)。
main.go 必须在模块根目录且包名严格为 main
tinygo 不支持子目录、不认 go.mod 子模块、不处理非 main 包。常见失败原因就是文件放错了位置:
-
main.go必须与go.mod在同一级目录,不能放在./cmd/、./src/或任意子文件夹里 - 文件名必须是
main.go,首行必须是package main(不能是package main_test,也不能带下划线) - 执行
tinygo build时,当前工作目录必须是含go.mod和main.go的目录;写成tinygo build ./cmd/main.go会失败 - 若还没
go.mod,先运行go mod init example.com/blink(模块名任意,结构合规即可)
target 名称必须精确匹配,烧录成功 ≠ 程序运行
tinygo flash -target=xxx 中的 xxx 决定内存布局、启动代码、引脚映射和烧录协议。选错 target,固件可能写进去了,但芯片卡死在复位向量——LED 不闪、UART 不吐字、USB 设备不识别。
立即学习“go语言免费学习笔记(深入)”;
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
常见错误:
- 凭经验缩写:
pico❌,正确是raspberry-pi-pico;micro:bit❌,正确是microbit - 混用芯片家族:
arduino(ATmega328P)≠arduino-nano33(nRF52840)≠feather-m0(ATSAMD21) - ESP32 系列必须区分:
esp32(S2)、esp32c3、esp32s3—— 分区表、USB 引脚、Flash 映射全不同 - 验证方法:先跑
tinygo build -target=xxx -o test.elf main.go,再用readelf -s test.elf | grep LED看符号是否解析成功
外设必须显式 Configure(),否则等于没接线
tinygo 不自动初始化任何硬件。调 machine.UART0.Write() 前没调 Configure(),函数立即返回 0 或卡住;调 machine.LED.High() 前没配 PinConfig{Mode: machine.PinOutput},LED 就是哑的。
关键细节:
-
uart.Configure(machine.UARTConfig{BaudRate: 115200})必须显式设置波特率,漏掉这行,串口监视器永远空白 - 不同板子默认 UART 引脚不同:
Feather M0用machine.SERIAL_TX_PIN,Arduinotarget 根本不支持硬件 UART,只能 bit-banging - Pico 板注意:
machine.UART0对应 GPIO 12/13,不连 USB;想用 USB 串口,得用machine.Serial(CDC ACM) - 配置必须在
main()开头做,不能在函数内重复调用Configure()—— 多数 target 不允许运行时重配模式
最常被忽略的点是:tinygo 的 target 名、引脚配置、外设初始化三者缺一不可。写对了 Go 语法,不代表能点亮 LED;烧录成功,也不代表程序在跑。真正的调试起点,永远是 readelf 看符号、tinygo targets 查名字、Configure() 补全那一行。

















