普中51开发板,用XPT2046芯片实现AD数模转换。protues仿真用ADC0808实现AD数模转化

普中51开发板,用XPT2046芯片实现AD数模转换。protues仿真用ADC0808实现AD数模转化

实验做完了,总结一下,这些都是做实验的时候自己收集整理总结的资料,下面分享一下

XPT2046芯片:
XPT2046的功能很多,这里只介绍怎么用该芯片来完成AD数模转换的实验。
XPT2046 是一种典型的逐次逼近型模数转换器(SAR ADC),包含了采样/保持、模数转换、串口数据输出等功能,因此我们可以用这个芯片来完成本次实验AD转换的内容。
本次实验使用的是XPT芯片的电压模式,首先看下面这个图,了解芯片的引脚和功能,我们要操作的引脚有DCLK 、CS非、DIN 、DOUT:
普中51开发板,用XPT2046芯片实现AD数模转换。protues仿真用ADC0808实现AD数模转化_第1张图片附上开发板ADC模块的原理图:
普中51开发板,用XPT2046芯片实现AD数模转换。protues仿真用ADC0808实现AD数模转化_第2张图片
我们主要了解和使用红色圈圈的几个引脚:
普中51开发板,用XPT2046芯片实现AD数模转换。protues仿真用ADC0808实现AD数模转化_第3张图片
了解完引脚之后,就要看怎么去使用和控制这些引脚来达成目标,
所以接下来要看的就是时序工作图,要了解芯片是如何工作,如何完成采样 保持 量化 编码这几个步骤的.。
一次完整的转换需要 24 个串行同步时钟(DCLK)来完成。(看DCLK时序那,一共出现了3次8, 3*8=24)
普中51开发板,用XPT2046芯片实现AD数模转换。protues仿真用ADC0808实现AD数模转化_第4张图片
要想启动选中该芯片,首先得给CS和CLK置0 (因为单片机默认引脚输出1) ,然后开始写入数据

处理器和转换器之间的的通信需要 8 个时钟周期,可采用 SPI、SSI 和Microwire 等同步串行接口。前面8个时钟就在进行通信。

前8个时钟就是用来通过DIN引脚输入控制字节。

先看DIN的时序(图中有几个英文单词,Idle的意思是闲置的意思,aquire是获取的意思,conversion是转换的意思,个人理解是图中把DIN在24个时钟周期内的变化,分成了几个段,闲置段,获取段,转换段)DIN的控制位有8位,下面开始从最高位开始介绍:

控制字的首位必须是 1,即 S=1。在 XPT2046 的 DIN 引脚检测到起始位前,所有的输入将被忽略。

A2-A0的选择,由于我选择的是工作在单端模式,则要选中XP输入(至于为什么是XP输入下面解释),所以A2-A0是选择001或者011都可以(二者都能选中XP输入)。如下图:
普中51开发板,用XPT2046芯片实现AD数模转换。protues仿真用ADC0808实现AD数模转化_第5张图片
我们可以看一下在单端模式下的原理图:(XP是接IN+输入的,所以我们要选中XP输入工作)
普中51开发板,用XPT2046芯片实现AD数模转换。protues仿真用ADC0808实现AD数模转化_第6张图片
MODE:模式选择位,用于设置 ADC 的分辨率。MODE=0,下一次的转换将是 12 位模式;MODE=1,下一次的转换将是 8 位模式。我选择的是8位

SER/ DFR非 :控制参考源模式,选择单端模式(SER/ DFR非 =1),或者差分模式。在单端模式下,转换器的参考电压固定为VREF相对于GND引脚的电压

PD0和PD1:控制掉电和内部参考电压配置的关系。我选择PD1和PD0都为0(为低功率模式)如下图:
普中51开发板,用XPT2046芯片实现AD数模转换。protues仿真用ADC0808实现AD数模转化_第7张图片
当DIN的控制字节处理完成之后,转换器进入转换状态,输入采样-保持器进入保持状态,触摸面板驱动器停止工作(单端工作模式)接着的 12 个时钟周期将完成真正的模数转换。

