51单片重要外设系列-AD/DA转换

AD/DA转换打开了计算机与模拟信号的大门,也就是计算机与外部真实世界交换信息的桥梁,为实现计算机控制外部环境打下了坚实基础51单片重要外设系列-AD/DA转换_第1张图片

 如上图所示,那个变化的阻值会引起上面电阻电压的变化,通过电压信号的变化,单片机读取到数值,这也就是AD转换的原理,模拟量和数字量成正比关系,读取到数字量换算成模拟量即可,输出就是反过来,他说的多个通道就是复用多个硬件电路,稍微好一点的芯片会把ADDA集成在内部芯片中,那样能节约IO口,不占那么多线路,DA用的少,它可以用PWM实现。

 51单片重要外设系列-AD/DA转换_第2张图片

以上是ADC芯片,CS片选,DCLK时钟信号,用的SPI串口通信,至于什么是SPI,I2C,这些通信协议在其他的方面会提到,DIN数据输入,DOUT数据输出,下面来看DA。 

51单片重要外设系列-AD/DA转换_第3张图片

他是在P21上面输出一个PWM波形然后驱动DA1这个灯亮灭,结合之前的PWM的原理即可。 

51单片重要外设系列-AD/DA转换_第4张图片

ADDA,B,C左下角三路来译码决定上面IN0到IN7是哪一路可以输出到AD转换中去,上面的START是开始信号,EOC是结束信号,CLOCK是时钟信号,OE是使能,最下面的是参考电压。

我们要分析的重点就是A\D转换如何把一个电压信号转化为八位的DB0到DB7数字信号的输出,这个是AD转换的核心也就是看所谓的时序图。 

DA转换器如下:D0到D7输入,经过两个缓存器到右边输出电压。那个8位D/A转换器,在下面会提到T型网络

51单片重要外设系列-AD/DA转换_第5张图片

下面介绍运算放大器:

51单片重要外设系列-AD/DA转换_第6张图片

为什么需要功率放大,因为输出的信号驱动能力很弱,所以需要一个功率放大器,

51单片重要外设系列-AD/DA转换_第7张图片

第二个图用虚短和虚断可以推出那个公式,通过电阻的调整可以调整那个放大倍数。

下面解释一下虚短的原理,VIN输出0.1V,大于+,通过前面的比较器可以得知Vout输出一个负的放大的电压,然后通过反馈回来,下拉那个电压,把电压拉下去,达到稳态的时候,正负相等,以上就是虚短的具体原理。正负电压相等,输出信号才会稳定。

虚断,输入阻抗很大,所以不会流入流出。

以上是虚短和续断的原理。

 51单片重要外设系列-AD/DA转换_第8张图片

同理,公式用虚断虚短去推理,同向放大器不需要电源跟随,电压跟随器可以提高驱动能力,左边公式中R1等于无穷大时,左边就是右边。 

接下是DA转换的原理图。

 51单片重要外设系列-AD/DA转换_第9张图片

由虚短虚断可知,V+=V-=0, 从右往左,总阻值为R,依次从右边等效到左边,汇集到多少份I0,即为有一个公式去一一换算,具体在视频中,这里不打出,总之是利用计算VREF来算出多少位打开,就是多少位对应的数值乘以电压,也就是数字量转换为输出的电压量,实际输出应该加个负号,以上少个负号。而开发板上的用的是另外一种DA转换器:

51单片重要外设系列-AD/DA转换_第10张图片二阶低通滤波器,可以滤掉输出的交流分量,Vh就是高电平5V,根据占空比的多少来看看输出电压的多少,他的优点是节省IO口只用一个输出口就可以了,缺点则是输出不稳定,可能用纹波也就是输出的直流分量不是很平滑,有一丝波动。

下面讲解AD原理:

 51单片重要外设系列-AD/DA转换_第11张图片

用输入的电压信号和DAC比较,当DAC与输入的信号相似时,那么就可以用已知的量表示未知的量,所以也叫逐次逼近型。以上讲完了两个原理,接下来分析ADDA转换的性能评价指标:

 51单片重要外设系列-AD/DA转换_第12张图片

下面开始讲解AD转换的时序图,前面没听懂都没关系,只需要明白电压变成一个内存的数据51单片重要外设系列-AD/DA转换_第13张图片 

他用的是SPI通信协议,51单片重要外设系列-AD/DA转换_第14张图片 

时序图,才是嵌入式的灵魂,下面开始讲解通信协议SPI:

 第一个CS片选,第二个是时钟信号,第三个DIN输入,第五个DOUT输出,三个线跟多个设备是共用的,根据片选信号来决定具体某一个设备是否开启。DCLK上升沿输入,下降沿输出,完成两个设备的通信,先片选,再发送,最后接送。记得看手册,时序在每一个芯片的手册中。

