多路数字电压表的设计
8.3 多路数字电压表的设计
数字电压表是电子测量中经常用到的电子器件,传统的指针式电压表功能单一、精度低、不能满足数字时代的要求。而采用单片机的数字电压表精度高、抗干扰能力强、可扩展性强、使用方便,在日常生活中广泛应用。
8.3.1 多路数字电压表的功能要求
多路数字电压表的功能要求如下: (1) 输入电压为8路。
(2) 电压值的范畴为0~5V 。
(3) 测量的最小分辨率为0.019V ,测量误差为0.02V 。。
(4) 能通过显示器显示通道和通道电压,有效位数为小数点后两位
8.3.2 多路数字电压表的总体设计
多路数字电压表的总体结构如图8.9所示,处理过程如下:先用A/D 转换器对各路电压值进行采样,得到相应的数字量,再按数字量与模拟量成正比关系运算得到对应的模拟电压值,然后把模拟值通过显示器显示出来,另外可以通过按键选择通道。
图8.9 多路数字电压表的总体结构图
根据系统的功能要求,控制系统采用AT89C52单片机,A/D 转换器采用ADC0808(0809)。ADC0808(0809)是8位的A/D 转换器。当输入电压为5.00V 时,输出的数据值为255(0FFH),因此最大分辨率为0.0196V(5/255)。ADC0808(0809)具有8路模拟量输入端口,通过3位地址输入端能从8路中选择一路进行转换。如每隔一段时间依次轮流改变3位地址输入端的地址,就能依次对8路输入电压进行测量。显示器采用LCD 显示器,显示效果好。按键可只设定一个,用于选择显示的当前通道。
8.3.3 多路数字电压表硬件电路
多路数字电压表具体硬件电路如图8.10所示。
51单片机
时钟电路
复位电路
LCD 按键
ADC0808
P 17P 16P 15P17
P16P15P07P 07P06P05P04P03P02P01P00P 00P 01P 02P 03P 04P 05P 06P 07
P 00P 01P 02P 03P 04P 05P 06P27
ST P23P26P21P22P20P24P25ADDC ADDB ADDA ADDA ADDB ADDC ST XTAL2
18
XTAL1
19
ALE 30EA
31
PSEN 29RST
9
P0.0/AD039P0.1/AD138P0.2/AD237P0.3/AD336P0.4/AD435P0.5/AD534P0.6/AD633P0.7/AD732P1.0/T21P1.1/T2EX 2P1.23P1.34P1.45P1.56P1.67P1.78
P3.0/RXD 10P3.1/TXD 11P3.2/INT012P3.3/INT113P3.4/T014P3.7/RD
17
P3.6/WR 16
P3.5/T115P2.7/A1528
P2.0/A821P2.1/A922P2.2/A1023P2.3/A1124P2.4/A1225P2.5/A1326P2.6/A1427U1
AT89C52
D 7
14
D 613D 512D 411D 310D 29D 18D 0
7E 6
R W 5R S 4V S S 1V D D 2V E E
3
LCD1
LM016L
R1
10k
234567891
RP1
RESPACK-8
OUT121ADD B 24ADD A
25ADD C 23VREF(+)12VREF(-)16IN31IN42IN53IN64IN75START 6OUT58EOC 7OE
9
CLOCK 10
OUT220OUT714OUT615OUT817OUT418OUT319IN228IN127IN0
26
ALE 22U2
ADC0808
X1
CRYSTAL
C1
1nF
C2
1nF
C3
1nF
R4
200
56%
RV1
1k
50%
RV2
1k
图8.10 多路数字电压表的电路原理图
其中,ADC0808(0809) 的数据线D0~D7与AT89C52的P2口相连,地址输入端
ADDA 、ADDB 、ADDC 与AT89C52的P3口的低3位P3.0、P3.1、P3.2相连,地址锁存控制端ALE 和启动信号START 连接在一起与P3.7相连,数据输出允许控制端OE 与P3.6相连,转换结束信号EOC 与P1.3相连。ADC0809的时钟信号输入端CLOCK 与P1.4相连,而P1.4由定时/计数器0控制,每10s 取反一次,则CLOCK 的时钟周期为20s ,频率为50KHz ,满足ADC0808(0809)的时钟要求。参考电压VREF+接+5V 电源,参考电压VREF-接地,则当输入电压为5.00V 时,输出的数据值为255(0FFH),当输入电压为0V 时,输出的数据值为0(00H),最大分辨率为0.0196V(5/255)。
显示器LCD1602的数据线与89C 52的P0口相连,RS 与P1.7相连,R/W 与P1.6相连,E 端与P1.5相连。按键只设定了一个K1,与AT89C52的P1.0,用于进行通道选择,当按下一次,通道加1,显示下一个通道。
8.3.4 多路数字电压表软件程序
多路数字电压表系统软件程序由主程序、A/D 转换子程序和显示驱动程序组成,这里只介绍主程序、A/D 转换子程序。
1.主程序
主程序流程如图8.11所示。首先是对定时计数器和LCD 初始化,在LCD 上显示提示信息,然后进入循环,在循环中依次为:调用A/D 转换子程序对8个通道转换一次,判
通道键是否按下,按下则当前通道地址加1,当前通道值转换成电压值,
显示当前通道。
2.A/D转换子程序
A/D转换子程序用于对ADC0808的8路输入模拟电压进行一次A/D转换,并将转换的数值存入8个相应的存储单元中,流程图如图8.12所示。A/D转换子程序每隔一定时间调用一次,即隔一段时间对输入电压采样一次。
图8.11 主程序流程图8.12 A/D转换子程序流程
3.汇编语言源程序清单
;30H~37H存放转换的数字量
;38H~3BH分别放电压当前通道电压的个位、小数点后1位、小数点后2位
;3CH单片为通道计数器
RS BIT P1.7 ;定义LCD1602端口线
RW BIT P1.6
E BIT P1.5
ST BIT P3.7 ;定义0808控制线
OE BIT P3.6
EOC BIT P1.3
CLK BIT P1.4
KEY1 BIT P1.0 ;通道选择按键
ORG 0000H
LJMP M AIN
ORG 000BH
CPL CLK ; 定时/计数器0中断,产生转换时钟
RETI
ORG 50H
;主程序
.
MAIN: MOV SP,#50H
MOV 39H,#'.'
MOV T MOD,#02H
MOV T H0,#246
MOV T L0,#246
SETB ET0
SETB EA
SETB TR0
LCALL DL10MS
ACALL INIT
MOV A,#81H ;写入显示缓冲区起始地址为第1行第1列
ACALL WC51R
MOV A,#'A' ;第1行第2列显示字母'H'
ACALL WC51DDR
MOV A,#'D' ;第1行第3列显示字母"O"
ACALL WC51DDR
MOV A,#'D' ;第1行第4列显示字母'W'
ACALL WC51DDR
MOV A,#'R' ;第1行第5列显示字母'U'
ACALL WC51DDR
MOV A,#':' ;第2行第6列显示字母'!'
ACALL WC51DDR
MOV A,#0C0H ;写入显示缓冲区起始地址为第2行第5列
ACALL WC51R
MOV A,#'V' ;第2行第5列显示字母'A'
ACALL WC51DDR
MOV A,#'A' ;第2行第6列显示字母'R'
ACALL WC51DDR
MOV A,#'L' ;第2行第7列显示字母'E'
ACALL WC51DDR
MOV A,#'U' ;第2行第8列显示字母' '
ACALL WC51DDR
MOV A,#'E' ;第2行第9列显示字母'Y'
ACALL WC51DDR
MOV A,#':' ;第2行第10列显示字母'O'
ACALL WC51DDR
LOOP: LCALL TEST ;调用ADC0808转换程序8个通道转换一次JB KEY1,NEXT ;有键按下,当前通道地址加1
WAIT2: JNB KEY1,WAIT2
INC 3CH
MOV A,3CH
CJNE A,#08,NEXT
MOV 3CH,#00
NEXT: MOV A,#30H ;取出当前通道值,转换成电压值所对应的字符ADD A,3CH
MOV R0,A
MOV A,@R0
MOV B,#51
DIV AB
ADD A,#30H
MOV 38H,A
MOV A,B
CLR F0
SUBB A,#1AH
MOV F0,C
MOV A,#10
MUL AB
MOV B,#51
DIV AB
JB F0,LOOP2
ADD A,#5
LOOP2: ADD A,#30H
MOV 3AH,A
MOV A,B
CLR F0
SUBB A,#1AH
MOV F0,C
MOV A,#10
MUL AB
MOV B,#51
DIV AB
JB F0,LOOP3
ADD A,#5
LOOP3: ADD A,#30H
MOV 3BH,A
MOV A,#88H ;写入显示缓冲区起始地址为第1行第9列
ACALL WC51R
MOV A,3CH
ADD A,#30H ;第1行第9列显示通道号
ACALL WC51DDR
MOV A,#0C8H ;写入显示缓冲区起始地址为第2行第9列
ACALL WC51R
MOV A,38H ;第2行第9列显示整数部分
ACALL WC51DDR
MOV A,39H ;第2行第10列显示小数点
ACALL WC51DDR
MOV A,3AH ;第2行第11列显示小数点后1位
ACALL WC51DDR
MOV A,3BH ;第2行第12列显示小数点后2位
ACALL WC51DDR
AJMP LOOP
;初始化子程序
INIT: MOV A,#00000001H ;清屏
ACALL WC51R
MOV A,#00111000B ;使用8位数据,显示两行,使用5×7的字型LCALL WC51R
MOV A,#00001100B ;显示器开,光标关,字符不闪烁
LCALL WC51R
MOV A,#00000110B ;字符不动,光标自动右移一格
LCALL WC51R
RET
;检查忙子程序
F_BUSY:PUSH ACC ;保护现场
MOV P0,#0FFH
CLR RS
SETB RW
WAIT: CLR E
SETB E
JB P0.7,WAIT ;忙,等待
POP ACC ;不忙,恢复现场
RET
;写入命令子程序
WC51R: ACALL F_BUSY
CLR E
CLR RS
CLR RW
SETB E
MOV P0,ACC
CLR E
RET
;写入数据子程序
WC51DDR:ACALL F_BUSY
CLR E
SETB RS
CLR RW
SETB E
MOV P0,ACC
CLR E
RET
;*****************************************************
;A/D转换子程序,8个通道转换一次转换结果依次存入30H~37H ;*****************************************************
TEST: MOV R0,#30H
MOV R2,#00H
TESTART:MOV P2,#0FFH
MOV A,R2
MOV P3,A
CLR ST
NOP
NOP
SETB ST
NOP
NOP
CLR ST
NOP
NOP
WAIT1: JNB EOC,WAIT1
MOVD: SETB OE
NOP
NOP
MOV A,P2
MOV @R0,A
CLR OE
NOP
NOP
INC R0
INC R2
CJNE R2,#8,TESTART
RET
;*************************************
;延时子程序
;*************************************
DL10MS: MOV R6,#0D0H ;延时10MS子程序
DL1: MOV R7,#10H
DL2: DJNZ R7,DL2
DJNZ R6,DL1
RET
END
4.C语言源程序清单
#include
#include
#include
#define uchar unsigned char
#define uint unsigned int
sbit RS=P1^7; //定义LCD1602端口线
sbit RW=P1^6;
sbit EN=P1^5;
sbit ST=P3^7; //定义0808控制线
sbit OE=P3^6;
sbit EOC=P1^3;
sbit CLK=P1^4;
sbit key1=P1^0; //通道选择按键
uchar data chnumber; //存放当前通道号
uchar disbuffer[4]={0,'.',0,0}; //定义显示缓冲区
uchar data ad_data[8]={0,0,0,0,0,0,0,0}; //0808的8个通道转换数据缓冲区uint temp;
//检查忙函数
void fbusy()
{
P0 = 0xff;
RS = 0;
RW = 1;
EN = 1;
EN = 0;
while((P0 & 0x80))
{
EN = 0;
EN = 1;
}
}
//写命令函数
void wc51r(uchar j)
fbusy();
EN = 0;
RS = 0;
RW = 0;
EN = 1;
P0 = j;
EN = 0;
}
//写数据函数
void wc51ddr(uchar j)
{
fbusy(); //读状态;
EN = 0;
RS = 1;
RW = 0;
EN = 1;
P0 = j;
EN = 0;
}
void init()
{
wc51r(0x01); //清屏
wc51r(0x38); //使用8位数据,显示两行,使用5*7的字型
wc51r(0x0c); //显示器开,光标开,字符不闪烁
wc51r(0x06); //字符不动,光标自动右移一格
}
/********0808转换子函数********/
test()
{
uchar m;
for (m=0;m<8;m++)
{
P3=m; //送通道地址
ST=0;_nop_();_nop_();ST=1;_nop_();_nop_();ST=0;//锁存通道地址启动转换_nop_();_nop_();_nop_();_nop_();
while (EOC==0); //等待转换结束
OE=1;ad_data[m]=P2;OE=0; //读取当前通道转换数据
}
}
//************延时函数************
void delay(uint i) //延时函数
{uint y,j;
for (j=0;j
for (y=0;y<0xff;y++){;}}
}
//定时器/计数器T0产生0808的时钟
void T0X(void)interrupt 1 using 0
{ CLK=~CLK; }
void main(void)
uchar i;
SP=0X50;TMOD=0x02;TH0=246;TL0=246;
ET0=1;EA=1;TR0=1;
delay(10);
init();
wc51r(0x81); //写入显示缓冲区起始地址为第1行第1列
wc51ddr('A'); //第1行第1列显示字母A
wc51ddr('D'); //第1行第2列显示字母D
wc51ddr('D'); //第1行第3列显示字母D
wc51ddr('R'); //第1行第4列显示字母R
wc51ddr(':'); //第1行第4列显示字母:
wc51r(0xC0); //写入显示缓冲区起始地址为第2行第1列
wc51ddr('V'); //第2行第1列显示字母V
wc51ddr('A'); //第2行第2列显示字母A
wc51ddr('L'); //第2行第3列显示字母L
wc51ddr('U'); //第2行第4列显示字母U
wc51ddr('E'); //第2行第5列显示字母E
wc51ddr(':'); //第2行第6列显示字母:
while(1)
{
test(); //调用ADC0808转换程序8个通道转换一次
if (key1==0) {while(key1==0); chnumber++;if (chnumber==8)chnumber=0;}
//有键按下,当前通道地址加1
temp=ad_data[chnumber]; //取出当前通道值,转换成电压值所对应的字符
temp=(temp*100)/51;
disbuffer[0]=temp/100+0x30; temp=temp%100;
disbuffer[2]=temp/10+0x30;
disbuffer[3]=temp%10+0x30;
wc51r(0x88);
wc51ddr(chnumber+0x30);
wc51r(0xc8); //显示当前通道
for (i=0;i<4;i++) wc51ddr(disbuffer[i]);
}
}
如有侵权请联系告知删除,感谢你们的配合!
如有侵权请联系告知删除,感谢你们的配合!