基于51单片机和ADC0809多通道模数转换的设计与实现.docx
《基于51单片机和ADC0809多通道模数转换的设计与实现.docx》由会员分享,可在线阅读,更多相关《基于51单片机和ADC0809多通道模数转换的设计与实现.docx(24页珍藏版)》请在冰豆网上搜索。
基于51单片机和ADC0809多通道模数转换的设计与实现
摘要
本文介绍了基于单片机的数据采集的硬件设计和软件设计,数据采集系统是模拟域与数字域之间必不可少的纽带,它的存在具有非常重要的作用。
本文介绍的重点是数据采集系统,而该系统硬件部分的重心在于单片机。
硬件部分是以单片机为核心,还包括A/D模数转换模块,LCD1602显示模块部分。
8路被测电压通过模数转换器ADC0809进行模数转换,实现对采集到的数据进行模拟量到数字量的转换,并将转换后的数据通过LCD1602显示器来显示所采集的结果,并且可以通过按键来查看任意通路的电压值,整个系统具有操作方便、线路简单、测量误差小等优点。
关键词:
单片机AT89S52、模数转换器ADC0809、数据采集、LCD1602显示器
1、方案设计
根据设计要求,采用的方案如下:
硬件部分实现对8路数据采集和显示的功能,包括MCS-51单片机、ADC0809、LCD1602;软件部分实现单片机对8路输入数据的采集以及对LCD1602的显示操作。
主要设计思想:
单片机P1与ADC0809相连,P0与LCD1602连接。
模拟信号通过IN0——IN7输入到ADC0809中转换为数字信号,P1获得此值后,经过处理得到每位的数据后,通过P0口写数据到LCD屏上。
数据采集电路的原理框如图1所示。
图1数据采集电路的原理框图
2、硬件电路的设计
2.1单片机的最小系统设计
单片机最小系统是能补足单片机工作的最简单电路,它由单片机、电源、晶体振荡器、复位电路等构成。
它是本系统的处理单元也是控制单元,负责处理信号、外设的接口与控制,同时它也是所有软件的载体。
本系统采用AT89C52是美国Atmel公司生产的低电压、高性能CMOS8位单片机,片内含8KB的可反复檫写的程序存储器和12B的随机存取数据存储器(RAM),器件采用Atmel公司的高密度、非易失性存储技术生产,兼容标准MCS-51指令系统,片内配置通用8位中央处理器(CPU)和Flash存储单元,功能强大的AT89C52单片机可灵活应用于各种控制领域。
AT89C52单片机属于AT89C51单片机的增强型,与Intel公司的80C52在引脚排列、硬件组成、工作特点和指令系统等方面兼容。
主要管脚有:
XTAL1(19脚)和XTAL2(18脚)为振荡器输入输出端口,外接12MHz晶振。
RST/Vpd(9脚)为复位输入端口,外接电阻电容组成的复位电路。
VCC(40脚)和VSS(20脚)为供电端口,分别接+5V电源的正负端。
P0~P3为可编程通用I/O脚,其功能用途由软件定义。
其管脚如下图2所示:
图2AT89C52单片机管脚图
本设计中,P0端口(32~39脚)被定义为N1功能控制端口,分别与N1的相应功能管脚相连接。
单片机正常工作时,都需要有一个时钟电路和一个复位电路。
本设计
中选择了内部时钟方式和按键电平复位电路,来构成单片机的最小电路。
如图3所示。
图3单片机最小系统
2.2ADC0809模数转换器设计电路
2.2.1ADC0809的结构功能
本数据采集系统采用计算机作为处理器。
电子计算机所处理和传输的都是不连续的数字信号,而实际中遇到的大都是连续变化的模拟量,模拟量经传感器转换成电信号后,需要模/数转换将其变成数字信号才可以输入到数字系统中进行处理和控制,因此,把模拟量转换成数字量输出的接口电路,即A/D转换器就是现实信号转换的桥梁。
目前,世界上有多种类型的A/D转换器,如并行比较型、逐次逼近型、积分型等。
本文采用逐次逼近型A/D转换器,该类A/D转换器转换精度高,速度快,价格适中,是目前种类最多,应用最广的A/D转换器。
逐次逼近型A/D转换器一般由比较器、D/A转换器、寄存器、时钟发生器以及控制逻辑电路组成。
ADC0809就是一种CMOS单片逐次逼近式A/D转换器,其内部结构如图4所示。
该芯片由8路模拟开关、地址锁存与译码器、比较器、8位开关树型D/A转换器、逐次逼近寄存器、三态输出锁存器等电路组成。
因此,ADC0809可处理8路模拟量输入,且有三态输出能力。
该器件既可与各种微处理器相连,也可单独工作。
其输入输出与TTL兼容。
图4ADC0809内部结构
ADC0809是8路8位A/D转换器(即分辨率8位),具有转换启停控制端,转换时间为100μs采用单+5V电源供电,模拟输入电压范围为0~+5V,且不需零点和满刻度校准,工作温度范围为-40~+85℃功耗可抵达约15mW。
ADC0809芯片有28条引脚,采用双列直插式封装,图5所示是其引脚排列图。
图5ADC0809的引脚排列图
各引脚的功能如下
IN0~IN7:
8路模拟量输入端;
D0~D7:
8位数字量输出端;
ADDA、ADDB、ADDC:
3位地址输入线,用于选通8路模拟输入中的一路;
ALE:
地址锁存允许信号,输入高电平有效;
START:
A/D转换启动信号,输入高电平有效;
EOC:
A/D转换结束信号,输出当A/D转换结束时,此端输出一个高电平(转换期间一直为低电平);
OE:
数据输出允许信号,输入高电平有效。
当A/D转换结束时,此端输入一个高电平才能打开输出三态门,输出为数字量;
CLK:
时钟脉冲输入端。
要求时钟频率不高640kHz;
REF(+)、REF(-):
基准电压;
Vcc:
电源,单一+5V;
GND:
地。
ADC0809的工作过程:
首先输入3位地址,并使ALE=1,将地址存入地址锁存器中。
此地址经译码选通8路模拟输入之一到比较器。
START上升沿将逐次逼近寄存器复位。
下降沿启动A/D转换,之后EOC输出信号变低,指示转换正在进行。
直到A/D转换完成,EOC变为高电平,指示A/D转换结束,结果数据已存入锁存器,这个信号可用作中断申请。
当OE输入高电平时,输出三态门打开,转换结果的数字量输出到数据总线上。
转换数据的传送A/D转换后得到的数据应及时传送给单片机进行处理。
数据传送的关键问题是如何确认A/D转换的完成,因为只有确认完成后,才能进行传送。
为此可采用下述三种方式。
(1)定时传送方式
对于一种A/D转换其来说,转换时间作为一项技术指标是已知的和固定的。
例如ADC0809转换时间为128μs,相当于6MHz的MCS-51单片机共64个机器周期。
可据此设计一个延时子程序,A/D转换启动后即调用此子程序,延迟时间一到,转换肯定已经完成了,接着就可进行数据传送。
(2)查询方式
A/D转换芯片由表明转换完成的状态信号,例如ADC0809的EOC端。
因此可以用查询方式,测试EOC的状态,即可确认转换是否完成,并接着进行数据传送。
(3)中断方式
把表明转换完成的状态信号(EOC)作为中断请求信号,以中断方式进行数据传送。
不管使用上述哪种方式,只要一旦确定转换完成,即可通过指令进行数据传送。
首先送出口地址并以信号有效时,OE信号即有效,把转换数据送上数据总线,供单片机接受。
ADC0809工作时,首先输入3位地址,并使ALE为1,以将地址存入地址锁存器中。
此地址经译码可选通8路模拟输入之一到比较器。
START上升沿将逐次逼近寄存器复位;下降沿则启动A/D转换,之后,EOC输出信号变低,以指示转换正在进行,直到A/D转换完成,EOC变为高电平,指示A/D转换结束,并将结果数据存入锁存器,这个信号也可用作中断申请。
当OE输入高电平时,ADC的输出三态门打开,转换结果的数字量可输出到数据总线。
A/D转换器的位数决定着信号采集的精度和分辨率。
对于8通道的输入信号,其分辨率为0.5%。
8位A/D转换器的精度为:
。
2.2.2ADC0809的工作时序
图6所示是ADC0809的工作时序图。
从该时序图可以看出,地址锁存信号ALE在上升沿将三位通道地址锁存,相应通道的模拟量经过多路模拟开关送到A/D转换器。
启动信号START上升沿复位内部电路,START的下降沿启动转换,此时转换结束信号EOC呈低电平状态,由于逐位逼近需要一定过程,所以,在此期间,模拟输入量应维持不变,比较器要一次次比较,直到转换结束,此时变为高电平。
若CPU发出输出允许信号OE(输出允许为高电平),则可读出数据。
另外,ADC0809具有较高的转换速度和精度,同时受温度影响也较小。
图6ADC0809的工作时序图
2.2.3ADC0809与AT89C52单片机的接口电路
ADC0809与AT89C52单片机的接口电路如图7所示。
图中,P2.0、P2.1、P2.2输出的低3位地址加到通道选择端A、B、C,可作为通道编码。
其通道基本地址为0000H~0007H。
输出数据与P0口连接,CLOCK、ALE一起与P2.4相连,START和P2.5连接,EOC与P2.3相连,OE和P2.6相连。
图7ADC0809与AT89C52单片机接口电路
2.3LCD1602显示电路
字符型液晶显示模块是一种专门用于显示字母、数字、符号等点阵式LCD,目前常用16*1,16*2,20*2和40*2行等的模块。
LCD1602分为带背光和不带背光两种,基控制器大部分为HD44780,带背光的比不带背光的厚,是否带背光在应用中并无差别。
LCD1602采用标准的14脚(无背光)或16脚(带背光)接口,各引脚接口说明如下表1所示:
表1LCD1602引脚接口说明
编号
符号
引脚说明
编号
符号
引脚说明
1
VSS
电源地
9
D2
数据
2
VDD
电源正极
10
D3
数据
3
VL
液晶显示偏压
11
D4
数据
4
RS
数据/命令选择
12
D5
数据
5
R/W
读/写选择
13
D6
数据
6
E
使能信号
14
D7
数据
7
D0
数据
15
BLA
背光源正极
8
D1
数据
16
BLK
背光源负极
1602液晶模块的读写操作、屏幕和光标的操作都是通过指令编程来实现的。
1602液晶模块内部的控制器共有11条控制指令,如下表2所示,其中1为高电平、0为低电平。
表2LCD1602控制指令
序号
指令
RS
R/W
D7
D6
D5
D4
D3
D2
D1
D0
1
清显示
0
0
0
0
0
0
0
0
0
1
2
光标返回
0
0
0
0
0
0
0
0
1
*
3
置输入模式
0
0
0
0
0
0
0
1
I/D
S
4
显示开/关控制
0
0
0
0
0
0
1
D
C
B
5
光标或字符移位
0
0
0
0
0
1
S/C
R/L
*
*
6
置功能
0
0
0
0
1
DL
N
F
*
*
7
置字符发生存贮器地址
0
0
0
1
字符发生存贮器地址
8
置数据存贮器地址
0
0
1
显示数据存贮器地址
9
读忙标志或地址
0
1
BF
计数器地址
10
写数到CGRAM或DDRAM)
1
0
要写的数据内容
指令1:
清显示,指令码01H,光标复位到地址00H位置。
指令2:
光标复位,光标返回到地址00H。
指令3:
光标和显示模式设置I/D:
光标移动方向,高电平右移,低电平左移S:
屏幕上所有文字是否左移或者右移。
高电平表示有效,低电平则无效。
指令4:
显示开关控制。
D:
控制整体显示的开与关,高电平表示开显示,低电平表示关显示C:
控制光标的开与关,高电平表示有光标,低电平表示无光标B:
控制光标是否闪烁,高电平闪烁,低电平不闪烁。
指令5:
光标或显示移位S/C:
高电平时移动显示的文字,低电平时移动光标。
指令6:
功能设置命令DL:
高电平时为4位总线,低电平时为8位总线N:
低电平时为单行显示,高电平时双行显示F:
低电平时显示5x7的点阵字符,高电平时显示5x10的点阵字符。
指令7:
字符发生器RAM地址设置。
指令8:
DDRAM地址设置。
指令9:
读忙信号和光标地址BF:
为忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙。
指令10:
写数据。
其操作时序图如下所示:
图8读操作时序图
图9写操作时序图
本设计中采用液晶LCD1602显示模数转换器采集到的数据,其D0~D7与单片机的P0端口连接,使能端E、RS、RW分别与单片机P3.1、P3.0、P3.2连接,此电路原理简单,电路连接方便,如图10所示。
图10液晶LCD1602显示电路
2.4键盘与单片机连接电路
本设计中使用了两个独立按键来选择显示对应通道的电压,其中KEY1每按一下通道数就减1并在LCD1602上显示对应通道的电压,KEY2每按一下通道数就加1并在LCD1602上显示对应通道的电压,这样就十分方便查看不同通道的数据。
键盘与单片机的连接电路如图11所示。
图11键盘与单片机的连接电路
2.5系统整体电路图
根据上述各个部分的电路,将每个部分的电路在仿真软件PROTUES中连接起来,仔细检查线路后确保无误后就可以得到系统的整体电路图如12所示。
图12系统整体电路图
3、软件设计
此次设计的多通道数据采集系统设置了8路模拟电压输入通道。
仿真中为了便于调节输入的模拟电压,在输入模拟信号时采用电阻分压,最终的采样输入电压便可根据测试需要调节,系统总流程图如图13所示:
图13系统流程图
4、系统仿真和测试结果
根据方案设计结果,进行了硬件电路在Proteus下的仿真。
当通过电位器调节AD转换器输入端的电压时,模拟电压值经过AD转换后,经由单片机将转换后的电压值发送至P0口,供LCD进行显示。
仿真过程描述:
通过KEIL软件对所编程序进行编译,生成.hex文件,在PROTUES软件中,用MCS51单片机调用.hex,即可进行硬件的仿真。
该仿真包括两部分:
1.对8路电压进行采集,经由AD转换器进行转化,转化后的16进制数存于单片机的内部存储器中。
2.对转换后的电压进行显示。
将内部存储器中存储的转化后的电压对应的16进制数付给P0口,由LCD进行显示。
调节电位器LCD的显示数据也会发生变化。
仿真数据如下图所示:
图14通路1数据采集结果
图15通路2数据采集结果
图16通路3数据采集结果
图17通路4数据采集结果
图18通路5数据采集结果
图19通路6数据采集结果
图20通路7数据采集结果
图21通路8数据采集结果
5、性能分析
根据上述仿真结果图14至图21可以得到:
8路模拟通道电压值分别设置为0.05V、0.85V、1.50V、2.30V、3.05V、3.70V、4.25V、5.00V。
经过系统处理,LCD1602显示的采集值分别为0.05V、0.84V、1.50V、2.29V、3.05V、3.70V、4.25V、5.00V。
系统误差为小于0.01。
如果想看到某一路的数据采集值,可以通过按键KEY1、KEY2来调节,这样就方便查看。
综上所述:
通过用PROTUES软件的仿真发现此次设计的系统原理图能够实现电压的正确测量,而且电压的误差极小,LCD1602液晶屏能够正确显示出8路电压测量结果。
整个作品能较好的实现基本功能和扩展功能。
6、心得与体会
7、参考文献
附录一:
源程序
#include
#include
#defineucharunsignedchar
#defineuintunsignedint
/********************定义LCD1602接口信息********************************/
sbitlcdrs=P3^0;//数据命令选择位
sbitlcden=P3^1;//使能位
sbitlcdrw=P3^2;
/********************定义ADC0808接口信息********************************/
sbitADA=P2^0;
sbitADB=P2^1;
sbitADC=P2^2;
sbitEOC=P2^3;
sbitCLK=P2^4;
sbitSTART=P2^5;
sbitOE=P2^6;
/*****************键盘管脚定义*************/
sbitkey1=P3^3;
sbitkey2=P3^7;
/*********************定义数据********************************/
uchartab1[]={48,46,48,48,48,46,48,48,48,46,48,48,48,46,48,48};
//存放AD采集数据
uchartab2[]={48,46,48,48,48,46,48,48,48,46,48,48,48,46,48,48};
uchartab3[]="TONGLU:
";
uchartab4[]="DIANYA:
";
uchartab5[]="12345678";
ucharnum,m=0,getdata=0;
uinttemp=0;
/*延时函数*/
voiddelay(uchart)
{
ucharx,y;
for(x=t;x>0;x--)
for(y=110;y>0;y--);
}
voiddelayl(ucharltime)
{
uchari;
for(i=ltime;i>0;i--)
delay(255);
}
/*写命令函数*/
voidwrite_com(ucharcom)
{
lcdrs=0;
P0=com;
delay(10);
lcden=1;
delay(10);
lcden=0;
}
/*写数据函数*/
voidwrite_data(uchardate)
{
lcdrs=1;
P0=date;
delay(10);
lcden=1;
delay(10);
lcden=0;
}
voiddisp(ucharh,l,uchar*p)
{
write_com(0x80+h*0x40+l);
while(*p!
='\0')
{
write_data(*p);
p++;
}
}
/*初始化函数*/
voidLcdInit()
{
lcdrw=0;
delay(5);
lcden=0;//使能位置低电平
write_com(0x38);
write_com(0x0c);
write_com(0x06);
write_com(0x01);
write_com(0x80);
delayl(20);
}
voidTimeInit()
{
TMOD=0x10;//定时器1工作于方式1,16位不重装初值
TH1=(65536-200)/256;//定时200us(5KHz)
TL1=(65536-200)%256;
EA=1;
ET1=1;
TR1=1;
}
voidAdTr(bitADDA,ADDB,ADDC,ucharchannel)
{
START=0;
OE=0;
START=1;
START=0;//A/D转换启动信号,正脉冲启动选中的模拟信号开始转换
ADA=ADDA;
ADB=ADDB;
ADC=ADDC;
delay(5);
while(EOC==0);//启动转换后EOC变为L,转换结束后变为H
OE=1;
getdata=P1;
temp=getdata*1.0/255*500;
OE=0;
if(channel<4)
{
tab1[4*channel]=temp/100+0x30;
tab1[4*channel+2]=(temp%100)/10+0x30;
tab1[4*channel+3]=(temp%100)%10+0x30;
}
if(channel>=4)
{
channel=channel-4;
tab2[4*channel]=temp/100+0x30;
tab2[4*channel+2]=(temp%100)/10+0x30;
tab2[4*channel+3]=(temp%100)%10+0x30;
}
}
voidkeyscan()/*按键2进行减1*/
{
uintk;
if(key1==0)
{
m--;
if(m<5)
{
write_com(0x80+0x07);
write_data(tab5[m-1]);
write_com(0x80+0x47);
for(k=0;k<4;k++)
write_data(tab1[4*(m-1)+k]);
}
if(m>=5&&m<9)
{
write_com(0x80+0x07);
write_data(tab5[m-1]);
write_com(0x80+0x47);
for(k=0;k<4;k++)
write_data(tab2[4*(m-5)+k]);
}
if(m==1)m=1;
}
while(key1==0);//等待按键释放
if(key2==0)
{
m++;
if(m<5)
{
write_com(0x80+0x07);
write_data(tab5[m-1]);
write_com(0x80+0x47);
for(k=0;k<4;k++)
write_data(tab1[4*(m-1)+k]);
}
if(m>=5&&m<9)
{
write_com(0x80+0x07);
write_data(tab5[m-1]);
write_com(0x80+0x47);
for(k=0;k<4;k++)
write_data(tab2[4*(m-5)+k]);
}
if(m==9)m=0;
}
while(key2==0);//等待按键释放
}
voidmain()
{
LcdInit();
TimeInit();
while
(1)
{
AdTr(0,0,0,0);
delay(5);
AdTr(0,0,1,1);
delay(5);
AdTr(0,1,0,2);
delay(5);
AdTr(0,1,1,3);
delay(5);
AdTr(1,0,0,4);
delay(5);
AdTr(1,0,1,5);
delay(5);
AdTr(1,1,0,6);
delay(5);
AdTr(1,1,1,7);
delay(5);
disp(0,0,tab3);
disp(1,