51单片机学习笔记——AD转换

一、AD转换器的分类

直接A/D转换器
  • 并行比较型

    优点:转换速度快,内含寄存器,无需附加采样-保持电路。
    缺点:需要很多电压比较器和触发器,高分辨率较难制造。

  • 反馈比较型

    分为计数型和逐次比较型,计数型又称为双积分型。
    其中,计数型且转换速度不高,转换时间长,但价格便宜;逐次比较型使用对分搜索法,因此转换速度要比计数型快很多。(ADC0804和XPT2046都属于逐次比较型)

间接A/D转换器
  • V-T(电压-时间)
  • V-F(电压-频率)

二、A/D转换器主要参数指标

1.分辨率

分辨率为A/D转换器对输入信号的分辨能力,其计算公式如下,其中n为A/D转换器的位数:
分 辨 率 = 1 2 n 分辨率=\frac{1}{2^{n}} =2n1
当A/D转换器支持输入负电压时,第一位代表正负,则分辨率的计算公式为:
分 辨 率 = 1 2 n − 1 分辨率=\frac{1}{2^{n-1}} =2n11
可以求得模拟电压的最小值如下, 满刻度为输入的模拟电压最大值:
变 化 最 小 值 = 满 刻 度 × 分 辨 率 变化最小值=满刻度\times 分辨率 =×

2.转换误差

转换误差表示A/D转换器实际输出的数字量与理论输出量的区别。分为量化误差、偏移误差和满刻度误差。其中偏移误差和满刻度误差合称为非线性误差。

3.转换精度

转换精度为实际模拟量输入与理论模拟输入之差的最大值。对于A/D转换器而言,可以在每个阶梯的水平中点进行测量,它包括了所有误差。

4.转换时间

即完成一次A/D转换所需要的时间(包括稳定时间)。而转换时间的倒数为转换速率,即每秒转换的次数。

三、ADC0804

概况

ADC0804是逐次比较型A/D转换器,共有20个引脚,分辨率为8位,输入电压范围为0-5V,模数转换时间大约100us。价格便宜,应用广泛。

1.引脚详情

51单片机学习笔记——AD转换_第1张图片

引脚 名称 解释
1 C S ‾ \overline{CS} CS 片选信号输入端,当输入低电平,表明A/D被选中
2 R D ‾ \overline{RD} RD 读信号输入端,低电平输出端有效
3 W R ‾ \overline{WR} WR 写信号输入端,低电平启用A/D转换
4 CLK 时钟信号输入端
5 I N T R ‾ \overline{INTR} INTR A/D转换结束信号,低电平表示转换完成
6-7 VIN(+),VIN(-) 两模拟信号输入端,可接收单极性,双极性和差模输入信号
8 AGND 模拟信号地
9 VREF/2 参考电平输入端,决定量化单位
10 DGND 数字信号地
11-18 DB7-DB0 具有三态特性的数字信号输出口
19 CLKR 内部时钟发生器外接电阻端
20 VCC(VREF) 芯片输入电源,为5V
2.时序图
  • 启动时序图
    51单片机学习笔记——AD转换_第2张图片
  • 读取时序图
    51单片机学习笔记——AD转换_第3张图片
3.例程:电位器A/D转换
#include
#include
typedef unsigned int u16;	  
typedef unsigned char u8;

sbit dula = P2^6;		//U1锁存端
sbit wela = P2^7;		//U2锁存端
sbit adwr = P3^6;		//A/D的WR端口 
sbit adrd = P3^7;		//A/D的RD端口

