【C51单片机】数字电压表设计

第一次写博客呀多多关照~

1、实现的功能

采用ADC0809和AT89C51单片机及显示电路完成0~5V、0~15V两个量程的直流电压的检测,并通过LCD1602液晶屏实时显示。通过开关SW1和SW2选择5V或15V,当所测电压超过量程时,报警电路的小灯闪烁、蜂鸣器发出警报,同时液晶屏显示QAQ(哈哈哈闲着没事干就加了),当两个开关同时按下也会触发报警电路。

至于两个档位的区别,为了模拟实际的电压表,所以设计的数字电压表显示的精度不一样,15V量程的精度为0.1V,5V量程的精度为0.001V。

2、Proteus仿真原理图

【C51单片机】数字电压表设计_第1张图片
(想说一下,我这里ADC0809的out输出接了上拉电阻,要不然显示屏显示不正常,但是参考别人的不接上拉电阻也可以正常工作QAQ)

3、仿真结果

选择5V量程:
【C51单片机】数字电压表设计_第2张图片
选择15V量程:
【C51单片机】数字电压表设计_第3张图片

4、完整的代码

使用keil编写的c语言代码.

#include                     
#define uchar unsigned char           //宏定义无符号字符型
#define uint  unsigned  int           //宏定义无符号整型
                                                          
sbit  START=P2^7;     //AD启动转换信号
sbit  OE=P2^5;        //数据输出允许信号
sbit  EOC=P2^6;       //AD转换结束信号
sbit  CLK=P2^4;       //时钟脉冲  
sbit  RS=P2^0;        //LCD1602数据/命令选择端(H/L)
sbit  RW=P2^1;        //LCD1602数/写选择端(H/L)
sbit  E=P2^2;         //LCD1602使能信号
sbit  led=P3^0;
sbit  buzzer=P3^1;
sbit  SW1=P3^2;      //5V量程选择开关
sbit  SW2=P3^3;    	 //15V量程选择开关
sbit  addr_a=P3^5;	
sbit  addr_b=P3^6;
sbit  addr_c=P3^7; 

//函数声明
uint ADC();									/* AD转换函数 */
void delayMS(uint xms);						/* 延时函数 */
bit lcd_busy_check();						/* 忙检测函数 */
void lcd_write_com(uchar com);				/* LCD1602写入8位命令子函数 */
void lcd_write_data(uchar date);			/* LCD1602写入8位数据子函数 */
void init_lcd();							/* LCD1602初始化子程序 */	
void lcd_show_string1(uchar a[]); 			/* 第一行从头开始显示字符串 */
void lcd_show_string2(uchar a[]);			/* 第二行从头开始显示字符串 */
void lcd_show_string(uchar add,uchar a[]);	/* 指定位置显示字符串 */
void display();								/* 显示函数 */
void alarm();								/* 报警函数 */
void range();								/* 量程选择函数 */

//定义全局变量
unsigned int volt;
unsigned long vo;
unsigned char code table[]="0123456789"; 

/**************************函数功能:AD转换子程序***************************/
uint ADC()
{		
	    START=0;             //确保进入正常AD转换状态
        OE=0;                //转化初始化        
        START=1;
        START=0;             //AD开始转换
        while(EOC==0);       //外部中断等待AD转换结束
        OE=1;				 //读取转换的AD值
        volt=P1;
        OE=0;			     //输出转换结束    
		return volt;   
}

/**********************函数功能:液晶屏LCD1602显示子程序****************/

/*延时函数:DelayMS()*/
void delayMS(uint xms)			
{
        uint i,j;
        for(i=xms;i>0;i--)
            for(j=110;j>0;j--);
}

/*忙检测函数:lcd_busy_check()*/
bit lcd_busy_check()                
{   
        bit  result;
        RS=0;
        RW=1;
        E=1;
        delayMS(10);
        result=(bit)(P0&0x80);
        E=0;
        return  result;
}

/*写命令函数:lcd_write_com()*/
void lcd_write_com(uchar com)                
{
        RS=0;
		E=0;
	    RW=0;
        P0=com;        
        delayMS(5);
        E=1;
        delayMS(5);                                                                           
        E=0;
}

/*写数据函数:lcd_write_data()*/
void lcd_write_data(uchar date)                
{
        RS=1;
		E=0;
	    RW=0;
        P0=date;
        delayMS(5);
        E=1;
        delayMS(5);
        E=0;
}

/* LCD1602初始化函数:init_lcd()*/

void init_lcd()                                       
{                                                                
        E=0;                                   //默认开始状态为关使能端  
        lcd_write_com(0x38);                   //显示模式设置
        lcd_write_com(0x01);                   //显示清屏,将上次的内容清除 
        lcd_write_com(0x0c);                   //开显示,不显光标,光标不闪
        lcd_write_com(0x06);                   //读一个字符光标加1
}

/* 指定位置显示字符串函数:lcd_show_string() */
/* 参数 add 地址    第一行 0~27				 */
/*                  第二行 40~67			 */
/*      a[] 字符串   "abc"                   */

void lcd_show_string(uchar add,uchar a[])
{
    	uchar i;
    	lcd_write_com(0x80+add);
    	for(i=0;a[i]!='\0';i++)
    	{
	    	lcd_write_data(a[i]);
    	}
}

/* 第一行显示字符串 */
void lcd_show_string1(uchar a[])
{
    	uchar i;
    	lcd_write_com(0x80);
    	for(i=0;a[i]!='\0';i++)
    	{
	    	lcd_write_data(a[i]);
    	}
}

