回答

收藏

[项目提交] 【FRDM-I.MX93】体验低功耗蓝牙读取小米温湿度计

2025 DigiKey AI应用创意挑战赛 2025 DigiKey AI应用创意挑战赛 541 人阅读 | 0 人回复 | 2025-11-24

【前言】

前面我测试了一下蓝牙,是没有成功的,今天我重新从镜像包中复制了一份驱动文件到驱动包中,然后蓝牙就正常工作了,现在分享一下读取小米温湿度计的工程。
【原因查找】
我原先工作是正常的,编译了开机加载wifi的脚本,脚本代码:
  1. #!/bin/sh -e
  2. # 功能:Wi-Fi自动联网 + 蓝牙自动启用+绑定 + 时间同步 + 时区设置
  3. # 适配:无 bluetoothctl/hciconfig,依赖 hcitool/rfcomm/ntpdate
  4. # 日志:所有输出写入 /var/log/rc_local.log,方便排查
  5. # ==============================================

  6. # --------------------------
  7. # 基础配置(用户按需修改!)
  8. # --------------------------
  9. WIFI_SSID="HUAWEI-H10R9U"          # 替换为你的Wi-Fi名称(已在wpa_supplicant.conf配置可忽略)
  10. WIFI_CONF="/etc/wpa_supplicant/wpa_supplicant.conf"  # Wi-Fi配置文件路径
  11. BLUETOOTH_MAC="" # 替换为你的蓝牙设备MAC(无需自动绑定则留空)
  12. BLUETOOTH_BAUD=9600               # 蓝牙串口波特率(如HC-05默认9600)
  13. NTP_SERVERS="ntp.aliyun.com ntp.tencent.com cn.pool.ntp.org"  # NTP同步服务器(多服务器冗余)
  14. TIMEZONE="Asia/Shanghai"          # 国内时区(固定无需改)

  15. # --------------------------
  16. # 日志函数(统一输出格式)
  17. # --------------------------
  18. log() {
  19.     echo "[$(date '+%Y-%m-%d %H:%M:%S')] [RC-LOCAL] $1" >> /var/log/rc_local.log
  20. }

  21. # --------------------------
  22. # 1. 初始化:时区设置(优先执行)
  23. # --------------------------
  24. log "=== 开始初始化系统配置 ==="
  25. export TZ="${TIMEZONE}"
  26. ln -sf /usr/share/zoneinfo/"${TIMEZONE}" /etc/localtime  # 兼容无 timedatectl 环境
  27. log "时区已设置为:${TIMEZONE}"

  28. # --------------------------
  29. # 2. Wi-Fi 自动联网(核心优化:增加重试+延时)
  30. # --------------------------
  31. log "=== 开始 Wi-Fi 联网 ==="
  32. # 加载 Wi-Fi 驱动(增加 3 秒延时,确保硬件就绪)
  33. modprobe moal mod_para=nxp/wifi_mod_para.conf || { log "Wi-Fi驱动加载失败"; exit 1; }
  34. log "Wi-Fi驱动加载成功"
  35. sleep 3

  36. # 启用以太网接口(mlan0)
  37. ip link set mlan0 up || { log "mlan0接口启用失败"; exit 1; }
  38. log "mlan0接口已启用"
  39. sleep 2

  40. # 启动 wpa_supplicant 连接 Wi-Fi(后台运行,失败重试1次)
  41. wpa_supplicant -i mlan0 -c "${WIFI_CONF}" -B || {
  42.     log "Wi-Fi连接失败,重试1次...";
  43.     sleep 2;
  44.     wpa_supplicant -i mlan0 -c "${WIFI_CONF}" -B || { log "Wi-Fi连接最终失败"; exit 1; }
  45. }
  46. log "wpa_supplicant启动成功,正在连接Wi-Fi: ${WIFI_SSID}"
  47. sleep 3

  48. # DHCP获取IP(重试3次,避免网络波动)
  49. for i in 1 2 3; do
  50.     dhclient mlan0 -v && { log "DHCP获取IP成功"; break; }
  51.     log "第${i}次DHCP获取IP失败,等待2秒重试...";
  52.     sleep 2;
  53.     [ ${i} -eq 3 ] && { log "DHCP获取IP失败(3次重试)"; exit 1; }
  54. done

  55. # --------------------------
  56. # 3. 蓝牙自动启用+绑定(适配 hcitool/rfcomm)
  57. # --------------------------
  58. log "=== 开始蓝牙初始化 ==="
  59. # 加载蓝牙驱动(btnxpuart)
  60. modprobe btnxpuart || { log "蓝牙驱动加载失败"; }
  61. log "蓝牙驱动加载成功"
  62. sleep 2

  63. # 重启蓝牙服务(确保服务就绪)
  64. systemctl restart bluetooth || { log "蓝牙服务重启失败"; }
  65. log "蓝牙服务已重启"
  66. sleep 1

  67. # 启用蓝牙接口(hcitool替代hciconfig hci0 up)
  68. hcitool cmd 0x03 0x0001 0x01 || { log "蓝牙接口启用失败"; }
  69. log "蓝牙接口hci0已启用"
  70. sleep 2

  71. # 自动绑定蓝牙设备(BLUETOOTH_MAC非空则执行)
  72. if [ -n "${BLUETOOTH_MAC}" ]; then
  73.     log "正在绑定蓝牙设备: ${BLUETOOTH_MAC}"
  74.     rfcomm release 0 2>/dev/null  # 先解除旧绑定(避免冲突)
  75.     sleep 1
  76.     rfcomm bind 0 "${BLUETOOTH_MAC}" || { log "蓝牙绑定失败(检查MAC/设备可配对)"; }
  77.     log "蓝牙设备绑定成功,映射串口: /dev/rfcomm0(波特率: ${BLUETOOTH_BAUD})"
  78. fi

  79. # --------------------------
  80. # 4. 时间同步(多服务器重试,确保成功)
  81. # --------------------------
  82. log "=== 开始时间同步 ==="
  83. sleep 5  # 等待网络完全稳定
  84. SYNC_SUCCESS=0
  85. for server in ${NTP_SERVERS}; do
  86.     ntpdate -u "${server}" && {
  87.         log "时间同步成功(服务器: ${server})";
  88.         hwclock -w  # 同步到硬件时钟,重启不失效
  89.         SYNC_SUCCESS=1;
  90.         break;
  91.     }
  92.     log "时间同步失败(服务器: ${server}),尝试下一个...";
  93. done

  94. [ ${SYNC_SUCCESS} -eq 0 ] && log "所有NTP服务器同步失败,请检查网络"

  95. # --------------------------
  96. # 脚本结束(必须保留 exit 0)
  97. # --------------------------
  98. log "=== 自启脚本执行完成 ==="
  99. exit 0
