在之前的帖子中我已经实现了FRDM-MCXW71的Zephyr环境搭建和DHT11获取环境温湿度,本文将介绍将数据通过蓝牙发送到手机app
在进行代码编写之前,需要先烧录ble的固件,其方法是断开电源 -> 按住SW3(ISP) -> 插上电源 -> 松开SW3,接着将mcuxw71_nbu_ble_hosted.sb3通过串口烧录进芯片固件

接着编写BLE相关代码,DHT11的读取方式在上一篇帖子中已经介绍了,这里不再赘述
定义蓝牙GATT服务相关参数
/* ================================================================ * BLE Custom GATT Service - DHT11 Temperature & Humidity * ================================================================ * * Service UUID: 12345678-1234-1234-1234-123456789abc * Temperature Char: 12345678-1234-1234-1234-123456789abd int16 (0.1°C) * Humidity Char: 12345678-1234-1234-1234-123456789abe int16 (0.1%RH) * Status String Char: 12345678-1234-1234-1234-123456789abf UTF-8 text * * All three characteristics support Read. * Temperature and Humidity support Notify for real-time updates. * Status String supports Notify with short format (T:xx.xC H:xx.x%). */ /* UUID definitions for the custom DHT11 GATT service */ #define BT_UUID_DHT11_SERVICE_VAL \ BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x1234, 0x1234, 0x123456789abc) #define BT_UUID_DHT11_TEMP_VAL \ BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x1234, 0x1234, 0x123456789abd) #define BT_UUID_DHT11_HUM_VAL \ BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x1234, 0x1234, 0x123456789abe) #define BT_UUID_DHT11_STATUS_VAL \ BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x1234, 0x1234, 0x123456789abf) /* UUID structures */ static struct bt_uuid_128 dht11_svc_uuid = BT_UUID_INIT_128(BT_UUID_DHT11_SERVICE_VAL); static struct bt_uuid_128 dht11_temp_uuid = BT_UUID_INIT_128(BT_UUID_DHT11_TEMP_VAL); static struct bt_uuid_128 dht11_hum_uuid = BT_UUID_INIT_128(BT_UUID_DHT11_HUM_VAL); static struct bt_uuid_128 dht11_status_uuid = BT_UUID_INIT_128(BT_UUID_DHT11_STATUS_VAL); /* Global sensor data shared between read callbacks and main loop */ static int16_t g_temperature_x10; /**< Temperature in 0.1°C */ static int16_t g_humidity_x10; /**< Humidity in 0.1%RH */ static bool g_ntf_enabled; /**< CCC notification enable flag */ static char g_status_str[64]; /**< Status string buffer */
定义一些温湿度读取的回调函数
/**
* @brief GATT read callback for temperature characteristic.
*
* Returns the current temperature value as int16 LE (0.1°C resolution).
* Example: value 279 = 27.9°C.
*/
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 val = sys_cpu_to_le16(g_temperature_x10);
return bt_gatt_attr_read(conn, attr, buf, len, offset, &val, sizeof(val));
}
/**
* @brief GATT read callback for humidity characteristic.
*
* Returns the current humidity value as int16 LE (0.1%RH resolution).
* Example: value 754 = 75.4%RH.
*/
static ssize_t read_humidity(struct bt_conn *conn,
const struct bt_gatt_attr *attr,
void *buf, uint16_t len, uint16_t offset)
{
int16_t val = sys_cpu_to_le16(g_humidity_x10);
return bt_gatt_attr_read(conn, attr, buf, len, offset, &val, sizeof(val));
}
/**
* @brief GATT read callback for status string characteristic.
*
* Returns the formatted status string as UTF-8 text.
* Example: "T:27.9C H:75.4%"
*/
static ssize_t read_status(struct bt_conn *conn,
const struct bt_gatt_attr *attr,
void *buf, uint16_t len, uint16_t offset)
{
return bt_gatt_attr_read(conn, attr, buf, len, offset,
g_status_str, strlen(g_status_str));
}
/**
* @brief CCC changed callback for DHT11 service characteristics.
*
* Called when the client enables or disables notifications (CCC descriptor
* write). Updates the global notification flag.
*/
static void dht11_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
{
g_ntf_enabled = (value == BT_GATT_CCC_NOTIFY);
printk("DHT11 notifications %s\n", g_ntf_enabled ? "enabled" : "disabled");
}定义消息输出的格式
/* GATT service definition macro - defines all attributes in order:
* attrs[0] = PRIMARY_SERVICE
* attrs[1] = Temperature characteristic declaration
* attrs[2] = Temperature characteristic value
* attrs[3] = Temperature CCC descriptor
* attrs[4] = Humidity characteristic declaration
* attrs[5] = Humidity characteristic value
* attrs[6] = Humidity CCC descriptor
* attrs[7] = Status String characteristic declaration
* attrs[8] = Status String characteristic value
* attrs[9] = Status String CCC descriptor
*/
BT_GATT_SERVICE_DEFINE(dht11_svc,
BT_GATT_PRIMARY_SERVICE(&dht11_svc_uuid),
/* Temperature (int16 LE, 0.1°C, Read + Notify) */
BT_GATT_CHARACTERISTIC(&dht11_temp_uuid.uuid,
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
BT_GATT_PERM_READ,
read_temperature, NULL, NULL),
BT_GATT_CCC(dht11_ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
/* Humidity (int16 LE, 0.1%RH, Read + Notify) */
BT_GATT_CHARACTERISTIC(&dht11_hum_uuid.uuid,
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
BT_GATT_PERM_READ,
read_humidity, NULL, NULL),
BT_GATT_CCC(dht11_ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
/* Status String (UTF-8 short text, Read + Notify) */
BT_GATT_CHARACTERISTIC(&dht11_status_uuid.uuid,
BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY,
BT_GATT_PERM_READ,
read_status, NULL, NULL),
BT_GATT_CCC(dht11_ccc_cfg_changed, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
);
/* ================================================================
* BLE Advertising Data
* ================================================================ */
/* Advertising packet: flags + 128-bit service UUID */
static const struct bt_data ad[] = {
BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_DHT11_SERVICE_VAL),
};
/* Scan response packet: device name */
static const struct bt_data sd[] = {
BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME,
sizeof(CONFIG_BT_DEVICE_NAME) - 1),
};蓝牙连接功能
/* ================================================================
* BLE Connection Management
* ================================================================ */
/* Connection state bits */
enum { STATE_CONNECTED, STATE_DISCONNECTED, STATE_BITS };
static ATOMIC_DEFINE(state, STATE_BITS); /**< Atomic connection state */
static struct bt_conn *g_ble_conn; /**< Active BLE connection handle */
/**
* @brief BLE connection established callback.
*
* Saves the connection handle with reference count and sets the
* connected state flag for the main loop to detect.
*/
static void connected(struct bt_conn *conn, uint8_t err)
{
if (err) {
printk("Connection failed, err 0x%02x %s\n", err, bt_hci_err_to_str(err));
} else {
printk("Connected\n");
g_ble_conn = bt_conn_ref(conn);
(void)atomic_set_bit(state, STATE_CONNECTED);
}
}
/**
* @brief BLE disconnection callback.
*
* Releases the connection handle and sets the disconnected state flag.
*/
static void disconnected(struct bt_conn *conn, uint8_t reason)
{
printk("Disconnected, reason 0x%02x %s\n", reason, bt_hci_err_to_str(reason));
if (g_ble_conn) {
bt_conn_unref(g_ble_conn);
g_ble_conn = NULL;
}
(void)atomic_set_bit(state, STATE_DISCONNECTED);
}
/* Register connection callbacks */
BT_CONN_CB_DEFINE(conn_callbacks) = {
.connected = connected,
.disconnected = disconnected,
};
/**
* @brief Send GATT notifications for all DHT11 characteristics.
*
* Sends notifications for temperature (attrs[2]), humidity (attrs[5]),
* and status string (attrs[8]) to the connected client.
* Only called when a BLE connection is active (g_ble_conn != NULL).
*/
static void dht11_notify(void)
{
if (!g_ble_conn) {
return;
}
int16_t temp_le = sys_cpu_to_le16(g_temperature_x10);
int16_t hum_le = sys_cpu_to_le16(g_humidity_x10);
bt_gatt_notify(g_ble_conn, &dht11_svc.attrs[2], &temp_le, sizeof(temp_le));
bt_gatt_notify(g_ble_conn, &dht11_svc.attrs[5], &hum_le, sizeof(hum_le));
bt_gatt_notify(g_ble_conn, &dht11_svc.attrs[8], g_status_str, strlen(g_status_str));
}在主函数中,读取DHT11获取到的温湿度,组装数据,发送到蓝牙接收器
/* ================================================================
* Application Entry Point
* ================================================================ */
/**
* @brief Application main function.
*
* Initialization sequence:
* 1. Configure DHT11 sensor on PTB4
* 2. Read first sample for immediate output
* 3. Initialize BLE stack
* 4. Start BLE advertising
* 5. Enter main loop: read DHT11 every 2 seconds, notify BLE client
*
* If BLE initialization fails, falls back to serial-only mode.
*/
int main(void)
{
int err;
printk("DHT11 BLE Sensor starting...\n");
/* ---- Initialize DHT11 sensor ---- */
printk("Initializing DHT11 on PTB4...\n");
err = dht11_init();
if (err) {
printk("DHT11: Init failed (err %d)\n", err);
} else {
printk("DHT11: Init OK\n");
int16_t t, h;
if (dht11_read(&t, &h) == 0) {
g_temperature_x10 = t;
g_humidity_x10 = h;
snprintf(g_status_str, sizeof(g_status_str),
"T:%d.%dC H:%d.%d%%",
t / 10, t % 10, h / 10, h % 10);
printk("%s\n", g_status_str);
}
}
/* ---- Initialize BLE ---- */
printk("Initializing Bluetooth...\n");
err = bt_enable(NULL);
if (err) {
printk("Bluetooth init failed (err %d), serial-only mode\n", err);
goto serial_only;
}
printk("Bluetooth initialized\n");
/* ---- Start BLE advertising ---- */
printk("Starting advertising...\n");
err = bt_le_adv_start(BT_LE_ADV_CONN_FAST_1, ad, ARRAY_SIZE(ad),
sd, ARRAY_SIZE(sd));
if (err) {
printk("Advertising failed (err %d)\n", err);
goto serial_only;
}
printk("Advertising started as '%s'\n", CONFIG_BT_DEVICE_NAME);
/* ---- Main loop: read sensor + notify BLE ---- */
while (1) {
k_sleep(K_SECONDS(2));
if (!dht11_dev) continue;
int16_t t, h;
if (dht11_read(&t, &h) != 0) continue;
g_temperature_x10 = t;
g_humidity_x10 = h;
snprintf(g_status_str, sizeof(g_status_str),
"T:%d.%dC H:%d.%d%%",
t / 10, t % 10, h / 10, h % 10);
printk("%s\n", g_status_str);
if (atomic_test_bit(state, STATE_CONNECTED)) {
dht11_notify();
}
}
return 0;
serial_only:
/* ---- Fallback: serial-only mode (no BLE) ---- */
printk("DHT11 serial-only mode (no BLE)\n");
while (1) {
k_sleep(K_SECONDS(2));
if (!dht11_dev) continue;
int16_t t, h;
if (dht11_read(&t, &h) == 0) {
printk("Temperature: %d.%d C, Humidity: %d.%d %%RH\n",
t / 10, t % 10, h / 10, h % 10);
}
}
return 0;
}编译烧录代码,可以进行了蓝牙初始化,并且以Zephyr Heartrate Sensor的蓝牙设备名出现,当手机端点击连接后,输出Connected字样作为提示信息
我是用nRF Connect,可以看到可以成功读取温湿度信息,并且可以实时变化

完整工程代码如下
我要赚赏金