51单片重要外设系列-AD/DA转换_第15张图片

从左到右,一个是电阻分压,一个是热敏电阻,一个是光敏电阻。

重点讲解以下的SPI通信协议:

51单片重要外设系列-AD/DA转换_第16张图片

这个芯片用的是SPI通信协议,CS片选独立的一根,其他的DCLK,DIN,DOUT跟其他设备共同挂载在三根线上,这是为了节约IO口,你不看说每加一个通信设备就给单片机加三根线对吧?到CS片选有效时,打开此芯片,单片机通过DIN输入到这个芯片中来,按照时序再从这个芯片中的DOUT读取相应的数据,以上就是通信的全过程。

 

 51单片重要外设系列-AD/DA转换_第17张图片

 

先片选,然后上升沿输入,下降沿输出,发送的第一个字节是状态控制字,ZeroFILLEed代表多出来的用0填充即可。

以下是AD转换的代码

#include 
#include "Delay.h"
#include "LCD1602.h"
#include "XPT2046.h"
	
unsigned int ADValue;


void main()
{

	LCD_Init();
	while(1)
	{
				ADValue=XPT2046_ReadAD(XPT2046_XP_8);
				LCD_ShowNum(2,1,ADValue,3);
				ADValue=XPT2046_ReadAD(XPT2046_YP_8);
				LCD_ShowNum(2,6,ADValue,3);
				ADValue=XPT2046_ReadAD(XPT2046_VBAT_8);
				LCD_ShowNum(2,11,ADValue,3);
				Delay(10);
	}
}
#include 


 
 
 
sbit XPT2046_CS=P3^5;
sbit XPT2046_DCLK=P3^6;
sbit XPT2046_DIN=P3^4;
sbit XPT2046_DOUT=P3^7;

unsigned int XPT2046_ReadAD(unsigned char Command)		//时序图中读出来的两个字节,用int类型接收,也就是读回来的AD值,Command是输入的值
{
	unsigned char i;
	unsigned int ADVAlue;	//要返回的两个字节值
	XPT2046_CS=0;	//拉低片选信号,选中这个设备进行通信
	XPT2046_DCLK=0;
	for(i=0;i<8;i++)
	{
				XPT2046_DIN=Command&(0x80>>i);	//获得Command的最高位
				XPT2046_DCLK=1;
				XPT2046_DCLK=0;
	}
	//把单片机中的数据发给XPT2046芯片
	XPT2046_DCLK=1;
	XPT2046_DCLK=0;
	for(i=0;i<16;i++)
	{
			XPT2046_DCLK=1;
			XPT2046_DCLK=0;
			//下降沿读出来
			if(XPT2046_DOUT){ADVAlue|=(0x8000>>i);}	//默认是16位0,有1就置1
	}
	XPT2046_CS=1;	//拉高片选信号,结束战斗
	if(Command&0x80)
		{
		return ADVAlue>>8;
		}
		else
		{
		return ADVAlue>>4;
		}
}

以下是DA转换的代码,原理就是PWM

#include 
#include "Delay.h"
#include "Key.h"
#include "Nixie.h"
#include "Timer0.h"

sbit DA=P2^1;	//电机极性端口

unsigned char Counter,Compare;//Counter为从0到100,每隔100清零,Compare为比较值,Counter与其比较大小并决定输出是1还是0
unsigned char i;


void main()
{
	Timer0Init();	//100微秒中断一次,与原来相比加快了十倍
	Compare=5;		//设置一个默认初值
	while(1)
	{
		for(i=0;i<100;i++)
		{
				Compare=i;
				Delay(10);
		}
		for(i=100;i>0;i--)
		{
				Compare=i;
			  Delay(10);
		}
	}

}

//在此程序中,为每隔一百微秒进来一次中断干别的,以下这个函数用来放PWM,主循环用来做别的,用定时器来做PWM,Counter相当于自增器,小于比较值输出0,大于比较值输出1,弄不清楚就画图
void Timer0_Routine() interrupt 1 //与普通函数没区别,此为中断函数程序书写,后面加个中断类型即可	
{
	TL0 = 0x9C;		//重新设置初值,每隔100微秒进来中断一次
	TH0 = 0xFF;		//记得重新初始化
	Counter++;		//
	Counter%=100;	//与下图程序实现的功能类似,每增加到100就自动重载为0,Counter相当于自增,每自增到100自动清零,与如下注释函数所实现的功能相同
	/*
	if(Counter==100)
	{
		Counter=0;
	}
	*/
	if(Counter

 

你可能感兴趣的:(单片机,嵌入式硬件)