这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【e起DIY】低功耗蓝牙温湿度计-过程贴

共1条 1/1 1 跳转至

【e起DIY】低功耗蓝牙温湿度计-过程贴

菜鸟
2026-06-16 01:52:03     打赏

基于peripheral_hr例程开发,

修改main.c

/* main.c - Application main entry point */

/*
 * Copyright (c) 2024 Nordic Semiconductor ASA
 * Copyright (c) 2015-2016 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr/device.h>
#include <zephyr/devicetree.h>

#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/hci.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>
#include <zephyr/bluetooth/services/bas.h>
#include <zephyr/bluetooth/services/hrs.h>

#include <zephyr/drivers/sensor.h>

#include "hts.h"

static bool hrf_ntf_enabled;

// DHT20传感器设备指针
static const struct device *dht20_dev;

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_UUID16_ALL,
              BT_UUID_16_ENCODE(BT_UUID_HRS_VAL),
              BT_UUID_16_ENCODE(BT_UUID_BAS_VAL),
              BT_UUID_16_ENCODE(BT_UUID_DIS_VAL),
              BT_UUID_16_ENCODE(BT_UUID_HTS_VAL)),
#if defined(CONFIG_BT_EXT_ADV)
    BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1),
#endif /* CONFIG_BT_EXT_ADV */
};

#if !defined(CONFIG_BT_EXT_ADV)
static const struct bt_data sd[] = {
    BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1),
};
#endif /* !CONFIG_BT_EXT_ADV */

enum {
    STATE_CONNECTED,
    STATE_DISCONNECTED,

    STATE_BITS,
};

static ATOMIC_DEFINE(state, STATE_BITS);

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");

        (void)atomic_set_bit(state, STATE_CONNECTED);
    }
}

static void disconnected(struct bt_conn *conn, uint8_t reason)
{
    printk("Disconnected, reason 0x%02x %s\n", reason, bt_hci_err_to_str(reason));

    (void)atomic_set_bit(state, STATE_DISCONNECTED);
}

BT_CONN_CB_DEFINE(conn_callbacks) = {
    .connected = connected,
    .disconnected = disconnected,
};

static void hrs_ntf_changed(bool enabled)
{
    hrf_ntf_enabled = enabled;

    printk("HRS notification status changed: %s\n",
           enabled ? "enabled" : "disabled");
}

static struct bt_hrs_cb hrs_cb = {
    .ntf_changed = hrs_ntf_changed,
};

static void auth_cancel(struct bt_conn *conn)
{
    char addr[BT_ADDR_LE_STR_LEN];

    bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));

    printk("Pairing cancelled: %s\n", addr);
}

static struct bt_conn_auth_cb auth_cb_display = {
    .cancel = auth_cancel,
};

static void bas_notify(void)
{
    uint8_t battery_level = bt_bas_get_battery_level();

    battery_level--;

    if (!battery_level) {
        battery_level = 100U;
    }

    bt_bas_set_battery_level(battery_level);
}

static void hrs_notify(void)
{
    static uint8_t heartrate = 90U;

    /* Heartrate measurements simulation */
    heartrate++;
    if (heartrate == 160U) {
        heartrate = 90U;
    }

    if (hrf_ntf_enabled) {
        bt_hrs_notify(heartrate);
    }
}

// 读取DHT20温湿度数据
static void read_dht20_data(float *temperature, float *humidity)
{
    struct sensor_value temp_val, humidity_val;
    int rc;

    if (!dht20_dev) {
        return;
    }

    /* 获取温湿度数据 */
    rc = sensor_sample_fetch(dht20_dev);
    if (rc < 0) {
        printk("Failed to fetch DHT20 sample: %d\n", rc);
        return;
    }

    /* 获取温度值 */
    rc = sensor_channel_get(dht20_dev, SENSOR_CHAN_AMBIENT_TEMP, &temp_val);
    if (rc < 0) {
        printk("Failed to get temperature: %d\n", rc);
        return;
    }

    /* 获取湿度值 */
    rc = sensor_channel_get(dht20_dev, SENSOR_CHAN_HUMIDITY, &humidity_val);
    if (rc < 0) {
        printk("Failed to get humidity: %d\n", rc);
        return;
    }

    *temperature = sensor_value_to_double(&temp_val);
    *humidity = sensor_value_to_double(&humidity_val);

    /* 打印温湿度数据 */
    printk("Temperature: %.2f °C, Humidity: %.2f %%\n", *temperature, *humidity);
}

#if defined(CONFIG_GPIO)
/* The devicetree node identifier for the "led0" alias. */
#define LED0_NODE DT_ALIAS(led0)

#if DT_NODE_HAS_STATUS_OKAY(LED0_NODE)
#include <zephyr/drivers/gpio.h>
#define HAS_LED     1
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
#define BLINK_ONOFF K_MSEC(500)

