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

共1条 1/1 1 跳转至

【eDIY】蓝牙低功耗温湿度计成果贴-通过蓝牙读取sht30数据

助工
2026-06-15 20:02:12     打赏

续上一篇帖子【eDIY】蓝牙低功耗温湿度计过程贴-在vscode上搭建环境,连接蓝牙-电子产品世界论坛 (eepw.com.cn)的例程,我们在例程中加入我们的sht30驱动代码,使用的型号为本次活动提供的sht30,查阅数据手册,发现该传感器区别于普通的sht30,这个是adc输出的接口,那么我们就只需要配置板子的adc输入通道,换算成温湿度即可。

aeb33044762b1ab316f7631041b662c6.jpg

### 1. 传感器数据读取 (`src/main.c`)```c/* ADC 配置 */#define ADC_CHANNEL_TEMP    0#define ADC_CHANNEL_HUM     1#define ADC_INPUT_TEMP      0x25    /* ADC0_B5 (ARD_A0 / PTD1) */#define ADC_INPUT_HUM       0x06    /* ADC0_A6 (ARD_A1 / PTD2) *//* SHT30 模拟输出转换公式 *//* Temperature(C) = -40 + 165 * (V_out / V_supply) *//* Humidity(%RH)  = 100 * (V_out / V_supply) */```### 2. BLE 服务定义 (`src/hts.c`)```c/* Health Thermometer Service (HTS) */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),);```### 3. 配置文件 (`prj.conf`)```CONFIG_ADC=yCONFIG_BT=yCONFIG_BT_PERIPHERAL=yCONFIG_BT_GATT_CLIENT=yCONFIG_BT_DIS=yCONFIG_BT_BAS=yCONFIG_LPADC_CHANNEL_COUNT=2CONFIG_CBPRINTF_FP_SUPPORT=y```### 4. 设备树覆盖 (`boards/frdm_mcxw71.overlay`)```dts/ {    aliases {        adc-sensor = &adc0;    };};&adc0 {    status = "okay";    pinctrl-0 = <&pinmux_lpadc0_sensor>;    pinctrl-names = "default";};

