数字电压表设计报告.docx
《数字电压表设计报告.docx》由会员分享,可在线阅读,更多相关《数字电压表设计报告.docx(22页珍藏版)》请在冰豆网上搜索。
数字电压表设计报告
s
作品名:
数字电压表
学院:
电气工程学院
专业:
姓名:
学号:
指导老师:
第一章:
设计方案…………………………….3
第二章:
硬件电路设计……………………….4
2.1主控芯片.....................................4
2.2模数转换部分……………………………………….4
2.3显示模块……………………………………………….6
第三章:
软件设计……………………………………….7
3.1主程序设计…………………………………………..7
3.2A/D转换子模块…………………………………...8
第四章:
系统调试……………………………………….9
4.1硬件调试………………………………………………..9
4.1.1硬件故障…………………………………………….9
4.1.2硬件调试方法……………………………………..9
4.2软件调试…………………………………………………9
4.2.1软件故障……………………………………….9
4.2.2软件调试方法…………………………………9
第五章:
实验数据处理.……………………………..10
5.1实验数据………………………………………..10
5.2实验数据分析………………………………….10
第六章:
结论……………………………………………….11
附录一:
作品图……………………………………………11
附录二:
程序……………………………………………….12
第一章:
设计方案
基于51单片机,以ADC0804芯片实现模数转换,由1602液晶屏显示,具有量程变换功能。
第二章:
硬件设计
2.1主控芯片
本电压表采用STC89C52为主控芯片,电路如下图所接:
晶振电路和复位电路略去,端口和上面各图的接口是一致的。
2.2模拟转换部分
该电压表采用的ADC0804,此芯片优点是并行输出,速率快,缺点是只有8位,精度不高。
下来ADC0804芯片图:
为了方便,将数字地和模拟地都直接接到了一起,DB0~DB7为并行输出口,CS,RD,WR为控制芯片模数转换及读取芯片数据和写数据的引脚,ADC0804可以自己产生时钟,只要在CLKR和CLKIN端接入电阻(10K)和电容(理论为150pf本人接的220pf),可产生脉冲信号。
VREF为参考电压端,VIN+和VIN-为电压输入端。
当电压加在VIN+和VIN-端时,在DB0~DB7可输出八位到单片机,本处参考电压为5V,则当输入电压U时,输出数据为temp,则U/temp=5/255.在自然状态下,最多也只能测5V电压,为了扩大量程,本人加了衰减网络,见下图:
接到ADC芯片上面的始终是VIN和地之前的电压,为了调精度,在上面加了滑动变阻器。
此处R22选用的是470K欧的,首先选的10K,因为内阻过小,导致在5V以下的电压测量不准确,choice和GND两端为外加的电压,这样,有部分电压会在R20或者R21上分压,只在保证在R22两端不超过5V,就可实现多量程电压测量。
2.3显示模块
本处用1602液晶显示,1602优点是价格便宜,可显示基本字符,对于做电压表这样的东西已足够。
电路如下:
第三章:
软件设计
3.1主程序
主程序包括初始化部分调用A/D转换子程序和调用显示程序,如下图所示:
3.2A/D转换子模块:
A/D转换子程序用于对ADC0804八路输入模拟电压进行A/D转换,并将转换的数值存入八个相应的存储单元中,如下图:
第四章:
系统调试
基于单片机的数字电压表在组装好以后,便可进入系统的在线调试,起主要任务是排除样机硬件故障并完善其硬件结构,试运行所设计的程序,排除程序错误,优化程序结构,使系统达到预期的功能,进而固化软件。
4.1硬件调试
单片机应用系统的硬件和软件调试时交叉进行的,但通常是先排除样机中明显的硬件故障,尤其是电源故障,才能安全和仿真器相连,进行综合调试。
4.1.1硬件电路故障
(1)错线开路短路;
(2)元器件损坏
(3)电源故障
4.1.2硬件调试方法
本设计调试中所用的调试方法是静态测试:
在样机加电之前,首先用万用表等工具,根据硬件电器原理图和装配图仔细检查样机线路的正确性,并核对元器件的型号规格和安装是否符合要求。
第二步是加电后检查各插件上引脚的点位,仔细测量各电位是否正常。
第三步是在不加电的情况下,除单片机以外,插上所有的元器件,最后用仿真适配器将样机的单片机插座盒仿真器的仿真接口相连,为联机调试做准备。
4.2软件调试
4.2.1软件电路故障
(1)当以断点或连续方式运行时,目标系统没有按规定的功能进行操作或什么结果也没有,这是由于程序转移到意外之外或在某处死循环所造成的。
(2)结果不正确
4.2.1软件调试方法
软件调试所使用的方法有:
计算程序的调试方法,I/O处理程序的调试法,综合调试法
第五章:
实验数据处理
5.1实验数据
0-5V量程为
0-50V量程
次数
标准值
电压示值
满度误差
次数
标准值
电压示值
满度误差
1
0.76
0.725
0.70%
1
1.34
1.5
0.52%
2
1.11
1.078
0.64%
2
2.35
2.5
0.30%
3
1.66
1.627
0.66%
3
4.42
4.7
0.56%
4
1.99
1.960
0.60%
4
7.17
7.1
0.14%
5
2.17
2.156
0.28%
5
10.6
10.1
1.00%
6
2.46
2.450
0.20%
6
13.0
12.9
0.20%
7
2.70
2.686
0.28%
7
14.6
14.4
0.40%
8
2.85
2.843
0.14%
8
16.7
16.1
1.00%
9
3.03
3.019
0.22%
9
18.2
17.6
1.20%
10
3.15
3.156
-0.12%
10
19.5
18.9
1.20%
11
3.09
3.098
-0.16%
11
21.7
21.2
1.00%
12
3.76
3.764
-0.08%
12
22.9
22.0
1.80%
13
3.79
3.803
-0.26%
13
23.9
23.0
1.80%
14
4.45
4.470
-0.40%
14
25.3
24.5
1.60%
15
4.65
4.686
-0.72%
15
25.8
24.9
1.80%
16
29.5
28.8
1.40%
17
30.4
29.5
1.80%
18
34.1
33.3
1.60%
19
36.5
35.6
1.80%
20
38.2
37.4
1.60%
5.2实验数据分析
0-5V量程精度为0.001V,满度误差均<1.00%,为一级电压表
0-50V量程精度为0.1V,满度误差均<2.50%,为2.5级电压表
第六章:
结论
1.输入电压易发生干扰不稳定,且驱动能力可能存在不足,需在被测信号的输入端加上一部分驱动电路,比如将量程转换电路改成放大能力的自动量程转换电路,将幅值较小的信号经适当放大后再测量,可显著提高精度;
2.输出量可用平均值算法来改善,使测量准确度更高;
3.若能将测量的电压值实时保存,使用时将更方便;
附录一:
作品图
附录二:
程序
主程序:
#include//头文件#include//头文件
#include
#include
#include
#include<1602.h>
#include
#include
#include
voidmain()
{
while
(1)
{
write_com(0x01);
lcd_init();
display_voltage();
}
}
1、宏定义和定义变量:
#defineucharunsignedchar//宏定义
#defineuintunsignedint
uchartable[]="measurement:
";
ucharrange5[]="RANGE0~20V:
";
ucharrange50[]="RANGE0~2A:
";
ucharrange500[]="RANGE0~100K:
";
ucharwarning[]="PleaseChoice!
";
/*ucharerror[]="error!
";*/
uintmeasure[10];
sbitkey3=P2^7;
sbitkey0=P2^2;
sbitkey1=P2^1;
sbitkey2=P2^0;
sbitlcd_rs=P2^3;//定义液晶的rs端口
sbitlcd_rw=P2^4;//定义液晶的rw端口
sbitlcd_en=P2^5;
sbitback=P2^6;
sbitspk=P2^7;//定义液晶的en端口
sbitcs=P3^2;//定义AD的cs端口
sbitrd=P3^1;//定义AD的rd端口
sbitwr=P3^0;
//sbitdula=P3^7;
sbitINTR=P3^7;//定义AD的wr端口
uinttemp,i,A1,A2,A3,A4;//定义变量
uintdate;
2、延时部分:
voiddelay(uintz)
{
uintx,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
voiddelay_lcd()//1602指令之间延时
{
uintx=5;
while(x--);
}
3、AD转换和数据传送:
voidAD_init()//初始化ADC0804
{
cs=0;
wr=1;
_nop_();
wr=0;
_nop_();
wr=1;
}
uintAD_switch()//AD转换部分
{
uinttemp;
P1=0xff;
rd=1;
_nop_();
rd=0;
_nop_();
temp=P1;//将转后的原始值返给单片机P1口
returntemp;
}
uintAD_smooth()//软件滤波
{
uintxx,i,temp;
AD_init();
for(i=0;i<20;i++)
{
measure[i]=AD_switch();
delay(10);//每隔10usADC转换并采集一次数据,将得
}//到的数据放到数组中,采集十个数据
for(xx=0;xx<20;xx++)//将十个数据冒泡法排序
for(i=xx;i<20;i++)
{
if(measure[xx]>measure[i])
{
temp=measure[i];
measure[i]=measure[xx];
measure[xx]=temp;
}
}
for(i=6;i<16;i++)//去掉了三个最小值和两个最大值,
{//取中间五个数的平均值
xx+=measure[i];
}
xx=xx/10;
returnxx;//将滤过波后的值存入单片机
}
4、1602子程序:
voidwrite_com(ucharcom)//写指令
{
delay(5);
lcd_en=0;
lcd_rs=0;
lcd_rw=0;
_nop_();
lcd_en=1;
P0=com;
lcd_en=0;
lcd_rs=0;
}
voidwrite_date(uchardate)//写数据
{
delay(5);
lcd_en=0;
lcd_rs=1;
lcd_rw=0;
_nop_();
lcd_en=1;
P0=date;
lcd_en=0;
lcd_rs=0;
}
voidlcd_init()//初始化
{
back=0;
delay(15);
lcd_en=0;
write_com(0x38);
write_com(0x38);
write_com(0x38);
write_com(0x06);
write_com(0x0c);
write_com(0x01);
}
5、键盘扫描:
uintkeyscan()
{
if(key0==0&&key1==1&&key2==1&&key3==1)
return1;
elseif(key0==1&&key1==0&&key2==1&&key3==1)
return
(2);
elseif(key0==1&&key1==1&&key2==0&&key3==1)
return(3);
elseif(key0==1&&key1==1&&key2==1&&key3==0)
return(4);
elseif(key0==1&&key1==1&&key2==1&&key3==1)
return(5);
elsereturn(6);
}
6、数据整理及显示:
voiddisplay5V(uinttemp)//量程为5V时的显示状态
{
uintnum0,num1,num2,num3;
if(temp<7)temp=0;
elsetemp=temp-7;
num0=temp/51;
num1=temp%51*10/51;
num2=temp%51*10%51*10/51;
num3=temp%51*10%51*10%51*10/51;
write_com(0x80+0x40+11);
write_date(num0+0x30);
delay_lcd();
write_com(0x80+0x40+12);
write_date('.');
delay_lcd();
write_com(0x80+0x40+13);
write_date(num1+0x30);
delay_lcd();
write_com(0x80+0x40+14);
write_date(num2+0x30);
delay_lcd();
write_com(0x80+0x40+15);
write_date(num3+0x30);
delay_lcd();
}
voiddisplay50V(uinttemp)//量程为50V的显示状态
{
uintnum0,num1,num2,num3;
//if(temp<7)temp=0;
//elsetemp=temp-7;
temp=(temp+temp*4/10)*11;
num0=temp/510;
num1=temp%510*10/510;
num2=temp%510*10%510*10/510;
num3=temp%510*10%510*10%51*10/510;
write_com(0x80+0x40+11);
write_date(num0+0x30);
delay_lcd();
write_com(0x80+0x40+12);
write_date(num1+0x30);
delay_lcd();
write_com(0x80+0x40+13);
write_date('.');
delay_lcd();
write_com(0x80+0x40+14);
write_date(num2+0x30);
delay_lcd();
write_com(0x80+0x40+15);
write_date(num3+0x30);
delay_lcd();
}
voiddisplay_voltage()
{
uintnumx,temp,temp0,temp1;
//floattemp;
numx=keyscan();
temp0=numx;
for(i=0;i<16;i++)
{
write_com(0x80+i);
write_date(table[i]);
delay_lcd();
}
if(numx==1||numx==4)
{
for(i=0;i<11;i++)
{
write_com(0x80+0x40+i);
write_date(range5[i]);
delay_lcd();
}
}
elseif(numx==2)
{
for(i=0;i<11;i++)
{
write_com(0x80+0x40+i);
write_date(range50[i]);
delay_lcd();
}
}
elseif(numx==3)
{
for(i=0;i<11;i++)
{
write_com(0x80+0x40+i);
write_date(range500[i]);
delay_lcd();
}
}
elseif(numx==5)
{
for(i=0;i<16;i++)
{
write_com(0x80+0x40+i);
write_date(warning[i]);
delay_lcd();
}
}
elsebeep();
while(temp0<=4&&numx!
=5&&numx!
=6)
{
temp=AD_smooth();
if(temp<5)temp=0;
if(numx==1)
display5V(temp);
numx=keyscan();
//if(numx==5)break;
if(numx==2)
display50V(temp);
numx=keyscan();
while((temp1-temp<7||temp-temp1<7)&&temp1==numx)
{
temp=AD_smooth();
numx=keyscan();
}
}
while(numx==6||numx==5)
{
numx=keyscan();
while(numx==6)
{
numx=keyscan();
beep();
}
}
}