static struct k_work_delayable blink_work;
static bool                  led_is_on;

static void blink_timeout(struct k_work *work)
{
    led_is_on = !led_is_on;
    gpio_pin_set(led.port, led.pin, (int)led_is_on);

    k_work_schedule(&blink_work, BLINK_ONOFF);
}

static int blink_setup(void)
{
    int err;

    printk("Checking LED device...");
    if (!gpio_is_ready_dt(&led)) {
        printk("failed.\n");
        return -EIO;
    }
    printk("done.\n");

    printk("Configuring GPIO pin...");
    err = gpio_pin_configure_dt(&led, GPIO_OUTPUT_ACTIVE);
    if (err) {
        printk("failed.\n");
        return -EIO;
    }
    printk("done.\n");

    k_work_init_delayable(&blink_work, blink_timeout);

    return 0;
}

static void blink_start(void)
{
    printk("Start blinking LED...\n");
    led_is_on = false;
    gpio_pin_set(led.port, led.pin, (int)led_is_on);
    k_work_schedule(&blink_work, BLINK_ONOFF);
}

static void blink_stop(void)
{
    struct k_work_sync work_sync;

    printk("Stop blinking LED.\n");
    k_work_cancel_delayable_sync(&blink_work, &work_sync);

    /* Keep LED on */
    led_is_on = true;
    gpio_pin_set(led.port, led.pin, (int)led_is_on);
}
#endif /* LED0_NODE */
#endif /* CONFIG_GPIO */

int main(void)
{
    int err;

    err = bt_enable(NULL);
    if (err) {
        printk("Bluetooth init failed (err %d)\n", err);
        return 0;
    }

    printk("Bluetooth initialized\n");

    bt_conn_auth_cb_register(&auth_cb_display);

    bt_hrs_cb_register(&hrs_cb);

    hts_init();

    /* 初始化DHT20传感器 */
    dht20_dev = DEVICE_DT_GET(DT_NODELABEL(dht20_sensor));
    if (!device_is_ready(dht20_dev)) {
        printk("DHT20 sensor device not ready\n");
        dht20_dev = NULL;
    } else {
        printk("DHT20 sensor initialized successfully\n");
    }

#if !defined(CONFIG_BT_EXT_ADV)
    printk("Starting Legacy Advertising (connectable and scannable)\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 to start (err %d)\n", err);
        return 0;
    }

#else /* CONFIG_BT_EXT_ADV */
    struct bt_le_adv_param adv_param = {
        .id = BT_ID_DEFAULT,
        .sid = 0U,
        .secondary_max_skip = 0U,
        .options = (BT_LE_ADV_OPT_EXT_ADV | BT_LE_ADV_OPT_CONN | BT_LE_ADV_OPT_CODED),
        .interval_min = BT_GAP_ADV_FAST_INT_MIN_2,
        .interval_max = BT_GAP_ADV_FAST_INT_MAX_2,
        .peer = NULL,
    };
    struct bt_le_ext_adv *adv;

    printk("Creating a Coded PHY connectable non-scannable advertising set\n");
    err = bt_le_ext_adv_create(&adv_param, NULL, &adv);
    if (err) {
        printk("Failed to create Coded PHY extended advertising set (err %d)\n", err);

        printk("Creating a non-Coded PHY connectable non-scannable advertising set\n");
        adv_param.options &= ~BT_LE_ADV_OPT_CODED;
        err = bt_le_ext_adv_create(&adv_param, NULL, &adv);
        if (err) {
            printk("Failed to create extended advertising set (err %d)\n", err);
            return 0;
        }
    }

    printk("Setting extended advertising data\n");
    err = bt_le_ext_adv_set_data(adv, ad, ARRAY_SIZE(ad), NULL, 0);
    if (err) {
        printk("Failed to set extended advertising data (err %d)\n", err);
        return 0;
    }

    printk("Starting Extended Advertising (connectable non-scannable)\n");
    err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT);
    if (err) {
        printk("Failed to start extended advertising set (err %d)\n", err);
        return 0;
    }
#endif /* CONFIG_BT_EXT_ADV */

    printk("Advertising successfully started\n");

#if defined(HAS_LED)
    err = blink_setup();
    if (err) {
        return 0;
    }

    blink_start();