这个芯片的AD是逐次逼近式AD,逐次逼近式AD转换器中有一个逐次逼近寄存器SAR,其数字量是由它产生的。
附上图片:
普中51开发板,用XPT2046芯片实现AD数模转换。protues仿真用ADC0808实现AD数模转化_第8张图片SAR使用对分搜索法产生数字量,以8位数字量为例,SAR首先产生8位数字量的一半,即b=1000000,试探模拟量Vi的大小。若Vo>Vi,清楚最高度位;反之,则保留最高位。在最高位确认后,SAR又以对分搜索法确定次高位,即以7位数字量的一半1000000(y由前面的过程已确回认)试探模拟量Vi的大小。依此类推,直到确定了bit0为止,转换结束。
普中51开发板,用XPT2046芯片实现AD数模转换。protues仿真用ADC0808实现AD数模转化_第9张图片
上面的解释可能不是很形象,那就举个具体的例子:模拟量经过内部的DA转换得到一个数字量108 二进制转换就是01101100(暂时称为A),首先先用10000000与A相比,A小于10000000,则第一位为0,保留,开始比较次高位,A大于01000000,则次高位保留1;下一位继续比较,A大于01100000,次次高位保留1,继续比较下一位,A小于01110000,则第4位(从左往右数)保留为0,继续比较,以此类推,一直比较到最后一位。

下面介绍一下ADC0808/0809

ADC0808芯片介绍:
内部结构和外部引脚:
ADC0808/0809的内部结构和外部引脚分别如图11.19和图11.20所示。内部各部分的作用和工作原理在内部结构图中已一目了然,在此就不再赘述,下面仅对各引脚定义分述如下:
普中51开发板,用XPT2046芯片实现AD数模转换。protues仿真用ADC0808实现AD数模转化_第10张图片
图11.19 ADC0808/0809内部结构框图
普中51开发板,用XPT2046芯片实现AD数模转换。protues仿真用ADC0808实现AD数模转化_第11张图片
图11.20 ADC0808/0809外部引脚图
(1) IN0~IN7——8路模拟输入,通过3根地址译码线ADDA、ADDB、ADDC来选通一路。
(2)D7~D0——A/D转换后的数据输出端,为三态可控输出,故可直接和微处理器数据线连接。8位排列顺序是D7为最高位,D0为最低位。
(3)ADDA、ADDB、ADDC——模拟通道选择地址信号,ADDA为低位,ADDC为高位。地址信号与选中通道对应关系如表11.3所示。
(4)VR(+)、VR(-)——正、负参考电压输入端,用于提供片内DAC电阻网络的基准电压。在单极性输入时,VR(+)=5V,VR(-)=0V;双极性输入时,VR(+)、VR(-)分别接正、负极性的参考电压。
(5)ALE——地址锁存允许信号,高电平有效。当此信号有效时,A、B、C三位地址信号被锁存,译码选通对应模拟通道。在使用时,该信号常和START信号连在一起,以便同时锁存通道地址和启动A/D转换。
(6)START——A/D转换启动信号,正脉冲有效。加于该端的脉冲的上升沿使逐次逼近寄存器清零,下降沿开始A/D转换。如正在进行转换时又接到新的启动脉冲,则原来的转换进程被中止,重新从头开始转换。
(7)EOC——转换结束信号,高电平有效。该信号在A/D转换过程中为低电平,其余时间为高电平。该信号可作为被CPU查询的状态信号,也可作为对CPU的中断请求信号。在需要对某个模拟量不断采样、转换的情况下,EOC也可作为启动信号反馈接到START端,但在刚加电时需由外电路第一次启动。
(8)OE——输出允许信号,高电平有效。当微处理器送出该信号时,ADC0808/0809的输出三态门被打开,使转换结果通过数据总线被读走。在中断工作方式下,该信号往往是CPU发出的中断请求响应信号。

ADC 0808/0809工作时序:
普中51开发板,用XPT2046芯片实现AD数模转换。protues仿真用ADC0808实现AD数模转化_第12张图片
ADC 0808/0809的工作时序如图11.21所示。
当通道选择地址有效时,ALE信号一出现,地址便马上被锁存,这时转换启动信号紧随ALE之后(或与ALE同时)出现。START的上升沿将逐次逼近寄存器SAR复位,在该上升沿之后的2μs加8个时钟周期内(不定),EOC信号将变低电平,以指示转换操作正在进行中,直到转换完成后EOC再变高电平。微处理器收到变为高电平的EOC信号后,便立即送出OE信号,打开三态门,读取转换结果。

END

有什么地方不对的地方,欢迎指出。

开发板实验代码:

