【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
相关推荐
程序员JerrySUN12 小时前
Linux UART 驱动开发全解析:从原理到实战
linux·运维·驱动开发
林政硕(Cohen0415)13 小时前
Linux驱动开发进阶(三)- 热插拔机制
linux·驱动开发·热插拔
sukalot13 小时前
Windows 图形显示驱动开发-WDDM 2.4功能-GPU 半虚拟化(十一)
windows·驱动开发
小麦嵌入式15 小时前
Linux驱动开发实战(十一):GPIO子系统深度解析与RGB LED驱动实践
linux·c语言·驱动开发·stm32·嵌入式硬件·物联网·ubuntu
触角0101000117 小时前
STM32F103低功耗模式深度解析:从理论到应用实践(上) | 零基础入门STM32第九十二步
驱动开发·stm32·单片机·嵌入式硬件·物联网
sukalot1 天前
Windows 图形显示驱动开发-WDDM 2.4功能-GPU 半虚拟化(三)
windows·驱动开发
星星点灯5082 天前
盛铂科技FlexDDS-NG:12通道相位连续DDS信号发生器,400MHz高频输出赋能量子光学与超冷原子研究
驱动开发·科技·测试工具·量子计算·模块测试·射频工程
小麦嵌入式3 天前
Linux驱动开发实战(九):Linux内核pinctrl_map详解与优势分析
linux·c语言·汇编·驱动开发·stm32·嵌入式硬件·硬件工程
触角010100013 天前
MPU6050模块详解:从原理到STM32驱动指南(上) | 零基础入门STM32第八十九步
驱动开发·stm32·单片机·嵌入式硬件·物联网
VermouthSp4 天前
Linux驱动开发 块设备
linux·驱动开发