```
这是开发过程中的一些操作步骤,下面是代码部分

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

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

#include <zephyr/types.h>
#include <stddef.h>
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/kernel.h>

#include <zephyr/settings/settings.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/cts.h>
#include <zephyr/bluetooth/services/hrs.h>
#include <zephyr/bluetooth/services/ias.h>
#include <zephyr/drivers/adc.h>

/* Custom Service Variables */
#define BT_UUID_CUSTOM_SERVICE_VAL \
    BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef0)

static const struct bt_uuid_128 vnd_uuid = BT_UUID_INIT_128(
    BT_UUID_CUSTOM_SERVICE_VAL);

static const struct bt_uuid_128 vnd_enc_uuid = BT_UUID_INIT_128(
    BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef1));

static const struct bt_uuid_128 vnd_auth_uuid = BT_UUID_INIT_128(
    BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef2));

#define VND_MAX_LEN 20
#define BT_HR_HEARTRATE_DEFAULT_MIN 90U
#define BT_HR_HEARTRATE_DEFAULT_MAX 160U

static uint8_t vnd_value[VND_MAX_LEN + 1] = { 'V', 'e', 'n', 'd', 'o', 'r'};
static uint8_t vnd_auth_value[VND_MAX_LEN + 1] = { 'V', 'e', 'n', 'd', 'o', 'r'};
static uint8_t vnd_wwr_value[VND_MAX_LEN + 1] = { 'V', 'e', 'n', 'd', 'o', 'r' };

static ssize_t read_vnd(struct bt_conn *conn, const struct bt_gatt_attr *attr,
            void *buf, uint16_t len, uint16_t offset)
{
    const char *value = attr->user_data;

    return bt_gatt_attr_read(conn, attr, buf, len, offset, value,
                 strlen(value));
}

static ssize_t write_vnd(struct bt_conn *conn, const struct bt_gatt_attr *attr,
             const void *buf, uint16_t len, uint16_t offset,
             uint8_t flags)
{
    uint8_t *value = attr->user_data;

    if (offset + len > VND_MAX_LEN) {
        return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
    }

    memcpy(value + offset, buf, len);
    value[offset + len] = 0;

    return len;
}

static uint8_t simulate_vnd;
static uint8_t indicating;
static struct bt_gatt_indicate_params ind_params;
static char vnd_ind_data[30]; /* Buffer for SHT30 temp/humidity string */

/* SHT30 Analog Sensor ADC Configuration
 * PTD2 = ADC0_A6 (channel 6) -> Temperature
 * PTD0 = ADC0_A5 (channel 5) -> Humidity
 * SHT30 output: 0.3~2.7V linear analog voltage
 * Formulas (from datasheet):
 *   Temperature(??C) = -66.875 + 72.917 * V
 *   Humidity(%RH)   = -12.5   + 41.667 * V
 */
/* LPADC: channel_id selects CMD register slot, input_positive selects hardware channel */
/* ADC0_A6 = channel 6 side A -> input_positive = 0x06 */
/* ADC0_A5 = channel 5 side A -> input_positive = 0x05 */
#define ADC_TEMP_CMD_ID     0   /* CMD slot 0 for temperature */
#define ADC_HUM_CMD_ID      1   /* CMD slot 1 for humidity */
#define ADC_TEMP_HW_CHAN    6   /* ADC0_A6 = PTD2 */
#define ADC_HUM_HW_CHAN     5   /* ADC0_A5 = PTD0 */
/*
 * LPADC on MCXW716 only supports ADC_GAIN_1 (full scale).
 * Gain 1/2 (kLPADC_SamplePartScale = 30/64) is NOT supported
 * because FSL_FEATURE_LPADC_HAS_CMDL_CSCALE is not defined.
 * See: adc_mcux_lpadc.c:270-277
 *
 * With gain=1: Vin = raw * Vref / 4096
 * Vref = 1.8V (internal VREF regulator)
 * Max measurable voltage: 1.8V
 * SHT30 at room temp: T~1.26V, RH~1.5V (within range)
 */
#define ADC_RESOLUTION      12
#define VREF_MV         1800    /* Internal VREF = 1.8V */
#define ABS(x)          ((x) < 0 ? -(x) : (x))

#define ADC_NODE    DT_ALIAS(adc0)

static const struct device *adc_dev;
static int16_t adc_sample_buffer[1];

static int adc_init(void)
{
    int err;

    adc_dev = DEVICE_DT_GET(ADC_NODE);
    if (!device_is_ready(adc_dev)) {
        printk("ADC device not ready\n");
        return -ENODEV;
    }

    /* Setup temperature channel (ADC0_A6, PTD2) */
    /* input_positive = ADC_TEMP_HW_CHAN (channel 6, side A)
     *
     * LPADC reference selection:
     * - ADC_REF_EXTERNAL1 = use SoC internal VREF regulator (1.8V)
     * - ADC_REF_INTERNAL is NOT supported by nxp,lpc-lpadc driver
     *   (driver rejects with -EINVAL at mcux_lpadc.c:285-299)
     *
     * LPADC gain: MCXW716 only supports ADC_GAIN_1 (full scale).
     * Gain 1/2 (30/64 scaling) is NOT available.
     * See: adc_mcux_lpadc.c:270-277
     * With gain=1: Vin = raw * 1800 / 4096, range = 0~1.8V
     */
    struct adc_channel_cfg temp_cfg = {
        .gain = ADC_GAIN_1,
        .reference = ADC_REF_EXTERNAL1,
        .acquisition_time = ADC_ACQ_TIME_DEFAULT,
        .channel_id = ADC_TEMP_CMD_ID,
        .input_positive = ADC_TEMP_HW_CHAN,
        .differential = 0,
    };

    /* Setup humidity channel (ADC0_A5, PTD0) */
    /* input_positive = ADC_HUM_HW_CHAN (channel 5, side A) */
    struct adc_channel_cfg hum_cfg = {
        .gain = ADC_GAIN_1,
        .reference = ADC_REF_EXTERNAL1,
        .acquisition_time = ADC_ACQ_TIME_DEFAULT,
        .channel_id = ADC_HUM_CMD_ID,
        .input_positive = ADC_HUM_HW_CHAN,
        .differential = 0,
    };

    err = adc_channel_setup(adc_dev, &temp_cfg);
    if (err != 0) {
        printk("ADC temp channel setup failed (err %d)\n", err);
        return err;
    }

    err = adc_channel_setup(adc_dev, &hum_cfg);
    if (err != 0) {
        printk("ADC humidity channel setup failed (err %d)\n", err);
        return err;
    }

    printk("ADC initialized for SHT30 sensor\n");
    return 0;
}

static int adc_read_channel(uint8_t channel, int32_t *mv_out, int16_t *raw_out)
{
    int err;
    struct adc_sequence sequence = {
        .channels = BIT(channel),
        .buffer = adc_sample_buffer,
        .buffer_size = sizeof(adc_sample_buffer),
        .resolution = ADC_RESOLUTION,
        .oversampling = 0,
    };

    err = adc_read(adc_dev, &sequence);
    if (err != 0) {
        printk("ADC read failed (err %d)\n", err);
        return err;
    }

    if (raw_out != NULL) {
        *raw_out = adc_sample_buffer[0];
    }

    *mv_out = (int32_t)adc_sample_buffer[0];
    /* LPADC gain=1 (full scale): Vin = raw * Vref / 4096
     * adc_raw_to_millivolts: mv = raw * 1800 * 1 / 4096
     * Range: 0 ~ 1.8V (SHT30 analog output 0.3~2.7V, only ~1.5V at mid-range fits)
     * SHT30 at 25°C/65%RH: T~1.26V, H~1.5V (within 0~1.8V range).
     * If sensor output >1.8V, an external voltage divider is needed.
     */
    adc_raw_to_millivolts(VREF_MV, ADC_GAIN_1,
                  ADC_RESOLUTION, mv_out);

    return 0;
}

static void vnd_ccc_cfg_changed(const struct bt_gatt_attr *attr, uint16_t value)
{
    simulate_vnd = (value == BT_GATT_CCC_INDICATE) ? 1 : 0;
}

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

static void indicate_destroy(struct bt_gatt_indicate_params *params)
{
    printk("Indication complete\n");
    indicating = 0U;
}

#define VND_LONG_MAX_LEN 74
static uint8_t vnd_long_value[VND_LONG_MAX_LEN + 1] = {
          'V', 'e', 'n', 'd', 'o', 'r', ' ', 'd', 'a', 't', 'a', '1',
          'V', 'e', 'n', 'd', 'o', 'r', ' ', 'd', 'a', 't', 'a', '2',
          'V', 'e', 'n', 'd', 'o', 'r', ' ', 'd', 'a', 't', 'a', '3',
          'V', 'e', 'n', 'd', 'o', 'r', ' ', 'd', 'a', 't', 'a', '4',
          'V', 'e', 'n', 'd', 'o', 'r', ' ', 'd', 'a', 't', 'a', '5',
          'V', 'e', 'n', 'd', 'o', 'r', ' ', 'd', 'a', 't', 'a', '6',
          '.', ' ' };

static ssize_t write_long_vnd(struct bt_conn *conn,
                  const struct bt_gatt_attr *attr, const void *buf,
                  uint16_t len, uint16_t offset, uint8_t flags)
{
    uint8_t *value = attr->user_data;

    if (flags & BT_GATT_WRITE_FLAG_PREPARE) {
        return 0;
    }

    if (offset + len > VND_LONG_MAX_LEN) {
        return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
    }

    memcpy(value + offset, buf, len);
    value[offset + len] = 0;

    return len;
}

static const struct bt_uuid_128 vnd_long_uuid = BT_UUID_INIT_128(
    BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef3));

static struct bt_gatt_cep vnd_long_cep = {
    .properties = BT_GATT_CEP_RELIABLE_WRITE,
};

static const struct bt_uuid_128 vnd_write_cmd_uuid = BT_UUID_INIT_128(
    BT_UUID_128_ENCODE(0x12345678, 0x1234, 0x5678, 0x1234, 0x56789abcdef4));

static ssize_t write_without_rsp_vnd(struct bt_conn *conn,
                     const struct bt_gatt_attr *attr,
                     const void *buf, uint16_t len, uint16_t offset,
                     uint8_t flags)
{
    uint8_t *value = attr->user_data;

    if (!(flags & BT_GATT_WRITE_FLAG_CMD)) {
        /* Write Request received. Reject it since this Characteristic
         * only accepts Write Without Response.
         */
        return BT_GATT_ERR(BT_ATT_ERR_WRITE_REQ_REJECTED);
    }

    if (offset + len > VND_MAX_LEN) {
        return BT_GATT_ERR(BT_ATT_ERR_INVALID_OFFSET);
    }

    memcpy(value + offset, buf, len);
    value[offset + len] = 0;

    return len;
}

/* Vendor Primary Service Declaration */
BT_GATT_SERVICE_DEFINE(vnd_svc,
    BT_GATT_PRIMARY_SERVICE(&vnd_uuid),
    BT_GATT_CHARACTERISTIC(&vnd_enc_uuid.uuid,
                   BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE |
                   BT_GATT_CHRC_INDICATE,
                   BT_GATT_PERM_READ_ENCRYPT |
                   BT_GATT_PERM_WRITE_ENCRYPT,
                   read_vnd, write_vnd, vnd_value),
    BT_GATT_CCC(vnd_ccc_cfg_changed,
            BT_GATT_PERM_READ | BT_GATT_PERM_WRITE_ENCRYPT),
    BT_GATT_CHARACTERISTIC(&vnd_auth_uuid.uuid,
                   BT_GATT_CHRC_READ | BT_GATT_CHRC_WRITE,
                   BT_GATT_PERM_READ_AUTHEN |
                   BT_GATT_PERM_WRITE_AUTHEN,
                   read_vnd, write_vnd, vnd_auth_value),
    BT_GATT_CHARACTERISTIC(&vnd_long_uuid.uuid, BT_GATT_CHRC_READ |
                   BT_GATT_CHRC_WRITE | BT_GATT_CHRC_EXT_PROP,
                   BT_GATT_PERM_READ | BT_GATT_PERM_WRITE |
                   BT_GATT_PERM_PREPARE_WRITE,
                   read_vnd, write_long_vnd, &vnd_long_value),
    BT_GATT_CEP(&vnd_long_cep),
    BT_GATT_CHARACTERISTIC(&vnd_write_cmd_uuid.uuid,
                   BT_GATT_CHRC_WRITE_WITHOUT_RESP,
                   BT_GATT_PERM_WRITE, NULL,
                   write_without_rsp_vnd, &vnd_wwr_value),
);

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_CTS_VAL)),
    BT_DATA_BYTES(BT_DATA_UUID128_ALL, BT_UUID_CUSTOM_SERVICE_VAL),
};

static const struct bt_data sd[] = {
    BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME, sizeof(CONFIG_BT_DEVICE_NAME) - 1),
};

void mtu_updated(struct bt_conn *conn, uint16_t tx, uint16_t rx)
{
    printk("Updated MTU: TX: %d RX: %d bytes\n", tx, rx);
}

static struct bt_gatt_cb gatt_callbacks = {
    .att_mtu_updated = mtu_updated
};

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

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

static void alert_stop(void)
{
    printk("Alert stopped\n");
}

static void alert_start(void)
{
    printk("Mild alert started\n");
}

static void alert_high_start(void)
{
    printk("High alert started\n");
}

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

BT_IAS_CB_DEFINE(ias_callbacks) = {
    .no_alert = alert_stop,
    .mild_alert = alert_start,
    .high_alert = alert_high_start,
};

static void bt_ready(void)
{
    int err;

    printk("Bluetooth initialized\n");

    if (IS_ENABLED(CONFIG_SETTINGS)) {
        settings_load();
    }

    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;
    }

    printk("Advertising successfully started\n");
}

static void auth_passkey_display(struct bt_conn *conn, unsigned int passkey)
{
    char addr[BT_ADDR_LE_STR_LEN];

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

    printk("Passkey for %s: %06u\n", addr, passkey);
}

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 = {
    .passkey_display = auth_passkey_display,
    .passkey_entry = NULL,
    .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 uint8_t bt_heartrate = BT_HR_HEARTRATE_DEFAULT_MIN;

static void hrs_notify(void)
{
    /* Heartrate measurements simulation */
    bt_heartrate++;
    if (bt_heartrate == BT_HR_HEARTRATE_DEFAULT_MAX) {
        bt_heartrate = BT_HR_HEARTRATE_DEFAULT_MIN;
    }

    bt_hrs_notify(bt_heartrate);
}

/**
 * variable to hold reference milliseconds to epoch when device booted
 * this is only for demo purpose, for more precise synchronization please
 * review clock_settime API implementation.
 */
static struct bt_cts_local_time local_time = {
    .timezone_offset = BT_CTS_TIMEZONE_DEFAULT_VALUE,
    .dst_offset = BT_CTS_DST_OFFSET_UNKNOWN,
};
static bool cts_notification_enabled;
static int64_t unix_ms_ref;

static void cts_notification_changed_cb(bool enabled)
{
    cts_notification_enabled = enabled;
}

static int cts_time_write_cb(struct bt_cts_time_format *cts_time)
{
    int err;
    int64_t unix_ms;

    if (IS_ENABLED(CONFIG_BT_CTS_HELPER_API)) {
        err = bt_cts_time_to_unix_ms(cts_time, &unix_ms);
        if (err != 0) {
            return err;
        }
    } else {
        return -ENOTSUP;
    }

    /* recalculate reference value */
    unix_ms_ref = unix_ms - k_uptime_get();
    return 0;
}

static int cts_fill_current_cts_time_cb(struct bt_cts_time_format *cts_time)
{
    int64_t unix_ms = unix_ms_ref + k_uptime_get();

    if (IS_ENABLED(CONFIG_BT_CTS_HELPER_API)) {
        return bt_cts_time_from_unix_ms(cts_time, unix_ms);
    } else {
        return -ENOTSUP;
    }
}

static int cts_local_time_write_cb(const struct bt_cts_local_time *cts_local_time)
{
    memcpy(&local_time, cts_local_time, sizeof(local_time));
    return 0;
}

static int cts_fill_local_time_cb(struct bt_cts_local_time *cts_local_time)
{
    memcpy(cts_local_time, &local_time, sizeof(local_time));
    return 0;
}

const struct bt_cts_cb cts_cb = {
    .notification_changed = cts_notification_changed_cb,
    .cts_time_write = cts_time_write_cb,
    .fill_current_cts_time = cts_fill_current_cts_time_cb,
    .cts_local_time_write = cts_local_time_write_cb,
    .fill_current_cts_local_time = cts_fill_local_time_cb,
};

static int bt_hrs_ctrl_point_write(uint8_t request)
{
    printk("HRS Control point request: %d\n", request);
    if (request != BT_HRS_CONTROL_POINT_RESET_ENERGY_EXPANDED_REQ) {
        return -ENOTSUP;
    }

    bt_heartrate = BT_HR_HEARTRATE_DEFAULT_MIN;
    return 0;
}

static struct bt_hrs_cb hrs_cb = {
    .ctrl_point_write = bt_hrs_ctrl_point_write,
};

int main(void)
{
    struct bt_gatt_attr *vnd_ind_attr;
    char str[BT_UUID_STR_LEN];
    int err;

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

    bt_ready();
    bt_cts_init(&cts_cb);
    bt_hrs_cb_register(&hrs_cb);

    bt_gatt_cb_register(&gatt_callbacks);
    bt_conn_auth_cb_register(&auth_cb_display);

    /* Initialize ADC for SHT30 sensor */
    err = adc_init();
    if (err != 0) {
        printk("ADC init failed (err %d)\n", err);
    }

    vnd_ind_attr = bt_gatt_find_by_uuid(vnd_svc.attrs, vnd_svc.attr_count,
                        &vnd_enc_uuid.uuid);
    bt_uuid_to_str(&vnd_enc_uuid.uuid, str, sizeof(str));
    printk("Indicate VND attr %p (UUID %s)\n", vnd_ind_attr, str);

    /* Implement notification. At the moment there is no suitable way
     * of starting delayed work so we do it here
     */
    while (1) {
        k_sleep(K_SECONDS(2));

        /* Read SHT30 temperature and humidity via ADC */
        int32_t temp_mv = 0, hum_mv = 0;
        int16_t temp_raw = 0, hum_raw = 0;
        bool adc_ok = true;

        if (adc_read_channel(ADC_TEMP_CMD_ID, &temp_mv, &temp_raw) != 0) {
            adc_ok = false;
        }
        if (adc_read_channel(ADC_HUM_CMD_ID, &hum_mv, &hum_raw) != 0) {
            adc_ok = false;
        }

        if (adc_ok) {
            /* SHT30 conversion formulas (integer math, result x10) */
            /* T(??C)*1000 = -66875 + 72917 * mv / 1000 */
            /* RH(%)*1000 = -12500  + 41667 * mv / 1000 */
            int32_t temp_x1000 = -66875 + (72917 * temp_mv) / 1000;
            int32_t hum_x1000  = -12500  + (41667 * hum_mv)  / 1000;
            int temp_x10 = temp_x1000 / 100;
            int hum_x10  = hum_x1000  / 100;

            /* Clamp to valid ranges */
            if (temp_x10 < -400) temp_x10 = -400;
            if (temp_x10 > 1250) temp_x10 = 1250;
            if (hum_x10 < 0) hum_x10 = 0;
            if (hum_x10 > 1000) hum_x10 = 1000;

            /* Format: "T:25.3C,H:65.2%" */
            snprintf(vnd_ind_data, sizeof(vnd_ind_data),
                 "T:%d.%dC,H:%d.%d%%\n",
                 temp_x10 / 10, ABS(temp_x10 % 10),
                 hum_x10 / 10, ABS(hum_x10 % 10));

            /* Print to serial port */
            printk("SHT30: T=%d.%d??C, H=%d.%d%%RH \n",
                   temp_x10 / 10, ABS(temp_x10 % 10),
                   hum_x10 / 10, ABS(hum_x10 % 10));
        }

        /* Current time update notification example
         * For testing purposes, we send a manual update notification every second.
         * In production `bt_cts_send_notification` should only be used when time is changed
         */
        if (cts_notification_enabled) {
            bt_cts_send_notification(BT_CTS_UPDATE_REASON_MANUAL);
        }
        /* Heartrate measurements simulation */
        hrs_notify();

        /* Battery level simulation */
        bas_notify();

        /* Vendor indication: send SHT30 temp/humidity data */
        if (simulate_vnd && vnd_ind_attr) {
            if (indicating) {
                continue;
            }

            ind_params.attr = vnd_ind_attr;
            ind_params.func = indicate_cb;
            ind_params.destroy = indicate_destroy;
            ind_params.data = vnd_ind_data;
            ind_params.len = strlen(vnd_ind_data);

            if (bt_gatt_indicate(NULL, &ind_params) == 0) {
                indicating = 1U;
                printk("BT Indicate sent: %s\n", vnd_ind_data);
            }
        }
    }
    return 0;
}

运行效果如下:
image.png





关键词: FRDM-MCXW71 e起DIY    

共1条 1/1 1 跳转至

回复

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