Linux下的使用字符设备驱动框架编写ADC驱动 ——MQ-4传感器

2024-08-29 20:28

本文主要是介绍Linux下的使用字符设备驱动框架编写ADC驱动 ——MQ-4传感器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

ADC的原理

 ADC 的作用:模拟信号转换为数字信号

模拟信号一般是指连续变化的电压信号,其数值在一定范围内变化。

而数字信号是由一系列离散的数字表示, 只能取有限的值,通常以二进制形式表示。

ADC通常由一个采样保持电路、一个比较器和一个计数器组成。

采样保持电路将输入的模拟电压保持在一个稳定的值,

比较器将这个稳定的值与一个参考电压进行比较,

计数器记录比较器的输出信号的次数。

ADC的分辨率是指ADC可以分辨的最小电压变化,通常用位数来表示。(8  10  12  16)

ADC的工作原理是将模拟信号分割成一系列离散的取样,并将每个取样值转换为相应的数字表示。这个过程 涉及到两个主要步骤:采样和量化。

细分为  采样–>保持–>量化–>编码

采样:ADC将连续变化的模拟信号在一定时间间隔内进行取样。取样频率决定了每秒采集的样本数,通常 以赫兹(Hz)表示。采样过程通过保持并测量模拟信号在每个采样时间点的电压值来实现。

量化:采样得到的连续模拟信号经过量化转换为数字形式。量化是将每个采样值映射到一个离散的数字值的过程。这通常通过比较采样值与参考电压之间的差异(逐次逼近法),并将其转换为数字表示。

逐次逼近法:ADC量化的过程是相对于一个基准值的,这个基准值称之为基准电压。一般采用逐次逼近法的ADC会先拿采用电压Vadc跟基准电压Vref(3.3v)的1/2进行比较,如果Vadc>Vref,则结果为1,否则结果为0。之后继续拿Vadc 和Vref的1/4或Vref的3/4继续比较。这个过程有点像二分法,每次比较都会使量化的结果逼近真实值。

很明显,比较的次数决定了测量的精度,这个精度被称之为ADC的分辨率。比如一个比较了8次的ADC外设,它就称为8位ADC,其结果是0~255(2的8次方)之间的一个数值,设该数值为n,那么实际电压就是Vref * (n/255)。如果把比较次数增加到10次,结果就是0~1023(2的10次方)之间的一个数。
 

例如,一个10位ADC可以分辨的最小电压变化为1/1024,这意味着ADC可以分辨的最小电变化为输入电压的1/1024。

 V = (AD / 2^n) * Vref 

 

其中,V表示实际电压值,AD表示AD转换的数字值,n表示AD转换的位数,Vref表示参考(基准)电压。

MQ-4传感器  可燃气体浓度检测传感器

参考博文:http://t.csdnimg.cn/TORnr

必须使用5v电压,否则会造成电压过低测不准

MQ-4传感器内置了一种特殊的材料,叫做敏感材料,它能与待测气体发生化学反应。

当检测到有害气体时,气体分子会被吸附在传感器的敏感层表面,并与敏感层中的化学物质发生反应。这种化学反应会改变敏感层的电阻值,从而使得整个传感器的电阻值发生变化。

U = IR

MQ- 4气体传感器所使用的气敏材料是在清洁空气中电导率较低的二氧化锡(SnO2)。

当传感器所处环境中存在可燃气体时,传感器的电导率随空气中可燃气体浓度的增加而增大。使用简单的电路即可将电导率的变化转换为与该气体浓度相对应的输出信号。

MQ-4气体传感器对甲烷的灵敏度高,对丙烷、丁烷也有较好的灵敏度。

敏感材料会随着使用时间的增长而老化,使得传感器的精度逐渐降低。因此,定期更换传感器是必要的。

输入电压:DC5V 功耗(电流):150mA

DO输出:TTL数字量0和1(0.1和5V)

AO输出:0.1-0.3V(相对无污染),最高浓度电压4V左右

特别提醒:传感器通电后,需要预热20S左右,测量的数据才稳定,传感器发热属于正常现象,因为内部有电热丝,如果烫手就不正常了。

 无天然气的环境下,实测AOUT端的电压为0.5V,当检测到天然气时,电压每升高0.1V,实际被测气体浓度增加200ppm