u8 code table[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//显示0~9的值
u8 bai,shi,ge;				//用于显示AD转换后的值


void AD_Init();				//A/D初始化函数
void AD_read();				//A/D读取函数
void delay(u16);			//延时函数
void display(u8,u8,u8);		//数码管显示函数

void main()
{
	AD_Init();
	while(1)
	{	
		AD_read();
	}
}

void AD_Init()				//A/D初始化函数
{
	wela=1;
	P0=0x7f;				//置CS片选为0,启动ADC0804
	wela=0;
}

void AD_read()				//A/D读取函数
{
	u8 i,adval;			//循环变量i,读取变量adval
	adwr=1;					//WR口先为高电平
	_nop_();				//_nop_函数位于intrins.h头文件中,作用是延时一个机器周期的时间
	adwr=0;					//延时一段时间后,WR口置低
	_nop_();				//又延时一段时间后
	adwr=1;					//WR口拉高 ADC0804被启动
	//由于连续读取数据,因此CS片选不必要反复操作
	//由于INTR由硬件控制,因此也不需要操作
	for(i=10;i>0;i--)		//TX-1C实验板AID工作频率较低,所以启动转换要多留点时间用来转换
		display(bai,shi,ge);//把显示部分放这里的原因也是为了延长转换时间
	P1=0xff;				//读取P1口之前先给其写全1
	adrd=1;					//先使RD拉高
	_nop_();				//延时一段时间
	adrd=0;					//RD拉低
	_nop_();				//再延时一段时间
	adval=P1;				//AD数据读取赋给P1口
	adrd=1;					//马上把RD拉高
	bai=adval/100;			//分出百,十和个位
	shi=adval% 100/10;
	ge=adval% 10;
}	

void delay(u16 ms)					//延时函数
{
	u16 i,j;
	for(i=ms;i>0;i--)
	for(j=110;j>0;j--);
}

void display(u8 bai,u8 shi,u8 ge)	//数码管显示函数
{
	/*百位*/
	dula=1;
	P0=table[bai];
	dula=0;
	P0=0xff;
	wela=1;
	P0=0x7e;
	wela=0;
	delay(5);

	/*十位*/
	dula=1;
	P0=table[shi];
	dula=0;
	P0=0xff;
	wela=1;
	P0=0x7d;
	wela=0;
	delay(5);

	/*个位*/
	dula=1;
	P0=table[ge]; 
	dula=0;
	P0=0xff;
	wela=1;
	P0=0x7b;
	wela=0;
	delay(5);
}

总结:代码是在郭天祥书中摘取后加入自己的想法进行的修改,做注释,增加可读性同时使每一步与时序图相对应。但由于博主手头没有相应的硬件,无法测试代码可行性。仅帮助理解ADC0804转换的过程。

四、XPT2046

概况

XPT2046本是电阻触控屏控制器,由于触摸控制器需要测量电压,因此可以作为A/D转换器使用。采用了逐次比较型A/D转换器,共有16个引脚,分辨率为12位,输入电压范围为0-6V。

1.引脚图与控制寄存器
  • 引脚图为QFN-16封装方式

51单片机学习笔记——AD转换_第4张图片

引脚 名称 解释
1 BUSY 忙时信号线,当 C S ‾ \overline{CS} CS为高电平时为高阻状态
2 DIN 串行数据输入端。当 C S ‾ \overline{CS} CS为低电平时,数据在DCLK上升沿锁存进来
3 C S ‾ \overline{CS} CS 片选信号。控制转换时序和使能串行输入输出寄存器,高电平时ADC掉电
4 DCLK 外部时钟信号输入端
5 VCC 电源输入端
6-9 XP,YP,XN,YN 信号输入端
10 GND 接地端
11 VBAT 电池监视输入端
12 AUX ADC辅助输入通道
13 VREF 参考电压输入/输出
14 IOVDD 数字电源输入端
15 P E N I R Q ‾ \overline{PENIRQ} PENIRQ 笔接触中断引脚
16 DOUT 串行数据输出端。数据在DCLK的下降沿移出,当 C S ‾ \overline{CS} CS高电平时为高阻状态
  • 控制寄存器
位序号 D7 D6 D5 D4 D3 D2 D1 D0
位符号 S A2 A1 A0 MODE S E R D F R SER\sqrt{DFR} SERDFR PD1 PD0
位序号 名称 解释
7 S 开始位。S=1表示新的控制字节到来,S=0表示忽略PIN引脚数据
6-4 A2-A0 通道选择位
3 MODE MODE=1为8位转换分辨率,MODE=0为12位转换分辨率
2 S E R D F R SER\sqrt{DFR} SERDFR S E R D F R SER\sqrt{DFR} SERDFR =1为单端输入方式, S E R D F R SER\sqrt{DFR} SERDFR =0为差分输入方式
1-0 PD1-PD0 低功率模式选择位,一般采用低功率模式,赋值00

注:
由于博主使用的是普中单片机开发板,且XPT2046仅作为AD转换器使用,因此仅使用单端模式,控制A0,A1,A2三个位即可,其余位较为固定。

控制位 A2 A1 A0 输入端口 外部设备
0x94/0xB4 0 0/1 1 X+ 电位器
0xD4 1 0 1 Y+ 热敏电阻
0xA4 0 1 0 VBAT 光敏电阻
0xE4 1 1 0 AUX 外部信号
2.时序图

51单片机学习笔记——AD转换_第5张图片

3.例程:电位器A/D转换
#include
#include
typedef unsigned int u16;	  
typedef unsigned char u8;

/*AD转换器的IO口设置*/
sbit DOUT = P3^7;	  //输出
sbit CLK  = P3^6;	  //时钟
sbit DIN  = P3^4;	  //输入
sbit CS   = P3^5;	  //片选
/*数码管的IO口设置*/
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;

u8 time;		//控制显示
u8 disp[4];		//存放数据的数组
u8 code smgduan[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//数码管显示表

void datapros();			//数据处理函数
u16 SPI_Read(void);			//采用SPI协议读取数据
void SPI_Write(u8 dat);		//写入数据
u16 Read_AD_Data(u8 cmd);	//读取AD
void delay(u16);			//延时函数
void DigDisplay();			//数码管显示函数

void main()
{	
	while(1)
	{
		datapros();	 //数据处理函数
		DigDisplay();//数码管显示函数		
	}		
}

void datapros()	//数据处理函数
{
	u16 temp;
	if(time==50)						//每隔一段时间显示一次,时间约为time循环50次
	{
		time=0;
		temp = Read_AD_Data(0x94);		//写入电位器端口,修改参数可以更换模式
	}
	time++;
	disp[0]=smgduan[temp/1000];			//千位
	disp[1]=smgduan[temp%1000/100];		//百位
	disp[2]=smgduan[temp%1000%100/10];	//十位
	disp[3]=smgduan[temp%1000%100%10];	//个位	
}

void SPI_Write(u8 dat)	//使用SPI写入数据
{
	u8 i;
	CLK = 0;				//时钟信号拉低
	for(i=0; i<8; i++)
	{
		DIN = dat >> 7;  	//放置最高位,DIN为控制寄存器
		dat <<= 1;			//每次写入移位
		CLK = 0;			//时钟信号上升沿放置数据
		CLK = 1;
	}
}

u16 SPI_Read(void)	//使用SPI读出数据
{
	u8 i;
	u16	dat=0;
	CLK = 0;				//时钟信号拉低
	for(i=0; i<12; i++)		//接收12位数据
	{
		dat <<= 1;			//每次写入移位
		CLK = 1;
		CLK = 0;			//时钟信号下降沿读取数据
		dat |= DOUT;		//由DOUT接口写入数据
	}
	return dat;	
}

u16 Read_AD_Data(u8 cmd)	//读AD数据
{
	u8 i;					//循环变量
	u16 AD_Value;			//存放读出的AD数据
	CLK = 0;				//时钟信号拉低
	CS  = 0;				//片选电位拉低
	SPI_Write(cmd);			//写数据
	for(i=6; i>0; i--); 	//延时等待转换结果
	CLK = 1;	 			//发送一个时钟周期,清除BUSY
	_nop_();				//延时一个时钟周期
	_nop_();				//延时一个时钟周期
	CLK = 0;				//时钟信号拉低
	_nop_();				//延时一个时钟周期
	_nop_();				//延时一个时钟周期
	AD_Value=SPI_Read();	//读出模拟值
	CS = 1;					//片选电位拉高
	return AD_Value;		//返回读出的值
}

void delay(u16 i)	//延时函数 i=1延时10us
{
	while(i--);	
}

void DigDisplay()	//数码管显示函数
{
	u8 i,j;
	for(i=0;i<4;i++)
	{
		switch(i)	 			//位选,选择点亮的数码管
		{
			case(0):
				LSA=0;LSB=0;LSC=0; break;//显示第0位
			case(1):
				LSA=1;LSB=0;LSC=0; break;//显示第1位
			case(2):
				LSA=0;LSB=1;LSC=0; break;//显示第2位
			case(3):
				LSA=1;LSB=1;LSC=0; break;//显示第3位	
		}
		P0=disp[3-i];			//发送数据
		delay(100); 			//间隔一段时间扫描	
		P0=0x00;				//消隐
	}		
}

总结:代码是在普中科技A/D转换例程改写的。与ADC0804不同的是,由于XPT2046功能较多,使用了控制寄存器,且对比前面的郭天祥的板子,普中的板子没有使用锁存器,所以数据要一位一位的写入/读取。

你可能感兴趣的:(单片机)