#endif /* HAS_LED */

    /* Implement notification. */
    while (1) {
        float temperature = 25.0f;
        float humidity = 50.0f;

        k_sleep(K_SECONDS(1));

        /* Heartrate measurements simulation */
        hrs_notify();

        /* Battery level simulation */
        bas_notify();

        /* 读取DHT20温湿度数据 */
        read_dht20_data(&temperature, &humidity);

        /* 推送温度数据到HTS服务 */
        hts_indicate(temperature);

        if (atomic_test_and_clear_bit(state, STATE_CONNECTED)) {
            /* Connected callback executed */

#if defined(HAS_LED)
            blink_stop();
#endif /* HAS_LED */
        } else if (atomic_test_and_clear_bit(state, STATE_DISCONNECTED)) {
#if !defined(CONFIG_BT_EXT_ADV)
            printk("Starting Legacy Advertising (connectable and scannable)\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 to start (err %d)\n", err);
                return 0;
            }

#else /* CONFIG_BT_EXT_ADV */
            printk("Starting Extended Advertising (connectable and non-scannable)\n");
            err = bt_le_ext_adv_start(adv, BT_LE_EXT_ADV_START_DEFAULT);
            if (err) {
                printk("Failed to start extended advertising set (err %d)\n", err);
                return 0;
            }
#endif /* CONFIG_BT_EXT_ADV */

#if defined(HAS_LED)
            blink_start();
#endif /* HAS_LED */
        }
    }

    return 0;
}

src目录增加hts.c

/** @file
 *  @brief HTS Service implementation
 */

/*
 * SPDX-License-Identifier: Apache-2.0
 */

#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>

#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/byteorder.h>

#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/hci.h>
#include <zephyr/bluetooth/conn.h>
#include <zephyr/bluetooth/uuid.h>
#include <zephyr/bluetooth/gatt.h>

static uint8_t indicate_enabled;
static uint8_t indicating;
static struct bt_gatt_indicate_params ind_params;

static void htmc_ccc_cfg_changed(const struct bt_gatt_attr *attr,
                 uint16_t value)
{
    indicate_enabled = (value == BT_GATT_CCC_INDICATE) ? 1 : 0;
    printk("HTS indication %s\n", indicate_enabled ? "enabled" : "disabled");
}

static void indicate_cb(struct bt_conn *conn,
            struct bt_gatt_indicate_params *params, uint8_t err)
{
    printk("Temperature indication %s\n", err != 0U ? "fail" : "success");
}

static void indicate_destroy(struct bt_gatt_indicate_params *params)
{
    indicating = 0U;
}

/* Health Thermometer Service Declaration */
BT_GATT_SERVICE_DEFINE(hts_svc,
    BT_GATT_PRIMARY_SERVICE(BT_UUID_HTS),
    BT_GATT_CHARACTERISTIC(BT_UUID_HTS_MEASUREMENT, BT_GATT_CHRC_INDICATE,
                   BT_GATT_PERM_NONE, NULL, NULL, NULL),
    BT_GATT_CCC(htmc_ccc_cfg_changed,
            BT_GATT_PERM_READ | BT_GATT_PERM_WRITE),
);

void hts_init(void)
{
    printk("Health Thermometer Service initialized\n");
}

void hts_indicate(float temperature)
{
    if (!indicate_enabled) {
        return;
    }

    if (indicating) {
        return;
    }

    static uint8_t htm[5];
    uint32_t mantissa;
    uint8_t exponent;

    mantissa = (uint32_t)(temperature * 100);
    exponent = (uint8_t)-2;

    htm[0] = 0; /* temperature in celsius */
    sys_put_le24(mantissa, (uint8_t *)&htm[1]);
    htm[4] = exponent;

    ind_params.attr = &hts_svc.attrs[2];
    ind_params.func = indicate_cb;
    ind_params.destroy = indicate_destroy;
    ind_params.data = &htm;
    ind_params.len = sizeof(htm);

    if (bt_gatt_indicate(NULL, &ind_params) == 0) {
        indicating = 1U;
    }
}

src目录增加hts.h

/** @file
 *  @brief HTS Service for temperature indication
 */

/*
 * SPDX-License-Identifier: Apache-2.0
 */

#ifdef __cplusplus
extern "C" {
#endif

void hts_init(void);
void hts_indicate(float temperature);

#ifdef __cplusplus
}
#endif

peripheral_hr目录增加app.over

// SPDX-License-Identifier: Apache-2.0

&lpi2c1 {
	status = "okay";
	clock-frequency = <100000>;

	dht20_sensor: dht20@38 {
		compatible = "aosong,dht20";
		reg = <0x38>;
		label = "DHT20";
	};
};

修改prj.conf

CONFIG_BT=y
CONFIG_LOG=y
CONFIG_BT_SMP=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_DIS=y
CONFIG_BT_DIS_PNP=n
CONFIG_BT_BAS=y
CONFIG_BT_HRS=y
# CONFIG_BT_DEVICE_NAME="Zephyr Heartrate Sensor"
CONFIG_BT_DEVICE_NAME="Zephyr Sensor"
CONFIG_BT_DEVICE_APPEARANCE=833

CONFIG_CBPRINTF_FP_SUPPORT=y

# DHT20传感器支持
CONFIG_SENSOR=y
CONFIG_DHT20=y
CONFIG_DHT20_CRC=y
CONFIG_I2C=y



共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]