ppm = (Voltage - 0.5) / 0.1 * 200;

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>int main(void)
{int fd = open("/dev/adc",O_RDWR);if(fd < 0){puts("error\n");return -1;}unsigned int short n;float C;float RS,PPM;while(1){read(fd,&n,2);printf("%d\n",n);C = ((float)n/1023)*3.3;RS = (5.0/C-1)*1.0;   //RS = (Vc/VRL-1)*RL//y = -0.003x + 0.1864     RS/R0 = -0.003X+0.1864PPM = ((RS/12.0)-0.1864)/(-0.0003);printf("C = %f\n",PPM);sleep(1);}
}

S3C2440 adc驱动程序  采用通道AIN1采集

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/miscdevice.h>
#include <linux/irqreturn.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/wait.h>
#include <mach/irqs.h>
#define ADCCON   (0x58000000)
#define ADCDAT0  (0x5800000C)
#define CLKCON   (0x4c00000C)
static unsigned int *REG_ADCCON;
static unsigned int *REG_ADCDAT0;
static unsigned int *REG_CLKCON;static int adc_driver_open(struct inode *pNode,struct file *fp)
{return 0;
}static int adc_driver_close(struct inode *pNode,struct file *fp)
{return 0;
}//采用读启动的方式启动adcstatic ssize_t adc_driver_read(struct file *fp,char __user*userBuffer,size_t len,loff_t *offset)
{unsigned short ret;*REG_ADCCON|=(0x01 << 0);  //启动一次ADC转换//while(!(*REG_ADCCON&(1<<15)));ret = *REG_ADCDAT0&0x3ff;//将转换的结果放入 adcdat0 的低10位中copy_to_user(userBuffer,&ret,2);//把结果返回用户层return 2;
}static ssize_t adc_driver_write(struct file *fp,const char __user *userBuffer,size_t len,loff_t*offset)
{	return 0;
}static struct file_operations fops =
{.owner = THIS_MODULE,.open = adc_driver_open,.release = adc_driver_close,.read = adc_driver_read,.write = adc_driver_write,
};
//自动获取设备号需要定义的变量
static dev_t dev_num;//设备号
struct cdev adc_dev;//  cdev 是一个描述字符设备的结构体//自动添加设备所需要定义的变量
static struct class *p_class;
static struct device *p_device;static int __init adc_driver_init(void)
{int ret;//申请设备号  此设备号的起始值为 0    申请1个设备   设备起个名字叫做 adc_deviceret = alloc_chrdev_region(&dev_num,0,1,"adc_device");if(ret){printk("alloc_chrdev_region is error\n");goto alloc_chrdev_region_err;}printk("major = %u,minior = %u\n",MAJOR(dev_num),MINOR(dev_num));//将设备初始化cdev_init(&adc_dev,&fops);//向内核添加驱动程序  相当于  register_chrdev函数 的注册ret = cdev_add(&adc_dev,dev_num,1);if(ret){printk("cdev_add is error\n");goto cdev_add_err;}//创建一个设备类  adc classp_class = class_create(THIS_MODULE,"adc class");if(IS_ERR(p_class)){printk("class_create is error!");goto class_create_err;}//创建一个设备类 属于 之前adc class的类别   这两步可以实现设备节点的自动添加//不需要使用mknod /dev/adc 手动添加设备节点p_device = device_create(p_class,NULL,dev_num,NULL,"adc");if(p_device == NULL){printk("device_create is error\n");goto device_create_err;}//把需要配置引脚的物理地址映射到虚拟地址REG_ADCCON = ioremap(ADCCON,4);  //io引脚的控制寄存器REG_ADCDAT0 = ioremap(ADCDAT0,4);  //io引脚的数据寄存器REG_CLKCON = ioremap(CLKCON ,4);*REG_CLKCON |=(1<< 15);//配置寄存器*REG_ADCCON |= (0X01 << 14)|(24<< 6);*REG_ADCCON &=~(0X07<<3);*REG_ADCCON |= (0X01<<3);//把adc的采样通道设置为AIN1*REG_ADCCON &=~(0X01<<2);*REG_ADCCON &=~(0X01 << 1);printk("adc_driver_init\n");return 0;device_create_err:class_destroy(p_class);
class_create_err:cdev_del(&adc_dev);
cdev_add_err:unregister_chrdev_region(dev_num,1);
alloc_chrdev_region_err:return ret;
}static void __exit adc_driver_exit(void)
{iounmap(REG_ADCCON);iounmap(REG_ADCDAT0);iounmap(REG_CLKCON);device_destroy(p_class,dev_num);class_destroy(p_class);cdev_del(&adc_dev);unregister_chrdev_region(dev_num,1);printk("adc_driver_exit ok\n");
}module_init(adc_driver_init);module_exit(adc_driver_exit);MODULE_LICENSE("GPL");

这篇关于Linux下的使用字符设备驱动框架编写ADC驱动 ——MQ-4传感器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1118809

相关文章

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

linux-基础知识3

打包和压缩 zip 安装zip软件包 yum -y install zip unzip 压缩打包命令: zip -q -r -d -u 压缩包文件名 目录和文件名列表 -q:不显示命令执行过程-r:递归处理,打包各级子目录和文件-u:把文件增加/替换到压缩包中-d:从压缩包中删除指定的文件 解压:unzip 压缩包名 打包文件 把压缩包从服务器下载到本地 把压缩包上传到服务器(zip

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

pdfmake生成pdf的使用

实际项目中有时会有根据填写的表单数据或者其他格式的数据,将数据自动填充到pdf文件中根据固定模板生成pdf文件的需求 文章目录 利用pdfmake生成pdf文件1.下载安装pdfmake第三方包2.封装生成pdf文件的共用配置3.生成pdf文件的文件模板内容4.调用方法生成pdf 利用pdfmake生成pdf文件 1.下载安装pdfmake第三方包 npm i pdfma