【FRDM-I.MX93】体验低功耗蓝牙读取小米温湿度计
【前言】前面我测试了一下蓝牙,是没有成功的,今天我重新从镜像包中复制了一份驱动文件到驱动包中,然后蓝牙就正常工作了,现在分享一下读取小米温湿度计的工程。
【原因查找】
我原先工作是正常的,编译了开机加载wifi的脚本,脚本代码:
#!/bin/sh -e
# 功能:Wi-Fi自动联网 + 蓝牙自动启用+绑定 + 时间同步 + 时区设置
# 适配:无 bluetoothctl/hciconfig,依赖 hcitool/rfcomm/ntpdate
# 日志:所有输出写入 /var/log/rc_local.log,方便排查
# ==============================================
# --------------------------
# 基础配置(用户按需修改!)
# --------------------------
WIFI_SSID="HUAWEI-H10R9U" # 替换为你的Wi-Fi名称(已在wpa_supplicant.conf配置可忽略)
WIFI_CONF="/etc/wpa_supplicant/wpa_supplicant.conf"# Wi-Fi配置文件路径
BLUETOOTH_MAC="" # 替换为你的蓝牙设备MAC(无需自动绑定则留空)
BLUETOOTH_BAUD=9600 # 蓝牙串口波特率(如HC-05默认9600)
NTP_SERVERS="ntp.aliyun.com ntp.tencent.com cn.pool.ntp.org"# NTP同步服务器(多服务器冗余)
TIMEZONE="Asia/Shanghai" # 国内时区(固定无需改)
# --------------------------
# 日志函数(统一输出格式)
# --------------------------
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> /var/log/rc_local.log
}
# --------------------------
# 1. 初始化:时区设置(优先执行)
# --------------------------
log "=== 开始初始化系统配置 ==="
export TZ="${TIMEZONE}"
ln -sf /usr/share/zoneinfo/"${TIMEZONE}" /etc/localtime# 兼容无 timedatectl 环境
log "时区已设置为:${TIMEZONE}"
# --------------------------
# 2. Wi-Fi 自动联网(核心优化:增加重试+延时)
# --------------------------
log "=== 开始 Wi-Fi 联网 ==="
# 加载 Wi-Fi 驱动(增加 3 秒延时,确保硬件就绪)
modprobe moal mod_para=nxp/wifi_mod_para.conf || { log "Wi-Fi驱动加载失败"; exit 1; }
log "Wi-Fi驱动加载成功"
sleep 3
# 启用以太网接口(mlan0)
ip link set mlan0 up || { log "mlan0接口启用失败"; exit 1; }
log "mlan0接口已启用"
sleep 2
# 启动 wpa_supplicant 连接 Wi-Fi(后台运行,失败重试1次)
wpa_supplicant -i mlan0 -c "${WIFI_CONF}" -B || {
log "Wi-Fi连接失败,重试1次...";
sleep 2;
wpa_supplicant -i mlan0 -c "${WIFI_CONF}" -B || { log "Wi-Fi连接最终失败"; exit 1; }
}
log "wpa_supplicant启动成功,正在连接Wi-Fi: ${WIFI_SSID}"
sleep 3
# DHCP获取IP(重试3次,避免网络波动)
for i in 1 2 3; do
dhclient mlan0 -v && { log "DHCP获取IP成功"; break; }
log "第${i}次DHCP获取IP失败,等待2秒重试...";
sleep 2;
[ ${i} -eq 3 ] && { log "DHCP获取IP失败(3次重试)"; exit 1; }
done
# --------------------------
# 3. 蓝牙自动启用+绑定(适配 hcitool/rfcomm)
# --------------------------
log "=== 开始蓝牙初始化 ==="
# 加载蓝牙驱动(btnxpuart)
modprobe btnxpuart || { log "蓝牙驱动加载失败"; }
log "蓝牙驱动加载成功"
sleep 2
# 重启蓝牙服务(确保服务就绪)
systemctl restart bluetooth || { log "蓝牙服务重启失败"; }
log "蓝牙服务已重启"
sleep 1
# 启用蓝牙接口(hcitool替代hciconfig hci0 up)
hcitool cmd 0x03 0x0001 0x01 || { log "蓝牙接口启用失败"; }
log "蓝牙接口hci0已启用"
sleep 2
# 自动绑定蓝牙设备(BLUETOOTH_MAC非空则执行)
if [ -n "${BLUETOOTH_MAC}" ]; then
log "正在绑定蓝牙设备: ${BLUETOOTH_MAC}"
rfcomm release 0 2>/dev/null# 先解除旧绑定(避免冲突)
sleep 1
rfcomm bind 0 "${BLUETOOTH_MAC}" || { log "蓝牙绑定失败(检查MAC/设备可配对)"; }
log "蓝牙设备绑定成功,映射串口: /dev/rfcomm0(波特率: ${BLUETOOTH_BAUD})"
fi
# --------------------------
# 4. 时间同步(多服务器重试,确保成功)
# --------------------------
log "=== 开始时间同步 ==="
sleep 5# 等待网络完全稳定
SYNC_SUCCESS=0
for server in ${NTP_SERVERS}; do
ntpdate -u "${server}" && {
log "时间同步成功(服务器: ${server})";
hwclock -w# 同步到硬件时钟,重启不失效
SYNC_SUCCESS=1;
break;
}
log "时间同步失败(服务器: ${server}),尝试下一个...";
done
[ ${SYNC_SUCCESS} -eq 0 ] && log "所有NTP服务器同步失败,请检查网络"
# --------------------------
# 脚本结束(必须保留 exit 0)
# --------------------------
log "=== 自启脚本执行完成 ==="
exit 0
今天开机,在加载日志查找到有报错信息:
Found device dev-ttyLP0.device - /dev/ttyLP0.
Failed to start gpuconfig.…NXP i.MX/LS GPU (Former rc_gpu.S).
See 'systemctl status gpuconfig.service' for details.
[ 6.649813] fec 42890000.ethernet end0: renamed from eth0
Started dbus.service - D-Bus System Message Bus.
Started avahi-daemon.service - Avahi mDNS/DNS-SD Stack.
Starting wpa_supplicant.service - WPA supplicant...
Started wpa_supplicant.service - WPA supplicant.
Reached target network.target - Network.
Starting ntpsec.service - Network Time Service...
Starting rc-local.service▒▒m - /etc/rc.local Compatibility...
Starting ssh.service - OpenBSD Secure Shell server...
Starting systemd-user-sess…vice - Permit User Sessions...
Finished e2scrub_reap.serv…ine ext4 Metadata Check Snapshots.
Started loadcpufreq.servic… needed to enable cpufreq scaling.
Started ntpsec.service - Network Time Service.
Finished systemd-user-sess…ervice - Permit User Sessions.
Started systemd-logind.service - User Login Management.
Starting cpufrequtils.serv…: set CPUFreq kernel parameters...
Starting lightdm.service - Light Display Manager...
[ 7.446894] mlan: loading out-of-tree module taints kernel.
Starting polkit.service - Authorization Manager...
[ 7.580534] wlan: Loading MWLAN driver
[ 7.611959] wlan: Register to Bus Driver...
vendor=0x0471 device=0x0205 class=0 function=1
m] Started cpufrequtils.servi…SB: set CPUFreq kernel parameters.
[ 7.650750] Attach moal handle ops, card interface type: 0x109
[ 7.665562] rps set to 0 from module param
[ 7.936006] SDIW612: init module param from usr cfg
[ 7.941478] card_type: SDIW612, config block: 0
[ 7.949769] cfg80211_wext=0xf
[ 7.952938] max_vir_bss=1
[ 7.955799] cal_data_cfg=none
[ 7.958853] ps_mode = 1
[ 7.961504] auto_ds = 1
[ 7.963954] host_mlme=enable
[ 7.966939] drv_mode = 1
[ 7.969609] fw_name=nxp/sduart_nw61x_v1.bin.se
[ 7.974239] SDIO: max_segs=128 max_seg_size=65535
[ 7.979021] rx_work=1 cpu_num=2
[ 7.982265] Enable moal_recv_amsdu_packet
[ 7.986434] Attach mlan adapter operations.card_type is 0x109.
[ 7.999043] wlan: Enable TX SG mode
[ 8.005623] wlan: Enable RX SG mode
[ 8.013492] Request firmware: nxp/sduart_nw61x_v1.bin.se
[ 8.019144] wlan_sdio mmc2:0001:1: loading /lib/firmware/nxp/sduart_nw61x_v1.bin.se failed with error -22
[ 8.028823] wlan_sdio mmc2:0001:1: Direct firmware load for nxp/sduart_nw61x_v1.bin.se failed with error -22
[ 8.038689] wlan_sdio mmc2:0001:1: Falling back to sysfs fallback for: nxp/sduart_nw61x_v1.bin.se
Started polkit.service - Authori[ 8.286184] cfg80211: failed to load regulatory.db
zation Manager.
[ 8.383945] imx8_media_dev: module is from the staging directory, the quality is unknown, you have been warned.
[ 8.395358] mx8-img-md: Registered mxc_isi.0.capture as /dev/video0
[ 8.423629] unregister ISI channel: mxc_isi.0
[ 8.586076] CAN device driver interface
[ 8.728557] rtc-pcf2131-i2c 2-0053: oscillator stop detected, date/time is not reliable
[ 8.795744] rtc-pcf2131-i2c 2-0053: registered as rtc1
[ 9.089033] fsl_mc_err_probe: No ECC DIMMs discovered
[ 9.257536] usb 1-1.2: Found UVC 1.00 device USB Camera (1bcf:28c4)
[ 9.318054] usbcore: registered new interface driver uvcvideo
[ 9.327884] WLAN: request_firmware() failed, error code = -2
[ 9.333629] woal_request_fw failed
[ 9.337095] Firmware Init Failed
[ 9.343103] Free module params
[ 9.350458] woal_add_card failed
[ 9.354932] usb 1-1.2: 3:1: cannot get freq at ep 0x86
[ 9.360275] wlan_sdio: probe of mmc2:0001:1 failed with error -1
[ 9.370562] wlan: Register to Bus Driver Done
[ 9.378650] wlan: Driver loaded successfully
[ 9.397460] usb 1-1.2: 3:2: cannot get freq at ep 0x86
[ 9.438675] usb 1-1.2: 3:3: cannot get freq at ep 0x86
[ 9.472384] usb 1-1.2: Warning! Unlikely big volume range (=4096), cval->res is probably wrong.
[ 9.481152] usb 1-1.2: FU ch = 1, val = 0/4096/1
[ 9.489006] usbcore: registered new interface driver snd-usb-audio
[ 12.391091] rc.local: Cannot find device "mlan0"
Failed to start rc-local.s…查找到出错信息:
loading /lib/firmware/nxp/sduart_nw61x_v1.bin.se failed with error -22
然后查看这个文件:-rw-r--r-- 1 root root 0 Nov 232025 sduart_nw61x_v1.bin.se
发现他的文件大小是0,因此考虑这个文件出错了。
【解决方法】
网上搜了好久都没有找到,因此想起我原来的安装包中有这个镜像的源文件,打开原来烧写SD卡的虚拟机找到压缩包,刚好找到了这个文件:
我将这个文件拷到/lib/firmware/nxp/目录,替换这个文件,然后重启系统,发现报错信息没有了。
【蓝牙测试】
安装bluez bluetooth库
apt install -y bluez bluetooth扫描发现可以成功的使用了:
(venv_mediapipe) root@localhost:/home/mypro# bluetoothctl
Agent registered
Controller 80:A1:97:50:27:AC Pairable: yes
#
【编写小米测试程序】
from dataclasses import dataclass
import asyncio
from bleak import BleakClient, BleakError
# 你的设备配置(和 Windows 脚本一致,无需修改)
MAC = "A4:C1:38:99:9A:07"
CHARACTERISTIC_UUID = "ebe0ccc1-7a0a-4b0c-8a1a-6ff2997da3a6"# 已验证正确的特征值
@dataclass
class Result:
temperature: float
humidity: int
voltage: float
battery: int = 0
async def read_ble_data(client):
"""读取并解析温湿度数据(完全复用你的 Windows 解析逻辑)"""
try:
# 读取特征值(和 Windows 脚本完全一致)
buff = await client.read_gatt_char(CHARACTERISTIC_UUID)
# 你的原始解析逻辑(保留不变,确保数据格式和 Windows 一致)
temp = int.from_bytes(buff, byteorder='little', signed=True) / 100
humidity = int.from_bytes(buff, byteorder='little')
voltage = int.from_bytes(buff, byteorder='little') / 1000
battery = round((voltage - 2) / (3.261 - 2) * 100, 2)
# 确保电池百分比在 0-100 之间(避免异常值)
battery = max(0, min(100, battery))
result = Result(
temperature=temp,
humidity=humidity,
voltage=voltage,
battery=int(battery)# 转为整数更直观
)
return result
except Exception as e:
print(f"数据读取/解析失败:{str(e)}")
return None
async def main(address):
client = BleakClient(address, timeout=30.0)
connect_attempts = 3# 连接重试次数(解决连接不稳定)
try:
# 连接重试逻辑(适配 Debian 蓝牙连接波动)
for attempt in range(connect_attempts):
print(f"\n🔌 连接设备 {address}(尝试 {attempt+1}/{connect_attempts})")
print("💡 请立即短按 LYWSD03MMC 侧面按键唤醒设备!")
await asyncio.sleep(0.5)# 给用户 0.5 秒按按键
try:
if not client.is_connected:
await client.connect()
if client.is_connected:
print("✅ 连接成功!")
print("📌 若后续读取失败,请再次短按设备按键唤醒\n")
break
except BleakError as e:
print(f"❌ 第 {attempt+1} 次连接失败:{str(e)}")
if attempt < connect_attempts - 1:
print("⏳ 3 秒后重试...")
await asyncio.sleep(3)
# 连接失败后的退出逻辑
if not client.is_connected:
print("\n❌ 所有连接尝试失败!")
print("排查:1. 设备是否有电 2. 距离是否 ≤ 1 米 3. 关闭手机等其他蓝牙设备")
return
# 循环读取数据(和 Windows 脚本一致,间隔 1 秒)
while True:
result = await read_ble_data(client)
if result:
print(f"[读取成功] {result}")
else:
print("⚠️未读取到有效数据,请短按设备唤醒")
# 异步睡眠(替代 time.sleep,不阻塞事件循环)
await asyncio.sleep(1)
except BleakError as e:
print(f"\n🔴 蓝牙连接异常:{str(e)}")
print("💡 解决方案:重新运行脚本,按提示及时唤醒设备")
except KeyboardInterrupt:
print("\n\n👋 手动退出程序")
finally:
# 确保断开连接
if client.is_connected:
await client.disconnect()
print("✅ 已断开设备连接")
if __name__ == "__main__":
# 适配 Debian 系统的 asyncio 事件循环(解决嵌入式 Linux 兼容问题)
try:
asyncio.run(main(MAC))
except RuntimeError as e:
# 若出现事件循环错误,用备用方式启动
loop = asyncio.get_event_loop()
loop.run_until_complete(main(MAC))
最后测试效果如下:
(venv_mediapipe) root@localhost:/home/mypro# python lywsd03mmc_read.py
🔌 连接设备 A4:C1:38:99:9A:07(尝试 1/3)
💡 请立即短按 LYWSD03MMC 侧面按键唤醒设备!
✅ 连接成功!
📌 若后续读取失败,请再次短按设备按键唤醒
[读取成功] Result(temperature=19.97, humidity=51, voltage=2.897, battery=71)
[读取成功] Result(temperature=19.97, humidity=51, voltage=2.897, battery=71)
[读取成功] Result(temperature=19.97, humidity=51, voltage=2.897, battery=71)
[读取成功] Result(temperature=19.97, humidity=51, voltage=2.897, battery=71)
[读取成功] Result(temperature=19.97, humidity=51, voltage=2.897, battery=71)
【总结】
经过一天一夜的排查,终于把蓝牙给用上了,下一步,我将实现与mcxw71的交互。
页:
[1]