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

共1条 1/1 1 跳转至

【e起DIY】【过程帖】低功耗蓝牙温湿度计 - Zephyr框架下的ADC采集

助工
2026-06-15 19:15:31     打赏

Zephyr框架下的ADC采集

想使用ADC采集数据,那首先得先找到板子上面,引出来了哪些ADC的引脚,在Arduino接口这里,可以看到有三路的ADC,那非常的完美,ADC的数量足够使用了。

c3e51b15-d108-4d42-8206-9cad13d0d1b5.png

没玩过NXP的MCU怎么办,我直接找到SDK的例程,先烧录进去看看是什么个情况,在//frdm_mcxw71/mcuxsdk/examples/driver_examples/lpadc/light_sensor路径中是官方提供的裸机的ADC环境光传感器的例程,烧录进去看看效果。不错不错,拿手电筒照射传感器和用手遮挡朱传感器串口打印出来的数据有明显的变化,在0~3.3V之间波动。

想外接需要采集的ADC数据怎么办,因为环境光传感器通过了0欧姆的电阻连接到Arduino的ADC接口,所以直接使用可能会有点影响,于是我就把这个R215拆掉了

28b25c88-195f-49a4-b724-eff9ffb812da.png

外部连接了USB的可调电源,在J4的4脚和J3的7脚。很奇怪的是只要当电压大于1V的时候,串口打印出来的数据就是3.3V了,当小于1V就会逐渐减小了,当直接接地显示的就是0V了,感觉这个ADC可以用,但是参考电压有点奇怪。

用是可以用,没问题就是范围只有0~1V,这个精度有点低。但奇怪的是一开始0欧姆的电阻还没有拆下来的时候,使用环境光传感器的时候,用万用表测试ADC采集的电压是是有接近3.3V的,奇怪的点就在软件啥都没有修改,只是将0欧姆的电阻拆下来,外接的电源。后来怀疑可能是USB转可调的电压驱动电流小,后续换成了稳压电源也是如此。找了好久的问题,也是还没有解决,那就先这样使用吧。。。

将ADC采集移植到Zephyr中

新建设备树文件:boards/frdm_mcxw71.overlay,填写双通道的描述

