天天看点

S5PV210系列 (裸机十七) 之 ADC

ADC的引入

什么是ADC

(1) ADC : analog digital converter, AD 转换,模数转换(也就是模拟转数字)

(2) CPU 本身是数字的,而外部世界变量(如电压、温度、高度、压力···)都是模拟的,所以需要用 CPU 来处理这些外部的模拟变量的时候就需要做 AD 转换。

为什么需要 ADC

(1)为了用数字技术来处理外部的模拟物理量。

关于模拟量和数字量

(1)模拟的就是连续的,现实生活当中的时间、电压、高度等都是模拟的(连续分布的,划分的话可以无限的更小划分)。模拟量反映在数学里面就是无限小数位(从 0 到 1 之间有无数个数)

(2)数字的就是离散的,离线的就是不连续的。这种离散处理实际上是从数学上对现实中的模拟量的一种有限精度的描述。数字化就是 离散化,就是把连续分布的模拟量按照一定精度进行取点(采样)变成有限多个不连续分布的数字值,就叫数字量。

(3)数字化的意义就在于可以用(离散)数学来简化描述模拟量,这东西是计算机技术的基础。

(4)计算机处理参量的时候都是数字化的,计算机需要数字化的值来参与运算。如果系统输入参数中有模拟量,就需要外加 AD 转换器将模拟量转成数字量再给计算机。

有 AD 自然就有 DA

(1) AD 是 analog to digital,DA 自然就是 digital to analog,数字转模拟。

(2)纯粹用 cpu 是不可能实现数字转模拟,因为 cpu 本身就是数字的。使用一些(具有一些积分或微分效果的)物理器件就可实现数字转模拟。

(3)数字转模拟的作用。譬如可以用来做波形发生器。

ADC的主要相关概念

量程(模拟量输入范围)

(1) AD 转换器是一个电子器件,所以他只能输入电压信号。其他种类的模拟信号要先经过传感器(Sensor)的转换变成模拟的电压信号然后才能给 AD。

(2) AD 输入端的模拟电压要求有一个范围,一般是 0〜3.3V 或 0〜5V 或者是 0〜12V 等等。模拟电压的范围是 AD 芯片本身的一个参数。实际工作时给 AD 的电压信号不能超过这个电压范围。

精度(分辨率 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)

转换速率( 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

通道数

(1) AD 芯片有多少路 analog input 通道,代表了将来可以同时进行多少路模拟信号的输入。

S5PV210 的 ADC 控制器

ADC 和(电阻式)触摸屏的关系

(1) ADC 在 210 的数据手册的 Section10.7

(2)电阻式触摸屏本身工作时依赖于 AD 转换,所以在 210 的 SoC 中电阻触摸屏接口本身和 ADC 接口是合二为一的。或者说电阻触摸屏接口使用了(复用了) ADC 的接口。

ADC的工作时钟框图

(1) ADCCLK 是 ADC 控制器工作的时钟,也就是1.13.2.3节中讲到的 conventor clock。从时钟框图可以看出,它是 PCLK(当然是 PCLK_PSYS )经过了一次分频后得到的。所以将来初始化 ADC 控制器时一定有一个步骤是初始化这里的分频器。

210 的 10 个 ADC 通道(注意 ADC 引脚和 GPIO 的区别)

(1)210 一共支持 10 个 ADC 通道,分别叫 AIN[0] ~ AIN[9]。理论上可以同时做 10 路 AD 转换。

(2) SoC 的引脚至少分 2 种:digit 数字引脚和 analog 模拟引脚。我们以前接触的GPIO 都属于数字引脚,ADC channel 通道引脚属于模拟引脚。数字引脚和模拟引脚一般是不能混用的。

ADC控制器的主要寄存器

TSADCCON0

TSDATX0 TSDATY0 转出来的AD值存在这里,我们读也是读这里

CLRINTADC0 清中断

ADCMUX 选择当前正在操作的AD通道

(1)等待触摸屏转换完毕的方法有2种:一种是检查标志位,第二种是中断。第一种方式下我们先开启一次转换然后循环不停检查标志位直到标志位为1表明已经转换完可以去读了;第二种方式下就是设置好中断,写好中断isr来读取AD转换数据。然后开启中断后CPU就不用管了,等AD转换完成后会生成一个中断信号给CPU,就会进入中断处理流程。第一种方法是同步的,第二种方式是异步的。

(2)AD转换都是需要反复进行的,那么转完一次一般要立即开启下一次转换,所以需要有一种机制能够在一次转完时自动开启下一次。这个机制就叫start by read,这个机制的工作方法是:当我们读取本次AD转换的AD值后,硬件自动开启下一次AD转换。

AD 转换的编程实践

AD 控制器初始化

循环进行 AD 采样

start by read 模式介绍

(1)应用方法:开启start by read模式,第一次先读一次丢掉,这次读就能开启下一次 AD 转换,然后以后就可以不停的读取 AD 值了。

#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  |= (<<);     // resolution set to 12bit
    rTSADCCON0  |= (<<);     // enable clock prescaler
    rTSADCCON0  &= ~(<<);
    rTSADCCON0  |= (<<);     // convertor clock = 66/66M=1MHz, MSPS=200KHz
    rTSADCCON0  &= ~(<<);        // normal operation mode
    rTSADCCON0  &= ~(<<);        // disable start by read mode

    rADCMUX     &= ~(<<); // MUX选择ADCIN0
}

// 注意:第一,延时要确实能延时;第二,延时时间必须合适。
static void delay(void)
{
    volatile unsigned int i, j;

    for (i=; i<; i++)
        for (j=; j<; j++);
}


// 测试ADC,完成的功能就是循环检测ADC并得到ADC转换数字值打印出来
void adc_test(void)
{
    unsigned int val = ;

    adc_init();

    while ()
    {
        // 第一步:手工开启ADC转换
        rTSADCCON0  |= (<<);
        // 第二步:等待ADC转换完毕
        while (!(rTSADCCON0 & (<<)));

        // 第三步:读取ADC的数字值
        // 第四步:处理/显示数字值
        val = rTSDATX0;
        printf("x: bit14 = %d.\n", (val & (<<)));
        printf("x: adc value = %d.\n", (val & (<<)));

        val = rTSDATY0;
        printf("y: bit14 = %d.\n", (val & (<<)));
        printf("y: adc value = %d.\n", (val & (<<)));

        // 第五步:延时一段
        delay();
    }
           

继续阅读