02 ADC 采集应用
本章节介绍 GK7206 的 ADC(模数转换器)采集应用示例 —— sample_lsadc。该应用演示了通过 /dev/lsadc 设备节点读取 ADC 通道数据的功能,支持单步扫描和连续扫描两种工作模式。
应用源码位于 SDK 目录 sample/lsadc/,是一个简单的硬件外设访问示例,展示了如何通过 Linux 字符设备接口与硬件驱动交互。
1 应用概述
1.1 功能特性
- 双扫描模式:支持单步扫描和连续扫描两种工作模式
- 多通道选择:支持选择不同的 ADC 输入通道
- 交互式操作:通过命令行交互选择模式和通道
- 实时数据显示:实时打印 ADC 采集的数值
- 低内存占用:内存占用极小,无复杂依赖
1.2 技术参数
| 参数 | 值 |
|---|---|
设备节点 | /dev/lsadc |
扫描模式 | 单步扫描、连续扫描 |
采样间隔 | 1 秒(可调整) |
采集次数 | 20 次(默认) |
内存占用 | 极小 |
内核模块 | 需加载 xm_lsadc.ko |
1.3 目录结构
sample/lsadc/
├── Makefile # 构建脚本
└── sample_lsadc.c # 主程序2 编译与部署
2.1 前置条件
在编译本应用之前,请确保已完成以下准备工作:
- SDK 环境已搭建:参照 SDK 编译 完成交叉编译工具链和 SDK 配置
- 内核模块已加载:需加载
xm_lsadc.ko模块
2.2 编译应用
# 进入 sample 目录
cd <SDK_PATH>/sample
# lsadc 不在顶层 objects,需单独编译
make -C lsadc clean && make -C lsadc提示
lsadc 示例不在顶层 Makefile 的 objects 列表中,需要单独编译。
2.3 部署到板端
# 使用 SCP 传输到开发板
scp sample/lsadc/sample_lsadc root@<板端IP>:/tmp/
# 或通过 TFTP 下载
tftp -g -r sample_lsadc <板端IP>相关信息
由于本应用体积很小,可以直接放在 /tmp 运行。
2.4 运行应用
# 添加执行权限
chmod +x /tmp/sample_lsadc
# 加载内核模块(首次运行需要)
insmod /opt/ko/xm_lsadc.ko
# 运行应用(交互式)
./sample_lsadc2.5 预期输出
启动界面
=============== LSADC TEST ===============
0:single step scan mode
1:continuous scan mode
please select the mode:单步扫描模式(选择模式 0)
选择通道后:
please select the channel:
0
get value:1234,chn[0]
get value:1235,chn[0]
get value:1233,chn[0]
get value:1236,chn[0]
get value:1234,chn[0]
get value:1237,chn[0]
get value:1232,chn[0]
get value:1238,chn[0]
get value:1235,chn[0]
get value:1239,chn[0]
get value:1233,chn[0]
get value:1236,chn[0]
get value:1234,chn[0]
get value:1237,chn[0]
get value:1232,chn[0]
get value:1238,chn[0]
get value:1235,chn[0]
get value:1239,chn[0]
get value:1233,chn[0]
get value:1236,chn[0]预期现象:
- 循环打印 20 次
get value:<ADC值>,chn[<通道>] - 每秒打印 1 次(
usleep(1000*1000)) - ADC 值范围:0~4095(12位ADC)
- ADC 值随输入电压变化
- 20次后自动退出
连续扫描模式(选择模式 1)
选择通道后:
please select the channel:
0
get value:1234,chn[0]
get value:1235,chn[0]
get value:1233,chn[0]
get value:1236,chn[0]
get value:1234,chn[0]
get value:1237,chn[0]
get value:1232,chn[0]
get value:1238,chn[0]
get value:1235,chn[0]
get value:1239,chn[0]
get value:1233,chn[0]
get value:1236,chn[0]
get value:1234,chn[0]
get value:1237,chn[0]
get value:1232,chn[0]
get value:1238,chn[0]
get value:1235,chn[0]
get value:1239,chn[0]
get value:1233,chn[0]
get value:1236,chn[0]预期现象:
- 循环打印 20 次
get value:<ADC值>,chn[<通道>] - 每秒打印 1 次
- ADC 值随输入电压变化
- 20次后自动退出
退出方式
- 自动退出:采集 20 次后自动退出
- 手动退出:按
Ctrl+C强制退出
错误情况
fail to open file:/dev/lsadc原因:xm_lsadc.ko 内核模块未加载 解决:insmod /opt/ko/xm_lsadc.ko
adc model select error.原因:模式参数无效 解决:确保输入 0 或 1
2.5 交互操作
单步扫描模式
please select the mode: 0
please select the channel: 0
get value:1234,chn[0]
get value:1235,chn[0]
...连续扫描模式
please select the mode: 1
please select the channel: 0
get value:1234,chn[0]
get value:1235,chn[0]
...3 内部执行逻辑详解
3.1 应用架构
本应用采用简单的交互式架构:
int main(void)
{
int mode, chn;
// 显示菜单
printf("=============== LSADC TEST ===============\n");
printf("0:single step scan mode\n");
printf("1:continuous scan mode\n");
printf("please select the mode:\n");
// 获取用户输入
scanf("%d", &mode);
// 根据 mode 选择扫描模式
switch(mode) {
case 0:
printf("please select the channel:\n");
scanf("%d", &chn);
sample_lsadc_single_step_scan_mode(mode, chn);
break;
case 1:
printf("please select the channel:\n");
scanf("%d", &chn);
sample_lsadc_continuous_scan_mode(mode, chn);
break;
default:
printf("invalid mode\n");
break;
}
return 0;
}3.2 单步扫描模式
单步扫描模式每次采集需要启动→获取→停止的完整流程:
xmedia_s32 sample_lsadc_single_step_scan_mode(lsadc_scan_mode mode, xmedia_s32 chn)
{
int i, value;
int fd = open(DEV_FILE, O_RDWR); // 打开 /dev/lsadc
if (fd < 0) {
fprintf(stderr, "fail to open file:%s\n", DEV_FILE);
return -1;
}
// 选择扫描模式
if(ioctl(fd, LSADC_IOC_MODEL_SEL, &mode) < 0) {
fprintf(stderr, "adc model select error.\n");
goto exit;
}
// 使能通道
if(ioctl(fd, LSADC_IOC_CHN_ENABLE, &chn) < 0) {
fprintf(stderr, "enable chn %d error.\n", chn);
goto exit;
}
// 循环采集 20 次
for(i = 0; i < 20; i++) {
// 启动 ADC
if(ioctl(fd, LSADC_IOC_START) < 0) {
fprintf(stderr, "start lsadc error.\n");
goto exit;
}
// 获取通道值
value = ioctl(fd, LSADC_IOC_GET_CHNVAL, &chn);
printf("get value:%d,chn[%d]\n", value, chn);
usleep(1000 * 1000); // 等待 1 秒
// 停止 ADC
if(ioctl(fd, LSADC_IOC_STOP) < 0) {
fprintf(stderr, "stop lsadc error.\n");
}
}
exit:
// 清理资源
if(ioctl(fd, LSADC_IOC_STOP) < 0) {
fprintf(stderr, "stop lsadc error.\n");
}
if(ioctl(fd, LSADC_IOC_CHN_DISABLE, &chn) < 0) {
fprintf(stderr, "disable chn %d error.\n", chn);
}
close(fd);
return 0;
}3.3 连续扫描模式
连续扫描模式只需启动一次,然后持续获取数据:
xmedia_s32 sample_lsadc_continuous_scan_mode(lsadc_scan_mode mode, xmedia_s32 chn)
{
int i, value;
int fd = open(DEV_FILE, O_RDWR);
if (fd < 0) {
fprintf(stderr, "fail to open file:%s\n", DEV_FILE);
return -1;
}
// 选择扫描模式
if(ioctl(fd, LSADC_IOC_MODEL_SEL, &mode) < 0) {
fprintf(stderr, "adc model select error.\n");
goto exit;
}
// 使能通道
if(ioctl(fd, LSADC_IOC_CHN_ENABLE, &chn) < 0) {
fprintf(stderr, "enable chn %d error.\n", chn);
goto exit;
}
// 启动 ADC(只启动一次)
if(ioctl(fd, LSADC_IOC_START) < 0) {
fprintf(stderr, "start lsadc error.\n");
goto exit;
}
// 循环获取数据
for(i = 0; i < 20; i++) {
value = ioctl(fd, LSADC_IOC_GET_CHNVAL, &chn);
printf("get value:%d,chn[%d]\n", value, chn);
usleep(1000 * 1000); // 等待 1 秒
}
exit:
// 清理资源
if(ioctl(fd, LSADC_IOC_STOP) < 0) {
fprintf(stderr, "stop lsadc error.\n");
}
if(ioctl(fd, LSADC_IOC_CHN_DISABLE, &chn) < 0) {
fprintf(stderr, "disable chn %d error.\n", chn);
}
close(fd);
return 0;
}3.4 IOCTL 命令
应用使用以下 IOCTL 命令与驱动交互:
| 命令 | 功能 | 参数 |
|---|---|---|
LSADC_IOC_MODEL_SEL | 选择扫描模式 | 0=单步,1=连续 |
LSADC_IOC_CHN_ENABLE | 使能通道 | 通道号 |
LSADC_IOC_CHN_DISABLE | 禁用通道 | 通道号 |
LSADC_IOC_START | 启动 ADC | 无 |
LSADC_IOC_STOP | 停止 ADC | 无 |
LSADC_IOC_GET_CHNVAL | 获取通道值 | 通道号 |
3.5 ADC 值的含义
ADC 返回的值是一个整数,范围通常在 0~4095 之间(12 位 ADC)。该值与输入电压成正比:
电压 = (ADC值 / 4095) × 参考电压例如,如果参考电压为 3.3V,ADC 值为 2048,则输入电压约为:
电压 = (2048 / 4095) × 3.3V ≈ 1.65V4 关键编程要点
4.1 设备节点操作
Linux 字符设备的标准操作模式:
// 打开设备
int fd = open("/dev/lsadc", O_RDWR);
// IOCTL 控制
ioctl(fd, LSADC_IOC_MODEL_SEL, &mode);
// 关闭设备
close(fd);4.2 错误处理
每个 IOCTL 调用都应检查返回值:
if(ioctl(fd, LSADC_IOC_START) < 0) {
fprintf(stderr, "start lsadc error.\n");
goto exit; // 跳转到清理代码
}4.3 资源清理
使用 goto 进行统一的资源清理:
exit:
// 禁用通道
if(ioctl(fd, LSADC_IOC_CHN_DISABLE, &chn) < 0) {
fprintf(stderr, "disable chn %d error.\n", chn);
}
// 关闭设备
close(fd);
return 0;
}5 常见问题排查
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
fail to open file:/dev/lsadc | 设备节点不存在 | 检查 xm_lsadc.ko 模块是否加载 |
adc model select error | 模式参数无效 | 检查 mode 是否为 0 或 1 |
enable chn X error | 通道号无效 | 检查通道号是否在有效范围内 |
| ADC 值始终为 0 | 输入未连接或电压过低 | 检查硬件连接 |
| ADC 值始终为 4095 | 输入电压过高或超过参考电压 | 检查输入电压范围 |
