-
项目名称:模拟电压表系统设计
-
项目功能:实现0 ~ 5V、5 ~ 10V双量程电压测量并显示
本项目是在这次疫情下,大三学期的课程设计,自己辛苦了一夜,最后成绩得了优(哈哈哈哈)。下面简单说明一下本项目,为像我一样笨手笨脚的同学提供些经验(嘻嘻嘻嘻)。
硬件部分
- MCU:89C51
- 显示模块:LCD1602
- 模数转换:ADC0808
- 警报:蜂鸣器
- 电压采集:采集电路
软件部分:
该部分无非是驱动及数据处理。
首先是驱动:
LCD1602.h
#ifndef __LCD1602_H__
#define __LCD1602_H__
#define uchar unsigned char
#define uint unsigned int
/******LCD端口设置******/
sbit LcdEn = P3^7;
sbit LcdRw = P3^6;
sbit LcdRs = P3^5;
/******定义测量按键******/
sbit Start = P3^2;
sbit Stop = P3^3;
void LcdDisplay();
void LcdPrintL1(char* str); /*第一行整屏左移显示*/
void LcdPrint1(char* str); /*第一行显示*/
void LcdPrint11(char* str); /*第一行显示,不清屏·*/
void LcdPrint2(char* str); /*第二行显示,不清屏*/
void WriteCom(uchar comData);
void WriteData(uchar Data);
void Delay_ms(unsigned int n);
void Delay_10ms();
#endif
LcdDisplay.c
/******LCD驱动及显示******/
#include
#include"LCD1602.h"
#define uchar unsigned char
#define uint unsigned int
extern code uchar table1[];
extern code uchar table2[];
extern code uchar table3[];
extern code uchar table4[];
extern code uchar table5[];
uchar num = 0;
/*-----------------LCD驱动程序----------------*/
/*******LCD写命令*******/
void WriteCom(uchar comData){
LcdRs = 0; //写命令
LcdRw = 0; //写选择端
//Delay_ms(5); //
P0 = comData; //将数据送达数据线
LcdEn = 1; //开始能
Delay_ms(5);
LcdEn = 0; //关始能
}
/******LCD写数据*******/
void WriteData(uchar Data){
LcdRs = 1; //写数据
LcdRw = 0; //写选择
P0 = Data;
Delay_ms(5);
LcdEn = 1;
Delay_ms(5);
LcdEn = 0;
}
/*---------------LCD初始化---------------*/
void LcdDisplay(){
LcdRw = 0;
LcdEn = 0;
WriteCom(0x38); //设置16x2显示,5x7点阵,8位数据接口
WriteCom(0x0c); //设置开显示,不显示光标
Delay_ms(1);
WriteCom(0x06); //写一个字符后地址指针加1
WriteCom(0x01); //显示清零,数据指针清零
Delay_ms(1);
WriteCom(0x80); //光标位置初始化
while(table1[num]!='\0'){ //没有换行符,一直执行
WriteData(table1[num]);
num++;
Delay_ms(2);
}
Delay_ms(1000);
}
/*---------------LCD显示指令--------------*/
/*******第一行显示指令*******/
void LcdPrint1(char* str){
uchar i = 0;
WriteCom(0x01);
WriteCom(0x80);
for(i=0;str[i]!=0;i++)
WriteData(str[i]);
}
/*******第一行显示指令,不清屏*******/
void LcdPrint11(char* str){
uchar i = 0;
// WriteCom(0x01);
WriteCom(0x80);
for(i=0;str[i]!=0;i++)
WriteData(str[i]);
}
/******第二行显示指令******/
void LcdPrint2(char* str){
uchar i = 0;
WriteCom(0x80 + 0x40);
for(i=0;str[i]!=0;i++)
WriteData(str[i]);
}
/******第一行整屏左移显示指令******/
void LcdPrintL1(char* str){
uchar i = 0;
WriteCom(0x01); //显示清零,指针清零
WriteCom(0x80);
for(i=0;str[i]!=0;i++)
WriteData(str[i]);
Delay_ms(150);
num = 0;
while(table4[num]!='\0'){
WriteCom(0x18); //整屏左移指令
num++;
Delay_ms(150); //控制移动速度
}
}
ADC0808.h
#ifndef __ADC0808_H__
#define __ADC0808_H__
#define uchar unsigned char
#define uint unsigned int
/******ADC0808端口设置******/
sbit START = P3^1; /*A/D转换启动信号,正脉冲有效*/
sbit EOC = P3^0; /*转换结束信号,高电平有效;该信号在A/D转换过程中为低电平,其余时间为高电平*/
sbit OE = P3^4; /*转换允许信号*/
/******定义ADC数据选择端口******/
sbit a = P1^0;
sbit b = P1^1;
sbit c = P1^2;
/******定义量程选择端口******/
sbit K1 = P1^3;
sbit K2 = P1^4;
uint ReadData();
void AdStar();
void SetData0(uchar addr,uint Data);
void SetData1(uchar addr,uint Data);
void DataSelector();
#endif
BuzzerWarning.c
/******BuzzerWarning******/
#include
#include"LCD1602.h"
#include"ADC0808.h"
#define uchar unsigned char
#define uint unsigned int
extern code uchar table5[];
extern code uchar table6[];
sbit SPEAKER = P1^7;
void BuzzerWarning0_5V(){
uint t,i;
//SPEAKER = 1;
//LcdPrint11(table5);
for(t=0;t<3;t++){
for(i=0;i<35;i++)
Delay_10ms();
SPEAKER =~ SPEAKER;
}
SPEAKER = 1;
Delay_ms(800);
}
主函数部分:
main.c
#include
#include
#include"LCD1602.h"
#include"ADC0808.h"
#include
#define uchar unsigned char
#define uint unsigned int
code uchar tablea[]="0123456789";
code uchar tableb[]="Voltage:00.00 V";
code uchar table1[]={"System ready."};
code uchar table2[]={"Press STAR to start measuring."};
code uchar table3[]={"Measuring... "};
code uchar table4[]={"Measurement end."};
code uchar table5[]={"Maximum range."};
code uchar table6[]={"Minimum range"};
uchar res = 0;
bit flag1 = 0;
bit flag2 = 1;
bit flag3 = 1;
uchar k = 1;
void Interrupt_eint();
void StartInt0();
void StopInt1();
void main(void){
/*------系统初始化------*/
LcdDisplay();
Interrupt_eint();
while(!IE0 && !IE1) LcdPrintL1(table2);
/*------系统运行------*/
while(1){
StartInt0();
StopInt1();
}
}
下面是数据处理部分及按键部分,由于老师要求有两个按键即:开始按键、结束按键;又由于在系统启动后会有字幕的提示信息,且提示信息是以滚动的方式显示的,所以这个项目的按键部分采用了中断的方式进行实现(效果:在提示信息显示及系统运行的任何时候都可以随时按下按键)。
注意:在系统刚启动后,只能按下 START按键,按下STOP按键无效,这是在程序中设计好的。
下面是程序:
Interrupt.c
/******利用外部中断函数实现按键功能******/
#include
#include"LCD1602.h"
#include"ADC0808.h"
#define uchar unsigned char
#define uint unsigned int
extern code uchar tablea[];
extern code uchar tableb[];
extern code uchar table1[]; /*系统准备就绪*/
extern code uchar table2[]; /*请按“Start”开始测量*/
extern code uchar table3[]; /*正在测量*/
extern code uchar table4[]; /*测量结束*/
extern code uchar table5[];
extern code uchar table6[];
extern uchar res; /*接收数据*/
extern bit flag2;
extern bit flag3;
void BuzzerWarning0_5V();
/******中断初始化******/
void Interrupt_eint(){
EX0 = 1; //开启外部中断0
IT0 = 0; //设置外部中断0触发模式:低电平触发
EX1 = 1; //开启外部中断1
IT1 = 0; //设置外部中断1触发模式
EA = 1; //开启总中断
PX0 = 1; //将外部中断的优先级提高
}
/******外部0中断服务函数******/
void StartInt0() interrupt 0{
if(IE0 && flag2 == 1){ //按下START
Delay_10ms();
flag2 = 0;
LcdPrint1(table3);
LcdPrint2(tableb);
while(!IE1){
WriteCom(0x80+0x40+8);
AdStar();
res = ReadData();
if(flag3){
SetData0(8,res);
if((res*1.0/255*500)/100 == 5){//判断电压是否超过或等于 5 V
LcdPrint11(table5);
BuzzerWarning0_5V();
}
else
LcdPrint11(table3);
}
else{
SetData1(8,res);
if(res*1.0/255*500*3 >= 1000){//判断电压是否超过或等于 10 V
LcdPrint11(table5);
BuzzerWarning0_5V();
}
else if(res*1.0/255*500*3/100 < 5){
LcdPrint11(table6);
BuzzerWarning0_5V();
}
else
LcdPrint11(table3);
}
}
}
}
/******外部1中断服务函数******/
void StopInt1() interrupt 2{
if(IE1 && flag2 == 0){ //按下STOP
Delay_10ms();
flag2 = 1;
LcdPrint1(table4);
LcdPrint2(tableb);
res = ReadData();
if(flag3)
SetData0(8,res);
else
SetData1(8,res);
while(!IE0);
}
}
以上就是所有的源程序啦。程序中也有些小细节,大多都有注释。
下面是Protues的仿真原理图:
5V时候的仿真:
好啦,以上就是所有内容啦,祝大家学习愉快!!!