/******************************************************************
功能:
数码管前2位显示AD字符,后三位电位器的数字量,最后三位显示对应电压值

实体机接线:
1,单片机-->AD/DAC模块
		   		P34-->DI
				P35-->CS
				P36-->CL
				P37-->DO
2,单片机-->动态数码管模块
		(P0端口)J22-->J6(动态数码管段选)
				P20-->J9(A)
				P21-->J9(B)
				P22-->J9(C)												  
******************************************************************/
#include "reg52.h"			 //单片机头文件
#include			 //含_nop_()函数
#define uchar unsigned char
#define uint unsigned int

sbit LSA=P2^0;
sbit LSB=P2^1;
sbit LSC=P2^2;

sbit DIN=P3^4;	  //串口输入
sbit CS=P3^5;	  //片选
sbit CLK=P3^6;	  //时钟脉冲
sbit DOUT=P3^7;	  //串口输出

uchar disp[8];	  //储存读取的数据的每个位数,由数码管输出
uchar code smgduan[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};

void delay(uint i)//延时子程序,因为本程序的延时不需要到ms级别,所以没有用之前的用法
{
	while(i--);	
}

void SPI_Write(uchar dat)	//dat传输的是9C这个控制指令
{
	uchar i;
	CLK = 0;
	for(i=0;i<8;i++)		//DIN是串行数据输入口,需要一位位读取数据
	{
		DIN = dat >> 7;  	//这里DIN取dat的最高位
		dat <<= 1;			//次高位左移一位变为最高位,方便下一次DIN读取数据
		CLK = 0;			//软件给予一个上升沿时序,用来放置数据
		_nop_();
		CLK = 1;
	}
}
uint SPI_Read()
{
	uint i, dat=0;			 //dat用来存放读取的数据
	CLK = 0;
	for(i=0; i<8; i++)		//接收8位数据,DOUT是串行数据输出,也是需要一个个读取
	{
		dat <<= 1;			//左移一位
		CLK = 1;			//软件给予一个下降沿时序,因为数据是在CLK为下降沿的时候移出
		_nop_();
		CLK = 0;
		dat |= DOUT;	 	//与DOUT相或,读取数据
	}
	return dat;				//返回数据
}
uint Read_AD_Data(uchar cmd)
{
	uchar i;
	uint AD_Value;
	CLK = 0; //默认引脚输出1,这里要先软件置0	 
	CS  = 0; //置0选中,启动AD
	SPI_Write(cmd);//写入数据
	for(i=6;i>0;i--);	//延时等待转换结果
	CLK=0;
	_nop_();
	CLK = 1; //发送一个正脉冲,清除BUSY ,表示可以开始转换了
	_nop_(); 
	CLK = 0;
	_nop_();
	_nop_();
	AD_Value=SPI_Read();   //AD_Value存放数据
	CS = 1;	//CS拉高,读取完毕
	return AD_Value;	
}

void datapros()
{
	uint temp,val;
	uchar i;
	if(i==50)
	{
		temp = Read_AD_Data(0x9c);
		/*
		0x9c是给DIN输入控制字节,9c=10011100,
		具体的每一位是什么作用可以看芯片手册
		*/
		val=temp*100/51;//原来式子是(((temp*5*100)/255)),把temp先扩大100倍然后乘以5除以255得到电压值;
	}
	i++;
	disp[0]=0x77;//显示A
	disp[1]=0x5e;//显示D
	disp[2]=smgduan[temp/100];//百位
	disp[3]=smgduan[temp/10%10];//十位	
	disp[4]=smgduan[temp%10];//个位	
	disp[5]=smgduan[val/100] |0x80;	//与0x80相或来得到小数点
	disp[6]=smgduan[val/10%10];
	disp[7]=smgduan[val%10];
}
void DigDisplay()
{
	uchar i;
	for(i=0;i<8;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位
			case(4):
				LSA=0;LSB=0;LSC=1; break;//显示第4位
			case(5):
				LSA=1;LSB=0;LSC=1; break;//显示第5位
			case(6):
				LSA=0;LSB=1;LSC=1; break;//显示第6位
			case(7):
				LSA=1;LSB=1;LSC=1; break;//显示第7位
		}
		P0=disp[i];//发送数据
		delay(100); //间隔一段时间扫描	
		P0=0x00;//消隐
	}		
}
void main()
{	
	while(1)
	{
		datapros();	 //数据处理函数
		DigDisplay();//数码管显示函数		
	}		
}

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