1.ADC的引入
1.1、什么是ADC
(1)ADC:analog digital converter,AD转换,模数转换(也就是模拟转数字)
(2)CPU本身是数字的,而外部世界变量(如电压、温度、高度、压力···)都是模拟的,所以需要用CPU来处理这些外部的模拟变量的时候就需要做AD转换。
1.2、为什么需要ADC
(1)为了用数字技术来处理外部的模拟物理量。
1.3、关于模拟量和数字量
(1)模拟的就是连续的,现实生活当中的时间、电压、高度等都是模拟的(连续分布的,划分的话可以无限的更小划分)。模拟量反映在数学里面就是无限小数位(从0到1之间有无数个数)
(2)数字的就是离散的,离线的就是不连续的。这种离散处理实际上是从数学上对现实中的模拟量的一种有限精度的描述。数字化就是离散化,就是把连续分布的模拟量按照一定精度进行取点(采样)变成有限多个不连续分布的数字值,就叫数字量。
(3)数字化的意义就在于可以用(离散)数学来简化描述模拟量,这东西是计算机技术的基础。
(4)计算机处理参量的时候都是数字化的,计算机需要数字化的值来参与运算。如果系统输入参数中有模拟量,就需要外加AD转换器将模拟量转成数字量再给计算机。
1.4、有AD自然就有DA
(1)AD是analog to digital,DA自然就是digital to analog,数字转模拟。
(2)纯粹用cpu是不可能实现数字转模拟,因为cpu本身就是数字的。使用一些(具有一些积分或微分效果的)物理器件就可实现数字转模拟。
(3)数字转模拟的作用。譬如可以用来做波形发生器。
2.ADC的主要相关概念
2.1、量程(模拟量输入范围)
(1)AD转换器是一个电子器件,所以他只能输入电压信号。其他种类的模拟信号要先经过传感器(Sensor)的转换变成模拟的电压信号然后才能给AD。
(2)AD输入端的模拟电压要求有一个范围,一般是0~3.3V或0~5V或者是0~12V等等。模拟电压的范围是AD芯片本身的一个参数。实际工作时给AD的电压信号不能超过这个电压范围。
2.2、精度(分辨率resolution)
(1)AD转换输出的数字值是有一定的位数的(譬如说10位,意思就是输出的数字值是用10个二进制位来表示的,这种就叫10位AD)。这个位数就表示了转换精度。
(2)10位AD就相当于把整个范围分成了1024个格子,每个格子之间的间隔就是电压的表示精度。加入AD芯片的量程是0~3.3V,则每个格子代表的电压值是3.3V/1024=0.0032265V。如果此时AD转换后得到的数字量是447,则这个数字量代表的模拟值是:447×0.0032265V=1.44V。
(3)AD的位数越多,则每个格子表示的电压值越小,将来算出来的模拟电压值就越精确。
(4)AD的模拟量程一样的情况下,AD精度位数越多精度越高,测出来的值越准。但是如果AD的量程不一样。譬如2个AD,A的量程是0~50V,B的量程是0~0.5V,A是12位的,B是10位的,可能B的精度比A的还要高。(A的精度:50/1024=0.04883,B的精度:0.5/4096=0.000122)
2.3、转换速率(MSPS与conventor clock的不同)
(1)首先要明白:AD芯片进行AD转换是要耗费时间的。这个时间需要多久,不同的芯片是不一样的,同一颗芯片在配置不一样(譬如说精度配置为10位时时间比精度配置为12位时要小,譬如说有些AD可以配转换时钟,时钟频率高则转换时间短)时转换时间也不一样。
(2)详细的需要时间可以参考数据手册。一般数据手册中描述转换速率用的单位是MSPS(第一个M是兆,S是sample,就是采样;PS就是per second,总的意思就是兆样本每秒,每秒种转出来多少M个数字值)
(3)AD工作都需要一个时钟,这个时钟有一个范围,我们实际给他配置时不要超出这个范围就可以了。AD转换是在这个时钟下进行的,时钟的频率控制着AD转换的速率。注意:时钟频率和MSPS不是一回事,只是成正比不是完全相等。譬如S5PV210中的AD转换器,MSPS = 时钟频率/5
2.4、通道数
(1)AD芯片有多少路analog input通道,代表了将来可以同时进行多少路模拟信号的输入。
3.S5PV210的ADC控制器
3.1、ADC和(电阻式)触摸屏的关系
(1)ADC在210的数据手册的Section10.7
(2)电阻式触摸屏本身工作时依赖于AD转换,所以在210的SoC中电阻触摸屏接口本身和ADC接口是合二为一的。或者说电阻触摸屏接口使用了(复用了)ADC的接口。
3.2、ADC的工作时钟框图
(1)ADCCLK是ADC控制器工作的时钟,也就是1.13.2.3节中讲到的conventor clock。从时钟框图可以看出,它是PCLK(当然是PCLK_PSYS)经过了一次分频后得到的。所以将来初始化ADC控制器时一定有一个步骤是初始化这里的分频器。
![](https://i-blog.csdnimg.cn/blog_migrate/14c31847a1d243b1dcc54b2c8b24ef5d.png)
3.3、210的10个ADC通道(注意ADC引脚和GPIO的区别)
(1)210一共支持10个ADC通道,分别叫AIN[0]~AIN[9]。理论上可以同时做10路AD转换。
(2)SoC的引脚至少分2种:digit数字引脚和analog模拟引脚。我们以前接触的GPIO都属于数字引脚,ADC channel通道引脚属于模拟引脚。数字引脚和模拟引脚一般是不能混用的。
3.4、ADC控制器的主要寄存器
TSADCCON0
TSDATX0 TSDATY0 转出来的AD值存在这里,我们读也是读这里
CLRINTADC0 清中断
ADCMUX 选择当前正在操作的AD通道
(1)等待触摸屏转换完毕的方法有2种:一种是检查标志位,第二种是中断。第一种方式下我们先开启一次转换然后循环不停检查标志位直到标志位为1表明已经转换完可以去读了;第二种方式下就是设置好中断,写好中断isr来读取AD转换数据。然后开启中断后CPU就不用管了,等AD转换完成后会生成一个中断信号给CPU,就会进入中断处理流程。第一种方法是同步的,第二种方式是异步的。
(2)AD转换都是需要反复进行的,那么转完一次一般要立即开启下一次转换,所以需要有一种机制能够在一次转完时自动开启下一次。这个机制就叫start by read,这个机制的工作方法是:当我们读取本次AD转换的AD值后,硬件自动开启下一次AD转换。
4.AD转换的编程实践1
4.1、AD控制器初始化
4.2、循环进行AD采样
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
#include "main.h"
#define TSADCCON0 0xE1700000
#define TSDATX0 0xE170000C
#define TSDATY0 0xE1700010
//#define CLRINTADC0 0xE1700000
#define ADCMUX 0xE170001C
#define rTSADCCON0 (*(volatile unsigned int *)TSADCCON0)
#define rTSDATX0 (*(volatile unsigned int *)TSDATX0)
#define rTSDATY0 (*(volatile unsigned int *)TSDATY0)
//#define rCLRINTADC0 (*(volatile unsigned int *)CLRINTADC0)
#define rADCMUX (*(volatile unsigned int *)ADCMUX)
// 初始化ADC控制器的函数
static
void
adc_init(
void
)
{
rTSADCCON0 |= (1<<16);
// resolution set to 12bit
rTSADCCON0 |= (1<<14);
// enable clock prescaler
rTSADCCON0 &= ~(0xFF<<6);
rTSADCCON0 |= (65<<6);
// convertor clock = 66/66M=1MHz, MSPS=200KHz
rTSADCCON0 &= ~(1<<2);
// normal operation mode
rTSADCCON0 &= ~(1<<1);
// disable start by read mode
rADCMUX &= ~(0x0F<<0);
// MUX选择ADCIN0
}
// 注意:第一,延时要确实能延时;第二,延时时间必须合适。
static
void
delay(
void
)
{
volatile
unsigned
int
i, j;
for
(i=0; i<4000; i++)
for
(j=0; j<1000; j++);
}
// 测试ADC,完成的功能就是循环检测ADC并得到ADC转换数字值打印出来
void
adc_test(
void
)
{
unsigned
int
val = 0;
adc_init();
while
(1)
{
// 第一步:手工开启ADC转换
rTSADCCON0 |= (1<<0);
// 第二步:等待ADC转换完毕
while
(!(rTSADCCON0 & (1<<15)));
// 第三步:读取ADC的数字值
// 第四步:处理/显示数字值
val = rTSDATX0;
printf
(
"x: bit14 = %d.\n"
, (val & (1<<14)));
printf
(
"x: adc value = %d.\n"
, (val & (0xFFF<<0)));
val = rTSDATY0;
printf
(
"y: bit14 = %d.\n"
, (val & (1<<14)));
printf
(
"y: adc value = %d.\n"
, (val & (0xFFF<<0)));
// 第五步:延时一段
delay();
}
}
|