基于单片机简易数字电压表的设计
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
目录
1.摘要及关键词-------------------------------------------3
2.总体设计方案-------------------------------------------3
3.硬件电路及仿真设计------------------------------------10
4.程序设计及调试----------------------------------------12
5.本人承担的小组工作以及设计体会------------------------13
6.参考文献----------------------------------------------13
7.元器件清单及程序清单----------------------------------13
摘要:
本次设计主要由三个模块组成:A/D转换模块,数据处理模块及显示模块。
A/D转换主要由芯片ADC0809来完成,它负责把采集到的模拟量转换为相应的数字量在传送到数据处理模块。
数据处理则由芯片AT89C52来完成,其负责把ADC0809传送来的数字量经过一定的数据处理,送到LCD1602液晶显示模块进行显示;此外,它还控制着ADC0809芯片工作。
关键词:
数字电路单片机 ADC0809 LCD1602
总体方案的设计:
本次设计的要求如下:
1.可以选择测量8路1-5V的8路电压值:
2.可轮流显示或单路选择显示(可选);
3.测量显示的最小分辨率为0.01V,测量的误差正负0.02V;
4.具有电压过低,过高声光报警功能,报警限可独立设置。
设计思路:
根据设计的要求,进行器件的选择。
芯片控制选取STC89C52单片机,由于要控制8路,故选取ADC0809的数模转换,显示部分选用目前很流行的LCD1602的液晶显示,最后采用8个开关控制8个通道,所以选取74LS148。
下面进行逐一叙述:
STC89C52单片机芯片管脚如下
STC89C52的管脚图
STC89C52是一种低功耗、高性能CMOS8位微控制器,具有 8K 在系统可编程Flash 存储器。
在单芯片上,拥有灵巧的8 位CPU 和在系统可编程Flash,使得STC89C52为众多嵌入式控制应用系统提供高灵活、超有效的解决方案。
具有以下标准功能: 8k字节Flash,512字节RAM, 32 位I/O 口线,看门狗定时器,内置4KB EEPROM,MAX810复位电路,三个16 位定时器/计数器,一个6向量2级中断结构,全双工串行口。
另外 STC89X52 可降至0Hz 静态逻辑操作,支持2种软件可选择节电模式。
空闲模式下,CPU 停止工作,允许RAM、定时器/计数器、串口、中断继续工作。
掉电保护方式下,RAM内容被保存,振荡器被冻结,单片机一切工作停止,直到下一个中断或硬件复位为止。
最高运作频率35Mhz,6T/12T可选。
复位电路设计
单片机在启动运行时都需要复位,使CPU和系统中的其他部件都处于一个确定的初始状态,并从这个状态开始工作。
MCS-51单片机有一个复位引脚RST,采用施密特触发输入。
当震荡器起振后,只要该引脚上出现2个机器周期以上的高电平即可确保时器件复位[1]。
复位完成后,如果RST端继续保持高电平,MCS-51就一直处于复位状态,只要RST恢复低电平后,单片机才能进入其他工作状态。
单片机的复位方式有上电自动复位和手动复位两种,下图是51系列单片机统常用的上电复位和手动复位组合电路,只要Vcc上升时间不超过1ms,它们都能很
好的工作[1]。
复位电路
时钟电路设计
单片机中CPU每执行一条指令,都必须在统一的时钟脉冲的控制下严格按时间节拍进行,而这个时钟脉冲是单片机控制中的时序电路发出的。
CPU执行一条指令的各个微操作所对应时间顺序称为单片机的时序。
MCS-51单片机芯片内部有一个高增益反相放大器,用于构成震荡器,XTAL1为该放大器的输入端,XTAL2为该放大器输出端,但形成时钟电路还需附加其他电路[1]。
本设计系统采用内部时钟方式,利用单片机内部的高增益反相放大器,外部电路简,只需要一个晶振和 2个电容即可,如下图所示。
时钟电路
ADC0809:
ADC0809是美国国家半导体公司生产的CMOS工艺8通道,8位逐次逼近式A/D模数转换器。
其内部有一个8通道多路开关,它可以根据地址码锁存译码后的信号,只选通8路模拟输入信号中的一个进行A/D转换。
是目前国内应用最广泛的8位通用A/D芯片。
下图是内部电路结构及外部管脚图:
1.主要特性
1)8路输入通道,8位A/D转换器,即分辨率为8位。
2)具有转换起停控制端。
3)转换时间为100μs(时钟为640kHz时),130μs(时钟为500kHz时)4)单个+5V电源供电
5)模拟输入电压范围0~+5V,不需零点和满刻度校准。
6)工作温度范围为-40~+85摄氏度
7)低功耗,约15mW。
2.内部结构
ADC0809是CMOS单片型逐次逼近式A/D转换器,内部结构如图所示,它由8路模拟开关、地址锁存与译码器、比较器、8位开关树型A/D转换器、逐次逼近寄存器、逻辑控制和定时电路组成。
3.外部特性(引脚功能)
ADC0809芯片有28条引脚,采用双列直插式封装,如图所示。
下面说明各引脚功能。
IN0~IN7:8路模拟量输入端。
2-1~2-8:8位数字量输出端。
ADDA、ADDB、ADDC:3位地址输入线,用于选通8路模拟输入中的一路ALE:地址锁存允许信号,输入,高电平有效。
START: A/D转换启动脉冲输入端,输入一个正脉冲(至少100ns宽)使其启动(脉冲上升沿使0809复位,下降沿启动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输入高电平时,输出三态门打开,转换结果的数字量输出到数据总线上。
注释:由于仿真软件proteus没有adc0809,故仿真的时候选取adc0808取代,只有输出数字信号时引脚的排序不同。
LCD1602液晶:
Lcd1602的引脚图
工业字符型液晶,能够同时显示16x02即32个字符。
(16列2行)注:为了表示的方便,后文皆以1表示高电平,0表示低电平。
1602液晶也叫1602字符型液晶它是一种专门用来显示字母、数字、符号等的点阵型液晶模块它有若干个5X7或者5X11等点阵字符位组成,每个点阵字符位都可以显示一个字符。
每位之间有一个点距的间隔每行之间也有间隔起到了字符间距和行间距的作用。
1602是指显示的内容为16X2,即可以显示两行,每行16个字符液晶模块(显示字符和数字)。
管脚功能
1602采用标准的16脚接口,其中:
第1脚:VSS为电源地
第2脚:VDD接5V电源正极
第3脚:V0为液晶显示器对比度调整端,接正电源时对比度最弱,接地电源时对比度最高(对比度过高时会产生“鬼影”,使用时可以通过一个10K的电位器调整对比度)。
第4脚:RS为寄存器选择,高电平1时选择数据寄存器、低电平0时选择指令寄存器。
第5脚:RW为读写信号线,高电平(1)时进行读操作,低电平(0)时进行写操作。
第6脚:E(或EN)端为使能(enable)端。
第7~14脚:D0~D7为8位双向数据端。
1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,这些字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是01000001B(41H),显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到字母“A”。
因为1602识别的是ASCII码,试验可以用ASCII码直接赋值,在单片机编程中还可以用字符型常量或变量赋值,如'A’。
以下是1602的16进制ASCII码表地址:
读的时候,先读左边那列,再读上面那行,如:感叹号!的ASCII为0x21,字母B的ASCII为0x42(前面加0x表示十六进制)
74LS148:
管脚图如上输入输出关系如下图
连接如图所示电路并仿真成功!
误差分析
通过以上仿真测量结果可得到简易数字电压表与“标准”数字电压表对比测试表,
初始工作状态设定,初始化子程序的主要工作是设置定时器的工作模式,初值预置,开中断和打开定时器等[9]。
A/D转换子程序
A/D转换子程序用来控制对输入的模块电压信号的采集测量,并将对应的数值
图13 A/D转换流程图
3 显示子程序
跟据LCD1602液晶的显示方式,先对其进行初始化,输入设置方式,在显示数值的时候要先写地址符号。
Write_LCD_Command(0x80);//设置显示的初始位置
LCD_Display(display_buffer[0]); //显示测得的数据
本人在小组中的工作及设计体会:
由于我承担小组长的职位,在设计的时候兼顾整体的方案。
根据本小组成员的需要及个人所长,工作分配如下:
XXX(我):仿真电路图的设计及程序的设计
XX:仿真电路图的设计及电路图的布线
XXX:元器件的采购及电路图的焊接
设计体会:
本次设计很大程度考验了一个团队的合作能力,一个人并不能擅长做所有的东西,而对于设计,其关键就在于设计的思路,有步骤的设计可以省去很多不必要的麻烦,我觉得做这样的课程设计,不仅仅是考验我们的设计能力,或者说是写程序能力,而是我们将成品做出来后,它并没有按照我们的设定工作,更大程度的考验我们解决问题的能力。
比如这次我们的设计,在仿真成功后,电路板焊接完毕,连线完毕,将程序输入到单片机里工作时就出了差错,检查了很久的连线都没有检查出来,然后就想到了测电位的方法来判断,当时就得出了结论:单片机没有工作。
省去了大量的不必要的检查导线的问题,最后查出复位开关焊接出错了,也就很容易的改正过来了!
参考文献:
1.MCS-51单片机原理、系统设计与应用(万福君等著清华大学出版社)
2.51单片机C语言教程(郭天祥著电子工业出版社)
元器件清单:
STC89C52单片机*1 LCD1602液晶 *1 杜邦线导线若干电阻1K *9 ADC0809 *1 按键 *1 晶振12M *1 74LS148 *1 排针若干
点解电容10uf *1 104电容 *2
程序清单:
#include <reg52.h>
#include <intrins.h>
#include<string.h>
#define dat_port P0
#define uchar unsigned char
#define uint unsigned int
#define delay4us() {_nop_();_nop_();_nop_();_nop_();}
sbit AB3=P3^0;//对74HC148进行判断
sbit AB2=P3^1;//报警设置
sbit RS=P2^0;//RS=1 数据 RS=0 命令
sbit RW=P2^1;//RW=1 读取 RW=0 写入
sbit E=P2^2;//E 使能信号
sbit EOC=P2^4;
sbit OE=P2^5;
sbit START=P2^3;
sbit CLOCK=P2^6;
void Refresh_show();
void delay50us(uint m)
{
uint n,k;
for(n=m;n>0;n--)
for(k=25;k>0;k--);
}
void Write_LCD_Command(uchar cmd);//向LCD写入命令
void Write_LCD_Data(uchar dat); //向LCD写入一个字节的数据函数void Initialize_LCD1602(); //液晶初始化函数
void LCD_Display(uchar *str);//在LCD上显示字符串
//---------------忙检查-------------------//
uchar LCD_Busy_Check()
{
uchar LCD_Status;
RS = 0;
RW = 1;
E = 1;
delay50us(4);
LCD_Status = P0;
E = 0;
return LCD_Status;
}
//--------------向LCD写入命令--------------------//
void Write_LCD_Command(uchar cmd)
{
while((LCD_Busy_Check()& 0x80)==0x80); //忙等待
RS = 0;
RW = 0;
E = 0;
P0 = cmd;
delay4us();
E = 1;
delay4us();
E = 0;
}
//-----------向LCD写入一个字节的数据函数-----------------*/ void Write_LCD_Data(uchar dat)
{
while((LCD_Busy_Check()&0x80)==0x80);
RS = 1;
RW = 0;
E = 0;
P0 = dat;
delay4us();
E = 1;
delay4us();
E = 0;
}
//-----------LCD初始化-----------------*/
void Initialize_LCD1602() //液晶初始化函数
{
Write_LCD_Command(0x38);delay50us(10); //功能设置,数据长度为8位,双行显示,5×7点阵字体
Write_LCD_Command(0x0C);delay50us(10); // 显示开,关光标
Write_LCD_Command(0x06);delay50us(10); //字符进入模式:屏幕不动,字符后移
Write_LCD_Command(0x01); delay50us(10);//清屏
}
//-----------在LCD上显示字符串-----------------*/ void LCD_Display(uchar *str)
{
uchar i;
for(i=0;i<strlen(str);i++)
{
Write_LCD_Data(str[i]);
delay50us(100);
}
}
unsigned long dat_adc0808;
uchar display_buffer[][16]={
{"voltage: "},
{"DC=0.00 "}
};
uint adc0808_init() // AD初始化
{
START=0;
START=1;
START=0;
while(EOC==0);
OE=1;
delay50us(20);
dat_adc0808=P1;
OE=0;
return dat_adc0808;
}
void Refresh_show() //刷新显示
{
uint t=dat_adc0808*500.0/255; //
if(t>400||t<100)//报警的上下限设置
AB2=1;
else
AB2=0;
display_buffer[1][3] = t/100+'0'; //整数位
display_buffer[1][5] = t/10%10+'0'; //两个小数位
display_buffer[1][6] = t%10+'0';
}
void main()
{
TMOD=0x02;
TH0=0x14;
TL0=0x00;
EA=1;
ET0=1;
TR0=1;
Initialize_LCD1602();
delay50us(10);
Write_LCD_Command(0x80);//设置显示的初始位置
LCD_Display(display_buffer[0]); //显示测得的数据
while(1)
{
if(AB3==1)
{
Write_LCD_Command(0xc0);//设置显示的初始位置
LCD_Display(display_buffer[1]); //显示测得的数据 }
else{
adc0808_init();
Refresh_show(); //更新测的电压数据
Write_LCD_Command(0xc0);//设置显示的初始位置
LCD_Display(display_buffer[1]); //显示测得的数据
}
}
}
void Timer0_INT() interrupt 1 using 1
{
CLOCK=!CLOCK;
}。