气体传感器MQ-2芯片驱动开发—【万物智能之开源鸿蒙OpenHarmony系统实战开发系列教程】
人体感应的真脚找过了。今天接气体报警。很多模块只有一根数字脚,而且这根脚可能和 I2C 时钟是同一根。
MQ-2 看起来像「模拟传感器」:金属网罩、加热丝、旁边一颗比较器。很多人第一反应是去读 ADC,换算出浓度 ppm。在这块 RK3568 底板上,扩展排针没有把 SARADC 引出来给这个模块。你能用的只有比较器翻出来的那根 DO(数字报警)。
所以本章的验收不是「屏幕上出现 237 ppm」,而是:预热之后,酒精棉凑到网罩 1~2 厘米,DO 翻转;拿开,DO 回去。就这一件事。
另一件会让你卡一天的事:实测这根 DO 常常落到 GPIO11,也就是 GPIO0_B3。这颗球同时是 I2C1 的 SCL。红外测温 MLX90614 挂在 i2c1 上时,这根脚属于 i2c 控制器,sysfs 导出 GPIO11 会失败。MQ-2 和红外测温不要同一时刻抢这根脚。

1. 通信怎么走
模块上典型有三块:气敏元件(要加热)、比较器、排针。比较器把模拟电压和电位器阈值比一下,OUT 翻成数字。
酒精 / 烟雾分子
│ 凑近金属网罩 1~2 cm
▼
气敏元件(加热丝要先预热)
│ 模拟电压(本底板没有引到 SARADC)
▼
板上比较器
│ DO:超过阈值翻转
▼
SoC GPIO(实测常为 GPIO0_B3 = linux 11)
│
▼
/sys/class/gpio/gpio11/value
│
▼
C 监测工具 / ArkTS 页面
AO(模拟)脚即使模块上有焊盘,底板这组排针也对不到 fe720000.saradc 的通道。第 29 章的 SARADC 在板载按键和专用 ADC 端子上。MQ-2 页面上如果留一个「读浓度」按钮,点下去找不到通道是预期,不要当故障修。
电位器在模块上,拧它改变报警阈值,不改变「有没有 DO 这根脚」。软件读不到浓度,硬件仍可能用电位器让它更灵敏或更钝。
2. 预热:加热丝常亮不是着火
上电之后金属网罩下面那根丝会红。这是加热,不是故障,更不是短路。数据手册要求预热,现场经验是 2~5 分钟 以后比较器才稳。刚上电立刻凑酒精,DO 可能完全不动,你会以为脚号又错了。
正确上电顺序:
- 插好模块,确认 VCC、GND。5 V 供电的模块不要接到 3.3 V 逻辑脚上当电源。
- 上电,看到加热丝亮。
- 走开,等至少两分钟,最好五分钟。
- 再开监测,用酒精棉凑网罩。
预热期内页面提示写成:「加热丝常亮正常,请等待预热,不要用明火。」不要弹「传感器异常」。
禁止:
- 打火机火焰直接烧网罩。气敏元件会坏,也有安全问题。
- 把模块塞进密闭盒子里长时间加热不管。
- 用口吹气当测试。隔半米吹一口气,浓度到不了阈值。
推荐刺激源:酒精棉或沾了酒精的棉签,直接凑近金属网罩 1~2 厘米,停一两秒。烟雾也可以,同样要近。厨房里隔着一米「比划一下」无效。
3. GPIO 编号再算一次
第 39 章的公式这里还用:
linux 编号 = bank × 32 + 组内偏移 + 位号
A=0 B=8 C=16 D=24
| 名字 | 计算 | 编号 | 备注 |
|---|---|---|---|
| GPIO0_B3 | 0×32+8+3 | **11** | 实测 DO;同时是 I2C1 SCL |
| GPIO0_B4 | 0×32+8+4 | 12 | 同时是 I2C1 SDA |
| GPIO2_B2 | 2×32+8+2 | 66 | 曾被误判为 DO,复测不动 |
| GPIO2_B1 | 2×32+8+1 | 73 | PIR,不是 MQ-2 |
/sys/kernel/debug/gpio 里 gpiochip0 是 GPIO0,编号 0~31。11 就在这颗 chip 上。
为什么 11 会和 I2C 打架:i2c1 的 pinctrl 组 i2c1_xfer 就是 GPIO0_B3 / GPIO0_B4。设备树 &i2c1 { status = "okay"; pinctrl-0 = <&i2c1_xfer>; } 一生效,这两根脚属于 i2c 控制器。再 echo 11 > export,内核返回 busy。
第 35 章红外测温、第 34 章环境光、第 36 章血氧、第 37 章温湿度、第 38 章手势,都挂 i2c1。它们活着的时候,不要指望 GPIO11 还能当普通输入。
4. 脚号是怎么扫出来的,以及第一次扫错
不要一上来就信某张「模块引脚表」。扩展排针丝印、原理图连接器号、设备树注释,三份对不上是常态。PIR 已经示范过一次。MQ-2 再示范一次,而且第一次扫还扫错了。
4.1 候选脚
把该插槽能碰到的、当前没被矩阵键盘等驱动占死的 GPIO 列出来。现场能 export 成功的包括 32、33、66、67、73、85、86,以及 11、12(若 i2c1 没占用)。被 keypad pinctrl 占住的 GPIO1 那一组 export 直接失败,跳过。
4.2 扫描脚本
放到板上 /data/local/tmp/scan_do.sh:
#!/system/bin/sh
# 用法:scan_do.sh 11 66 32 33
# 每 200 ms 打一行各脚电平。凑酒精时盯着哪一列在翻。
PINS="$*"
[ -z "$PINS" ] && PINS="11 66 32 33 73"
for g in $PINS; do
[ -d /sys/class/gpio/gpio$g ] || echo $g > /sys/class/gpio/export 2>/dev/null
echo in > /sys/class/gpio/gpio$g/direction 2>/dev/null
done
echo "time $(echo $PINS | tr ' ' '_')"
i=0
while [ $i -lt 80 ]; do
line="$i"
for g in $PINS; do
if [ -f /sys/class/gpio/gpio$g/value ]; then
v=$(cat /sys/class/gpio/gpio$g/value)
else
v="x"
fi
line="$line $v"
done
echo "$line"
i=$((i + 1))
usleep 200000
done
hdc file send scan_do.sh /data/local/tmp/scan_do.sh
hdc shell chmod 0755 /data/local/tmp/scan_do.sh
hdc shell "/data/local/tmp/scan_do.sh 11 66 32 33"
预热完成后开始跑。跑到一半,酒精棉凑上网罩,再拿开。看输出哪一列跟着变。
4.3 第一次误判:66
某次扫描里,GPIO66 那一列出现过一次 0→1。当时认定 DO=66,应用默认填了 66,极性还写成高电平报警。客户现场凑烟,页面不动。
复测:同样的脚本再跑三遍。66 全程:
1 1 1 1 1 1 1 1 1 1
酒精棉贴上去,66 仍是 1。那一次「翻转」是接触抖动或者读的瞬间碰到了别的脚。单次跳变不能当结论。
4.4 复测:11 才跟着烟走
同一段日志里 GPIO11 在凑近时变成:
1 1 1 1 0 0 0 0 1 1 1
拿开酒精棉,回到 1。再凑一次,再变 0。三遍稳定。极性是 空闲 1、报警 0。
所以:
- 默认 DO 填 11;
- 判定
v === 0为报警(以这颗模块为准); - 页面必须是连续监测,不能「点一下读一次」——报警可能只持续一两秒,单次采样会错过。
扫描纪律:
- 预热后再扫。
- 连续轮询,不要
cat一次就下结论。 - 同一刺激源至少复现三次。
- 拔掉模块再读候选脚:如果拔掉后仍按「报警」节奏自己翻,那根脚不是 DO。
- 写下极性,写进页面提示,不要只写在聊天记录里。
5. 和 I2C1 抢脚:export 失败不是脚本写错
GPIO11 = GPIO0_B3 = I2C1_SCL。设备树默认 &i2c1 { status = "okay"; },因为环境光、红外测温、血氧都在这条总线上。
此时:
hdc shell "echo 11 > /sys/class/gpio/export"
典型输出:
sh: write error: Device or resource busy
debugfs:
hdc shell "cat /sys/kernel/debug/gpio" | grep gpio-11
可能看到这根脚的名字是 i2c 相关,而不是 sysfs。pinctrl:
hdc shell "cat /sys/kernel/debug/pinctrl/pinctrl-rockchip/pinmux-pins" | grep -i 'gpio0-11\|0-b3\|i2c1'
会看到 i2c1_xfer 占用。
board-perm.sh 里对 11 的导出失败,串口会出现:
[BOARD_PERM] gpio11: 导出失败。73 查 pinctrl;11 查是否被 i2c1 占用
这不是脚本 bug。三条路,选一条:
路 A:测 MQ-2 时关掉 i2c1。 设备树临时 &i2c1 { status = "disabled"; },重打 dtb / boot_linux。红外测温、环境光、血氧、手势这一组全部消失。测完 MQ-2 改回 okay。这和 CAN 镜像是同一类「共脚二选一」,见第 33 章、第 58 章。
路 B:DO 改接到另一根空闲 GPIO。 如果模块排针允许你把 OUT 飞到 73 以外的空脚(不要和 PIR 抢 73),软件把编号改成那根脚。硬件改动要画清楚,不要口头传说。
路 C:不要同时测。 交付演示分时段:先演示 I2C 传感器,再切镜像或改接线演示 MQ-2。页面上写明「GPIO11 被 i2c1 占用时读不到 DO」。
不要走「强行 unbind i2c 驱动再 export」这种演示技巧。能临时通,重启又回去,客户无法复现。
CAN0 的 TX/RX 也是 GPIO0_B3/B4。开 CAN 的镜像同样会让 GPIO11 消失。MQ-2、I2C1 传感器、CAN,三选一坐这组脚。
6. 开机预导出:沿用第 39 章脚本
HAP 依然写不了 export。第 39 章的 board-perm.sh 已经循环 for g in 11 73。这里把和 MQ-2 相关的部分再强调一遍,脚本全文仍以第 39 章为准,不要维护两份互相覆盖的版本。
关键片段:
# 11 = MQ-2 DO(GPIO0_B3,⚠与 i2c1 SCL 共球)
# 73 = PIR OUT(GPIO2_B1)
for g in 11 73; do
[ -d /sys/class/gpio/gpio$g ] || echo $g > /sys/class/gpio/export 2>/dev/null
echo in > /sys/class/gpio/gpio$g/direction 2>/dev/null
chmod 0666 /sys/class/gpio/gpio$g/value 2>/dev/null
chmod 0666 /sys/class/gpio/gpio$g/direction 2>/dev/null
done
for g in 11 73; do
if [ -d /sys/class/gpio/gpio$g ]; then
log "gpio$g: direction=$(cat /sys/class/gpio/gpio$g/direction) value=$(cat /sys/class/gpio/gpio$g/value)"
else
log "gpio$g: 导出失败。73 查 pinctrl;11 查是否被 i2c1 占用"
fi
done
init 配置、BUILD.gn、刷 vendor 分区,全部和第 39 章同一套。改脚本只重打 vendor.img,刷 p8。只装 HAP 不够。
临时、没重打镜像时:
hdc shell "echo 11 > /sys/class/gpio/export"
hdc shell "echo in > /sys/class/gpio/gpio11/direction"
hdc shell "chmod 0666 /sys/class/gpio/gpio11/value"
若第一步 busy,先解决 i2c1,不要在应用里死循环 export。
7. 完整 C:mq2_watch.c
和 PIR 的 gpio_watch 同类,但带极性提示、busy 诊断,以及「预热倒计时」口吻。可以和上一章共用同一个二进制,只是默认脚和文案不同。这里给一份独立文件,复制就能编。
/* mq2_watch.c
* OpenHarmony 32 位 musl。
* 用法:
* mq2_watch # 默认 gpio11,间隔 200 ms
* mq2_watch 11 200
* mq2_watch 11 200 0 # 第三个参数:报警电平,0=低有效(本模块实测)
*/
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static int gpio_exported(int num)
{
char dir[64];
snprintf(dir, sizeof(dir), "/sys/class/gpio/gpio%d", num);
return access(dir, F_OK) == 0;
}
static int gpio_export(int num)
{
if (gpio_exported(num))
return 0;
char buf[8];
int len = snprintf(buf, sizeof(buf), "%d", num);
int fd = open("/sys/class/gpio/export", O_WRONLY);
if (fd < 0) {
fprintf(stderr, "open export: %s\n", strerror(errno));
fprintf(stderr, "HAP 会在这里失败;命令行若也失败,查是否 root。\n");
return -1;
}
ssize_t n = write(fd, buf, (size_t)len);
int err = errno;
close(fd);
if (n < 0) {
fprintf(stderr, "export gpio%d: %s\n", num, strerror(err));
if (err == EBUSY && num == 11) {
fprintf(stderr,
"gpio11=GPIO0_B3=I2C1_SCL。i2c1 okay 时不能当 DO。\n"
"关掉 i2c1,或把 DO 改接到空闲脚,或不要同时测红外测温。\n");
}
return -1;
}
usleep(50000);
return 0;
}
static int write_str(const char *path, const char *s)
{
int fd = open(path, O_WRONLY);
if (fd < 0)
return -1;
ssize_t n = write(fd, s, strlen(s));
close(fd);
return n < 0 ? -1 : 0;
}
static int gpio_read(int num)
{
char path[64];
snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", num);
int fd = open(path, O_RDONLY);
if (fd < 0)
return -1;
char c = 0;
ssize_t n = read(fd, &c, 1);
close(fd);
if (n <= 0)
return -1;
return (c == '1') ? 1 : 0;
}
int main(int argc, char **argv)
{
int num = (argc >= 2) ? atoi(argv[1]) : 11;
int interval = (argc >= 3) ? atoi(argv[2]) : 200;
int alarm_level = (argc >= 4) ? atoi(argv[3]) : 0; /* 本模块实测低有效 */
printf("MQ-2 DO watch gpio%d interval=%dms alarm_when=%d\n",
num, interval, alarm_level);
printf("预热 2-5 分钟;加热丝亮是正常的。酒精棉凑网罩 1-2cm。\n");
printf("禁止明火。隔空吹气无效。本底板无 ADC,只认 DO。\n");
if (gpio_export(num) < 0)
return 1;
char dirp[64];
snprintf(dirp, sizeof(dirp), "/sys/class/gpio/gpio%d/direction", num);
if (write_str(dirp, "in") < 0) {
fprintf(stderr, "direction: %s\n", strerror(errno));
return 1;
}
int last = -1;
int flips = 0;
int alarms = 0;
int i = 0;
for (;;) {
int v = gpio_read(num);
if (v < 0) {
fprintf(stderr, "read: %s(value 是否 0666?)\n", strerror(errno));
return 1;
}
if (last >= 0 && v != last)
flips++;
int is_alarm = (v == alarm_level);
if (is_alarm)
alarms++;
printf("[%03d] gpio%d=%d %s flips=%d\n",
i, num, v,
is_alarm ? "ALARM" : "idle ",
flips);
last = v;
i++;
usleep((useconds_t)interval * 1000);
}
return 0;
}
编译:
OHOS=$HOME/code/opcode/OpenHarmony
CLANG=$OHOS/prebuilts/clang/ohos/linux-x86_64/llvm/bin/clang
SYSROOT=$OHOS/prebuilts/ohos-sdk/linux/11/native/sysroot
$CLANG --target=arm-linux-ohos --sysroot=$SYSROOT \
-O2 -Wall \
-Wl,--dynamic-linker=/system/lib/ld-musl-arm.so.1 \
-o mq2_watch mq2_watch.c
file mq2_watch
hdc file send mq2_watch /data/local/tmp/mq2_watch
hdc shell chmod 0755 /data/local/tmp/mq2_watch
预热后:
hdc shell "/data/local/tmp/mq2_watch 11 200 0"
空闲应连续 gpio11=1 idle。酒精棉凑上:
[042] gpio11=1 idle flips=0
[043] gpio11=1 idle flips=0
[044] gpio11=0 ALARM flips=1
[045] gpio11=0 ALARM flips=1
[046] gpio11=1 idle flips=2
flips 增加,功能通。若全程 idle:
- 还在预热;
- 酒精太远;
- 脚不是 11(再跑
scan_do.sh); - 极性反了,把第三个参数改成
1试; - 电位器拧到极钝。
若一启动就 export ... Busy,停,去看 i2c1,不要改 C 里的重试次数。重试消除不了共脚。
对比复测 66:
hdc shell "/data/local/tmp/mq2_watch 66 200 0"
酒精棉贴上去,flips 仍接近 0。不要把 66 写回默认值。
8. NAPI 仍然只用 gpioRead
和 PIR 共用 libboard.so 的 gpioRead。不要为 MQ-2 再开一个 ioctl。不要在 so 里写 ADC 换算假装有浓度。
/* 与第 39 章相同:只 open value,不 export */
static napi_value GpioRead(napi_env env, napi_callback_info info)
{
size_t argc = 1;
napi_value a[1];
napi_get_cb_info(env, info, &argc, a, nullptr, nullptr);
int num = -1;
napi_get_value_int32(env, a[0], &num);
int val = -1;
if (num >= 0) {
char p[64];
snprintf(p, sizeof(p), "/sys/class/gpio/gpio%d/value", num);
int fd = open(p, O_RDONLY);
if (fd >= 0) {
char c = 0;
if (read(fd, &c, 1) > 0)
val = (c == '1') ? 1 : 0;
close(fd);
}
}
napi_value ret;
napi_create_int32(env, val, &ret);
return ret;
}
返回 -1 时,ArkTS 要把「i2c1 占用 GPIO11」和「没放权」分成两句人话,否则现场会去重编应用。
9. ArkTS 页面
import board from 'libboard.so';
@Entry
@Component
struct Mq2Page {
@State gpioNum: string = '11';
@State live: number = -1;
@State watching: boolean = false;
@State hint: string = '加热丝常亮正常。预热 2~5 分钟后点监测,酒精棉凑网罩 1~2cm。';
@State alarmLow: boolean = true; /* 实测 GPIO11:0=报警 */
private timer: number = -1;
aboutToDisappear() {
this.stop();
}
statusText(): string {
if (this.live < 0) {
return 'DO: -';
}
let alarm: boolean = this.alarmLow ? (this.live === 0) : (this.live === 1);
return alarm ? '报警(检测到气体)' : '正常(无报警)';
}
toggle() {
if (this.watching) {
this.stop();
this.hint = '已停止';
return;
}
let n: number = parseInt(this.gpioNum);
if (Number.isNaN(n)) {
this.hint = '先填 DO 的 GPIO 号';
return;
}
let probe: number = board.gpioRead(n);
if (probe < 0) {
this.hint =
'GPIO' + n + ' 读不到。两种可能:\n' +
'1) 开机 board-perm 没预导出 / value 不是 0666,需重打 vendor;\n' +
'2) GPIO11 是 I2C1 SCL,红外测温占用时 export 失败,二者不要同时测。';
return;
}
this.watching = true;
this.live = probe;
this.hint = '监测中。酒精棉贴网罩 1~2cm,看电平翻不翻。远距离吹气无效。';
this.timer = setInterval(() => {
let v: number = board.gpioRead(n);
if (v >= 0) {
this.live = v;
}
}, 300);
}
stop() {
if (this.timer >= 0) {
clearInterval(this.timer);
this.timer = -1;
}
this.watching = false;
}
build() {
Column({ space: 10 }) {
Text('气体传感器 MQ-2').fontSize(20).fontWeight(FontWeight.Bold)
Text('只读 DO,本排针没有 ADC。不要指望 ppm 读数。').fontSize(13)
Text('加热丝常亮是预热。禁止明火烧网罩。').fontSize(13)
Row() {
Text('DO GPIO').margin({ right: 8 })
TextInput({ text: this.gpioNum })
.width(80)
.onChange((v: string) => { this.gpioNum = v; })
Button(this.watching ? '停止监测' : '开始监测')
.onClick(() => { this.toggle(); })
.margin({ left: 8 })
}
Button(this.alarmLow ? '极性:低电平=报警(点此对调)'
: '极性:高电平=报警(点此对调)')
.onClick(() => { this.alarmLow = !this.alarmLow; })
Text('电平: ' + (this.live < 0 ? '-' : this.live.toString())).fontSize(18)
Text(this.statusText()).fontSize(22).fontWeight(FontWeight.Bold)
Text(this.hint).fontSize(14)
}
.padding(16)
.width('100%')
}
}
监测间隔 300 ms 和 PIR 一样。气体报警沿不是微秒级。单次「读 DO」按钮可以留,但文档要写:报警脉冲短,点不准。演示一律走监测。
不要在页面上放一个 ADC 通道输入还声称「浓度」。若留调试入口,注明「本槽无 SARADC,读到的是板载通道,与 MQ-2 无关」。
10. 排障过程
按这个顺序,不要先改应用默认脚号来回试。
1. 加热丝亮不亮。
不亮:没供电、插反、模块坏。亮:进入预热等待。看表两分钟起。
2. i2c1 还在不在。
hdc shell "ls -l /sys/bus/i2c/devices/i2c-1"
hdc shell "cat /proc/device-tree/i2c@fe5c0000/status"
# 节点名以你板子 /proc/device-tree 实际路径为准
hdc shell "i2cdetect -y -r 1"
i2cdetect 能扫到 0x5a(MLX90614)说明 i2c1 活着,GPIO11 大概率 busy。先决定这次要测哪一个。
3. export 11。
hdc shell "echo 11 > /sys/class/gpio/export"
hdc shell "ls -l /sys/class/gpio/gpio11/value"
busy → 回步骤 2。成功 → direction 设 in,chmod 0666。
4. 空闲值。
人、酒精、烟雾都远离。连续读 20 次。记下多数值,那是 idle。本模块常见 1。
5. 酒精棉 1~2 cm。
mq2_watch 11 200 0 跑着,棉签贴网罩。要看到 ALARM。拿开回到 idle。复现三次。
6. 对照 66。
同样刺激,66 不应跟着翻。防止旧默认值混进页面。
7. HAP -1。
hdc shell "ls -l /sys/class/gpio/gpio11/value"
hdc shell "grep BOARD_PERM /proc/kmsg"
hdc shell "ls -l /vendor/bin/board-perm.sh"
value 不是 0666,HAP 读失败。root 的 mq2_watch 能跑、HAP 不能,就是放权问题,不是脚号问题。
8. HAP 能读但不报警。
- 预热不够;
- 棉签太远;
- 极性反了,点页面「对调」;
- 电位器过钝;
- 监测没开,只点了一次读。
9. 误报不停。
电位器过灵、旁边有酒精瓶敞口、预热未完输出乱跳。先拿开所有刺激源,等预热结束,看 idle 是否稳定。稳定后再谈阈值。
11. 和别的章的关系
| 章 | 关系 |
|---|---|
| 33 I2C | i2c1 占用 GPIO0_B3/B4,MQ-2 用 11 时要让路 |
| 35 MLX90614 | 同抢 I2C1 SCL,不要同时测 |
| 39 PIR | 同一套 `board-perm.sh`、同一个 `gpioRead`;脚是 73,不是 11 |
| 29 SARADC | MQ-2 这组排针用不上;别把按键通道当浓度 |
| 58 CAN | can0m0 也是 GPIO0_B3/B4,三选一 |
演示脚本建议写成时段表,不要指望一张镜像、一个插槽把 I2C 传感器、MQ-2、CAN 同时点亮。共脚不是软件 bug。
12. 验收
同时满足才算过:
- 加热丝上电常亮,预热满 2 分钟(演示给 5 分钟更稳)。
gpio11能导出,或你已经改接到另一根空闲脚并在页面写明编号。- 空闲连续 10 秒电平稳定。
- 酒精棉或烟雾 1~2 cm 凑近网罩,DO 翻转;拿开后恢复。复现三次。
- 远距离吹气不要求翻转。
- 未使用明火。
- HAP 监测模式能显示报警/正常,且 HAP 自己没有写
export。 - 若 i2c1 保持 okay,允许 GPIO11 导出失败,但页面必须给出「与红外测温抢脚」的说明,而不是空白 -1。
- 不把 ADC 读数当作本模块浓度指标。
第 8 条是给「默认交付镜像开着 i2c1」留的口。你可以选择交两份镜像,也可以选择演示时拔掉 I2C 模块、关掉 i2c1。选哪条写进你的说明,不要让客户自己猜。
本章小结
MQ-2 在这块底板上是 DO 数字报警,不是浓度计。加热丝亮、预热数分钟是正常的。刺激源贴网罩 1~2 厘米。实测 DO 常为 GPIO11,空闲 1、报警 0,仍以监测为准。GPIO11 与 I2C1 SCL 共球,和红外测温冲突时换时段或换脚。扫描脚号要连续轮询并复测,66 那次误判不要再传。HAP 继续走第 39 章的预导出。
路径清单
| 路径 | 干什么 |
|---|---|
| `device/board/rk/rk3568_evb/kernel/*.dts` 的 `&i2c1` | okay 时 GPIO11 属于 SCL |
| `device/board/rk/rk3568_evb/board_perm/board-perm.sh` | 预导出 11 和 73 |
| `/sys/class/gpio/gpio11/value` | DO 电平 |
| `/sys/kernel/debug/gpio` | 看 11 被谁占 |
| `/data/local/tmp/mq2_watch` | 命令行监测 |
| `/data/local/tmp/scan_do.sh` | 扫脚,复测三次 |
| `libboard.so` `gpioRead` | HAP 只读 |
系列第 40 篇 · 芯片:瑞芯微 RK3568 · OpenHarmony 4.1(API 11) · Linux 5.10
更多推荐


所有评论(0)