Linux通过shell命令读取ADC电压

Linux的ADC在应用层上可以直接操作/sys/bus/iio/devices/iio:\device0/目录的文件,而对于Linux的ADC操作有两种模式,一种是单次读取模式,第二种是多次读取模式。

一、单次读取

对于Linux系统上的ADC读取,在m3352上支持4路ADC输入,系统提供/sys文件系统接口操作,
在/sys/bus/iio/devices/iio:\device0/目录下有in_voltage4_raw~in_voltage7_raw这四个文件,
分别读取这4个文件,可获得对应的ADC值。

cat /sys/bus/iio/devices/iio\:device0/in_voltage4_raw 2782转换公式

二、多次读取

官方直接写一个C的程序去实现的,可能水平不够,没太看懂这样做的意义。直接用shell写个脚本多执行几次上面的命令不就成多次读取了吗,等以后回来来看看两者的利弊

我写的shell

#!/bin/bash
for a in {1..10}
do
 cat /sys/bus/iio/devices/iio\:device0/in_voltage$1_raw
 sleep 1
done

官方给的就复杂了

1.定义两个API函数
int find_type_by_name(const char name, const char type)
获取设备,其中name为需要打开的文件名

int build_channel_array(const char device_dir, struct iio_channel_info **ci_array, int counter)
根据ADC文件获取相应的ADC

2.程序源码

dev_num = find_type_by_name(device_name, "iio:device");            /*获取ADC设备,返回设备序号*/
if (dev_num < 0) {
    printf("Failed to find the %s\n", device_name);
    ret = -ENODEV;
    goto error_ret;
}
asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num);            /*将要操作的ADC文件*/
ret = build_channel_array(dev_dir_name, &infoarray, &num_channels);    /*获取相应的ADC渠道信息*/
if (ret) {
    printf("Problem reading scan element information\n");
    printf("diag %s\n", dev_dir_name);
    goto error_ret;
}
ret = asprintf(&buf_dir_name, "%siio:device%d/buffer", iio_dir, dev_num);/*ADC对应的buffer文件位置*/
if (ret < 0) {
    ret = -ENOMEM;
    goto error_ret;
}
ret = write_sysfs_int("length", buf_dir_name, buf_len);                /*设置ADC的数据长度*/
if (ret < 0)
    goto error_free_buf_dir_name;
/* Enable the buffer */
ret = write_sysfs_int("enable", buf_dir_name, 1);                    /*使能ADC*/
if (ret < 0)
    goto error_free_buf_dir_name;
ret = asprintf(&buffer_access, "/dev/iio:device%d", dev_num);            /*ADC文件目录*/
if (ret < 0) {
    ret = -ENOMEM;
    goto error_free_buf_dir_name;
}
/* Attempt to open non blocking the access dev */
fp = open(buffer_access, O_RDONLY | O_NONBLOCK);            /*打开ADC通道*/
if (fp == -1) { /*If it isn't there make the node */
    printf("Failed to open %s\n", buffer_access);
    ret = -errno;
goto error_free_buf_dir_name;
}
scan_size = size_from_channelarray(infoarray, num_channels);            /*获取渠道数据大小*/
data = malloc(scan_size*buf_len);
if (!data) {
    ret = -ENOMEM;
    goto error_close_buffer_access;
}
for (j = 0; j < num_loops; j++) {                                /*循环读取*/
    usleep(timedelay);
    read_size = read(fp, data, buf_len*scan_size);
    if (read_size == -EAGAIN) {
    printf("nothing available\n");
        continue;
    }
    for (i = 0; i < read_size/4; i++, data+=4)
printf("ADC Value: %d\n", *(long*)data);
}
/* Stop the ring buffer */
ret = write_sysfs_int("enable", buf_dir_name, 0);                    /*禁止使能*/
if (ret < 0)
    goto error_close_buffer_access;

值得注意的是,ADC的多次读取模式中,每次只能开启一个通道,若要切换通道必须先关闭已打开的ADC通道。

(1)创建设备节点
创建/dev/iio:device0设备节点,节点信息,参考/sys/bus/iio/devices/iio:device0/dev文件:
#cat /sys/bus/iio/devices/iio:device0/dev
251:0
设备节点主次设备号是251,0。创建命令:

(2)设置continuos模式
[root@M3352 ~]# echo continuous > /sys/bus/iio/devices/iio\:device0/mode

(3)使能通道4
[root@M3352 ~]# echo 1 > /sys/bus/iio/devices/iio\:device0/scan_elements/in_volta4_en

(4)运行范例程序

[root@M3352 ~]# ./generic_buffer -n tiadc -l 16 -c 5
ADC Value: 2199
ADC Value: 2199
ADC Value: 2199
ADC Value: 2200
ADC Value: 2202

其中,l和c参数,请参考generic_buffer.c源码。
 
(5)切换通道
切换通道时,则需要先关闭通道4,打开需要的通道,如通道5:

[root@M3352 ~]# echo 0 > /sys/bus/iio/devices/iio\:device0/scan_elements/in_volta4_en
[root@M3352 ~]# echo 1 > /sys/bus/iio/devices/iio\:device0/scan_elements/in_volta5_en

 然后继续读取即可。

Logo

更多推荐