我的第一个 TinyGo 项目:ESP32-C3 + DHT11 + SSD1306
前言
最近开始学习 TinyGo,这是我的第一个 TinyGo 嵌入式项目。作为一个 Go 语言爱好者,能用熟悉的语法来编写嵌入式程序,这种感觉非常奇妙。项目已开源在 Gitee 上:gitee.com/magic_drago...
为什么选择 TinyGo?
TinyGo 是 Go 语言的一个编译器子集,专门针对微控制器和 WebAssembly 等资源受限环境。相比 C/C++,它有这些吸引我的地方:
- 语法熟悉 --- 如果你已经会 Go,上手几乎零成本
- 垃圾回收 --- 不用手动管理内存,嵌入式开发也能享受 GC 的便利
- Goroutine --- 虽然在 MCU 上用得不多,但并发模型依然可用
- 丰富的驱动库 ---
tinygo.org/x/drivers提供了大量常见传感器的驱动
项目简介
这个项目使用 ESP32-C3 开发板,搭配 DHT11 温湿度传感器和 SSD1306 OLED 显示屏,实现了一个简单的环境监测小装置:
- 每 2 秒读取一次 DHT11 的温度和湿度数据
- 将温湿度及 LED 状态实时显示在 OLED 屏幕上
- 通过按钮中断控制 LED 开关,带软件消抖
硬件连接
| 外设 | ESP32-C3 引脚 | 说明 |
|---|---|---|
| LED | GPIO2 | 通过 330Ω 电阻接 LED 正极 |
| 按钮 | GPIO3 | 一端接 GPIO3,另一端接 GND |
| DHT11 DAT | GPIO4 | DHT11 模块的数据引脚 |
| OLED SDA | GPIO5 | I2C 数据线 |
| OLED SCL | GPIO6 | I2C 时钟线 |
核心代码解读
1. I2C 总线与 OLED 初始化
go
i2c.Configure(machine.I2CConfig{
SCL: machine.GPIO6,
SDA: machine.GPIO5,
Frequency: 400_000,
})
disp = ssd1306.NewI2C(i2c)
disp.Configure(ssd1306.Config{
Width: 128,
Height: 64,
Address: 0x3C,
})
SSD1306 通过 I2C 总线通信,配置为 400kHz 快速模式。128x64 分辨率的屏幕使用 0x3C 地址。
2. DHT11 传感器读取
go
dhtSensor = dht.New(machine.GPIO4, dht.DHT11)
dhtSensor.Configure(dht.UpdatePolicy{
UpdateTime: 2 * time.Second,
UpdateAutomatically: true,
})
DHT11 数据手册要求最小读取间隔为 2 秒,设置 UpdateAutomatically 后调用 TemperatureFloat / HumidityFloat 会自动触发读取,非常方便。
3. 按钮中断与消抖
go
button.SetInterrupt(machine.PinFalling, func(p machine.Pin) {
if time.Since(lastPress) < 50*time.Millisecond {
return
}
lastPress = time.Now()
led.Set(!led.Get())
})
机械按钮按下时触点会弹跳,产生多次快速电平变化。通过记录上次触发时间,忽略 50ms 内的重复触发,实现软件消抖。
4. 超级循环模式
go
for {
err := dhtSensor.ReadMeasurements()
if err != nil {
show("DHT11 Error", "", "")
} else {
temp, _ := dhtSensor.TemperatureFloat(dht.C)
hum, _ := dhtSensor.HumidityFloat()
show(
fmt.Sprintf("T:%.1fC", temp),
fmt.Sprintf("H:%.1f%%", hum),
fmt.Sprintf("LED:%v", led.Get()),
)
}
time.Sleep(2 * time.Second)
}
嵌入式程序的核心结构:无限循环中不断读取传感器、处理数据、刷新显示。注意 main 函数不能退出,否则设备会重启。
踩坑记录
- DHT11 读取间隔 --- 刚开始频繁读取导致数据全是错误,后来才注意到数据手册要求至少间隔 2 秒
- OLED 地址 --- 128x64 的屏幕地址是 0x3C,128x32 是 0x3D,搞混了屏幕不会亮
- 按钮消抖 --- 不加消抖逻辑的话,按一次按钮 LED 会翻转多次,50ms 的消抖阈值实测效果不错
- main 不能退出 --- 嵌入式程序的 main 函数必须保持运行,退出后芯片会自动重启
编译与烧录
bash
# 编译并烧录到 ESP32-C3
tinygo flash -target=esp32c3 .
# 仅编译生成固件
tinygo build -target=esp32c3 -o firmware.bin .
总结
作为第一个 TinyGo 项目,虽然功能简单,但覆盖了嵌入式开发的几个核心知识点:GPIO 控制、I2C 通信、传感器驱动、中断处理。TinyGo 的开发体验确实不错,Go 的简洁语法让嵌入式编程也变得优雅起来。
接下来打算尝试:
- 接入 WiFi,把温湿度数据上报到服务器
- 尝试 MQTT 协议
- 用 Goroutine 实现更复杂的并发逻辑
如果你也对 TinyGo 感兴趣,欢迎交流!
项目地址 :gitee.com/magic_drago...