尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Linux驱动-ADC篇-ADC基本知识点

发布时间:2026/9/29 21:25:21

资讯中心
01
ARTICLE

Linux驱动-ADC篇-ADC基本知识点

Linux驱动-ADC篇-ADC基本知识点
Linux驱动-ADC篇-ADC基本知识点文章目录前言一、初识ADCADCADC 分辨率RK3568开发板ADC接口了解SARADC TSADC 区别和联系按键ADC外设板载剩余ADC 说明SARADC工作原理二、操作ADC通过sysfs接口操作ADC通过C系统程序编程操作ADC三、ADC驱动程序-编写ADC涉及到的函数iio_channel_get()函数iio_read_channel_raw()函数ADC编写设备树ADC驱动程序编写驱动程序编写应用程序的编写测试验证总结前言先搞清楚 ADC 要学习什么一、初识ADCADCADC 是 Analog-to-Digital Converter 的缩写 可以翻译为模数转换器 它是一种电子设备或电路模块 用于将连续变化的模拟信号转换为离散的数字信号。模拟信号是一种连续变化的信号 其值可以在一定范围内取任意值 它在时间上和幅度上都是连续的 能够精确地反映自然界中的物理量变化。 而数字信号是一种离散的信号 其值只能在有限的范围内取特定的数值 通常以二进制形式表示 它在时间上和幅度上都是离散的ADC 应用领域1 传感器信号采集 温度传感器、 压力传感器、 光敏传感器等采集到的环境数据通常以模拟信号形式存在。2 音频处理 麦克风拾取的声音信号是模拟信号。3 图像处理 摄像头捕捉的光信号本质上是模拟信号。4 工业自动化 各种物理量如速度、 位置、 压力等 的测量通常依赖于传感器输出的模拟信号。-5 医疗设备 许多生物信号如心电图、 脑电图等 是以模拟信号形式采集的。ADC 分辨率ADC 分辨率指的是模数转换器能够区分的最小信号变化的能力ADC 的分辨率通常用位数来表示 位数决定了 ADC 输出的离散数值数量 n 位 ADC 可以表示 2^n 个不同的数值。 例如 8 位 ADC 可以表示 2^8256 个不同的数值 位数越高 分辨率越高 能够区分的信号变化越小分辨率可以通过以下公式计算1 量程是指 ADC 输入信号的最大范围2 n 是 ADC 的位数3 2^n 表示 ADC 能够区分的离散数值总数。假设一个 3 位 ADC 的参考电压量程 为 2V 计算他的分辨率是多少1 题干 1 量程 2V2 题干 2 位数为 3 2^n 2^3 8代入分辨率计算公式可得 2V/8 0.25V。 这意味着该 ADC 能够将输入信号分成 8 个离散的等级 每个等级之间的步长为 0.25V。除了分辨率之外 ADC 还有另外几个重要的参数RK3568开发板ADC接口了解打开文件Rockchip RK3568 Datasheet V1.0-20201210.pdf框图如下也就是说 这个RK3568 使用手册上面 描述的是8路SARADC实际应该还是6路SARADC2路TS-ADC。SARADC TSADC 区别和联系特性SARADCTSADC全称Successive Approximation Register ADC逐次逼近型 ADC Temperature Sensor ADC温度传感器 ADC核心用途通用模拟信号采集。用于测量外部电压如电位器、光敏电阻、传感器输出的模拟电压。芯片内部测温。用于监控 SoC 自身的温度防止过热烧毁。分辨率10 bitRK3568 典型值温度分辨率 5°C通常输出 10 位或 12 位数字量对应温度输入范围0 ~ 1.8V外部引脚输入-20°C ~ 120°C内部 PN 结温度通道数8 路8 个外部引脚可接 8 个不同传感器双路通常监控芯片内部两个不同位置的温度采样率最高 1MS/s每秒 100 万次最高 50KS/s每秒 5 万次驱动子系统IIOIndustrial I/O子系统Thermal热管理子系统sysfs 路径/sys/bus/iio/devices/iio:deviceX//sys/class/thermal/thermal_zoneX/按键ADC外设由于 TS-ADC 只负责检测 CPU 和 GPU 的温度所以处理器并未引出 因此接下来介绍在iTOP-RK3568 开发板上使用 SARADC 的外设 首先是 ADC 按键 ADC 按键的工作原理是将多个按键连接到同一个 SARADC 引脚上 并通过不同的分压电阻产生不同的电压 通过 ADC 测量该电压 并与预设的电压范围进行比对 从而判断哪个按键被按下。 按键原理图如下板载剩余ADC 说明板载剩余的 4 路 SARADC 被连接到了 6pin 的座子上 相应原理图如图SARADC工作原理SARADC 全称为逐次逼近型 ADCSuccessive Approximation Register ADC 是一种常见的模数转换器 其工作原理通过逐步比较输入模拟信号与内部生成的参考电压 最终确定一个接近输入信号的数字值二、操作ADC通过sysfs接口操作ADC首先进入开发板/sys/bus/iio/devices/iio:device0目录下 目录内容如图1 in_voltageX_raw 属性表示 ADC 某个通道的原始采样值 其中 X 是通道编号如 0, 1,2, …, 7 。 它以整数形式存储 ADC 转换后的原始采样值。2 in_voltage_scale 属性表示将 ADC 原始采样值转换为实际电压值的缩放因子 以浮点数形式表示 单位可以是毫伏mV 或伏特V 具体取决于硬件实现。 将 in_voltageX_raw属性原始值乘以 in_voltage_scale 属性值 即可得到对应 ADC 通道的实际电压值。SARADC 的通道 7 为例进行演示 对应的硬件为 iTOP-RK3568 开发板底板的 J24 接口的第 5 脚 相关原理图如图 239.2 所示使用杜邦线将 ADC 的通道 7 接到 GND 上 重新使用 cat 命令读取 in_voltage7_raw 属性 读取结果如图 239.5 所示 可以看到采集的原始数据为 15 计算得到实际电压值为 0.02V,趋近于 0V 因为是把 ADC 连接到了 GND 上 所以趋近于 0 说明 ADC 采样的值正确除了 SARADC 之外 还有用来测量 CPU 和 GPU 温度的 TSADC 可以在开发板上使用cat /sys/devices/virtual/thermal/thermal_zone0/temp可以得到现在 GPU 的温度为 43.75 摄氏度通过C系统程序编程操作ADC本小节将会通过 C 系统编程来实现获取并打印 SARADC 通道 7 采集到的电压 核心原理为使用 C 代码通过 sysfs 接口读取 ADC 的值#includestdio.h#includestdlib.h#includemath.hintmain(intargc,char*argv[]){intscale0;// 用于存储从文件中读取的原始 ADC 值FILE*fpNULL;// 文件指针 用于打开和读取文件floatvalue0.0;// 用于存储计算后的实际电压值// 打开 ADC 原始值文件fpfopen(/sys/bus/iio/devices/iio:device0/in_voltage7_raw,r);if(fpNULL){// 检查文件是否成功打开printf(fopen error\n);return-1;}//从文件中读取ADC原始值fscanf(fp,%d,scale);// 计算实际电压值// 假设参考电压为 1.8V ADC 分辨率为 10 位2^10 1024value(1.8/1024)*(float)scale;// 输出计算结果 保留两位小数printf(ADC value is %.2fV\n,value);fclose(fp);return0;// 程序正常结束}scale 是读取到的原始值 而(1.8/1024)是缩放因子 缩放因子可以通过计算的方式得到也可以直接获取 in_voltage_scale 的值最后编译aarch64-linux-gnu-gcc -o adc adc.c根据打印结果可以得到 ADC 第 7 通道默认情况下的电压是 1.79V 然后通过杜邦线与 GND相连 重新运行该程序三、ADC驱动程序-编写ADC涉及到的函数iio_channel_get()函数这个函数的作用是在驱动中建立与设备树DTS中定义的 IIO 通道的连接。函数原型struct iio_channel *iio_channel_get(const char *name, const char *channel_name);参数说明name 表示 IIO 设备的名称或 ID。 如果为 NULL 则表示默认设备。channel_name 表示要获取的通道名称。返回值成功时返回一个指向 struct iio_channel 的指针 表示获取到的 IIO 通道对象。返回值struct iio_channel结构体用于描述 IIO 通道 其定义如代码清单 所示struct iio_channel{struct iio_device*indio_dev;// 关联的 IIO 设备constchar*channel_name;// 通道名称intchannel_index;// 通道索引bool is_output;// 是否为输出通道};当获取的通道对象不再被需要时 需要使用 iio_channel_release()函数释放相关资源。设备树DTS的配合adc_demo:adc_demo{compatiblefirefly,rk356x-adc;io-channelssaradc 2;// 获取 saradc 的通道 2// 如果有多个通道// io-channels saradc 2, saradc 3;// io-channel-names channel2, channel3;};驱动中调用iio_channel_get(pdev-dev, NULL)就会自动解析并获取到saradc 2这个通道。iio_read_channel_raw()函数这个函数用于从已获取的通道中读取未经处理的原始 ADC 数值。参数理解channeliio_channel_get()返回的通道指针。val输出参数用于存放读取到的原始值如 10 位 ADC 的 0~1023。intret,raw_val;retiio_read_channel_raw(adc-chan,raw_val);if(ret0){dev_err(pdev-dev,Failed to read raw value: %d\n,ret);returnret;}printk(Raw ADC value: %d\n,raw_val);iio_read_channel_raw()读到的只是原始数字量比如 983。要得到真实的电压值mV需要结合in_voltage_scale进行换算实际电压(mV) raw_val × scalescale 值可以通过iio_read_channel_processed()自动换算或者手动读取 sysfs 的in_voltage_scale节点获取。ADC编写设备树路径arch/arm64/boot/dts/rockchip/rk3568-evb.dtsi添加如下代码adc7:adc-test{compatiblemyadc;io-channelssaradc 7;};该节点的重点在 io-channels 属性 io-channels 属性表示要使用 ADC 的第 7 个通道 然后重新编译内核源码 编译完成之后烧写到开发板即可。ADC驱动程序编写驱动程序编写注册一个杂项设备,在 dev 目录下生成一个名为 adc 的设备节点 通过对该节点进行操作可以得到 ADC 通道采集到的电压值#includelinux/module.h#includelinux/fs.h#includelinux/uaccess.h#includelinux/ioctl.h#includelinux/platform_device.h#includelinux/iio/consumer.h#includelinux/miscdevice.h#includelinux/of.h// 添加对设备树的支持#defineCMD_READ_SCALE_IOR(A,0x1,int)// 定义 ioctl 命令staticstruct iio_channel*adc_chan;// IIO 通道指针// 文件操作ioctl 实现staticlongadc_dev_ioctl(struct file*file,unsignedintcmd,unsignedlongarg){intscale0;switch(cmd){caseCMD_READ_SCALE:// 从 ADC 通道读取原始值if(iio_read_channel_raw(adc_chan,scale)0){pr_err(Failed to read ADC channel raw value\n);return-EIO;}// 将数据复制到用户空间if(copy_to_user((int*)arg,scale,sizeof(scale))){pr_err(Failed to copy data to user space\n);return-EFAULT;}break;default:pr_err(Invalid ioctl command\n);return-EINVAL;}return0;}// 文件操作结构体staticconststruct file_operations adc_dev_fops{.ownerTHIS_MODULE,.unlocked_ioctladc_dev_ioctl,};// 杂项设备结构体staticstruct miscdevice adc_dev{.minorMISC_DYNAMIC_MINOR,// 动态分配次设备号.nameadc,// 设备名称.fopsadc_dev_fops,// 文件操作接口};// 设备树匹配表staticconststruct of_device_id adc_driver_match[]{{.compatiblemyadc},{}};MODULE_DEVICE_TABLE(of,adc_driver_match);// 平台设备探测函数staticintadc_driver_probe(struct platform_device*pdev){// 获取 IIO 通道adc_chaniio_channel_get(pdev-dev,NULL);if(IS_ERR(adc_chan)){pr_err(Failed to get IIO channel\n);returnPTR_ERR(adc_chan);}// 注册杂项设备if(misc_register(adc_dev)){pr_err(Failed to register misc device\n);iio_channel_release(adc_chan);// 释放 IIO 通道return-ENODEV;}pr_info(ADC driver probed successfully\n);return0;}// 平台设备移除函数staticintadc_driver_remove(struct platform_device*pdev){// 注销杂项设备misc_deregister(adc_dev);// 释放 IIO 通道iio_channel_release(adc_chan);pr_info(ADC driver removed successfully\n);return0;}// 平台设备驱动结构体staticstruct platform_driver adc_driver{.probeadc_driver_probe,.removeadc_driver_remove,.driver{.namemyadc,// 驱动名称.ownerTHIS_MODULE,.of_match_tableadc_driver_match,},};// 模块初始化函数staticint__initadc_driver_init(void){intret;// 注册平台设备驱动retplatform_driver_register(adc_driver);if(ret){pr_err(Failed to register platform driver\n);returnret;}pr_info(ADC driver module loaded\n);return0;}// 模块退出函数staticvoid__exitadc_driver_exit(void){// 注销平台设备驱动platform_driver_unregister(adc_driver);pr_info(ADC driver module unloaded\n);}module_init(adc_driver_init);module_exit(adc_driver_exit);MODULE_LICENSE(GPL);MODULE_AUTHOR(topeet);首先利用杂项驱动框架注册了一个字符设备(设备节点为/dev/adc) 用户空间可通过该设备节点与驱动交互 在 probe 函数中通过 iio_channel_get()函数获取 ADC 通道 并使用 iio_read_channel_raw()函数读取 ADC 原始值 除此之外定义了一个 ioctl 接口命令 CMD_READ_SCALE用于在用户空间触发 ADC 数据读取操作 在 ioctl 实现中调用 IIO API 获取数据并通过 copy_to_user 将结果传递给用户空间 从而实现简单的 ADC 数据采集功能。应用程序的编写编写与驱动程序匹配的应用程序 该应用程序通过/dev/adc 设备节点读取ADC 值编写完成的应用程序#includestdio.h#includestdlib.h#includeunistd.h#includesys/types.h#includesys/stat.h#includefcntl.h#includesys/ioctl.h#defineCMD_READ_SCALE_IOR(A,1,int)intmain(intargc,char*argv[]){intscale0;intfd;floatvalue0.0;// 用于存储计算后的实际电压值// 打开设备文件fdopen(/dev/adc,O_RDWR);if(fd0){printf(open error\n);return-1;}// 使用 ioctl 读取 scale 值if(ioctl(fd,CMD_READ_SCALE,scale)0){printf(ioctl error\n);close(fd);return-1;}value(1.8/1024)*(float)scale;// 打印读取到的 scale 值printf(val is %lf\n,value);// 关闭设备文件close(fd);return0;}该程序的重点在于 ioctl 函数的使用 应该程序可以通过 ioctl 系统调用向 ADC 驱动发送自定义命令 CMD_READ_SCALE 触发驱动读取 ADC 数据 并将结果存储到用户空间变量 scale 中测试验证编译驱动加载到修改好设备树的开发版上insmod adc.ko驱动成功加载之后会在/dev 目录下生成一个名为 adc 的设备节点如图然后使用./app 运行测试程序以看到默认情况下 adc 引脚的电压是 1.8V 然后通过杜邦线将 ADC 第 7 通道的引脚接到GND 上 然后重新运行该程序 运行结果如图获取到的结果趋近于 0V 证明测试结果是准确的总结提示这里对文章进行总结例如以上就是今天要讲的内容本文仅仅简单介绍了pandas的使用而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。