版权声明
本文档所有内容文字资料由凌云实验室郭工编著,主要用于凌云嵌入式Linux教学内部使用,版权归属作者个人所有。任何媒体、网站、或个人未经本人协议授权不得转载、链接、转帖或以其他方式复制发布/发表。已经授权的媒体、网站,在下载使用时必须注明来源,违者本人将依法追究责任。
Copyright (C) 2022 凌云物网智科实验室·郭工
Author: Guo Wenxue Email: guowenxue@gmail.com QQ: 281143292
2.6 ADC编程烟雾传感器采样
2.6.1 ADC简介
ADC Analog to Digital Converter的缩写,中文名称模数转换器。它可以将外部的模拟信号转化成数字信号。对于 GPIO口来说高于某个电压值,它读出来的只有高电平,低于就是低电平。假如我想知道具体的电压数值就要借助于 ADC的帮助,它可以将一个范围内的电压精确的读取出来。假设我们的 GPIO 口只要高于 1.7V的都认为是高电平,例如,比如某个 IO口上外接了一个设备它能提供 0-2V的电压变化,我们在这个 IO口上使用 GPIO模式去读取的话我们只能获得0和1两个数据,但是我们使用ADC模式去读取就可以获得 0-2V之间连续变化的数值。
ADC有几个比较重要的参数:
测量范围
测量范围对于 ADC来说就好比尺子的量程, ADC测量范围决定了你外接的设备其信号输出电压范围,不能超过 ADC的测量范围。如果所使用的外部传感器输出的电压信号范围和所使用的 ADC测量范围不符 合,那么就需要自行设计相关电压转换电路。
分辨率
就是尺子上的能量出来的最小测量刻度,例如我们常用的厘米尺它的最小刻度就是 1毫米,表示最小测量精度就是 1毫米。假如 ADC的测量范围为 0-5V,分辨率设置为 12位,那么我们能测出来的最小电压就是 5V除以 2的 12次方,也就是 5/4096=0.00122V。很明显,分辨率越高,采集到的信号越精确,所以分辨率是衡量 ADC的一个重要指标。
精度 是影响结果准确度的因素之一,比如在厘米尺上我们能测量出大概多少毫米的尺度但是毫米后一点点我们却不能准确的量出。经过计算我们 ADC在 12位分辨率下的最小测量值是 0.00122V但是我们 ADC的精度最高只能到 11位也就是 0.00244V。也就是 ADC测量出0.00244V的结果是要比 0.00122V要可靠,也更准确。
采样时间 当 ADC在某时刻采集外部电压信号的时候,此时外部的信号应该保持不变,但实际上外部的信号是不停变化的。所以在 ADC内部有一个保持电路,保持某一时刻的外部信号,这样 ADC就可以稳定采集了,保持这个信号的时间就是采样时间。
采样率 也就是 在一秒的时间内采集多少次。很明显,采样率越高越好,当采样率不够的时候可能会丢失部 分信息,所以 ADC采样率是衡量 ADC性能的另一个重要指标。
总之,只要是需要模拟信号转为数字信号的场合,那么肯定要用到ADC。很多数字传感器内部会集成 ADC,传感器内部使用 ADC来处理原始的模拟信号,最终给用户输出数字信号。
2.6.2 MQ-2烟雾传感器简介
MQ-2常用于家庭和工厂的气体泄漏监测装置,适宜于液化气、苯、烷、酒精、氢气、烟雾等的探测。故因此,MQ-2可以准确来说是一个多种气体探测器。
MQ-2的探测范围极其的广泛。它的优点:灵敏度高、响应快、稳定性好、寿命长、驱动电路简单。一般MQ-2模块如下图所示:
2.6.2.1 MQ-2工作原理与特性
MQ-2型烟雾传感器属于二氧化锡半导体气敏材料,属于表面离子式N型半导体。处于200~300摄氏度时,二氧化锡吸附空气中的氧,形成氧的负离子吸附,使半导体中的电子密度减少,从而使其电阻值增加。当与烟雾接触时,如果晶粒间界处的势垒收到烟雾的浓度而变化,就会引起表面导电率的变化。利用这一点就可以获得这种烟雾存在的信息,烟雾的浓度越大,导电率越大,输出电阻越低,则输出的模拟信号就越大。
MQ-2传感器特性
MQ-2型传感器对天然气、液化石油气等烟雾有很高的灵敏度,尤其对烷类烟雾更为敏感,具有良好的抗干扰性,可准确排除有刺激性非可燃性烟雾的干扰信息。
MQ-2型传感器具有良好的重复性和长期的稳定性。初始稳定,响应时间短,长时间工作性能好。需要注意的是:在使用之前必须加热一段时间,否则其输出的电阻和电压不准确。
其检测可燃气体与烟雾的范围是100~10000ppm(ppm为体积浓度。1ppm=1立方厘米/1立方米)
电路设计电压范围宽,24V以下均可,加热电压5±0.2V
注意:如果加热电压过高,会导致输入电流过大,将内部的信号线熔断,从而器件报废。
2.6.2.1 MQ-2应用电路
MQ-2常用的电路有两种,一种使用采用比较器电路监控,另一种为ADC电路检测。
以下图中的模块仅有比较器电路,ADC部分使用IGKBoard的主控集成的ADC进行检测,下文进行详细介绍和使用。
MQ-2的引脚4输出随烟雾浓度变化的直流信号,被加到比较器U1A的2脚,Rp构成比较器的门槛电压。当烟雾浓度较高输出电压高于门槛电压时,比较器输出低电平(0v),此时LED亮报警;当浓度降低传感器的输出电压低于门槛电压时,比较器翻转输出高电平(Vcc),LED熄灭。调节Rp,可以调节比较器的门槛电压,从而调节报警输出的灵敏度。R1串入传感器的加热回路,可以保护加热丝免受冷上电时的冲击。
对于ADC电路而言,只需使用杜邦线将AOUT连接至ADC模拟输入端即可。
2.6.3 开发板ADC检测实验
2.6.3.1 模块硬件连接说明
MQ-2传感器的工作电压在24V以下即可,建议使用板载5V进行供电。这样在ADC电路设计时候,MQ-2在与开发板相连时候,主要连接如下三个引脚:
GND,该引脚要连到开发板的GND扩展引脚上;
VCC, 该引脚要连到开发板的 5v 供电引脚上;
AOUT, 是MQ-2模块的模拟输出引脚,该引脚应该连开发板上ADC功能的GPIO引脚上;
在IGKBoard开发板上,提供了两个ADC模拟输入的引脚,位于开发板的8pin扩展口上,其管脚名为TS_XP和TS_YN,在Linux系统启动时如果启用了 ADC overlay 后,它俩会默认作为ADC模拟输入口使用。这样,MQ-2的AO引脚应该连接上其中之一即可。
如下是MQ-2烟雾传感器连接到IGKBoard上的实物示意图。
实物连接图如下。
2.6.3.2 ADC驱动配置使用说明
在前面,我们将MQ-2的AOUT引脚连到了IGKBoard开发板扩展接口的TS_YN引脚上(GPIO01_IO01),该引脚在系统启动时有可能 默认作为GPIO功能使用。如果想作为MQ-2的模拟信号采样引脚使用的话,我们需要修改开发板上的DTOverlay配置文件,添加该引脚的 ADC 支持。
具体方法为修改 eMMC 启动介质的 boot 分区下的 config.txt 文件,在 dtoverlay_extra 选项中添加 adc 支持即可。
root@igkboard:~# vim /run/media/mmcblk1p1/config.txt
# Enable extra overlays
dtoverlay_extra=adc
修改完成后重启系统,系统启动时将会自动加载IGKBoard的芯片内置ADC驱动。查看驱动加载是否成功,我们可以在**/sys/bus/iio/devices**目录下查看ADC对应的iio设备:iio:deviceX
root@igkboard:/sys/bus/iio/devices# ls
iio:device0
我们使用 ls 命令看看,这个文件夹下有哪些文件。
root@igkboard:/sys/bus/iio/devices/iio:device0# ls
buffer dev in_voltage0_raw in_voltage2_raw in_voltage4_raw in_voltage_scale of_node sampling_frequency_available subsystem uevent
buffer0 in_conversion_mode in_voltage1_raw in_voltage3_raw in_voltage_sampling_frequency name power scan_elements trigger
在这里,只用关心三个文件:
in_voltage1_raw :ADC1通道 1原始值文件,即**TS_YN(GPIO01_IO01)**管脚的输入模拟值转换的数字值,范围0-4095;
in_voltage4_raw :ADC1通道 4原始值文件,即**TS_XP(GPIO01_IO04)**管脚的输入模拟值转换的数字值,范围0-4095;
in_voltage_scale: ADC1比例文件 (分辨率 ),单位为 mV。实际电压值 (mV) = in_voltage1_raw * in_voltage_scale。
我们开发板当前的in_voltage1_raw和 in_voltage_scale这两个文件内容如下:
root@igkboard:/sys/bus/iio/devices/iio:device0# cat in_voltage1_raw
1002
root@igkboard:/sys/bus/iio/devices/iio:device0# cat in_voltage_scale
0.805664062
经计算,当前TS_YN管脚上的实际电压是 1002 * 0.805664062 ≈ 807.3 mV,即0.8073V
MQ-2的浓度值也就可以计算出为 1002/4095 * 100% = 24.5%
2.6.3.3 测试程序应用编程
由上文驱动配置说明知道,ADC采样到的数据和其计算方法,下面是获取MQ-2的浓度值的代码。
guowenxue@ubuntu20:~/igkboard/apps$ vim adc_mq2.c
/*********************************************************************************
* Copyright: (C) 2022 LingYun IoT System Studio
* All rights reserved.
*
* Filename: adc_mq2.c
* Description: This file is mq2 concentration source code.
*
* Version: 1.0.0(2022/10/19)
* Author: Guo Wenxue <guowenxue@gmail.com>
* ChangeLog: 1, Release initial version on "2022/10/19 22:13:26"
*
********************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
//需要读取的文件绝对路径
static char *file_path[] = {
"/sys/bus/iio/devices/iio:device0/in_voltage_scale",
"/sys/bus/iio/devices/iio:device0/in_voltage1_raw",
};
enum path_index {
IN_VOLTAGE_SCALE = 0,
IN_VOLTAGE1_RAW,
};
typedef struct adc_dev_s
{
int raw; //原始数据,数字值
float scale;//精度值
float act; //实际值
float conc; //浓度值
}adc_dev_t;
static int file_data_read(char *filename, char *buf, size_t buf_size);
int main(int argc, char *argv[])
{
char adc_buf[30] = {};
adc_dev_t mq2;
memset(&mq2, 0, sizeof(mq2));
while(1)
{
if(file_data_read(file_path[IN_VOLTAGE_SCALE], adc_buf, sizeof(adc_buf)) < 0)
{
printf("Error : Read %s failure.\n", file_path[0]);
}
mq2.scale = atof(adc_buf);//将字符串转换为浮点类型
// printf("Read ADC scale = %f\n", mq2.scale);
if(file_data_read(file_path[IN_VOLTAGE1_RAW], adc_buf, sizeof(adc_buf)) < 0)
{
printf("Error : Read %s failure.\n", file_path[1]);
}
mq2.raw = atoi(adc_buf);//将字符串转换为整型
// printf("Read ADC raw = %d\n", mq2.raw);
mq2.act = (mq2.raw * mq2.scale) / 1000.f;//计算其实际电压值
mq2.conc = ((float)mq2.raw / 4095.f) * 100.f;//计算其实际浓度值
printf("MQ-2 实际电压值为 %.3fV , 浓度为%.1f%%\n", mq2.act, mq2.conc);
sleep(1);
}
return 0;
}
//读取文件的字符串
static int file_data_read(char *filename, char *buf, size_t buf_size)
{
int ret = 0;
int fd = -1;
if(!filename || !buf || !buf_size)
{
printf("Error filename or str \n");
return -1;
}
fd = open(filename, O_RDONLY);
if(fd < 0)
{
printf("Open file '%s' failure: %s\n", filename, strerror(errno));
ret = -2;
goto cleanup;
}
memset(buf, 0, buf_size);
if(read(fd, buf, buf_size) < 0)
{
printf("Read data from '%s' failure: %s\n", filename, strerror(errno));
ret = -3;
goto cleanup;
}
cleanup:
if(fd >= 0)
close(fd);
return ret;
}
编写Makefile如下
guowenxue@ubuntu20:~/igkboard/apps$ vim Makefile
CC=arm-linux-gnueabihf-gcc
APP_NAME=adc_mq2
all:clean
@${CC} ${APP_NAME}.c -o ${APP_NAME}
clean:
@rm -f ${APP_NAME}
2.6.3.4 交叉编译运行测试
在ubuntu下的相关源码路径下执行make命令将会编译源码生成ARM开发板上的可执行文件。
guowenxue@ubuntu20:~/igkboard/apps$ make
guowenxue@ubuntu20:~/igkboard/apps$ ls
Makefile adc_mq2 adc_mq2.c
现在我们在开发板上通过 tftp 命令 或其它方式将编译生成的测试程序下载到开发板上。
root@igkboard:~# tftp -gr adc_mq2 192.168.2.2
接下来,我们给该程序加上执行权限并运行。可以正常打印当前开发板周围的危险气体浓度值。使用打火机释放甲烷进行测试,可以见到浓度骤增然后打火机关闭放气阀后浓度缓慢下降。
root@igkboard:~# chmod a+x adc_mq2
root@igkboard:~# ./adc_mq2
MQ-2 实际电压值为 0.360V , 浓度为%10.9
MQ-2 实际电压值为 0.362V , 浓度为%11.0
MQ-2 实际电压值为 0.363V , 浓度为%11.0
MQ-2 实际电压值为 0.366V , 浓度为%11.1
MQ-2 实际电压值为 2.691V , 浓度为%81.6
MQ-2 实际电压值为 2.744V , 浓度为%83.2
MQ-2 实际电压值为 2.373V , 浓度为%71.9
MQ-2 实际电压值为 2.473V , 浓度为%75.0
MQ-2 实际电压值为 3.299V , 浓度为%100.0
MQ-2 实际电压值为 2.929V , 浓度为%88.8
MQ-2 实际电压值为 2.445V , 浓度为%74.1
MQ-2 实际电压值为 2.045V , 浓度为%62.0
MQ-2 实际电压值为 1.974V , 浓度为%59.8
MQ-2 实际电压值为 1.781V , 浓度为%54.0
MQ-2 实际电压值为 1.546V , 浓度为%46.9
MQ-2 实际电压值为 1.324V , 浓度为%40.1
MQ-2 实际电压值为 1.150V , 浓度为%34.8
MQ-2 实际电压值为 1.008V , 浓度为%30.5
MQ-2 实际电压值为 0.914V , 浓度为%27.7
MQ-2 实际电压值为 0.844V , 浓度为%25.6
MQ-2 实际电压值为 0.777V , 浓度为%23.6
MQ-2 实际电压值为 0.728V , 浓度为%22.1
MQ-2 实际电压值为 0.686V , 浓度为%20.8