背景
首先,在搞这个之前,我还纳闷,NXP的IOT Toolbox那玩意,不是他们家的测试上位机吗?照理来说,这种软件不都指定了特定设备才能正确识别吗?但是问了一遍豆包,都报直接回这个应用不管哪家的都能用。既然豆包都这么回了,那就直接写一个试试。
这写的动作,我还是交给了大模型帮忙做,虽然提需求加说问题之说了那么七八句,但毕竟用的是国外的大模型,整个推理加编译通过用了将近半小时才完成。
环境准备
frdm-mcxw72的readme直接说明,要玩ble,需先烧录blobs文件,烧录前,需先安装blobs烧录器。
安装blhost
烧录blobs需要安装blhost软件,这个软件不太好下载。我的操作方法是:
直接去官网下zip包,具体资源链接为:https://www.nxp.com/design/design-center/software/development-software/mcuxpresso-software-and-tools-/mcu-bootloader-for-nxp-microcontrollers:MCUBOOT
下载好后,解压该包,解压完毕后,输入以下命令安装:
sudo cp -r blhost_2.6.7 /usr/local/bin/blhost sudo chmod +x /usr/local/bin/blhost
下载blobs文件
执行命令 west blobs fetch hal_nxp,那就先执行这个命令,执行完没有任何打印,但是可以通过查看目录~/zephyrproject/modules/hal/nxp/zephyr/blobs/ 查看是否存在mcxw72的blobs文件。
(.venv) oxlm@oxlm-ThinkPad-X280:~/zephyrproject/zephyr$ ls ~/zephyrproject/modules/hal/nxp/zephyr/blobs/ | grep "w72" mcxw72
烧录blobs文件
首先,查看blobs文件
(.venv) oxlm@oxlm-ThinkPad-X280:~/zephyrproject/zephyr$ ls -lah ~/zephyrproject/modules/ha l/nxp/zephyr/blobs/mcxw72 总计 896K drwxrwxr-x 3 oxlm oxlm 4.0K 4月 4 18:02 . drwxrwxr-x 12 oxlm oxlm 4.0K 4月 4 18:03 .. drwxrwxr-x 2 oxlm oxlm 4.0K 4月 4 18:02 libieee -rw-rw-r-- 1 oxlm oxlm 292K 4月 4 18:02 mcxw72_nbu_ble_15_4_dyn.bin -rw-rw-r-- 1 oxlm oxlm 312K 4月 4 18:02 mcxw72_nbu_ble_15_4_dyn_mac.bin -rw-rw-r-- 1 oxlm oxlm 277K 4月 4 18:01 mcxw72_nbu_ble_all_hosted.bin
基本上可以看到,有3个blobs文件,其中一个明确写的是all_hosted,估摸着是用作ble host端的,可以放最后尝试,前面两个,看着就后面一个多了个mac,我估摸着和w71类似(见https://forum.eepw.com.cn/thread/399760/1),带mac是说mac层固化到nbu固件中。之后便是执行烧录,烧录方法如下:
blhost -p /dev/ttyACM0 flash-erase-all 0 blhost -p /dev/ttyACM0 flash-erase-all 2 blhost -p /dev/ttyACM0 write-memory 0x48800000 ~/zephyrproject/modules/hal/nxp/zephyr/blobs/mcxw72/mcxw72_nbu_ble_15_4_dyn.bin
代码修改
这部分的修改很少,只是修改了app目录下的两个文件(prj.conf 和 main.c)。
prj.conf
这部分的修改很少,就是启用了蓝牙,然后把蓝牙的BLE名称设置成了FRDM-MCXW72-AHT20,最后开启GATT服务和多重通知功能。实际上除了这部分,还有不少蓝牙相关的开关也同步打开了,只是因为在KConfig那部分默认是开的,所以就没有显式地在conf文件中写出来了。
CONFIG_BT=y CONFIG_BT_PERIPHERAL=y CONFIG_BT_DEVICE_NAME="FRDM-MCXW72-AHT20" CONFIG_BT_GATT_NOTIFY_MULTIPLE=y
main.c
这部分全部让大模型写了,不过确实,虽然AI已经很强大了,但是生成的代码还是需要再检查,指明问题后让大模型进行进一步的优化,直到看不出明显的问题。
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/sensor.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/sys/printk.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/uuid.h>
/* BLE device name advertised by this peripheral, sourced from CONFIG_BT_DEVICE_NAME */
#define DEVICE_NAME CONFIG_BT_DEVICE_NAME
/* Device tree bindings for AHT20 temperature and humidity virtual sensors */
static const struct device *temp_dev = DEVICE_DT_GET_ONE(aosong_aht20_temp);
static const struct device *hum_dev = DEVICE_DT_GET_ONE(aosong_aht20_hum);
/* Notification enable flags for temperature and humidity characteristics */
static bool temp_notify_enabled;
static bool hum_notify_enabled;
/* Fetch the latest temperature value from the AHT20 sensor.
* Returns 0 on success or a negative error code if the fetch fails.
*/
static int read_sensor_temperature(int16_t *temp_raw)
{
int ret;
struct sensor_value temp;
ret = sensor_sample_fetch(temp_dev);
if (ret) {
return ret;
}
sensor_channel_get(temp_dev, SENSOR_CHAN_AMBIENT_TEMP, &temp);
*temp_raw = temp.val1 * 100 + temp.val2 / 10000;
return 0;
}
/* Fetch the latest humidity value from the AHT20 sensor.
* Returns 0 on success or a negative error code if the fetch fails.
*/
static int read_sensor_humidity(uint16_t *hum_raw)
{
int ret;
struct sensor_value hum;
ret = sensor_sample_fetch(hum_dev);
if (ret) {
return ret;
}
sensor_channel_get(hum_dev, SENSOR_CHAN_HUMIDITY, &hum);
*hum_raw = hum.val1 * 100 + hum.val2 / 10000;
return 0;
}
/* Read callback for signed 16-bit temperature characteristic values */
static ssize_t read_temperature(struct bt_conn *conn,
const struct bt_gatt_attr *attr,
void *buf, uint16_t len, uint16_t offset)
{
int16_t temp_raw;
int ret = read_sensor_temperature(&temp_raw);
if (ret) {
printk("BLE read: Failed to read temperature sensor (err %d)n", ret);
return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
}
int16_t value = sys_cpu_to_le16(temp_raw);
return bt_gatt_attr_read(conn, attr, buf, len, offset, &value,
sizeof(value));
}
/* Read callback for unsigned 16-bit humidity characteristic values */
static ssize_t read_humidity(struct bt_conn *conn,
const struct bt_gatt_attr *attr,
void *buf, uint16_t len, uint16_t offset)
{
uint16_t hum_raw;
int ret = read_sensor_humidity(&hum_raw);
if (ret) {
printk("BLE read: Failed to read humidity sensor (err %d)n", ret);
return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
}
uint16_t value = sys_cpu_to_le16(hum_raw);
return bt_gatt_attr_read(conn, attr, buf, len, offset, &value,
sizeof(value));
}
/* Callback when the temperature characteristic CCC descriptor changes */
static void temp_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
{
temp_notify_enabled = (value == BT_GATT_CCC_NOTIFY);
}
/* Callback when the humidity characteristic CCC descriptor changes */
static void hum_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
{
hum_notify_enabled = (value == BT_GATT_CCC_NOTIFY);
}
/* Environmental Sensing Service (ESS) with temperature and humidity characteristics.
* This service exposes sensor data over BLE GATT, allowing clients to read current
* values and subscribe to notifications for real-time updates.
*/
BT_GATT_SERVICE_DEFINE(ess_svc,
BT_GATT_PRIMARY_SERVICE(BT_UUID_ESS),
BT_GATT_CHARACTERISTIC(BT_UUID_TEMPERATURE,
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
BT_GATT_PERM_READ,
read_temperature, NULL, NULL),
BT_GATT_CCC(temp_ccc_cfg_changed,
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
BT_GATT_CHARACTERISTIC(BT_UUID_HUMIDITY,
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
BT_GATT_PERM_READ,
read_humidity, NULL, NULL),
BT_GATT_CCC(hum_ccc_cfg_changed,
BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
);
/* Log the temperature value to the console. */
static void log_temperature(int16_t temp_raw)
{
printk("Temperature: %d.%02d Cn", temp_raw / 100, abs(temp_raw % 100));
}
/* Log the humidity value to the console. */
static void log_humidity(uint16_t hum_raw)
{
printk("Humidity: %d.%02d %%n", hum_raw / 100, hum_raw % 100);
}
/* Send BLE notification for temperature if enabled. */
static void notify_temperature(int16_t temp_raw)
{
if (temp_notify_enabled) {
int16_t value = sys_cpu_to_le16(temp_raw);
bt_gatt_notify(NULL, &ess_svc.attrs[2], &value, sizeof(value));
}
}
/* Send BLE notification for humidity if enabled. */
static void notify_humidity(uint16_t hum_raw)
{
if (hum_notify_enabled) {
uint16_t value = sys_cpu_to_le16(hum_raw);
bt_gatt_notify(NULL, &ess_svc.attrs[5], &value, sizeof(value));
}
}
/* Advertisement flags for LE general discoverable mode, BR/EDR disabled */
static const uint8_t ad_flags[] = { BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR };
/* Initialize and verify AHT20 temperature and humidity sensors are ready.
* Returns 0 on success or a negative error code if sensors are not available.
*/
static int sensors_init(void)
{
if (!device_is_ready(temp_dev)) {
printk("AHT20 temperature sensor not readyn");
return -ENODEV;
}
if (!device_is_ready(hum_dev)) {
printk("AHT20 humidity sensor not readyn");
return -ENODEV;
}
return 0;
}
/* Initialize Bluetooth stack and start advertising as a connectable peripheral.
* Returns 0 on success or a negative error code on failure.
*/
static int bluetooth_init(void)
{
int ret;
ret = bt_enable(NULL);
if (ret) {
printk("Bluetooth init failed (err %d)n", ret);
return ret;
}
printk("Bluetooth initializedn");
static const struct bt_data ad[] = {
BT_DATA(BT_DATA_FLAGS, ad_flags, sizeof(ad_flags)),
BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, sizeof(DEVICE_NAME) - 1),
};
ret = bt_le_adv_start(BT_LE_ADV_CONN_FAST_1, ad, ARRAY_SIZE(ad), NULL, 0);
if (ret) {
printk("Advertising failed (err %d)n", ret);
return ret;
}
printk("Advertising as: %sn", DEVICE_NAME);
return 0;
}
/* Main sensor reading and notification loop.
* Continuously reads sensor values, logs them, and notifies BLE clients every second.
* Handles sensor read failures independently.
*/
static void run_sensor_loop(void)
{
while (1) {
int16_t temp_raw;
uint16_t hum_raw;
if (read_sensor_temperature(&temp_raw) == 0) {
log_temperature(temp_raw);
notify_temperature(temp_raw);
} else {
printk("Temperature fetch failedn");
}
if (read_sensor_humidity(&hum_raw) == 0) {
log_humidity(hum_raw);
notify_humidity(hum_raw);
} else {
printk("Humidity fetch failedn");
}
k_sleep(K_SECONDS(1));
}
}
/* Application entry point.
* Initializes sensors and Bluetooth, then enters the sensor monitoring loop.
* Exits on initialization failure.
*/
int main(void)
{
int ret;
ret = sensors_init();
if (ret) {
return 0;
}
ret = bluetooth_init();
if (ret) {
return 0;
}
run_sensor_loop();
return 0;
}烧录后运行
先说结论,很遗憾的是,nxp的IOT Toolbox的sensor选项并不能找到这个传感器,但是nordic的nrf connect已经很明确地可以读到数据了。也不知道nxp的iot toolbox有什么限制条件,只能看其他人是否有环境抓取iot toolbox能读到的数据的软件的细节再去反查了。
nrf connect读到的数据

运行过程打印
** Booting Zephyr OS build v4.4.0-rc2-34-g41082f40fc8f *** Bluetooth initialized Advertising as: FRDM-MCXW72-AHT20 Temperature: 28.47 C Humidity: 64.60 % Temperature: 28.41 C Humidity: 64.77 % Temperature: 28.41 C Humidity: 64.97 % Temperature: 28.37 C Humidity: 65.11 % Temperature: 28.34 C Humidity: 65.25 % Temperature: 28.29 C Humidity: 65.31 % Temperature: 28.26 C Humidity: 65.48 % Temperature: 28.25 C Humidity: 65.62 % Temperature: 28.19 C Humidity: 65.68 % Temperature: 28.15 C Humidity: 65.80 % Temperature: 28.13 C Humidity: 65.91 % Temperature: 28.11 C Humidity: 66.05 %
我要赚赏金
