目录
AD/DA模型
注意:
- AD: 将模拟信号转换为计算机可操作的数字信号;**DA:**将计算机输出的数字信号转换为模拟信号
- AD一般是对电压进行转化的,所以左图中将热敏电阻的变化转化为电压的变化就需要在上面串联一个电阻分压,这样热敏电阻的变化就会引起对应点位的电压变化
- 若要将模拟量转换为数字量,则需要对模拟量进行采样,同时模拟量的大小也和数字量的大小成正比关系
- 对模拟量采样,一般采用需要对模拟量进行判断,当该模拟量高于一定值就对应高的数字量,低于一定值就将他对应低的数字量
- AD/DA转换打开了计算机与模拟信号的大门,极大的提高了计算机系统的应用范围,也为模拟信号数字化处理提供了可能
AD/DA的性能址标
- **分辨率:**指的是AD/DA数字量的精细程度,通常用位数表示,例如,对于5V电源系统来说,8位的AD可将5V等分为256份,AD/DA的位数越高,分辨率就越高(分辨率:电源大小/对应位所分的份数)
- **转换误差:**通常以输出误差的最大值形式给出,他表示AD转换器实际输出的数字量和理论输出数字量之间的一个差别。
- **转换速度:**能重复进行数据转换的一个速度(每秒转换的次数)
51单片机与DAC接口
前言:
- DA转换器就是把输入的数字量转化为与之对应的模拟量
- DA就是我们构建一种电路,使他的输出能够随着数字量的开关这个量进行变化。
T型电阻网络DA转换器
理解:
- 下面D0-D7为8位输入数字量,这些数字量是控制着上面的模拟开关(若给0就接左边,若给1就接右边)最终得输出就是运算放大器得输出Vout
- 先看后面的运算放大器,正向输入端接地,负向输入端接Vref电路,反馈电阻Rfb
- 通过虚短可知,运放左边两个输出原点位电压为0,由虚断可知Vref端流过的电流会经过Rfb到Vout
- 看左上的电路,由并联电阻公式得,所有电阻加起来为R,那么干路电流I=Vref/R;
- 由每路得电流等于后面电流的2倍得出:I=256倍I0,因此I0=I/256;由上一行结论带入:I0=Vref/(256*R)
- 而下面的8个开关决定了电路中的I是多少个I0,就取决于(D7------D0)数字量表示的数
- 由第三行结论算出Vout=0-[(D7---D0)/256][(VrefRfb)/R]
PWM型DA转换器
**理解:**PWM本身就具有DA的属性,他的占空比就和DA得属性差不多,若是个惯性系统的话那么直接输出PWM就可以实现DA得效果,若让他变成模拟信号就可以将PWM信号加双层的滤波器,然后在通过电压跟随器进行输出(增强驱动能力)。
**输出电压:**Vout=(PWM占空比)*Vh
DAC0832
**前言:**DAC0832分辨率为8位,满刻度误差+-1LSB,线性误差+-0.1%,建立时间1um,功耗20mW,其数字输入端具有双重缓冲功能,可以双缓冲、单缓冲或直通方式输入。
DAC0832引脚
- **D10---D17:**8位数字量输入端(D10为最低位)
- **ILE:**数据允许控制输入线,高电平有效
- **CS杠:**片选信号
- **WR1杠:**写信号线1
- **WR2杠:**写信号线2
- **XFER杠:**数据传送控制信号输入线,低电平有效
- **Rfb:**片内反馈电阻引出线
- **Vref:**基准电压输入线,电压范围-10------+10V(该参数决定了输出波的电压幅值)
- **Vcc:**工作电源输入端,可接+5------+15V
- **Iout1:**模拟电流输出线1(他是数字量输出为1的模拟电流输出端)
- **Iout2:**模拟电流输出线2(他是数字量输出为0的模拟电流输出端)
- **AGND:**模拟地
- **DGND:**数字地
DA案例
**前言:**D/A转换器在实际中经常作为波形发生器使用,通过它可以产生各种各样的波形。D/A转换器产生波形的原理如下:利用D/A转换器输出模拟量与输入数字量成正比这一特点,通过程序控制CPU向D/A转换器送出随时间呈一定规律变化的数字,则D/A转换器输出端就可以输出随时间按一定规律变化的波形。
DAC0832实现方波
电路图
注意: 单片机控制DAC0832的片选和寄存器选通引脚,并且对DAC输出波形数据,最终得到DAC输出的模拟量。由于DAC0832输出的模拟量是电流值,因此加一个运放可以得到与参考电压反向的输出电压值,随后加一个反向器就会得到的希望的正向电压(当然,你不想加反相器你也可以把Vref改成负的你想基准的电压也可以),用示波器采集。
示波器
**注意:**示波器有4个通道,分别为a,b,c,d通道,最右边4个是调节特定通道的电压值,比如通道a我用一格表示1V,左下的旋钮用来调整特定通道的时间的,比如我调的是a通道中用10ms表示一格。
keil文件
cpp
#include "reg51.h"
void delay(unsigned int n){
int i=0,j=0;
for(i=0;i<n;i++){
for(j=0;j<120;j++);
}
}
void PWM(){
P2=0;
delay(50);
P2=255;
delay(50);
}
void main()
{
while(1){
PWM();
}
}
DAC0832实现三角波
**前言:**电路图和上面的一样。
示波器
keil文件
cpp
#include "reg51.h"
void stair(){
int i=0;
for(i=0;i<255;i++){
P2=i;
}
for(i=255;i>0;i--){
P2=i;
}
}
void main()
{
while(1){
stair();
}
}
51单片机与ADC接口
ADC简介
- 单片机系统内部运算的都是数字量,因此对于单片机系统而言无法操作模拟量,必须要将模拟量转换为数字量单片机才能进行操作
- ADC也称为模数转换器,是指将模拟信号转变为数字信号。
- 51单片机内部没有ADC接口,因此要让他采集模拟信号就需要在单片机IO口的前端增加AD转换电路(模拟信号转变为数字信号)
ADC转换原理
**前言:**AD转换器将模拟信号转换为数字信号通常要经过4个步骤(采样、保持、量化、编码)
- **采样:**将上一个时间上连续变化的模拟量转化为时间上离散的模拟量
- **保持:**将采样结果保存起来直到下一次采样
- **量化:**将采样电平规划为与之接近的离散数字电平
- **编码:**将量化后的结果按照一定的数字形式表示
计数型AD转换器
**理解:**计数器有向上计数的功能,最开始DA转换器相运放输出的为0V电压,而模拟输入不是0V,最终导致比较器Vout输出高电平导致计数器增加,进而使DA转换器的输出电平增加,当增加到模拟输入与DA转换器内部数值相等时不再增加,那么此时计数器的值就相当于模拟输入的等效值进而实现了模拟量转换为数字量的一个过程。
逐次逼近型AD转换器
**理解:**当我们的模拟信号进来之后,我们通过比较器和DAC输出的电压进行比较(因为我们不知道模拟信号的电压)然后反馈给DAC,若模拟信号大,那么就把DAC输出信号输出高一点(二分法),反之低一点,最终让这两个电压接近相等(未知的和已知的非常接近)那么这个已知的数字量就可以表示未知数字的模拟量然后进行输出。
ADC0808
**前言:**ADC0808是8位CMOS逐次逼近型AD转换器,最小误差为+-1/2LSB,采用单一5V供电。
理解: 该芯片的输入有8位通道,8个通道首先进入通道选择开关选择一路后到AD转换(模拟开关的选择取决于地址锁存与译码的引脚),然后通过start和clock线将IN通道的电压值输出到右边转化AD信号,转化完成后数字信号通过锁存器进行输出缓存,最后通过OE引脚输出使能将8位数据输出出去。
ADC0808引脚
- **IN0---IN7:**8路模拟量输入端
- **D0---D7:**8位数字量输出端(D7为低位,D0为高位)
- **ADDA,ADDB,ADDC:**3位地址输入线,用于选择8路通道的1路
- **ALE:**地址锁存允许信号,输入信号,高电平有效
- **START:**AD转换启动信号,输入信号,高电平有效
- **EOC:**AD转换结束信号。
- **CLK:**时钟脉冲输入端,要求时钟频率不高于640khz
- **OE:**数据输出允许信号,输入信号,高电平有效
- **Vref+,Vref-:**基准电压输入端,Vref+为正向基准,Vref-为负向基准
- **VCC:**电源,接+5V电源
- **GND:**接地
|------|------|------|------|
| ADDC | ADDB | ADDA | 对应通道 |
| 0 | 0 | 0 | IN0 |
| 0 | 0 | 1 | IN1 |
| 0 | 1 | 0 | IN2 |
| 1 | 1 | 1 | IN3 |
| 1 | 0 | 0 | IN4 |
| 1 | 0 | 1 | IN5 |
| 1 | 1 | 0 | IN6 |
| 1 | 1 | 1 | IN7 |
ADC0808的工作流程
- 输入三位地址,并使ALE=1,将地址存入地址锁存器中,将地址译码器译码从8路模拟通道中选通一路模拟量送到比较器
- 送START一高脉冲信号,START的上升沿使逐次逼近寄存器复位,下降沿启动A/D转换,并使EOC信号为低电平。
- 当转换结束时,转换的结果送到三态输出锁存器,并使EOC信号回到高电平,通知CPU已经转换结束
- 当CPU执行一读数据指令,使OE为高电平,则从输入端D0------D7读出数据
仿真案例
**需求:**使用ADC0808制作数字电压表(量程为5V)。
电路图
注意:
- clock信号配置成500K
- 显示的数与电压表差0.01是因为adc0808有误差
- adc0808引脚中D7为低位,D0为高位
- Vref+决定了模数转换的最大电压最大值,Vref-决定了转化的最小电压值(上图的显示表示:你滑动变阻器的2.5V占据我Vref+的一半[Vref-为0],因此会显示127[255的一半])
keil文件
cpp
#include "reg51.h"
sbit RS=P3^3;
sbit RW=P3^4;
sbit E=P3^5;
void delay(unsigned int n){
unsigned int i=0,j=0;
for(i=0;i<n;i++){
for(j=0;j<120;j++);
}
}
#写指令
void writecom(unsigned char com){
RS=0;
RW=0;
E=0;
P1=com;
delay(5);
E=1;
E=0;
}
#写数据
void writedat(unsigned char dat){
RS=1;
RW=0;
E=0;
P1=dat;
delay(5);
E=1;
E=0;
}
#初始化液晶屏
void initlcd(){
writecom(0x38);
writecom(0x0c);
writecom(0x06);
writecom(0x01);
}
//ADC0808模块
sbit start=P3^0;
sbit eoc=P3^1;
sbit oe=P3^2;
unsigned int vol=0;
unsigned char tab[]={"0123456789"};
void adc(){
//因为地址我们已经默认全接地,那么就默认选择了IN0,而且看我电路图,我把start和ale放在一起了
start=0;
start=1;
delay(5);
start=0;
//等待AD转化完成
while(eoc!=1);
//准备读取结果
oe=1;
vol=P2;
oe=0;
}
void display(){
unsigned char temp0=0,temp1=0,temp2=0;
//直接转换出的vol值是0-255的与电压成正比的值,我要固定电压值
vol=vol*100/51;
temp0=vol/100;
temp1=(vol%100)/10;
temp2=vol%10;
//将从电阻读出的电压写到LCD第一行第一列
writecom(0x80);
delay(5);
writedat(tab[temp0]);
delay(5);
writedat('.');
delay(5);
writedat(tab[temp1]);
delay(5);
writedat(tab[temp2]);
delay(5);
}
void main(){
initlcd();
while(1){
adc();
display();
}
}