/* 第二行显示字符串 */
void lcd_show_string2(uchar a[])
{
    	uchar i;
  	    lcd_write_com(0x80+0X40);
    	for(i=0;a[i]!='\0';i++)
    	{
	    	lcd_write_data(a[i]);
    	}
}

/* LCD1602显示函数:display()*/
void display1()								//5V的显示
{       
        uint v_1v,v_100mv,v_10mv,v_1mv;    //定义变量用于显示		
        vo = volt*19.6;     		       //转换值处理 (满量程为5V,转换分辩率为8位即最大值是255,5/255=19.6mV,即1代表19.6mV)        
		v_1v = vo/1000; 				   //1伏显示位
        v_100mv = vo/100%10;               //100毫伏显示位      
        v_10mv = vo/10%10;                 //10毫伏显示位
		v_1mv =	vo/1%10;			       //1毫伏显示位

        lcd_write_com(0x80+0x40+0x05);     //选中第二行第5个位置
        lcd_write_data(table[v_1v]);  
		lcd_write_data('.');		                 
		lcd_write_data(table[v_100mv]);                   
		lcd_write_data(table[v_10mv]);                   
	    lcd_write_data(table[v_1mv]);                                                                
        lcd_write_data('V');               //显示电压的单位V
		lcd_write_data(' ');
	    lcd_write_data(' ');
		lcd_write_data(' ');
}

void display2()						       //15V的显示
{       
        uint v_10v,v_1v,v_100mv;           		
        vo = volt*19.6;     		              
		v_10v = vo/10000; 				   //10伏显示位
		v_1v = vo/1000%10; 				   //1伏显示位
        v_100mv = vo/100%10;               //100毫伏显示位      

        lcd_write_com(0x80+0x40+0x05);     
        lcd_write_data(table[v_10v]);  
		lcd_write_data(table[v_1v]);  
		lcd_write_data('.');		                 
		lcd_write_data(table[v_100mv]);                                                                                 
        lcd_write_data('V');               
		lcd_write_data(' ');
	    lcd_write_data(' ');
		lcd_write_data(' ');
		lcd_write_data(' ');
		lcd_write_data(' ');
}

void display3()							  //报警时的显示
{
	   lcd_write_com(0x01);
	   lcd_show_string1("      QAQ      ");
	   delayMS(50);
	   lcd_show_string2("   Ooooooops   ");
	   delayMS(50);
}

/***************************函数功能:报警********************************/
void alarm()
{	
     	int i;   	
    	display3();				//调用报警时的显示
    	for(i=0;i<100;i++) 
    	{
            led=1;              //控制发光二极管D2闪烁,发出光报警信号
            buzzer=~buzzer;     //控制蜂鸣器发声,发出声音报警信号
	    	delayMS(1);
    		led=0;
	    	buzzer=~buzzer;   
	    	delayMS(1);
    	}
}

/********************函数功能:选择量程 15V or 5V 并测量电压************************/
void range()
{
        if((SW1==0)&&(SW2!=0))			   	        //按下SW1
		{		      
			 lcd_show_string(0x06,"0~5V     ");		//LCD1602显示->量程5V
			 lcd_show_string1("Range:");	    	//LCD1602显示->第一行为Range: 
		     lcd_show_string2("Volt:");	            //LCD1602显示->第二行为Volt:
			 addr_a=0;
             addr_b=0;
             addr_c=0;
			 ADC();			                        //调用模数转换程序
			 if(volt>=0xFF)                         //当大于5v时,使用LED和蜂鸣器报警
               { alarm(); }
			 else                                   //否则取消报警
             {
                led=0;                              //控制发光二极管D2灭
                buzzer=0;                           //控制蜂鸣器不发声
				display1();                         //调用显示程序1
		 	 }
		} 
		else if((SW1!=0)&&(SW2==0))		            //按下SW2
		{
			 lcd_show_string(0x06,"0~15V        ");	//LCD1602显示->量程15V
			 lcd_show_string1("Range:");		    //LCD1602显示->第一行 
		     lcd_show_string2("Volt:");	            //LCD1602显示->第二行
			 addr_a=1;
             addr_b=0;
             addr_c=0;
			 ADC();	
			 volt=3*volt;		 					//转换的值*3,变为15v范围
			 if(volt>=0x2FD)                        //当大于15v时,使用LED和蜂鸣器报警
               { 
			        alarm(); 
			   }
			 else                                   //否则取消报警
             {
                led=0;                              //控制发光二极管D2灭
                buzzer=0;                           //控制蜂鸣器不发声					
				display2();                         //调用显示程序2
		 	 }
		} 
		else if((SW1==0)&&(SW2==0))		            //同时按下SW1、SW2的误操作,报警
		{     										
		     alarm();			 
		 }
		else 
		{											//SW1、SW2均未按下,提示选择量程
			 lcd_show_string1(" Choose   range ");	 
			 delayMS(1);
		     lcd_show_string2("   5V  or  15V  ");	
			 delayMS(1);
		}
}

/***************************函数功能:主程序********************************/
void main(void)
{   	 
        TMOD=0x01;                   //设定定时计数工作方式	                   
    	TH0=0XFF;				     //为定时器初赋值
        TL0=0XB4;	
		EA=1;                        //开总中断				 
    	ET0=1;                       //开定时器0中断 
    	TR0=1;                       //开启定时器0 
		led=0;
		buzzer=0;
		init_lcd();					 //LCD1602初始化函数
		while(1) 
		{	    
		     range(); 				    	       			       
		}
}

/**************************函数功能:定时器0时钟信号*************************/
void timer() interrupt 1
{
	    TH0=0XFF;			//初值重置
        TL0=0XF0;
	    CLK=~CLK;           //取反 产生时钟信号
}

你可能感兴趣的:(C51单片机,编程语言)