复制代码
今天开机,在加载日志查找到有报错信息:
  1. Found device dev-ttyLP0.device - /dev/ttyLP0.
  2. [FAILED] Failed to start gpuconfig.…NXP i.MX/LS GPU (Former rc_gpu.S).
  3. See 'systemctl status gpuconfig.service' for details.
  4. [    6.649813] fec 42890000.ethernet end0: renamed from eth0
  5. [  OK  ] Started dbus.service - D-Bus System Message Bus.
  6. [  OK  ] Started avahi-daemon.service - Avahi mDNS/DNS-SD Stack.
  7.          Starting wpa_supplicant.service - WPA supplicant...
  8. [  OK  ] Started wpa_supplicant.service - WPA supplicant.
  9. [  OK  ] Reached target network.target - Network.
  10.          Starting ntpsec.service - Network Time Service...
  11.          Starting rc-local.service▒▒m - /etc/rc.local Compatibility...
  12.          Starting ssh.service - OpenBSD Secure Shell server...
  13.          Starting systemd-user-sess…vice - Permit User Sessions...
  14. [  OK  ] Finished e2scrub_reap.serv…ine ext4 Metadata Check Snapshots.
  15. [  OK  ] Started loadcpufreq.servic… needed to enable cpufreq scaling.
  16. [  OK  ] Started ntpsec.service - Network Time Service.
  17. [  OK  ] Finished systemd-user-sess…ervice - Permit User Sessions.
  18. [  OK  ] Started systemd-logind.service - User Login Management.
  19.          Starting cpufrequtils.serv…: set CPUFreq kernel parameters...
  20.          Starting lightdm.service - Light Display Manager...
  21. [    7.446894] mlan: loading out-of-tree module taints kernel.
  22.          Starting polkit.service - Authorization Manager...
  23. [    7.580534] wlan: Loading MWLAN driver
  24. [    7.611959] wlan: Register to Bus Driver...
  25. [  OK      7.627216] vendor=0x0471 device=0x0205 class=0 function=1
  26. m] Started cpufrequtils.servi…SB: set CPUFreq kernel parameters.
  27. [    7.650750] Attach moal handle ops, card interface type: 0x109
  28. [    7.665562] rps set to 0 from module param
  29. [    7.936006] SDIW612: init module param from usr cfg
  30. [    7.941478] card_type: SDIW612, config block: 0
  31. [    7.949769] cfg80211_wext=0xf
  32. [    7.952938] max_vir_bss=1
  33. [    7.955799] cal_data_cfg=none
  34. [    7.958853] ps_mode = 1
  35. [    7.961504] auto_ds = 1
  36. [    7.963954] host_mlme=enable
  37. [    7.966939] drv_mode = 1
  38. [    7.969609] fw_name=nxp/sduart_nw61x_v1.bin.se
  39. [    7.974239] SDIO: max_segs=128 max_seg_size=65535
  40. [    7.979021] rx_work=1 cpu_num=2
  41. [    7.982265] Enable moal_recv_amsdu_packet
  42. [    7.986434] Attach mlan adapter operations.card_type is 0x109.
  43. [    7.999043] wlan: Enable TX SG mode
  44. [    8.005623] wlan: Enable RX SG mode
  45. [    8.013492] Request firmware: nxp/sduart_nw61x_v1.bin.se
  46. [    8.019144] wlan_sdio mmc2:0001:1: loading /lib/firmware/nxp/sduart_nw61x_v1.bin.se failed with error -22
  47. [    8.028823] wlan_sdio mmc2:0001:1: Direct firmware load for nxp/sduart_nw61x_v1.bin.se failed with error -22
  48. [    8.038689] wlan_sdio mmc2:0001:1: Falling back to sysfs fallback for: nxp/sduart_nw61x_v1.bin.se
  49. [  OK  ] Started polkit.service - Authori[    8.286184] cfg80211: failed to load regulatory.db
  50. zation Manager.
  51. [    8.383945] imx8_media_dev: module is from the staging directory, the quality is unknown, you have been warned.
  52. [    8.395358] mx8-img-md: Registered mxc_isi.0.capture as /dev/video0
  53. [    8.423629] unregister ISI channel: mxc_isi.0
  54. [    8.586076] CAN device driver interface
  55. [    8.728557] rtc-pcf2131-i2c 2-0053: oscillator stop detected, date/time is not reliable
  56. [    8.795744] rtc-pcf2131-i2c 2-0053: registered as rtc1
  57. [    9.089033] fsl_mc_err_probe: No ECC DIMMs discovered
  58. [    9.257536] usb 1-1.2: Found UVC 1.00 device USB Camera (1bcf:28c4)
  59. [    9.318054] usbcore: registered new interface driver uvcvideo
  60. [    9.327884] WLAN: request_firmware() failed, error code = -2
  61. [    9.333629] woal_request_fw failed
  62. [    9.337095] Firmware Init Failed
  63. [    9.343103] Free module params
  64. [    9.350458] woal_add_card failed
  65. [    9.354932] usb 1-1.2: 3:1: cannot get freq at ep 0x86
  66. [    9.360275] wlan_sdio: probe of mmc2:0001:1 failed with error -1
  67. [    9.370562] wlan: Register to Bus Driver Done
  68. [    9.378650] wlan: Driver loaded successfully
  69. [    9.397460] usb 1-1.2: 3:2: cannot get freq at ep 0x86
  70. [    9.438675] usb 1-1.2: 3:3: cannot get freq at ep 0x86
  71. [    9.472384] usb 1-1.2: Warning! Unlikely big volume range (=4096), cval->res is probably wrong.
  72. [    9.481152] usb 1-1.2: [7] FU [Mic Capture Volume] ch = 1, val = 0/4096/1
  73. [    9.489006] usbcore: registered new interface driver snd-usb-audio
  74. [   12.391091] rc.local[371]: Cannot find device "mlan0"
  75. [FAILED] Failed to start rc-local.s…[0m - /etc/rc.local Compatibility.
复制代码
查找到出错信息:
loading /lib/firmware/nxp/sduart_nw61x_v1.bin.se failed with error -22
然后查看这个文件:-rw-r--r-- 1 root root      0 Nov 23  2025 sduart_nw61x_v1.bin.se
发现他的文件大小是0,因此考虑这个文件出错了。
【解决方法】
网上搜了好久都没有找到,因此想起我原来的安装包中有这个镜像的源文件,打开原来烧写SD卡的虚拟机找到压缩包,刚好找到了这个文件:

我将这个文件拷到/lib/firmware/nxp/目录,替换这个文件,然后重启系统,发现报错信息没有了。
【蓝牙测试】
安装bluez bluetooth库
  1. apt install -y bluez bluetooth
复制代码
扫描发现可以成功的使用了:
  1. (venv_mediapipe) root@localhost:/home/mypro# bluetoothctl
  2. Agent registered
  3. [CHG] Controller 80:A1:97:50:27:AC Pairable: yes
  4. [bluetooth]#
复制代码
【编写小米测试程序】
  1. from dataclasses import dataclass
  2. import asyncio
  3. from bleak import BleakClient, BleakError

  4. # 你的设备配置(和 Windows 脚本一致,无需修改)
  5. MAC = "A4:C1:38:99:9A:07"
  6. CHARACTERISTIC_UUID = "ebe0ccc1-7a0a-4b0c-8a1a-6ff2997da3a6"  # 已验证正确的特征值


  7. @dataclass
  8. class Result:
  9.     temperature: float
  10.     humidity: int
  11.     voltage: float
  12.     battery: int = 0


  13. async def read_ble_data(client):
  14.     """读取并解析温湿度数据(完全复用你的 Windows 解析逻辑)"""
  15.     try:
  16.         # 读取特征值(和 Windows 脚本完全一致)
  17.         buff = await client.read_gatt_char(CHARACTERISTIC_UUID)
  18.         
  19.         # 你的原始解析逻辑(保留不变,确保数据格式和 Windows 一致)
  20.         temp = int.from_bytes(buff[0:2], byteorder='little', signed=True) / 100
  21.         humidity = int.from_bytes(buff[2:3], byteorder='little')
  22.         voltage = int.from_bytes(buff[3:5], byteorder='little') / 1000
  23.         battery = round((voltage - 2) / (3.261 - 2) * 100, 2)
  24.         
  25.         # 确保电池百分比在 0-100 之间(避免异常值)
  26.         battery = max(0, min(100, battery))
  27.         
  28.         result = Result(
  29.             temperature=temp,
  30.             humidity=humidity,
  31.             voltage=voltage,
  32.             battery=int(battery)  # 转为整数更直观
  33.         )
  34.         return result
  35.     except Exception as e:
  36.         print(f"数据读取/解析失败:{str(e)}")
  37.         return None


  38. async def main(address):
  39.     client = BleakClient(address, timeout=30.0)
  40.     connect_attempts = 3  # 连接重试次数(解决连接不稳定)
  41.    
  42.     try:
  43.         # 连接重试逻辑(适配 Debian 蓝牙连接波动)
  44.         for attempt in range(connect_attempts):
  45.             print(f"\n🔌 连接设备 {address}(尝试 {attempt+1}/{connect_attempts})")
  46.             print("💡 请立即短按 LYWSD03MMC 侧面按键唤醒设备!")
  47.             await asyncio.sleep(0.5)  # 给用户 0.5 秒按按键
  48.             
  49.             try:
  50.                 if not client.is_connected:
  51.                     await client.connect()
  52.                 if client.is_connected:
  53.                     print("✅ 连接成功!")
  54.                     print("📌 若后续读取失败,请再次短按设备按键唤醒\n")
  55.                     break
  56.             except BleakError as e:
  57.                 print(f"❌ 第 {attempt+1} 次连接失败:{str(e)}")
  58.                 if attempt < connect_attempts - 1:
  59.                     print("⏳ 3 秒后重试...")
  60.                     await asyncio.sleep(3)
  61.         
  62.         # 连接失败后的退出逻辑
  63.         if not client.is_connected:
  64.             print("\n❌ 所有连接尝试失败!")
  65.             print("排查:1. 设备是否有电 2. 距离是否 ≤ 1 米 3. 关闭手机等其他蓝牙设备")
  66.             return
  67.         
  68.         # 循环读取数据(和 Windows 脚本一致,间隔 1 秒)
  69.         while True:
  70.             result = await read_ble_data(client)
  71.             if result:
  72.                 print(f"[读取成功] {result}")
  73.             else:
  74.                 print("⚠️  未读取到有效数据,请短按设备唤醒")
  75.             
  76.             # 异步睡眠(替代 time.sleep,不阻塞事件循环)
  77.             await asyncio.sleep(1)
  78.    
  79.     except BleakError as e:
  80.         print(f"\n🔴 蓝牙连接异常:{str(e)}")
  81.         print("💡 解决方案:重新运行脚本,按提示及时唤醒设备")
  82.     except KeyboardInterrupt:
  83.         print("\n\n👋 手动退出程序")
  84.     finally:
  85.         # 确保断开连接
  86.         if client.is_connected:
  87.             await client.disconnect()
  88.             print("✅ 已断开设备连接")


  89. if __name__ == "__main__":
  90.     # 适配 Debian 系统的 asyncio 事件循环(解决嵌入式 Linux 兼容问题)
  91.     try:
  92.         asyncio.run(main(MAC))
  93.     except RuntimeError as e:
  94.         # 若出现事件循环错误,用备用方式启动
  95.         loop = asyncio.get_event_loop()
  96.         loop.run_until_complete(main(MAC))
复制代码


最后测试效果如下:
  1. (venv_mediapipe) root@localhost:/home/mypro# python lywsd03mmc_read.py

  2. 🔌 连接设备 A4:C1:38:99:9A:07(尝试 1/3)
  3. 💡 请立即短按 LYWSD03MMC 侧面按键唤醒设备!
  4. ✅ 连接成功!
  5. 📌 若后续读取失败,请再次短按设备按键唤醒

  6. [读取成功] Result(temperature=19.97, humidity=51, voltage=2.897, battery=71)
  7. [读取成功] Result(temperature=19.97, humidity=51, voltage=2.897, battery=71)
  8. [读取成功] Result(temperature=19.97, humidity=51, voltage=2.897, battery=71)
  9. [读取成功] Result(temperature=19.97, humidity=51, voltage=2.897, battery=71)
  10. [读取成功] Result(temperature=19.97, humidity=51, voltage=2.897, battery=71)
复制代码
【总结】
经过一天一夜的排查,终于把蓝牙给用上了,下一步,我将实现与mcxw71的交互。

分享到:
回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /2 下一条