/*
 * Copyright 2026 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>;

	channel@0 {
		reg = <0>;
		zephyr,gain = "ADC_GAIN_1";
		zephyr,reference = "ADC_REF_EXTERNAL1";
		zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
		zephyr,resolution = <12>;
		zephyr,vref-mv = <3300>;
		zephyr,input-positive = <MCUX_LPADC_CH2A>;
	};

	channel@1 {
		reg = <1>;
		zephyr,gain = "ADC_GAIN_1";
		zephyr,reference = "ADC_REF_EXTERNAL1";
		zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
		zephyr,resolution = <12>;
		zephyr,vref-mv = <3300>;
		zephyr,input-positive = <MCUX_LPADC_CH2B>;
	};
};

prj.conf中使能ADC,添加以下内容

CONFIG_ADC=y

就可以开始编写src/main.c,初始化ADC、读取ADC,是个伪代码,下一个章节中会贴出完成的

#define ADC_OVERSAMPLING 7U
#define TX_BUFFER_SIZE 128U

#define ADC_DT_SPEC_AND_COMMA(node_id, prop, idx) \
	ADC_DT_SPEC_GET_BY_IDX(node_id, idx),

BUILD_ASSERT(TX_BUFFER_SIZE <= UINT16_MAX,
	     "TX_BUFFER_SIZE is too large for one NUS notification");

static const struct adc_dt_spec adc_channels[] = {
	DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), io_channels,
			     ADC_DT_SPEC_AND_COMMA)
};

static const char *const adc_channel_names[] = {
	"ADC0_A6",
	"ADC0_B6",
};

BUILD_ASSERT(ARRAY_SIZE(adc_channels) == 2U,
	     "Expected ADC0_A6 and ADC0_B6 io-channels");
BUILD_ASSERT(ARRAY_SIZE(adc_channels) == ARRAY_SIZE(adc_channel_names),
	     "ADC channel names must match io-channels");

struct adc_input_sample {
	uint16_t raw;
	int32_t mv;
	int err;
	bool mv_valid;
};

static int adc_inputs_init(void)
{
	int err;

	for (size_t i = 0U; i < ARRAY_SIZE(adc_channels); i++) {
		if (!adc_is_ready_dt(&adc_channels[i])) {
			printk("ADC controller %s is not ready\n",
			       adc_channels[i].dev->name);
			return -ENODEV;
		}

		err = adc_channel_setup_dt(&adc_channels[i]);
		if (err < 0) {
			printk("Failed to set up %s channel %d: %d\n",
			       adc_channels[i].dev->name,
			       adc_channels[i].channel_id, err);
			return err;
		}
	}

	printk("ADC inputs initialized: ADC0_A6, ADC0_B6\n");

	return 0;
}

static int adc_input_read_channel(const struct adc_dt_spec *channel,
				  struct adc_input_sample *sample)
{
	struct adc_sequence sequence = {
		.buffer = &sample->raw,
		.buffer_size = sizeof(sample->raw),
		.oversampling = ADC_OVERSAMPLING,
	};
	int err;

	sample->raw = 0U;
	sample->mv = 0;
	sample->err = 0;
	sample->mv_valid = false;

	(void)adc_sequence_init_dt(channel, &sequence);

	err = adc_read_dt(channel, &sequence);
	if (err < 0) {
		sample->err = err;
		return err;
	}

	sample->mv = sample->raw;
	err = adc_raw_to_millivolts_dt(channel, &sample->mv);
	sample->mv_valid = (err == 0);

	return 0;
}

static void adc_inputs_read(struct adc_input_sample samples[])
{
	int err;

	for (size_t i = 0U; i < ARRAY_SIZE(adc_channels); i++) {
		err = adc_input_read_channel(&adc_channels[i], &samples[i]);
		if (err < 0) {
			printk("%s read failed: %d\n", adc_channel_names[i], err);
		}
	}
}

static int append_adc_sample(char *buf, size_t buf_size, size_t *len,
			     const char *name,
			     const struct adc_input_sample *sample)
{
	size_t remaining;
	int written;

	if (*len >= buf_size) {
		return -ENOMEM;
	}

	remaining = buf_size - *len;

	if (sample->err < 0) {
		written = snprintk(&buf[*len], remaining, " %s err=%d",
				   name, sample->err);
	} else if (sample->mv_valid) {
		written = snprintk(&buf[*len], remaining,
				   " %s raw=%u mv=%" PRId32,
				   name, sample->raw, sample->mv);
	} else {
		written = snprintk(&buf[*len], remaining, " %s raw=%u mv=NA",
				   name, sample->raw);
	}

	if ((written < 0) || ((size_t)written >= remaining)) {
		return -ENOMEM;
	}

	*len += (size_t)written;

	return 0;
}

static int format_adc_payload(char *buf, size_t buf_size, uint32_t sample_count,
			      const struct adc_input_sample samples[])
{
	size_t len;
	int written;
	int err;

	written = snprintk(buf, buf_size, "n=%" PRIu32, sample_count);
	if ((written < 0) || ((size_t)written >= buf_size)) {
		return -ENOMEM;
	}

	len = (size_t)written;

	for (size_t i = 0U; i < ARRAY_SIZE(adc_channels); i++) {
		err = append_adc_sample(buf, buf_size, &len,
					adc_channel_names[i], &samples[i]);
		if (err < 0) {
			return err;
		}
	}

	return (int)len;
}

int main(void)
{
	//……
	printk("Inputs: ADC0_A6 and ADC0_B6\n");

	err = adc_inputs_init();
	if (err < 0) {
		printk("ADC initialization failed: %d\n", err);
		return err;
	}
	while(1)
	{
		adc_inputs_read(samples);

		payload_len = format_adc_payload(tx_buf, sizeof(tx_buf), tx_count, samples);
		if (payload_len < 0) {
			printk("Failed to format ADC payload: %d\n", payload_len);
			continue;
		}
		
		//……
	}

至此在Zephry中的ADC也完成了




关键词: Zephyr     ADC    

共1条 1/1 1 跳转至

回复

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