25、Android Things与IoT:嵌入式场景、外设控制、云端对接
说到Android Things,我脑子里第一个蹦出来的画面,是几年前在实验室里调试一块智能灯板。灯板死活不亮,我折腾了整整一个下午。最后发现,是GPIO的引脚号写错了。嗯,这种低级错误,我相信不止我一个人犯过。
Android Things,说白了就是Google为IoT设备定制的Android系统。它砍掉了手机上的那些花哨功能,保留了核心的Linux内核和Android框架。你想想看,一个智能音箱、一个工业传感器网关,它们不需要跑微信和抖音,它们需要的是稳定、低功耗、能直接操作硬件引脚。
这就是Android Things存在的意义。
嵌入式场景:Android Things能做什么?
我个人习惯把IoT设备分成三类:
- 智能家居类:智能灯、智能插座、温控器。这类设备对实时性要求不高,但需要稳定的Wi-Fi连接。
- 工业监测类:传感器数据采集、设备状态上报。这类设备往往7×24小时运行,掉线了要能自动重连。
- 边缘计算类:在设备端做简单的AI推理,比如人脸识别门禁。这类设备需要一定的算力。
Android Things在这三类场景里都能找到位置。我记得有个项目,客户要求在工厂里部署一批温湿度监测器。用单片机做吧,开发周期长;用树莓派跑Linux吧,又太重了。最后我们选了Android Things,开发效率高,而且OTA升级机制现成的。
核心优势:Android Things继承了Android的权限管理、网络栈、多媒体框架。你不需要从零开始写驱动,大部分外设都有现成的API。
外设控制:GPIO、PWM、I2C、SPI
外设控制是嵌入式开发的核心。Android Things提供了统一的Peripheral API,操作起来比Linux原生的sysfs要友好得多。
GPIO:最基础的数字信号
GPIO就是高低电平。控制一个LED,或者读取一个按键状态,都用它。
// 初始化GPIO引脚
PeripheralManager manager = PeripheralManager.getInstance();
Gpio ledGpio = manager.openGpio("BCM17"); // 树莓派上的GPIO17
// 设置为输出模式
ledGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);
// 点亮LED
ledGpio.setValue(true);
// 读取按键状态
Gpio buttonGpio = manager.openGpio("BCM18");
buttonGpio.setDirection(Gpio.DIRECTION_IN);
boolean isPressed = buttonGpio.getValue();
我曾经踩过一个坑:GPIO的引脚编号在不同平台上不一样。树莓派上叫BCM17,在NXP i.MX7D上可能叫GPIO1_IO12。所以代码里最好用配置文件来管理引脚映射,别写死。
PWM:控制电机速度、灯光亮度
PWM就是脉冲宽度调制。通过改变占空比,可以控制LED的亮度,或者直流电机的转速。
Pwm pwm = manager.openPwm("PWM0");
pwm.setPwmFrequencyHz(1000); // 1kHz
pwm.setPwmDutyCycle(50.0); // 50%占空比
pwm.setEnabled(true);
小技巧:PWM频率不要设得太高。人眼对100Hz以上的闪烁就不敏感了,但电机驱动需要几百Hz到几kHz。我一般LED用200Hz,电机用1kHz。
I2C与SPI:与传感器通信
I2C和SPI是嵌入式世界里最常见的两种总线协议。I2C适合连接多个低速设备,SPI适合高速数据传输。
举个例子,读取一个BME280温湿度传感器(I2C接口):
I2cDevice i2c = manager.openI2cDevice("I2C1", 0x76); // 设备地址0x76
// 读取温度寄存器
byte[] data = new byte[2];
i2c.readRegBuffer(0xFA, data, 2); // 0xFA是温度寄存器地址
// 解析数据(简化版)
int rawTemp = ((data[0] & 0xFF) << 8) | (data[1] & 0xFF);
double temperature = rawTemp / 100.0;
这里要注意:I2C设备的地址是7位的,但很多数据手册写的是8位地址(左移了一位)。我刚开始做的时候,拿着0xEC去通信,死活没响应。后来才发现,Android Things的API用的是7位地址,0x76才对。
避坑指南:我曾经在SPI通信时忽略了片选信号的电平极性。有些设备是低电平有效,有些是高电平有效。不匹配的话,数据根本读不出来。一定要仔细看数据手册。
云端对接:MQTT与Firebase
设备采集了数据,总得传到云端吧。Android Things设备通常通过Wi-Fi联网,云端对接最常用的协议是MQTT。
MQTT:轻量级物联网协议
MQTT的优点是:协议开销小、支持QoS(消息质量)、支持发布/订阅模式。非常适合低带宽、不稳定的网络环境。
// 使用Eclipse Paho MQTT客户端
MqttClient client = new MqttClient("tcp://broker.emqx.io:1883", "device_001");
MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(true);
options.setConnectionTimeout(10);
options.setKeepAliveInterval(60);
client.connect(options);
// 发布传感器数据
String payload = "{\"temperature\":25.3, \"humidity\":60.1}";
MqttMessage message = new MqttMessage(payload.getBytes());
message.setQos(1); // 至少一次
client.publish("sensor/temperature", message);
// 订阅控制指令
client.subscribe("device/001/control", (topic, msg) -> {
String command = new String(msg.getPayload());
if ("led_on".equals(command)) {
ledGpio.setValue(true);
}
});
我个人习惯把MQTT的Broker地址和Topic都放在配置文件中,不要硬编码。因为设备出厂后,Broker地址可能会变。用Firebase Remote Config或者本地配置文件来管理,方便后期维护。
Firebase:快速搭建云端后台
如果你不想自己搭服务器,Firebase是个不错的选择。Android Things设备可以直接集成Firebase SDK,把数据写到Firestore或者Realtime Database里。
// 初始化Firebase
FirebaseApp.initializeApp(context);
FirebaseFirestore db = FirebaseFirestore.getInstance();
// 上传传感器数据
Map<String, Object> data = new HashMap<>();
data.put("temperature", 25.3);
data.put("humidity", 60.1);
data.put("timestamp", System.currentTimeMillis());
db.collection("sensors")
.document("device_001")
.set(data)
.addOnSuccessListener(aVoid -> Log.d("IoT", "数据上传成功"))
.addOnFailureListener(e -> Log.e("IoT", "上传失败", e));
注意:Firebase SDK体积不小,对于存储空间有限的IoT设备来说,要掂量一下。我一般只在内存大于512MB的设备上用Firebase,小内存设备还是用MQTT更合适。
知识体系总览
下面这张图,是我梳理的Android Things IoT开发的核心知识结构。你可以把它当作一张地图,开发时按图索骥就好。
避坑总结
做Android Things开发,有几个坑我反复踩过,分享给你:
- 引脚复用问题:很多SoC的引脚有多个功能。比如同一个引脚,既可以做GPIO,也可以做I2C的SCL。如果你在代码里同时用了两个功能,系统会报错。记得在Board Support Package里确认引脚配置。
- 电源管理:IoT设备很多是电池供电的。Android Things默认的电源策略是为手机设计的,耗电很快。我建议关掉不必要的系统服务,比如蓝牙、GPS,用JobScheduler来管理后台任务。
- 网络断连:Wi-Fi在IoT环境里并不总是稳定。设备掉线后,要能自动重连。我一般会在onNetworkFailure回调里,启动一个指数退避的重连策略。
- 日志管理:设备跑在现场,出了问题你没法插USB看logcat。所以一定要把关键日志写到本地文件,或者通过MQTT上报到云端。我习惯用Timber库,配合一个自定义的Tree,把日志同时写到文件和网络。
最后说一句:Android Things虽然已经停止更新了,但它的设计思路和API接口,对现在主流的嵌入式Android开发(比如基于AOSP裁剪的系统)依然有很强的参考价值。你学会了这些,换个平台也能很快上手。
公众号:蓝海资料掘金营,微信deep3321