【IMX6ULL驱动开发学习】22.IMX6ULL开发板读取ADC(以MQ-135为例)

IMX6ULL一共有两个ADC,每个ADC都有八个通道,但他们共用一个ADC控制器

1.设备树

在imx6ull.dtsi文件中已经帮我们定义好了adc1的节点部分信息

c 复制代码
adc1: adc@02198000 {
	compatible = "fsl,imx6ul-adc", "fsl,vf610-adc";
	reg = <0x02198000 0x4000>;
	interrupts = <GIC_SPI 100 IRQ_TYPE_LEVEL_HIGH>;
	clocks = <&clks IMX6UL_CLK_ADC1>;
	num-channels = <2>;
	clock-names = "adc";
	status = "disabled";
};

注意 num-channels = <2>;,这个表示指定使用ADC1的两个通道,即通道1和通道2

如果你要使用多个ADC通道,修改这个值即可

配置ADC引脚的 pinctrl,在自己的设备树(.dts)中引用adc1并指定 pinctrl子系统,也就是指定引脚

首先在根节点下定义 pinctrl

c 复制代码
/* chenshao ADC1_CH1 GPIO1_IO01 */
pinctrl_adc1: adc1grp {
	fsl,pins = <
		MX6UL_PAD_GPIO1_IO01__GPIO1_IO01   0xb0 
	>;
};

接着regulators 节点下设置ADC的参考电压,设置为5V(因为MQ135输出最大模拟电压是5V)

c 复制代码
/* chenshao ADC vref 5.0V */
reg_vref_adc: regulator@2 {
	compatible = "regulator-fixed";
	regulator-name = "VREF_5V";
	regulator-min-microvolt = <5000000>;
	regulator-max-microvolt = <5000000>;
};

最后在根节点之外引用adc1节点,并指定引脚可参考电压节点

c 复制代码
/* chenshao ADC1 */
&adc1 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_adc1>;
	num-channels = <2>;             /* 2个通道,gpio1_io0占用一个 */
	vref-supply = <&reg_vref_adc>;
	status = "okay";	
};

2.直接查看ADC值

c 复制代码
1.进入iio总线下的设备目录
cd /sys/bus/iio/devices/iio:device0/

2.ls查看
------------------------
dev                            of_node
in_voltage0_raw                power
in_voltage1_raw                sampling_frequency_available
in_voltage_sampling_frequency  subsystem
in_voltage_scale               uevent
name

3.查看ADC通道1原始值(由于IMX6ULL ADC为12位,所以最小值为0,最大值为4095(2^12),分别对应0V,3.3V或5V)
cat in_voltage1_raw 
721


4.查看电压规模
cat in_voltage_scale 
1.220703125

5.计算实际电压
in_voltage1_raw  * in_voltage_scale 即可,注意单位是毫伏

3.应用程序获取ADC和电压

读取 /sys/bus/iio/devices/iio:device0/in_voltage1_raw 文件得到ADC原始值

读取 /sys/bus/iio/devices/iio:device0/in_voltage_scale 文件得到电源规模值

两者相乘,再除以1000即可得到电压值(单位V)

PS:

读取文件前使用 rewind函数 将光标移到最开头,
可以使用 fscanf 读取文件
利用 atoi 和 atof 库函数转换类型

c 复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <unistd.h>


const char *voltage1_raw = "/sys/bus/iio/devices/iio:device0/in_voltage1_raw";
const char *voltage_scale = "/sys/bus/iio/devices/iio:device0/in_voltage_scale";

int main(int argc, char *argv[])
{
	FILE *raw_fd, *scale_fd;
	int len1, len2, res;
	char data[20];
	int raw;
	double scale;

	while(1){
		/* 1.打开文件 */
		raw_fd = fopen(voltage1_raw, "r");
		if(raw_fd == NULL){
			printf("open raw_fd failed!\n");
			return -1;
		}

		scale_fd = fopen(voltage_scale, "r");
		if(scale_fd == NULL){
			printf("open scale_fd failed!\n");
			return -2;
		}
	
		/* 2.读取文件 */
		rewind(raw_fd);   // 将光标移回文件开头
		res = fscanf(raw_fd, "%s", data);
		raw = atoi(data);

		memset(data, 0, sizeof(data));
		rewind(scale_fd);   // 将光标移回文件开头
		res = fscanf(scale_fd, "%s", data);
		scale = atof(data);
		

		printf("ADC原始值:%d,电压值:%.3fV\r\n", raw, raw * scale / 1000.f);

		fclose(raw_fd);
		fclose(scale_fd);
		sleep(2);
	}

	return 0;
}

测试成功

c 复制代码
# ./adcApp
ADC原始值:390,电压值:0.476V
ADC原始值:399,电压值:0.487V
ADC原始值:413,电压值:0.504V
ADC原始值:416,电压值:0.508V
ADC原始值:410,电压值:0.500V
ADC原始值:407,电压值:0.497V
相关推荐
疯狂飙车的蜗牛8 小时前
从零玩转CanMV-K230(4)-小核Linux驱动开发参考
linux·运维·驱动开发
嵌入式进阶行者20 小时前
【驱动开发初级】内核模块静态和动态添加功能的步骤
驱动开发
逝灮1 天前
【蓝桥杯——物联网设计与开发】拓展模块3 - 温度传感器模块
驱动开发·stm32·单片机·嵌入式硬件·物联网·蓝桥杯·温度传感器
__NULL__USER2 天前
petalinux-adi ---添加AD9361驱动(二)
linux·驱动开发
7yewh2 天前
嵌入式驱动RK3566 HDMI eDP MIPI 背光 屏幕选型与调试提升篇-eDP屏
linux·arm开发·驱动开发·嵌入式硬件·嵌入式linux·rk·edp
少年、潜行4 天前
树莓派3B+驱动开发(8)- i2c控制PCF8591
驱动开发·树莓派·3b+
千千道4 天前
深入理解 Linux 内核启动流程
linux·arm开发·驱动开发
SunshineBooming4 天前
qemu源码解析【05】qemu启动初始化流程
c++·驱动开发·源码软件
嵌入式大圣5 天前
单片机MQTT通信
驱动开发·单片机·嵌入式硬件·物联网
嵌入(师)5 天前
嵌入式驱动开发详解19(regmap驱动架构)
驱动开发·架构