一、AD转换中的一些概念
- 位数,AD转换后转出来的二进制由几位二进制数来表示。位数越多,越细腻。
- 量程:AD转换器可以接受的模拟量的范围
- 精度:简单理解就是转出来到底有多准
- 分辨力:AD转换器转出来的二进制数,每一格表示多少
- 转换速率:转换时间,精度越高,转换速率越慢
二、如何实现AD转换
由于51单片机内部并没有AD转换的相关模块,因此使用外接外部芯片的方式,来进行AD转换的操作,我们使用的是XPT2046这个芯片来做的,这个芯片使用的是SPI的接口,主要有4根线来进行通讯:DCLK:外部时钟信号输入 CS:片选信号,低电平时芯片使能。DIN:串行数据输入端,当CS为低电平时,数据在DCLK的上升沿锁存。DOUT:串行数据输出端,数据在DCLK的下降沿移出,当CS为高电平时为高阻态。
ET2046的控制字:bit7:始终为1, bit6-4:决定采用的是那一路(AIN0, AIN1, AIN2, AIN3)
|------|------|---------|
| AIN0 | X+ | 011/001 |
| AIN1 | Y+ | 101 |
| AIN2 | VBAT | 010 |
| AIN3 | AUX | 110 |
[bit6-4]
bit3:设置采样位数,0表示12bit, 1表示8bit
bit2:1表示用的单端模式,0表示用差分模式
bit1-0:power down模式使能,00表示使能,也就是在转换期间处于低功耗模式
三、AD转换时序分析及程序实现
有了时序图我们只需要按照时序图进行编程就行,需要注意的是这个通信无论是发送还是接收都是高位在前,低位在后。在发送数据的时候,一定要将数据放好,然后在产生上升沿,这样就可以了。在接收数据的时候,先产生下降沿然后再去读取数据,这样就好了。你可以将整个时序写成一个函数,也可以将这个时序拆分成几个不同的函数来实现。这两种方法在本质上没有区别,在这里我演示后面一种方法。需要注意的是,我这里没有去检测BUSY线的状态,而是给他足够的一段延时,保证他一定可以完成AD转换。下面就是具体的函数实现
cpp
void delay15us(void) //误差 0us
{
unsigned char a;
for(a=6;a>0;a--);
}
void spi_write(uchar cmd)
{
uchar i = 0;
for (i=0; i<8; i++)
{
DIN = (cmd >> 7);
_nop_();
cmd <<= 1;
DCLK = 1;
_nop_();
DCLK = 0;
_nop_();
}
}
uint spi_read(void)
{
uint date = 0;
uchar i = 0;
for (i=0; i<12; i++)
{
DCLK = 1;
_nop_();
DCLK = 0;
_nop_();
date <<= 1;
date |= DOUT;
_nop_();
}
return date;
}
//0-3分别是AIN0-AIN3,分表表示电位器,热敏电阻,光敏电阻,外部输入
//我这里都采用的是12位的AD转换
uint ad_convert(uchar cmd)
{
uchar i = 0, addr[4] = {0x94, 0xd4, 0xa4, 0xe4};
uint date = 0;
DCLK = 0;
_nop_();
CS = 0;
_nop_();
spi_write(addr[cmd]);
delay15us();
date = spi_read();
CS = 1;
return date;
}
针对上面的函数,其实你只需要使用最后一个就可以了,前面的函数都会在这个函数里面调用,需要注意的是,最后这个函数的输出量是采集到的12位的AD输出,还没有进行电压值的转换。如果需要电压值,需要进一步进行计算。下面来写一个函数,进行计算,并在串口打印出来,我这里的串口打印直接打印的是字符,而不是HEX编码。对于程序里面的一些端口的定义,宏定义,函数声明等我就没有写在里面,自己补充就可以了。
cpp
//在AD转换中通过串口以字符形式发送转换到的电压值
//temp是12位转换到的AD值
//这里我只保留了小数点后3位
void uart_send_ad(uint temp)
{
float date = 0;
uchar i = 0, dat[4] = 0;
date = ((temp + 0.0) / 4096) * 5;
temp = date * 1000;
for (i=0; i<4; i++)
{
dat[i] = (temp % 10) + '0';
temp /= 10;
}
for (i=0; i<4; i++)
{
uart_send_byte(dat[3-i]);
if (i == 0)
{
uart_send_byte('.');
}
}
}