【e起DIY】低功耗蓝牙温湿度计-过程篇
板卡实物图

接下来接到了重头戏部分
SHT30 传感器驱动开发
• 完成 NXP FRDM-MCXW71 开发板与 SHT30 传感器的 I2C 物理连接
• 实现温度与湿度数据读取函数, 在串口终端打印原始数据与解析后的温湿度值,格式为:Temperature: 23.5°C, Humidity: 45.2%RH
上述任务说明写的是通过I2C总线连接SHT30传感器模块
可通过活动详情页https://www.eepw.com.cn/event/action/element14_diy/index.html#flow1
点击之后看到的是模拟接口的SHT30
https://www.element14.cn/dfrobot/dfr0588/sensor-module-temperature-humidity/dp/3974111
当时没注意,已经下单到手了,本着既来之则安之的心态,一样可以启动起来
结合ai工具,告诉ai,我们想通过frdm-mcxw71连接模拟输出的sht30并运行zephyr操作系统
可根据ai指导完成工程配置
首先是硬件连接
DFR0588 引脚FRDM-MCXW71(J2 Arduino)说明
| VCC | 3.3V | 模块供电,严禁 5V |
| GND | GND | 共地 |
| TEMP | A0(PTB0/ADC0_CH0) | 温度模拟电压输出→ADC0 通道 0 |
| HUM | A1(PTB1/ADC0_CH1) | 湿度模拟电压输出→ADC0 通道 1 |
DFR0588 电压换算规则(官方 Gravity 模拟 SHT30):
温度:Vtemp ∈ 0~3.3V → T = -40 + (165 × Vtemp / 3.3) ℃(-40~+125℃线性)
湿度:Vhum ∈ 0~3.3V → RH = 0 + (100 × Vhum / 3.3) % RH(0~100% RH 线性)
实物接线图

接下来上设备树
/*
* Copyright 2024 NXP
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/dt-bindings/adc/adc.h>
#include <zephyr/dt-bindings/adc/mcux-lpadc.h>
/ {
zephyr,user {
io-channels = <&adc0 0>, <&adc0 1>;
};
};
&adc0 {
#address-cells = <1>;
#size-cells = <0>;
/* voltage-ref = <0> 表示使用 Alt1,即 VREFH/3.3V(而非默认 1.8V) */
voltage-ref = <0>;
/* 告诉驱动 VREFH=3300mV,用于计算实际电压值 */
nxp,references = <&vref 3300>;
channel@0 {
reg = <0>;
zephyr,gain = "ADC_GAIN_1";
zephyr,reference = "ADC_REF_EXTERNAL0";
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
zephyr,resolution = <12>;
zephyr,vref-mv = <3300>;
/* channel 0 ptd1 adc0_b5 MCUX_LPADC_CH1B */
zephyr,input-positive = <MCUX_LPADC_CH1B>;
};
channel@1 {
reg = <1>;
zephyr,gain = "ADC_GAIN_1";
zephyr,reference = "ADC_REF_EXTERNAL0";
zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
zephyr,resolution = <12>;
zephyr,vref-mv = <3300>;
/* channel 1 ptd2 adc0_a6 MCUX_LPADC_CH2A */
zephyr,input-positive = <MCUX_LPADC_CH2A>;
};
};程序代码
/*
* Copyright (c) 2020 Libre Solar Technologies GmbH
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <inttypes.h>
#include <stddef.h>
#include <stdint.h>
#include <zephyr/device.h>
#include <zephyr/devicetree.h>
#include <zephyr/drivers/adc.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
#include <zephyr/sys/util.h>
#if !DT_NODE_EXISTS(DT_PATH(zephyr_user)) || \
!DT_NODE_HAS_PROP(DT_PATH(zephyr_user), io_channels)
#error "No suitable devicetree overlay specified"
#endif
#define DT_SPEC_AND_COMMA_FOR_INPUTS(node_id, prop, idx) \
COND_CODE_1(DT_PHA_HAS_CELL_AT_IDX(node_id, prop, idx, input), \
(ADC_DT_SPEC_GET_BY_IDX(node_id, idx),), ())
/* Data of ADC io-channels specified in devicetree. */
static const struct adc_dt_spec adc_channels[] = {
DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), io_channels,
DT_SPEC_AND_COMMA_FOR_INPUTS)
};
float get_temp_by_volatge(uint32_t value)
{
float tempValue = 0.0;
tempValue = -66.875f + 72.917f * ((float)value / 1000.0f);
return tempValue;
}
float get_humi_by_volatge(uint32_t value)
{
float humiValue = 0.0;
humiValue = -12.5f + 41.667f * ((float)value / 1000.0f);
return humiValue;
}
int main(void)
{
int err;
uint32_t count = 0;
uint32_t buf = 0;
struct adc_sequence sequence = {
.buffer = &buf,
/* buffer size in bytes, not number of samples */
.buffer_size = sizeof(buf),
#if CONFIG_SAMPLE_ADC_CALIBRATE_REQUIRED
.calibrate = true,
#endif
};
float temp, humi;
/* Configure channels individually prior to sampling. */
for (size_t i = 0U; i < ARRAY_SIZE(adc_channels); i++) {
if (!adc_is_ready_dt(&adc_channels[i])) {
printk("ADC controller device %s not ready\n", adc_channels[i].dev->name);
return 0;
}
err = adc_channel_setup_dt(&adc_channels[i]);
if (err < 0) {
printk("Could not setup channel #%d (%d)\n", i, err);
return 0;
}
}
#ifndef CONFIG_COVERAGE
while (1) {
#else
for (int k = 0; k < 10; k++) {
#endif
printk("ADC reading[%u]:\n", count++);
for (size_t i = 0U; i < ARRAY_SIZE(adc_channels); i++) {
int32_t val_mv;
/*
* Clear buffer before reading. This ensures the upper 16-bits will be zero
* when the adc uses a 16-bit buffer size.
*/
buf = 0;
printk("- %s, channel %d: ",
adc_channels[i].dev->name,
adc_channels[i].channel_id);
(void)adc_sequence_init_dt(&adc_channels[i], &sequence);
err = adc_read_dt(&adc_channels[i], &sequence);
if (err < 0) {
printk("Could not read (%d)\n", err);
continue;
}
/*
* If using differential mode, the 16 bit value
* in the ADC sample buffer should be a signed 2's
* complement value.
*/
if (adc_channels[i].channel_cfg.differential) {
val_mv = (int32_t)((int16_t)buf);
} else {
val_mv = (int32_t)buf;
}
printk("%"PRId32, val_mv);
err = adc_raw_to_millivolts_dt(&adc_channels[i],
&val_mv);
/* conversion to mV may not be supported, skip if not */
if (err < 0) {
printk(" (value in mV not available)\n");
} else {
printk(" = %"PRId32" mV\n", val_mv);
}
if (i)
{
humi = get_humi_by_volatge(val_mv);
printk("--- humi == %f % ---\n", (double)humi);
}
else
{
temp = get_temp_by_volatge(val_mv);
printk("--- temp == %f °C ---\n", (double)temp);
}
}
k_sleep(K_MSEC(3000));
}
return 0;
}prj.conf
CONFIG_ADC=y CONFIG_REQUIRES_FLOAT_PRINTF=y CONFIG_CBPRINTF_FP_SUPPORT=y
这样之后直接编译就行

接下来烧录程序

串口输出样式

到这里,过程贴就算完成了
过程中有参考课程老师的帖子
https://forum.eepw.com.cn/thread/399659/1
我要赚赏金
