AD/DA转换打开了计算机与模拟信号的大门,也就是计算机与外部真实世界交换信息的桥梁,为实现计算机控制外部环境打下了坚实基础
如上图所示,那个变化的阻值会引起上面电阻电压的变化,通过电压信号的变化,单片机读取到数值,这也就是AD转换的原理,模拟量和数字量成正比关系,读取到数字量换算成模拟量即可,输出就是反过来,他说的多个通道就是复用多个硬件电路,稍微好一点的芯片会把ADDA集成在内部芯片中,那样能节约IO口,不占那么多线路,DA用的少,它可以用PWM实现。
以上是ADC芯片,CS片选,DCLK时钟信号,用的SPI串口通信,至于什么是SPI,I2C,这些通信协议在其他的方面会提到,DIN数据输入,DOUT数据输出,下面来看DA。
他是在P21上面输出一个PWM波形然后驱动DA1这个灯亮灭,结合之前的PWM的原理即可。
ADDA,B,C左下角三路来译码决定上面IN0到IN7是哪一路可以输出到AD转换中去,上面的START是开始信号,EOC是结束信号,CLOCK是时钟信号,OE是使能,最下面的是参考电压。
我们要分析的重点就是A\D转换如何把一个电压信号转化为八位的DB0到DB7数字信号的输出,这个是AD转换的核心也就是看所谓的时序图。
DA转换器如下:D0到D7输入,经过两个缓存器到右边输出电压。那个8位D/A转换器,在下面会提到T型网络
下面介绍运算放大器:
为什么需要功率放大,因为输出的信号驱动能力很弱,所以需要一个功率放大器,
第二个图用虚短和虚断可以推出那个公式,通过电阻的调整可以调整那个放大倍数。
下面解释一下虚短的原理,VIN输出0.1V,大于+,通过前面的比较器可以得知Vout输出一个负的放大的电压,然后通过反馈回来,下拉那个电压,把电压拉下去,达到稳态的时候,正负相等,以上就是虚短的具体原理。正负电压相等,输出信号才会稳定。
虚断,输入阻抗很大,所以不会流入流出。
以上是虚短和续断的原理。
同理,公式用虚断虚短去推理,同向放大器不需要电源跟随,电压跟随器可以提高驱动能力,左边公式中R1等于无穷大时,左边就是右边。
接下是DA转换的原理图。
由虚短虚断可知,V+=V-=0, 从右往左,总阻值为R,依次从右边等效到左边,汇集到多少份I0,即为有一个公式去一一换算,具体在视频中,这里不打出,总之是利用计算VREF来算出多少位打开,就是多少位对应的数值乘以电压,也就是数字量转换为输出的电压量,实际输出应该加个负号,以上少个负号。而开发板上的用的是另外一种DA转换器:
二阶低通滤波器,可以滤掉输出的交流分量,Vh就是高电平5V,根据占空比的多少来看看输出电压的多少,他的优点是节省IO口只用一个输出口就可以了,缺点则是输出不稳定,可能用纹波也就是输出的直流分量不是很平滑,有一丝波动。
下面讲解AD原理:
用输入的电压信号和DAC比较,当DAC与输入的信号相似时,那么就可以用已知的量表示未知的量,所以也叫逐次逼近型。以上讲完了两个原理,接下来分析ADDA转换的性能评价指标:
下面开始讲解AD转换的时序图,前面没听懂都没关系,只需要明白电压变成一个内存的数据
时序图,才是嵌入式的灵魂,下面开始讲解通信协议SPI:
第一个CS片选,第二个是时钟信号,第三个DIN输入,第五个DOUT输出,三个线跟多个设备是共用的,根据片选信号来决定具体某一个设备是否开启。DCLK上升沿输入,下降沿输出,完成两个设备的通信,先片选,再发送,最后接送。记得看手册,时序在每一个芯片的手册中。
从左到右,一个是电阻分压,一个是热敏电阻,一个是光敏电阻。
重点讲解以下的SPI通信协议:
这个芯片用的是SPI通信协议,CS片选独立的一根,其他的DCLK,DIN,DOUT跟其他设备共同挂载在三根线上,这是为了节约IO口,你不看说每加一个通信设备就给单片机加三根线对吧?到CS片选有效时,打开此芯片,单片机通过DIN输入到这个芯片中来,按照时序再从这个芯片中的DOUT读取相应的数据,以上就是通信的全过程。
先片选,然后上升沿输入,下降沿输出,发送的第一个字节是状态控制字,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