ADC(Analog-to-Digital Converter) 指模数转换器。是指将连续变化的模拟信号转换为离散的数字信号的器件。真实世界的模拟信号,例如温度、压力、声音或者图像等,需要转换成更容易储存、处理和发射的数字形式。模数转换器可以实现这个功能,在各种不同的产品中都可以找到它的身影。与之相对应的 DAC(Digital-to-Analog Converter),它是 ADC 模数转换的逆向过程。ADC 最早用于对无线信号向数字信号转换。如电视信号,长短播电台发接收等。
如下图所示模数转换一般要经过采样、保持和量化、编码这几个步骤。在实际电路中,有些过程是合并进行的,如采样和保持,量化和编码在转换过程中是同时实现的。
ADC 转换过程
采样是将时间上连续变化的模拟信号转换为时间上离散的模拟信号。采样取得的模拟信号转换为数字信号都需要一定时间,为了给后续的量化编码过程提供一个稳定的值,在采样电路后要求将所采样的模拟信号保持一段时间。
将数值连续的模拟量转换为数字量的过程称为量化。数字信号在数值上是离散的。采样保持电路的输出电压还需要按照某种近似方式归化到与之相应的离散电平上,任何数字量只能是某个最小数量单位的整数倍。量化后的数值最后还需要编码过程,也就是 A/D 转换器输出的数字量。
分辨率是衡量 A/D 转化器分辨输入模拟量最小变化程度的指标。分辨率以输出二进制(或十进制)数的位数来表示,它说明模数转换器对输入信号的分辨能力,一般有8位、10位、12位、16位等。在最大输入电压(参考电压)一定时,输出位数愈多,分辨率愈高。例如模数转换器输出为 8 位二进制数,输入信号最大值为 5V,那么这个转换器应能区分出输入信号的最小电压为 19.53mV(1 LSB),计算方法为:5/256 = 19.53mV。也就是低于 19.53mV 的输入电压的输出值都为0。如果模数转换器输出为 12 位二进制数,则输入信号最大值为 5V 对应的能区分的最小电压为:5/4096 = 1.22mV(1 LSB)。从 2 个最小电压来看位数越高能采集到更小的电压。
量化误差是由 A/D 转换器有限字长数字量对输入模拟量进行离散取样(量化)引起的误差。其大小在理论上为一个单位(1 LSB)。提高分辨率可以减小量化误差。
转换速率是指 A/D 转换器在每秒钟能完成的转换次数。转换时间为 A/D 转换从启动到结束所需的时间,转换时间和转换速率互为倒数。例如,某 A/D 转换器的转换速率为 1MHz,则转换时间为 1 微秒。
应用程序通过 RT-Thread 提供的 ADC 设备管理接口来访问 ADC 硬件,相关接口如下所示:
函数原型 | 功能简介 |
---|---|
rt_device_find() | 根据 ADC 设备名称查找设备获取设备句柄 |
rt_adc_enable() | 使能 ADC 设备 |
rt_adc_read() | 读取 ADC 设备数据 |
rt_adc_disable() | 关闭 ADC 设备 |
应用程序根据 ADC 设备名称获取设备句柄,进而可以操作 ADC 设备,查找设备函数如下所示:
1rt_device_t rt_device_find(const char* name);
参数 | 描述 |
---|---|
name | ADC 设备名称 |
返回 | —— |
设备句柄 | 查找到对应设备将返回相应的设备句柄 |
RT_NULL | 没有找到设备 |
一般情况下,注册到系统的 ADC 设备名称为 adc0,adc1等,使用示例如下所示:
1#define ADC_DEV_NAME "adc1" /* ADC 设备名称 */
2rt_adc_device_t adc_dev; /* ADC 设备句柄 */
3/* 查找设备 */
4adc_dev = (rt_adc_device_t)rt_device_find(ADC_DEV_NAME);
在读取 ADC 设备数据前需要先使能设备,通过如下函数使能设备:
1rt_err_t rt_adc_enable(rt_adc_device_t dev, rt_uint32_t channel);
参数 | 描述 |
---|---|
dev | ADC 设备句柄 |
channel | ADC 通道 |
返回 | —— |
RT_EOK | 成功 |
-RT_ENOSYS | 失败,设备操作方法为空 |
其他错误码 | 失败 |
使用示例如下所示:
1#define ADC_DEV_NAME "adc1" /* ADC 设备名称 */
2#define ADC_DEV_CHANNEL 5 /* ADC 通道 */
3rt_adc_device_t adc_dev; /* ADC 设备句柄 */
4/* 查找设备 */
5adc_dev = (rt_adc_device_t)rt_device_find(ADC_DEV_NAME);
6/* 使能设备 */
7rt_adc_enable(adc_dev, ADC_DEV_CHANNEL);
读取 ADC 通道采样值可通过如下函数完成:
1rt_uint32_t rt_adc_read(rt_adc_device_t dev, rt_uint32_t channel);
参数 | 描述 |
---|---|
dev | ADC 设备句柄 |
channel | ADC 通道 |
返回 | —— |
读取的数值 |
使用 ADC 采样电压值的使用示例如下所示:
1#define ADC_DEV_NAME "adc1" /* ADC 设备名称 */
2#define ADC_DEV_CHANNEL 5 /* ADC 通道 */
3rt_adc_device_t adc_dev; /* ADC 设备句柄 */
4rt_uint32_t value;
5/* 查找设备 */
6adc_dev = (rt_adc_device_t)rt_device_find(ADC_DEV_NAME);
7/* 使能设备 */
8rt_adc_enable(adc_dev, ADC_DEV_CHANNEL);
9/* 读取采样值 */
10value = rt_adc_read(adc_dev, ADC_DEV_CHANNEL);
11/* 转换为对应电压值,3.3V对应12位最大值4096,数据精度乘以100保留2位小数 */
12vol = value * 330 / 4096;
13rt_kprintf("the voltage is :%d.%02d \n", vol / 100, vol % 100);
实际电压值的计算公式为:采样值 * 最大可转换电压 / (1 << 分辨率位数),上面示例代码乘以 100 将数据放大,最后通过 vol / 100 获得电压的整数位值,通过 vol % 100 获得电压的小数位值。
关闭 ADC 通道可通过如下函数完成:
1rt_err_t rt_adc_disable(rt_adc_device_t dev, rt_uint32_t channel);
参数 | 描述 |
---|---|
dev | ADC 设备句柄 |
channel | ADC 通道 |
返回 | —— |
RT_EOK | 成功 |
-RT_ENOSYS | 失败,设备操作方法为空 |
其他错误码 | 失败 |
使用示例如下所示:
1#define ADC_DEV_NAME "adc1" /* ADC 设备名称 */
2#define ADC_DEV_CHANNEL 5 /* ADC 通道 */
3rt_adc_device_t adc_dev; /* ADC 设备句柄 */
4rt_uint32_t value;
5/* 查找设备 */
6adc_dev = (rt_adc_device_t)rt_device_find(ADC_DEV_NAME);
7/* 使能设备 */
8rt_adc_enable(adc_dev, ADC_DEV_CHANNEL);
9/* 读取采样值 */
10value = rt_adc_read(adc_dev, ADC_DEV_CHANNEL);
11/* 转换为对应电压值,3.3V对应12位最大值4096,数据精度乘以100保留2位小数 */
12vol = value * 330 / 4096;
13rt_kprintf("the voltage is :%d.%02d \n", vol / 100, vol % 100);
14/* 关闭通道 */
15rt_adc_disable(adc_dev, ADC_DEV_CHANNEL);
在使用设备前,需要先查找设备是否存在,可以使用命令 adc probe
后面跟注册的 ADC 设备的名称。如下所示:
1msh >adc probe adc1
2probe adc1 success
使能设备的某个通道可以使用命令 adc enable
后面跟通道号。
1msh >adc enable 5
2adc1 channel 5 enables success
读取 ADC 设备某个通道的数据可以使用命令 adc read
后面跟通道号。
1msh >adc read 5
2adc1 channel 5 read value is 0x00000FFF
3msh >
关闭设备的某个通道可以使用命令 adc disable
后面跟通道号。
1msh >adc disable 5
2adc1 channel 5 disable success
3msh >
ADC 设备的具体使用方式可以参考如下示例代码,示例代码的主要步骤如下:
首先根据 ADC 设备名称 “adc1” 查找设备获取设备句柄。
使能设备后读取 adc1 设备对应的通道 5 的采样值,然后根据分辨率为 12 位,参考电压为 3.3V 计算实际的电压值。
最后关闭 ADC 设备对应通道。
运行结果:打印实际读取到的转换的原始数据和经过计算后的实际电压值。
1/*
2 * 程序清单:ADC 设备使用例程
3 * 例程导出了 adc_sample 命令到控制终端
4 * 命令调用格式:adc_sample
5 * 程序功能:通过 ADC 设备采样电压值并转换为数值。
6 * 示例代码参考电压为3.3V,分辨率为12位。
7*/
8
9#include
10#include
11
12#define ADC_DEV_NAME "adc1" /* ADC 设备名称 */
13#define ADC_DEV_CHANNEL 5 /* ADC 通道 */
14
15static int adc_vol_sample(int argc, char *argv[])
16{
17 rt_adc_device_t adc_dev;
18 rt_uint32_t value, vol;
19 rt_err_t ret = RT_EOK;
20
21 /* 查找设备 */
22 adc_dev = (rt_adc_device_t)rt_device_find(ADC_DEV_NAME);
23 if (adc_dev == RT_NULL)
24 {
25 rt_kprintf("adc sample run failed! can't find %s device!\n", ADC_DEV_NAME);
26 return RT_ERROR;
27 }
28
29 /* 使能设备 */
30 ret = rt_adc_enable(adc_dev, ADC_DEV_CHANNEL);
31
32 /* 读取采样值 */
33 value = rt_adc_read(adc_dev, ADC_DEV_CHANNEL);
34 rt_kprintf("the value is :%d \n", value);
35
36 /* 转换为对应电压值,3.3V对应12位最大值4096,数据精度乘以100保留2位小数 */
37 vol = value * 330 / 4096;
38 rt_kprintf("the voltage is :%d.%02d \n", vol / 100, vol % 100);
39
40 /* 关闭通道 */
41 ret = rt_adc_disable(adc_dev, ADC_DEV_CHANNEL);
42
43 return ret;
44}
45/* 导出到 msh 命令列表中 */
46MSH_CMD_EXPORT(adc_vol_sample, adc voltage convert sample);