1081|3

324

帖子

5

TA的资源

纯净的硅(中级)

楼主
 

【ST NUCLEO-C031C6开发板测评】搭配光线传感器使用ADC功能 [复制链接]

一、硬件了解

从手册可以得知,STM32C0上提供了一如既往的优秀的ADC支持:

 

在Nucleo-C031C6开发板上,兼容Arduino Uno R3接口的CN8区域,可以直接作为ADC引脚使用:

 

 

 

具体对应开发板上的位置:

 

 

二、zephyr中对应的配置

在zephyr/boards/arm/nucleo_c031c6/nucleo_c031c6.dts中,有如下的配置:

 

这个定义了adc1的基础配置信息。

可以在adc1的通道中,使用pa0、pa1、pa4进行ADC外设测量。

 

另外,在 zephyr/samples/drivers/adc/boards/nucleo_c031c6.overlay中,提供了具体channel的配置:

 / {
	zephyr,user {
		/* adjust channel number according to pinmux in board.dts */
		io-channels = <&adc1 0>, <&adc1 1>, <&adc1 4>;
	};
};

&adc1 {
	#address-cells = <1>;
	#size-cells = <0>;

	channel@0 {
		reg = <0>;
		zephyr,gain = "ADC_GAIN_1";
		zephyr,reference = "ADC_REF_INTERNAL";
		zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
		zephyr,resolution = <12>;
	};

	channel[url=home.php?mod=space&uid=490]@1[/url] {
		reg = <1>;
		zephyr,gain = "ADC_GAIN_1";
		zephyr,reference = "ADC_REF_INTERNAL";
		zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
		zephyr,resolution = <12>;
	};

	channel[url=home.php?mod=space&uid=28485]@4[/url] {
		reg = <4>;
		zephyr,gain = "ADC_GAIN_1";
		zephyr,reference = "ADC_REF_INTERNAL";
		zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>;
		zephyr,resolution = <12>;
	};
};

上述adc1对应的channel@0、channel@1、channel@4的reg对应dts中adc1_in0_pa0、adc1_in1_pa1、adc1_in4_pa4

另外,配置中的resolution,对应实际要使用的分辨率,可用值见参考手册如下:

 

 

三、模拟光线传感器

我手头有一个DFRobot的模拟环境光线传感器:

 

对应的引脚如下:

 

 

这个模拟传感器可以使用+3~5V DC,可以借到开发板上的3.3V 、GND、PA0使用:

 

四、代码编写

参考 zephyr/samples/drivers/adc/src/main.c,编写如下的代码:

#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(node_id, prop, idx) \
	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)
};

uint8_t val_to_light(int32_t buf)
{
	float temp = 0;
	temp = 100*((float) buf/4096);
	return (uint8_t)temp;
}

int main(void)
{
	int err;
	uint32_t count = 0;
	uint16_t buf;
	struct adc_sequence sequence = {
		.buffer = &buf,
		/* buffer size in bytes, not number of samples */
		.buffer_size = sizeof(buf),
	};

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

	struct adc_dt_spec adc_channel = adc_channels[0];
	while (1) {
		printk("ADC reading[%u]:\n", count++);

		int32_t val_mv;
		uint8_t light;

		printk("- %s, channel %d: ",
				adc_channel.dev->name,
				adc_channel.channel_id);

		(void)adc_sequence_init_dt(&adc_channel, &sequence);

		err = adc_read_dt(&adc_channel, &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_channel.channel_cfg.differential) {
			val_mv = (int32_t)((int16_t)buf);
		} else {
			val_mv = (int32_t)buf;
		}
		printk("%"PRId32, val_mv);
		light = val_to_light(val_mv);

		err = adc_raw_to_millivolts_dt(&adc_channel,
							&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", val_mv);
		}

		printk(", Light is %"PRId8"%%\n\n", light);

		k_sleep(K_MSEC(1000));
	}
	return 0;
}

上述代码中,通过  zephyr_user / io_channels 对应 zephyr/samples/drivers/adc/boards/nucleo_c031c6.overlay中配置的adc1 channels。

然后,使用adc_is_ready_dt()、adc_channel_setup_dt()来检查设备和配置设备,再通过adc_sequence_init_dt()来进行数据读取初始化,并使用adc_read_dt()读取数据到sequence。

sequence.buffer对应buf变量,即为读取的原始值,再使用val_to_light()转换原始值到亮度百分比。该值根据配置中的resolution来确定范围。val_to_light()中的4096,也根据resolution来进行设置,2^12对应为4096。

最后,可以调用 adc_raw_to_millivolts_dt()将原始值转换为mV值。

 

五、输出结果

编译烧录到开发板以后,就可以读取输出了。

当把模拟光线传感器的光敏二极管完全罩住后,输出如下:

 

 

正常放置,输出如下:

 

今天天气比较阴沉,所以亮度较低。

 

打开灯,或者用手机手电筒照射,输出如下:

 

 

上述结果,都为12位分辨率的情况,对应的原始值最大位2^12=4096,电压为3300mV。

 

如果将分辨率修改位8位:

 

 

uint8_t val_to_light(int32_t buf)
{
	float temp = 0;

	temp = 100*((float) buf/256);
	return (uint8_t)temp;
}

 

则正常情况下的输出如下:

 

 

六、总结

上述内容为ADC功能的基础使用。

实际使用中,可以根据光线强度值来进行下一步的处理,例如如果光线强度过低,则自动开灯补光。

其他类似模拟烟雾传感器、模拟湿度传感器等,都可以采用类似方式测量数据和进行处理。

 

七、参考资料

此帖出自stm32/stm8论坛

最新回复

太谦虚了,从帮主大佬的文章中看出,zephyr在跟厂商的合作,还是非常用功的。   详情 回复 发表于 2024-2-18 19:39
点赞 关注
 

回复
举报

6960

帖子

11

TA的资源

版主

沙发
 

帮主在zephyr这方面,深有研究,做为STM32CubeIDE的很大补充呀。

此帖出自stm32/stm8论坛

点评

刚进行zephyr入门学习,正在摸坑中。  详情 回复 发表于 2024-2-18 17:56
 
 

回复

324

帖子

5

TA的资源

纯净的硅(中级)

板凳
 
lugl4313820 发表于 2024-2-18 16:09 帮主在zephyr这方面,深有研究,做为STM32CubeIDE的很大补充呀。

刚进行zephyr入门学习,正在摸坑中。

此帖出自stm32/stm8论坛

点评

太谦虚了,从帮主大佬的文章中看出,zephyr在跟厂商的合作,还是非常用功的。  详情 回复 发表于 2024-2-18 19:39
 
 

回复

6960

帖子

11

TA的资源

版主

4
 
HonestQiao 发表于 2024-2-18 17:56 刚进行zephyr入门学习,正在摸坑中。

太谦虚了,从帮主大佬的文章中看出,zephyr在跟厂商的合作,还是非常用功的。

此帖出自stm32/stm8论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表