
清空记录
历史记录
取消
清空记录
历史记录

ADC是嵌入式开发中绕不开的外设——按键检测、电池电压监测、温感与各类模拟传感器接入,几乎每一步都会用到。本系列环境基于触觉智能RK3576开发板Purple Pi OH2 ( Android14系统/Linux6.1内核)进行讲解与实机调试,从概念、设备树、驱动到用户空间调试逐步展开。
大家如需真机验证开发,获取资料可关注公众号「触觉智能」,回复关键词"客服"联系客服领取:瑞芯微RK开发板/核心板相关资料,可技术支持对接、项目选型与需求咨询。前20位申领资料,可获赠开发板大额购买折扣。机会有限,先到先得!
一、ADC基本概念
ADC(Analog-to-Digital Converter,模数转换器)将模拟电压信号转换为数字值,常用于:按键检测(ADC按键)、电池电压监测、温度传感器读取、模拟传感器接口。
参数 | 说明 | 影响 |
分辨率 | 输出位数(如 10bit、12bit) | 精度 |
采样率 | 每秒采样次数 | 速度 |
输入范围 | 可测量的电压范围 | 量程 |
精度 | 实际值与理想值的偏差 | 准确度 |
•10-bit分辨率
•多路输入通道
•输入电压范围:0~1.8V
•采样率可达1MSPS
二、ADC转换原理
数字值 = (Vin / Vref) × (2^n - 1)其中:- Vin: 输入电压- Vref: 参考电压 (1.8V)- n: 分辨率 (10bit)Vin = (数字值 / 1023) × 1.8V
三、ADC设备树配置
本板设备树入口文件为kernel-6.1/arch/arm64/boot/dts/rockchip/ido-evb7609-v1a-mipi.dts,包含关系如下:
ido-evb7609-v1a-mipi.dts └── ido-evb7609-v1a.dtsi ├── rk3576.dtsi ├── rk3576-linux.dtsi ├── ido-som7608.dtsi │ └── ido-evb7609-v1a-mipi.dtsi ← SARADC 使能处 └── 其他 dtsi...
SARADC在ido-som7608.dtsi(设备树)中使能:
&saradc { status = "okay"; vref-supply = <&vcca_1v8_s0>;};ADC按键定义在ido-evb7609-v1a-mipi.dtsi中,使用SARADC通道1:
/ { adc_keys: adc-keys { compatible = "adc-keys"; io-channels = <&saradc 1>; /* 使用通道 1 */ io-channel-names = "buttons"; keyup-threshold-microvolt = <1800000>; /* 按键释放阈值 1.8V */ poll-interval = <100>; /* 轮询间隔 100ms */ vol-up-key { label = "volume up"; linux,code = ; press-threshold-microvolt = <17000>; /* ~17mV */ }; vol-down-key { label = "volume down"; linux,code = ; press-threshold-microvolt = <417000>; /* ~417mV */ }; menu-key { label = "menu"; linux,code = ; press-threshold-microvolt = <890000>; /* ~890mV */ }; back-key { label = "back"; linux,code = ; press-threshold-microvolt = <1235000>; /* ~1.235V */ }; };}; 工作原理:多个按键通过电阻分压连接到同一个ADC通道,不同按键按下时产生不同的电压值。驱动通过比较检测电压与预设阈值来判断哪个按键被按下。
如果需要添加电池电压检测等ADC传感器,可在设备树中添加:
/ { battery: battery { compatible = "simple-battery"; voltage-monitored-battery { compatible = "voltage-monitored-battery"; io-channels = <&saradc 2>; /* 使用通道 2 */ io-channel-names = "voltage"; /* OCV 容量曲线 */ ocv-capacity-celsius = <20>; ocv-capacity-table-0 = <4200 100>, <4000 80>, <3800 50>, <3600 20>, <3400 5>, <3200 0>; }; };};四、ADC驱动开发
#include#include struct my_adc_dev { struct iio_channel *chan; struct device *dev;};/* 读取 ADC 电压值(单位:mV) */static int read_adc_value(struct my_adc_dev *priv, int *val){ int ret; int raw_val, scale_val; /* 读取原始 ADC 值 */ ret = iio_read_channel_raw(priv->chan, &raw_val); if (ret < 0) { dev_err(priv->dev, "Failed to read ADC: %d\n", ret); return ret; } /* 读取比例因子(单位:mV) */ ret = iio_read_channel_scale(priv->chan, &scale_val); if (ret < 0) { dev_err(priv->dev, "Failed to read scale: %d\n", ret); return ret; } /* 计算实际电压:raw * scale */ *val = raw_val * scale_val; return 0;}static int my_adc_probe(struct platform_device *pdev){ struct my_adc_dev *priv; int val, ret; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; priv->dev = &pdev->dev; /* 获取 IIO 通道(名称需与设备树 io-channel-names 匹配) */ priv->chan = devm_iio_channel_get(&pdev->dev, "voltage"); if (IS_ERR(priv->chan)) { ret = PTR_ERR(priv->chan); if (ret != -EPROBE_DEFER) dev_err(&pdev->dev, "Failed to get IIO channel: %d\n", ret); return ret; } /* 测试读取 */ ret = read_adc_value(priv, &val); if (ret == 0) dev_info(&pdev->dev, "ADC value: %d mV\n", val); platform_set_drvdata(pdev, priv); return 0;}static const struct of_device_id my_adc_of_match[] = { { .compatible = "mycompany,my-adc-device" }, { }};static struct platform_driver my_adc_driver = { .probe = my_adc_probe, .driver = { .name = "my-adc", .of_match_table = my_adc_of_match, },};module_platform_driver(my_adc_driver);MODULE_LICENSE("GPL");
#include#define SARADC_CTRL 0x00#define SARADC_DATA 0x04#define SARADC_STAS 0x08#define SARADC_EN BIT(0)#define SARADC_START BIT(4)struct saradc_regs { void __iomem *base; struct clk *clk;};static int saradc_read_channel(struct saradc_regs *regs, int channel){ u32 ctrl; int timeout = 1000; /* 使能 ADC */ writel(SARADC_EN, regs->base + SARADC_CTRL); /* 配置通道并启动转换 */ ctrl = SARADC_EN | SARADC_START | (channel << 6); writel(ctrl, regs->base + SARADC_CTRL); /* 等待转换完成 */ while (!(readl(regs->base + SARADC_STAS) & BIT(0))) { if (--timeout == 0) return -ETIMEDOUT; udelay(1); } /* 读取结果(10-bit) */ return readl(regs->base + SARADC_DATA) & 0x3ff;}
五、用户空间操作&调试方法
# 查看 ADC 设备ls /sys/bus/iio/devices/# 读取原始值(10-bit)cat /sys/bus/iio/devices/iio:device0/in_voltage0_raw# 读取比例因子cat /sys/bus/iio/devices/iio:device0/in_voltage0_scale# 计算实际电压# V = raw * scale / 1000000
#include#include #include #include #include #define ADC_PATH "/sys/bus/iio/devices/iio:device0"int read_adc_raw(int channel){ char path[256]; char buf[32]; int fd, val; snprintf(path, sizeof(path), "%s/in_voltage%d_raw", ADC_PATH, channel); fd = open(path, O_RDONLY); if (fd < 0) { perror("Failed to open ADC"); return -1; } if (read(fd, buf, sizeof(buf)) < 0) { perror("Failed to read ADC"); close(fd); return -1; } close(fd); return atoi(buf);}int read_adc_scale(void){ char path[256]; char buf[32]; int fd; snprintf(path, sizeof(path), "%s/in_voltage_scale", ADC_PATH); fd = open(path, O_RDONLY); if (fd < 0) return -1; if (read(fd, buf, sizeof(buf)) < 0) { close(fd); return -1; } close(fd); return (int)(atof(buf) * 1000000); /* 转换为微伏 */}int main(void){ int raw, scale, channel = 0; float voltage; printf("Reading ADC channel %d...\n", channel); raw = read_adc_raw(channel); if (raw < 0) { printf("Failed to read ADC\n"); return -1; } scale = read_adc_scale(); if (scale < 0) { printf("Failed to read scale\n"); return -1; } voltage = (float)raw * scale / 1000000.0; printf("Raw value: %d\n", raw); printf("Scale: %d uV/LSB\n", scale); printf("Voltage: %.3f V\n", voltage); return 0;}
# 查看 IIO 设备ls /sys/bus/iio/devices/cat /sys/bus/iio/devices/iio:device0/name# 查看所有通道ls /sys/bus/iio/devices/iio:device0/ | grep in_voltage# 读取所有通道值for i in 0 1 2 3; do echo "Channel $i: $(cat /sys/bus/iio/devices/iio:device0/in_voltage${i}_raw)"done# 查看按键事件evtest /dev/input/event0# 查看按键映射cat /proc/bus/input/devices# 单独读取 ADC 按键通道值cat /sys/bus/iio/devices/iio:device0/in_voltage1_raw
•[RKDocs/common/SARADC/](RKDocs/common/SARADC/)
•[Documentation/iio/](kernel-6.1/Documentation/iio/)
产品简介
