基于单片机89C51模拟电压表系统(双量程)


  • 项目名称:模拟电压表系统设计

  • 项目功能:实现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<reg51.h>
#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<reg51.h>
#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<reg51.h>
#include<intrins.h>
#include"LCD1602.h"
#include"ADC0808.h"
#include<stdio.h>
#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<reg51.h>
#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时候的仿真:

好啦,以上就是所有内容啦,祝大家学习愉快!!!


作者:一只废材,发布于:2020/07/30
原文:https://www.cnblogs.com/this-is-changjiang/p/13398590.html