首页 文章 精选 留言 我的

精选列表

搜索[爬虫系统],共10000篇文章
优秀的个人博客,低调大师

温湿度传感器驱动开发—【万物智能之开源鸿蒙OpenHarmony系统实战开发系列教程】

血氧的读法见过了。今天是温湿度:要先触发转换再读。有的料在总线上根本不应答,那是硬件边界。 同一条 `i2c1` 上,环境光 0x10 能出数,红外测温 0x5a 能出数,血氧 0x57 轮询 FIFO 也能出数。轮到 **HDC1080,地址 0x40**,很多人会在这里浪费两天。 症状很统一:设备树写了节点,`/sys/bus/i2c/devices/1-0040` 在,`driver` 软链指着 `hdc100x`,IIO 也枚举出来了。一读温度,`ENXIO`。dmesg 里有一句冷冰冰的: ```bash hdc100x 1-0040: cannot set seq config ``` 这句话的意思不是「序列模式配错了再改一版驱动就好」。意思是:**驱动往 0x40 写配置寄存器,芯片连 ACK 都没有。** 总线在,地址在设备树里,硅片没说话。 这章把协议讲死,把「组合读会重触发」这个坑讲死,再把「部分板子 0x40 完全 NACK」定性成硬件。软件层不要空转。同类芯片可以看 **AHT20,地址 0x38**——很多底板把温湿度备在这颗上,DTS 里常常 `disabled`,因为 HDF 传感器模型想独占。 --- ![](https://developer.qcloudimg.com/http-save/yehe-12803057/37cb2a391563c76ef3e11851b2b2ccda.png) ![](https://developer.qcloudimg.com/http-save/yehe-12803057/8cd389fa0b7256506396a3546ef82306.png) ## 1\. 先把一次失败走完,免得你重复交学费 工程上真实发生过的顺序,我按时间摊开。你对照自己的日志,卡在哪一步就从哪一步跳出来。 **第一天,按 IIO 习惯找名字。** ```bash hdc shell for d in /sys/bus/iio/devices/iio:device*; do echo -n "$d " cat $d/name done ``` 环境光叫 `veml6040`,红外叫 `mlx90614`,温湿度呢?没有 `hdc1080` 这几个字母。有人以为驱动没编进来,打开 `menuconfig`,打开 `CONFIG_HDC100X`,重编内核,刷 `boot_linux`。半小时后名字还是没有 `hdc1080`。 因为它就叫 **`1-0040`**:i2c 总线号 + 7 位地址。`hdc100x.c` 把 `indio_dev->name` 设成了 client 的名字,不是芯片型号字符串。`findIio("hdc1080")` 永远空,`findIio("0040")` 才能撞上。 **第二天,找到了 `1-0040`,读 `in_temp_raw` 恒 ENXIO。** 去看驱动。probe 里写序列模式配置,**返回值没查**。写失败照样 `iio_device_register`。于是 sysfs 里设备「在」,第一次真正读才暴露 NACK。dmesg 翻到: ```bash hdc100x 1-0040: cannot set seq config ``` 有人开始改驱动:序列模式 ACQ\_MODE 翻来覆去、`msleep(20)` 加长、每次读前重写 config。两次内核重建,现象不变。 **第三天,放弃 IIO,用户态 `/dev/i2c-1` 按手册裸跑。** 写 config 到 0x02,ioctl 返回 -1。和内核走的是同一条电气通路。0x10、0x57、0x5a 在同一根 SDA/SCL 上 ACK 正常。结论到这里才能下:**0x40 这颗在这颗模块上电气不应答。** 量芯片 VDD 脚(不是连接器上的 3.3 V 总线上),看独立 LDO 有没有出来。虚焊、LDO 没焊、芯片本身死,都不是 C 能救的。 如果你的板子写 config 是成功的,后面的协议章节对你有用。如果是 NACK,读到第 8 节「定性硬件」就可以停,去 AHT20。 --- ## 2\. 通信怎么走 HDC1080 是 I2C,但转换时序像「启动一次 ADC,过一会儿来取结果」。 寄存器(16 位宽,高字节先): | 指针 | 含义 | | --- | --- | | 0x00 | 温度。写这个指针 = 触发转换 | | 0x01 | 湿度。单独测湿时写它 | | 0x02 | 配置。bit12 是序列模式 ACQ\_MODE:1 表示一次触发温+湿 | 序列模式(本章用的)时序: ```bash 主机 HDC1080 | | |--S 0x40+W 0x02 0x10 0x00 P--> 写 config = 0x1000 | | |--S 0x40+W 0x00 P------> 只写指针,不带数据,开始转 | | 内部 ADC,约 15 ms 温 + 湿 | (等 20 ms) | |--S 0x40+R 4 bytes P--> 裸读:T_H T_L H_H H_L ``` 换算: ```bash T = rawT / 65536 * 165 - 40 单位 ℃ H = rawH / 65536 * 100 单位 %RH ``` `rawT`、`rawH` 都是大端 16 位。 **禁止组合读。** 组合读是: ```bash S 0x40+W 0x00 Sr 0x40+R 4bytes P ``` 对很多 EEPROM 风格的芯片这叫「设地址再读」。对 HDC1080,写 0x00 **本身就是触发**。你组合读的时候又写了一次 0x00,芯片刚转完(或者还在转)被重新砸进转换,读的那一拍总线上空的,NACK 或者读到 0。手册要求触发之后只发读,不再发寄存器地址。第 33 章的 `i2cRdPlain` 就是为它准备的。 单独测温度也可以:config 不打开序列位,写指针 0x00,等 7~15 ms,裸读 2 字节。本章用序列模式一次拿温湿,少一次总线事务。 --- ## 3\. 设备树和内核驱动 ```bash device/board/rk/rk3568_evb/kernel/rk3568-evb-linux.dts kernel/linux/linux-5.10/drivers/iio/humidity/hdc100x.c ``` ```bash &i2c1 { status = "okay"; clock-frequency = ; /* 400 kHz 上这颗也不稳 */ hdc1080: hdc1080@40 { compatible = "ti,hdc1080"; reg = ; status = "okay"; }; /* 同类:AHT20 / DHT20,地址 0x38。 * 若 HDF 传感器模型要独占,内核节点保持 disabled。 */ aht20: aht20@38 { compatible = "aosong,aht20"; reg = ; status = "disabled"; }; }; ``` `compatible` 用 `ti,hdc1080` 或 `ti,hdc100x`,驱动同一份。`CONFIG_HDC100X=y` 三处同步。 打开驱动看 probe,你要自己确认那句「写 config 失败仍然注册」: ```bash /* hdc100x.c 里大意如此,行号随版本浮动 */ if (hdc100x_update_config(data) dev, "cannot set seq config"); /* 注意:这里常常没有 return 那个错误,后面照样 iio_device_register */ ``` 所以验收 **不要** 以「有没有 IIO 设备」为准,以「写 0x02 成不成功」为准。 i2c1 上 0x40 还有别的居民:RK8600 一类 CPU 供电芯片在 **i2c0** 上也是 0x40,那是另一条总线,别看花眼。`i2cdetect -y -r 1` 看到的 40 才是这颗温湿度。 --- ## 4\. 完整 C:照手册跑,写 config 失败立刻退出 存成 `hdc1080_tool.c`。 ```bash #include #include #include #include #include #include #include #ifndef I2C_RDWR #define I2C_RDWR 0x0707 #endif #ifndef I2C_M_RD #define I2C_M_RD 0x0001 #endif struct i2c_msg { uint16_t addr; uint16_t flags; uint16_t len; uint8_t *buf; }; struct i2c_rdwr_ioctl_data { struct i2c_msg *msgs; uint32_t nmsgs; }; #define ADDR 0x40 #define REG_TEMP 0x00 #define REG_CONF 0x02 static int i2cWr(int fd, uint8_t addr, uint8_t reg, const uint8_t *data, int len) { uint8_t b[24]; int i; b[0] = reg; for (i = 0; i 温度 = %.1f C 湿度 = %.0f %%RH\n", tr, hr, *t, *h); if (tr == 0 && hr == 0) printf("注意: 全 0,像没转完或读错方式。确认没用组合读、等够 20 ms。\n"); return 0; } int main(int argc, char **argv) { const char *dev = "/dev/i2c-1"; int combined = 0; int loop = 0; int fd, i; double t = 0, h = 0; for (i = 1; i /sys/bus/i2c/drivers/hdc100x/unbind ``` **5.2 dmesg 一句定音。** ```bash dmesg | grep -i hdc ``` `cannot set seq config` 出现过,就不要再猜 IIO 通道名、scale、offset。那是写 0x02 失败。用户态工具会打出同一件事的人话。 **5.3 量电压。** 连接器上的 3.3 V 有电,不代表芯片 VDD 脚有电。这类模块经常给温湿度单独一颗 LDO。表笔要挨着芯片电源脚。0 V:跟 LDO、虚焊。3.3 V 仍 NACK:芯片死或地址脚被焊成别的值(HDC1080 地址是固定 0x40,没有地址脚可改,所以更像死芯片或 SDA 没接到这颗)。 **5.4 别在 400 kHz 上自欺。** i2c1 曾经 400 kHz,MLX90614 先罢工,HDC1080 也不稳。已经降到 100 kHz 仍然 NACK,就不是速率问题。不要把时钟来回改当进度。 **5.5 IIO 读法(仅活芯片、且你想走内核时)。** ```bash BASE=/sys/bus/iio/devices/iio:deviceN # name 含 0040 cat $BASE/name cat $BASE/in_temp_raw cat $BASE/in_temp_offset cat $BASE/in_temp_scale cat $BASE/in_humidityrelative_raw ``` `hdc100x` 的换算和用户态公式同类,但 offset/scale 拆法以 sysfs 为准。读 raw 得到 ENXIO,立刻回头跑用户态工具,不要在 sysfs 上循环。 **5.6 和 RK8600 搞混。** ```bash ls /sys/bus/i2c/devices/ # 0-0040 可能是 i2c0 上的供电芯片 # 1-0040 才是 i2c1 上的 HDC1080 ``` 对 0-0040 发温湿度协议,轻则 NACK,重则 CPU 供电被你写乱。工具写死 `/dev/i2c-1`。 --- ## 6\. ArkTS:一次读取,失败文案要诚实 `index.d.ts`: ```bash export const hdc1080Read: () => string; ``` 页面: ```bash import board from 'libboard.so'; @Entry @Component struct HdcPage { @State line: string = '点「读温湿度」。若写 config 被拒,是硬件,不要反复点。'; build() { Column() { Text('HDC1080 温湿度').fontSize(20).margin({ bottom: 8 }) Text('i2c1 地址 0x40。触发后裸读 4 字节,禁止组合读。') .fontSize(14).fontColor('#666').margin({ bottom: 12 }) Button('读温湿度').onClick(() => { this.line = board.hdc1080Read(); }) Text(this.line).fontSize(16).margin({ top: 16 }).fontColor('#1565C0') } .padding(16) .width('100%') .alignItems(HorizontalAlign.Start) } } ``` NAPI 把 `read_once` 包一层,成功返回 `"温度 = 26.3 °C 湿度 = 48 %"`,失败把 `ERR:HDC1080 写config被拒` 原样交上去。**不要** 在失败时返回 `"--"` 或上次的 26 ℃。界面上要让人看见「被拒」。 循环刷新的话间隔 1 秒够了。每次循环都要走完整触发+20 ms+裸读,不能假设芯片会自己更新一个保持寄存器。 --- ## 7\. 同类对照:AHT20 @ 0x38 HDC1080 这条线若定性硬件,温湿度演示还可以走 AHT20(有的料单写成 DHT20,同一颗核)。地址 **0x38**,也在 i2c1。 协议和 HDC 不同,不要复用 `i2cRdPlain` 那套指针: 1. 软复位、等 20 ms。 2. 发触发命令 `0xAC 0x33 0x00`。 3. 等 80 ms。 4. 读 6~7 字节,里面是状态 + 20 bit 湿 + 20 bit 温。 DTS 里那颗 `aht20@38` 默认 `disabled`,常见原因:HDF 传感器模型要在 HCS 里声明同一地址,两边一起 okay 会抢。你走用户态 i2c-dev 时,保持内核节点 disabled,HCS 里也别同时开。只留 i2c1 控制器本身。 `i2cdetect -y -r 1` 在 0x38 看到 ACK,再写 AHT20 的工具。没 ACK 就同样是硬件或没贴这颗。本章不把 AHT20 的完整 C 展开,避免两套时序缠在一起。你要写的时候,独立文件 `aht20_tool.c`,不要在 `hdc1080_tool.c` 里加 `if (chip==aht)`。 --- ## 8\. 定性硬件之后做什么 写进测试记录,一行就够: ```bash HDC1080 @ i2c1 0x40:写 config NACK。同总线 VEML6040/MAX30100/MLX90614 ACK。 dmesg: hdc100x 1-0040: cannot set seq config。用户态 I2C_RDWR 同样拒。 结论:硬件。不改驱动。备选 AHT20@0x38。 ``` 然后停。不要: - 再降 I2C 速率到 50 kHz、10 kHz「试试看」; - 把 `compatible` 改成 `hdc1008` 碰运气; - 在 ArkTS 里 catch 住错误显示 25 ℃ 25% 以免「页面难看」; - 为了过验收去模拟一组数。验收方拿同一套工具跑,假数撑不过现场。 活芯片的验收才是呼气湿度变。死芯片的验收是 **工具稳定打出 ERR**,记录里写硬件。两种都叫「这章做完了」。没做完的是:明明 NACK,还在改软件。 --- ## 9\. 坑 **IIO 名字。** `hdc1080` 搜不到。搜 `0040`。更好的办法是根本不靠 IIO。 **probe 成功幻觉。** 驱动作者省了一次 `return ret`。你要用写 config 的返回值当活口。 **组合读。** 第 33 章把 `i2cRdReg` 讲得太好,到这颗芯片要收起来。HDC 用 `i2cRdPlain`。MAX30100 用 `i2cRdReg`。PAJ7620 用 `i2cRdReg`。按芯片选,不要按喜好选。 **20 ms 不够就加到 30 ms,不要减到 5 ms。** 手册给的转换时间是上限附近。提前去读,NACK 或全 0。 **len=0 的写。** `i2cWr(..., NULL, 0)` 只发寄存器地址。有人改成发一个 0x00 数据字节,芯片理解成往温度寄存器写数据,行为未定义。 **和 CPU 供电 0x40 抢脑子。** 总线号必须是 1。 **HDF 同时开。** 若 HCS 里也声明了温湿度 I2C 从设备,用户态偶发 NACK。二选一。 **呼气验收对着模块外壳吹。** 要靠近传感窗口。隔着塑料壳,湿度变化慢,别一秒钟没变就判死。活芯片 `loop` 模式看趋势,10 秒窗口。 --- ## 10\. 验收 活芯片: 1. `hdc1080_tool` 打出室温附近的温度(15~35 ℃ 这个宽范围),不是 0,不是 -40。 2. `loop` 对着窗口呼气,湿度上升至少几个百分点,离开后回落。 3. `combined` 参数下失败或全 0,证明你真的理解了裸读。 4. 应用按钮读一次,文案带单位 ℃ 和 %。 死芯片: 1. 工具 ERR,dmesg 有 `cannot set seq config`(若内核驱动还绑着)。 2. `i2cdetect` 上 0x10/0x57/0x5a 仍在。 3. 记录表写「硬件」,备选 AHT20 的地址 0x38 是否 ACK 另测一行。 4. 应用显示 ERR 原文,不显示假温湿度。 --- ## 对照:AHT20 在 0x38,协议不是这一套 HDC1080 判死之后,同总线常备一颗 AHT20(也有人写作 DHT20,I2C 地址一样是 0x38)。它不是「换个地址的 HDC1080」。 AHT20 典型流程: 1. 软复位、等 20 ms 以上。 2. 写初始化命令。 3. 发触发测量,等 80 ms 量级。 4. 读 6 字节,里面塞了状态、湿度 20 位、温度 20 位。 把它套进本章的「写 0x02 = 0x1000,再裸读 4 字节」,会得到一堆无意义的数,或者 NACK。DTS 里 `aht20@38` 常常 `disabled`,是因为 HDF 传感器模型想独占这颗。内核 IIO 和 HDF 同时 bind,必有一方失败。 对照实验只做一件事: ```bash i2cdetect -y -r 1 # 看 38 这一格是 UU、38,还是 -- ``` `--`:这颗也不在,温湿度这条产品线要换模块或修硬件。 `38`:芯片 ACK,没有驱动占着,用户态可以按 AHT20 协议另写工具。 `UU`:已经有驱动或 HDF 占着,先查是谁,再决定还让不让用户态碰。 不要把 HDC1080 的公式用在 AHT20 的 20 位字段上。不要把 AHT20 的 6 字节当 HDC1080 的 4 字节。料号不同,时序不同。 0x40 完全 NACK、0x38 有 ACK:验收表写成「HDC1080 硬件不应答,温湿度改测 0x38」。这比再交两次内核、再猜一遍 IIO 名字要诚实。 --- ## 路径清单 | 路径 | 用途 | | --- | --- | | \`device/board/rk/rk3568\_evb/kernel/rk3568-evb-linux.dts\` | \`hdc1080@40\`、\`aht20@38\` | | \`kernel/linux/linux-5.10/drivers/iio/humidity/hdc100x.c\` | 内核驱动,注意写 config 失败路径 | | \`kernel/linux/linux-5.10/Documentation/devicetree/bindings/iio/humidity/hdc100x.txt\` | 绑定 | | defconfig \`CONFIG\_HDC100X=y\` | 三处同步 | | \`/dev/i2c-1\` | 用户态 | | \`/sys/bus/i2c/devices/1-0040/\` | 节点与 driver 软链 | | \`/sys/bus/iio/devices/iio:deviceN/name\` | 常为 \`1-0040\` | | \`hdc1080\_tool.c\`(本章) | 验收工具 | | \`libboard.so\` 的 \`hdc1080Read\` | 应用 | --- ## 万用表怎么量,才叫「定性硬件」 软件停手之后,还差一次电。连错测量点会得出假结论。 连接器上的 3.3 V 有电,只说明排针供电到了模块板。HDC1080 往往有自己的小 LDO,输出才进芯片 VDD。量连接器、芯片照样没电,dmesg 仍然 `cannot set seq config`。表笔要碰到 **芯片 VDD 脚对地**,不是排针丝印 3V3。 SDA、SCL 对地应能看到上拉带来的高电平(接近 3.3 V)。两根都接近 0:上拉没焊,或某颗从设备把总线卡死。这时 0x10/0x57/0x5a 也会一起消失,不是 HDC1080 单独的事。只有 0x40 NACK、邻机正常:总线健康,问题在这颗从设备的供电、虚焊、地址脚、死芯。 不要为了「再试一次软件」把 i2c1 改回 400 kHz。那会把已经能绑上的红外测温打掉,换来 HDC1080 依然 NACK。速率不是这颗的救命稻草。 记录表建议三行,以后的人就不必再编两次内核: ```bash i2c1 100 kHz 0x10 ACK / 0x57 ACK / 0x5a ACK / 0x40 NACK hdc100x: cannot set seq config 用户态写 0x02 同样失败 结论:硬件,改测 0x38 或换模块 ``` 工具同样 32 位 musl。多一个开关值得当面跑一次: ```bash hdc shell /data/local/tmp/hdc1080_tool # 成功:温度接近室温,对着芯片呼气,湿度往上跳 hdc shell /data/local/tmp/hdc1080_tool combined # 预期失败或全 0。这就是「禁止组合读」的现场,不是工具写错。 ``` 写 config 已经 ERR 的板子,`combined` 不必跑。再跑也是 NACK,只会让人以为还有软件空间。把 ERR 原文和 `i2cdetect` 那一行贴进记录表,这章对这颗硬件就算闭合。 ArkTS 调 `hdc1080Read`,返回值是带单位的字符串,或者 `ERR:` 开头。界面遇到 `ERR:` 原样显示,不要解析成 0 ℃ / 0 %——那会让下一个人以为芯片活着、房间真的在冰点。按钮就一个「读温湿度」,成功再加一个「连续读」看呼气。 NAPI 里写 config 失败立刻 return,不要兜底返回上次缓存。缓存会把硬件 NACK 伪装成「数值卡住」。 ```bash hdc shell "cat /proc/partitions" hdc shell "ls -l /dev/i2c-1 /dev/ttyS0" hdc shell "dmesg | grep -E 'i2c|mlx|hdc|uart0|vcc-camera' | tail -30" ``` 上面三条在换模块、改 dts、刷完分区之后各跑一次,比在应用里加 log 便宜。输出贴进记录,下一轮对照。 --- 系列第 37 篇 · 芯片:瑞芯微 RK3568 · OpenHarmony 4.1(API 11) · Linux 5.10

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册