`
海王子1994
  • 浏览: 45202 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

基于ADuC848的智能电压监视仪

 
阅读更多

设计一个智能电压监视仪;电网电压的信号可用变压器从市电上取得,也可用+5V的电位器模拟。

要求:

1)显示内容:电压当前值;最大电压值;最小电压值;电压合格率;超上限率;超下限率;电压上、下限给定值、当前时间

2)利用小键盘实现电压上、下限给定值的输入和显示选择命令

3)电压采样周期为1秒,平均值的计算周期为2分钟,所求得的电压平均值作为统计和计算的依据,统计和计算以一天为单位,超过24小时则从头开始统计计算

4)超上限率=(其中超上限的次数)/(采样计算得到的总的电压平均值次数)*100%;超下限率的计算公式与此类似

5)合格率=1-超上限率-超下限率

6)显示北京时间,可调整

7)当前电压超上限或下限时,利用蜂鸣器报警

 

以上就是该电压监视仪的功能,然后我们根据要求分析需要使用板子上的哪些模块。

 

1)电源模块(不需要编写代码)

2)显示模块(采用LCD1602)

3)键盘模块(采用行列式扫描)

4)蜂鸣器

5)时钟模块(采用DS1307,能掉电后继续计时;若采用定时器,则掉电后重新计时)

6)AD模块(ADuC848有内置AD,没有专门的AD转换芯片)

 

下面就根据各模块逐步讲解代码:

 

显示模块:

 

 

#include <lcd1602.h>

//延时函数	
void lcd_delay(uint t)
{
	while(--t);
}
//检测忙信号
void Check_Busy(void)
{
	P0 = 0xff;      //P0口作为输入
	lcd_delay(50);
	rs = 0;
	rw = 1;
	e = 1;
	lcd_delay(50);
	while(P0&0X80);
	e = 0;
	rw = 0;	
	P0 = 0X00;
} 
//lcd写指令
void lcd_wc(uchar cmd)
{
   Check_Busy();
	rs=0;
	rw=0;
	e=1;
	P0=cmd;
	lcd_delay(3);
	e=0;
	lcd_delay(65535);
	lcd_delay(65535);
}
//lcd写数据
void lcd_wd(uchar dat)
{
	Check_Busy();
	rs=1;
	rw=0;
	e=1;
	P0=dat;
	lcd_delay(3);
	e=0;
	lcd_delay(250);
}

//显示位置
void lcd_pos(uchar pos )
{
   	pos+=0x80;
	lcd_wc(pos);
} 

 //lcd初始化
void lcd_init()
{
    uchar code table[]={"Voltage Monitor"};
	uint i=0;

	lcd_delay(60000);
	lcd_delay(60000);
	lcd_delay(60000);
	lcd_delay(60000);
	lcd_wc(0x38);
	lcd_delay(60000);
	lcd_delay(60000);
	lcd_wc(0x38);
	lcd_delay(60000);
	lcd_delay(60000);
	lcd_wc(0x38);
	lcd_delay(60000);
	lcd_delay(60000);
	lcd_wc(0x38);		//设置16x2显示,5x7点阵,8位数据接口
	lcd_wc(0x0c);		//开显示,不显示光标
	lcd_wc(0x06);		//地址指针加1,且光标加1,整屏显示不移动
	lcd_wc(0x01);		//清屏
//	lcd_wc(0x0f);     //显示开关

	 
	 lcd_pos(0);	 
	 while(table[i]!='\0')
	{    
	   lcd_wd(table[i]);
	   i++;
	}					
	 	
}

 

 

 

 

 

 

 

这里需要注意三个函数:lcd_init()、lcd_wc()、lcd_wd()。

 

lcd_init()是lcd1602的初始化函数,就是设置几行显示、是否显示光标、文字是否滚动。在主函数刚开始就需要调用,后面就不再需要。

 

lcd_wc()是写命令函数,可以写清屏等命令,或者要将字符写在显示屏的位置。举例来说,液晶显示屏的第一行初始位置是0x80,第二行初始位置是0xc0,若你想在第一行起始位置输入一个字符,就要调用lcd_wc(0x80);之后的位置逐渐+1既是。

 



 

 

1602液晶模块的读写操作、屏幕和光标的操作都是通过指令编程来实现的。(说明:1为高电平、0为低电平)

 

指令1:清显示,指令码01H,光标复位到地址00H位置。

 

指令2:光标复位,光标返回到地址00H

 

指令3:光标和显示模式设置 I/D:光标移动方向,高电平右移,低电平左移 S:屏幕上所有文字是否左移或者右移。高电平表示有效,低电平则无效。

 

指令4:显示开关控制。 D:控制整体显示的开与关,高电平表示开显示,低电平表示关显示 C:控制光标的开与关,高电平表示有光标,低电平表示无光标 B:控制光标是否闪烁,高电平闪烁,低电平不闪烁。

 

指令5:光标或显示移位 S/C:高电平时移动显示的文字,低电平时移动光标。

 

指令6:功能设置命令 DL:高电平时为4位总线,低电平时为8位总线 N:低电平时为单行显示,高电平时双行显示 F: 低电平时显示5x7的点阵字符,高电平时显示5x10的点阵字符。

 

指令7:字符发生器RAM地址设置。

 

指令8DDRAM地址设置。

 

指令9:读忙信号和光标地址 BF:为忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙。

 

指令10:写数据。

 

 

 

指令11:读数据。

 

 

 

 

 

lcd_wd()是写数据函数,就是你要显示的内容。它是和写命令函数共同使用的。一般一句写命令跟一句写数据,但也有一句写命令跟多句写数据(通过数组实现)。

 

例:代码红色部分,lcd_pos(0)表示显示屏最初始位置。

 

----------------------------------------------------------------------------------------------

DS1307模块(显示北京时间)

 

DS1307模块要用DS1307时钟芯片,想要具体了解可以查看该芯片使用说明书,这里就不详谈了。直接给出所有需要调用的函数。

 

#include<DS1307.h>
//#include<LCD1602.h>

    //#define uchar unsigned char
    //#define uint  unsigned int

void iic_delay_4us()
{
	uchar t=25+5;	//适当增加延时,保证信号
	while(--t);
}

void iic_delay_5us()
{
	uchar t=32+5;
	while(--t);
}

void iic_init()
{
	I2CM=1;		//master模式
	MDE=1;
	MCO=0;		//允许SDA改变
	MDO=1;		//释放SDA
}

void iic_start()
{
	MDE=1;			//允许输出
	MCO=0;			//时钟拉低,允许数据线改变
	MDO=0;			//下面在数据线上产生一个脉冲
	MCO=1;			//制造起始条件
	iic_delay_4us();//等待稳定
	MDO=1;			//上升			
	iic_delay_5us();//等待稳定
	MDO=0;			//拉低数据线,产生起始信号
	iic_delay_4us();//等待稳定
	MCO=0;			//时钟拉低,开始
}

void iic_stop()
{
	MDE=1;			//允许输出
	MCO=0;
	MDO=0;
	MCO=1;
	iic_delay_4us();
	MDO=1;
	iic_delay_5us();
//	MDO=0;			//中止后应该释放数据线
}
//1307读入位数据
void iic_write_bit(bit dat)
{
	MDE=1;
	MCO=0;
	MDO=dat;
	iic_delay_4us();
	MCO=1;
	iic_delay_4us();
	MCO=0;
	iic_delay_4us();
}
//1307写出,输出1307发送出的位数据
bit iic_read_bit()
{
	bit dat;
	MDE=1;
	MCO=0;
	MDO=1;	//释放数据线
	MDE=0;
	iic_delay_4us();
	MCO=1;
	iic_delay_4us();
	dat=MDI;
	MCO=0;
	iic_delay_4us();
	return dat;
}
 //判断1307写出是否有效,即从机是否接受,输出应答信号。该信号为低,则表明有效
bit iic_write_char(uchar dat)
{
	uchar i;
	bit res;
	for(i=0;i<8;i++)
	{
		iic_write_bit((dat>>(7-i))&0x01);
	}
	res=iic_read_bit();	
	return res;
}
 //读入1307,输出写入的字符数据
uchar iic_read_char(bit nack)
{
	uchar dat=0,i;
	for(i=0;i<8;i++)
	{
		dat<<=1;
		if(iic_read_bit()==1)dat++;
	}
	iic_write_bit(nack);
	return dat;
}
 //判断写地址是否有效
bit iic_write_address(uchar id,uchar address)
{
	iic_start();
	if(iic_write_char(id)!=0)return 1;
	if(iic_write_char(address)!=0)return 1;
	return 0;
}


 

 

 

----------------------------------------------------------------------------------------------

AD模块

 

ADuC848中包含一个双通道16ADC模块,该开发板采用内部参考电压,因此使用ADC模块时只需配置相关寄存器,AD转换完成时即可读取转换值。

 

AD流程图

 

#include <lcd1602.h>
#include <AD.h>

#define v_count 9
#define a_count 3

unsigned char InterruptCounter=0;//定义中断计数变量并赋初值0 
unsigned int count=0;//定义秒计数变量并赋初值0
unsigned int count1=0;

 unsigned int max,min;//电压最大、最小值
 unsigned int CurrentValue;//电压当前值
 unsigned int qual_rate,overup_rate,overlow_rate;//电压上、下限值、合格率、超上限率、超下限率
unsigned int upper_limit=20000;
unsigned int lower_limit=0;
bit bz_flag;//设标志位,区分对象是电压值还是百分比,输出“V”还是“%”
unsigned int Fir_bit,Sec_bit,Thi_bit,Fou_bit; //电压位 


unsigned int num=0,num1=0;	 //num为电压采样周期内总计数,num1为平均值计算周期内总计数
unsigned int num_up=0,num_low=0;  //num_up为超上限次数,num_low为超下限次数
unsigned int sum=0;					  //sum为电压采样周期内电压总数和

unsigned int  value[v_count];	//取样电压值数组,存放一个平均值计算周期内的每秒电压值
unsigned int   average[a_count];	//平均值数组,存放平均值





 
void Init()
{
	
	ADCMODE = 0X23;   //一直转换  /CHOP使能
	ADC0CON1 = 0x27;   //主ADC选用放大1倍,单端输入,1.28V
	ADC0CON2 = 0x0C;   //选用内部参考电源,模拟信号从AIN5 AIN6输入
		
 /*
	TMOD=0x01;
	TH0=(65536-50000)/256;
	TL0=(65536-50000)%256;
	EA=1;
	ET0=1;
	TR0=1;	  */
	TMOD=0x01;//配置定时器0为16位模式,时钟是core clock,默认为1.572864MHz
    IE=0x82;//使能定时器0中断和全局中断
    TH0=0X00;
    TL0=0X00;
    TR0=1;//开启定时器0

}
void Data_Process(unsigned char ad)
{
   	
	unsigned int w;   	
				
	 
	if(RDY0)
	{
	   
		   	   CurrentValue=((ADC0H*256)+ADC0M)*0.1953125;
			 //  CurrentValue=1000;
		
			  
			   value[num] = ((ADC0H*256)+ADC0M)*0.1953125;

			   max=value[0];
			   min=value[0];

			   //求最大、小值
			   for(w=1;w<num;w++)
			   {
			      if(value[w-1]>value[w])
				  {
				     value[w]=value[w-1];
				  }
				  else
				  {
				     max=value[w];
				  }

				  if(value[w-1]<value[w])
				  {
				     value[w]=value[w-1];
				  }
				  else
				  {
				     min=value[w];
				  }
			   }	
								  
			   	sum+=value[num];//求电压采样周期内电压总和		  
				   
				average[num1]=sum/v_count;     //取计算周期内所有采样电压值总和的平均值 
				   
			 
			   //计算上、下限率
			   overup_rate=(num_up/num1)*100;
			   overlow_rate=num_low/num1*100;  
			   qual_rate=100*(1-overup_rate/100-overlow_rate/100);
			   			   	  			  
			   	   		   
			   //当超过上下限值时,蜂鸣器鸣响报警
			  if(CurrentValue>upper_limit||CurrentValue<lower_limit)
			  {
			  	 	beep=0;delay_beep(10);
					beep=1;delay_beep(10);
			  }
			   
			 		
   	   //选择显示对应AD标号电压值或比率
	   switch(ad)
	   {
	      case 1:	 	AD_display(CurrentValue);
						break;
		  case 2:	 	AD_display(max);						
		                break;
		  case 3:	 	AD_display(min); 						
		                break;
		  case 4:	 	AD_display(qual_rate);						
		                break;
		  case 5:	 	AD_display(overup_rate);
		                break;
		  case 6:	 	AD_display(overlow_rate);
		                break;
		  case 7:	 	AD_display(upper_limit);
		                break;
		  case 8:	 	AD_display(lower_limit);
		                break;	 	   
	   
	   }
	   				 

	    RDY0 = 0;
    }		
}

void delay_beep(unsigned int z)
{
     unsigned int x,y;
	for(x=z;x>0;x--)
	{
		for(y=100;y>0;y--);
	}
}



//定时器中断
void timer0() interrupt 1
{

  unsigned int k;
  
	InterruptCounter++;
    if(InterruptCounter>=24*8)
    {
        InterruptCounter=0;
        count++;
		num++;
		//1秒采样一个电压
	    if(count>1)
		{
		  count=0;
		}
		//每一个采样周期获得一个平均值
		if(num==v_count)
		{
		  num1++;
		  num=0;
		  sum=0;
		  //一个采样周期后采样电压值清零,重新存储
		  for(k=0;k<v_count;k++)
		  {
		    value[k]=0;
		  }
		}			

		//判断电压是否超上下限
	           for(k=0;k<num1;k++)
			   {
			   	 if(average[k]>upper_limit&&num_up<a_count)
				 {
				   num_up++;
				 }
				 if(average[k]<lower_limit&&num_low<a_count)
				 {
				 	num_low++;
				 }
			   }

		  //一个计算周期后清零重置
		if(num1==a_count)
		{
		   num1=0;
		   num=0;
		   num_up=0;
		   num_low=0;

		   for(k=0;k<a_count;k++)
		   {
		     average[k]=0;
		   }
		}
    }

}

//将电压数据或者比率显示在lcd上
void AD_display(unsigned int d)
{
   
  if(RDY0)
  {				 	

	  if(bz_flag==0)
	  {

		Fir_bit = d/10000;		 		
		Sec_bit = d/1000%10;
		Thi_bit = d/100%10;
		Fou_bit = d/10%10;	 

		lcd_pos(lcd_next);	//向液晶写指令
		lcd_wd(0x30+Fir_bit);	   
		lcd_wd(0x2e);	//向液晶写'.'
		lcd_wd(0x30+Sec_bit);
		lcd_wd(0x30+Thi_bit);
		lcd_wd(0x30+Fou_bit);	
		lcd_wd(0x56);	//向液晶写'V'
	  }
				  
	else
	  {  
		d*=100;

	  	Fir_bit = d/1000;		 		
		Sec_bit = d/100%10;
		Thi_bit = d/10%10;
		Fou_bit = d%10;

		if(Fir_bit>9)
		{
		  Fir_bit=9;
		}
	    
	    lcd_pos(lcd_next);	//向液晶写指令
		lcd_wd(0x30+Fir_bit); 		
		lcd_wd(0x30+Sec_bit);
		lcd_wd(0x2e);	//向液晶写'.'
		lcd_wd(0x30+Thi_bit);
		lcd_wd(0x30+Fou_bit);	
		lcd_wd(0x25);//向液晶写'%'
				  
	  }
/*
	  if(bz_flag==1)
	  {
	      d*=100;

	  	Fir_bit = d/1000;		 		
		Sec_bit = d/100%10;
		Thi_bit = d/10%10;
		Fou_bit = d%10;
	    
	    lcd_pos(lcd_next);	//向液晶写指令
		lcd_wd(0x30+Fir_bit); 		
		lcd_wd(0x30+Sec_bit);		
		lcd_wd(0x30+Thi_bit);
		lcd_wd(0x2e);	//向液晶写'.'
		lcd_wd(0x30+Fou_bit);	
		lcd_wd(0x25);//向液晶写'%'
	  
	  }					*/

		RDY0=0;
	}
}
//加压
void tiaoya_add(unsigned char temp)
{
  	
	Fir_bit++;
   
	if(Fir_bit>9)
	{
	  Fir_bit=0; 
	 
	}

	lcd_wc(0xc0);
	lcd_wd(0x30+Fir_bit);
	lcd_wc(0xc0);
	
	if(temp==1)
	{
	   upper_limit=Fir_bit*10000;	 
	}
	if(temp==2)
	{
	   lower_limit=Fir_bit*10000;
	}	
}

//减压
void tiaoya_sub(unsigned char temp)
{
  	
	if(Fir_bit==0)
	{
	  Fir_bit=10;
	}

	Fir_bit--;	   
	
	lcd_wc(0xc0);
	lcd_wd(0x30+Fir_bit);
	lcd_wc(0xc0);
	
	if(temp==1)
	{
	   upper_limit=Fir_bit*10000;	 
	}
	if(temp==2)
	{
	   lower_limit=Fir_bit*10000;
	}	
}
//设定标志位区分电压值或者比率
void  setbz_flag(bit nack)
{
   bz_flag=nack;
}

 

 

 

红色部分就是修改寄存器的操作。

 

-----------------------------------------------------------------------------------------------

 

键盘模块

 

首先先谈下键盘扫描的原理:

 

矩阵键盘两端都与单片机I/O口相连,因此在检测时需通过单片机一端的I/O口人为产生低电平。检测时,先使第一列为低电平,其余几列全为高电平,然后检测各行是否有低电平,若检测到第一行为低电平,则可确认第一行第一列的按键被按下。用同样的方法轮流送各列一次低电平,再轮流检测一次各行是否变为低电平,这样即可检测完所有的按键,当有键被按下时便可判断出按下的键是哪一个键,然后根据返回的键值取相应的数码管段码。

 

键盘流程图如下:



 

然后我们开始设计下各键盘按钮的作用,在此之前我们再明确下要实现的功能。

 

具体功能如下

 

功能一:显示当前电压值。

功能二:显示最大电压值。

功能三:显示最小电压值。

功能四:显示电压合格率。

        电压合格率=1-超上线率-超下限率

功能五:显示电压上限率。

电压上限率=超上限率=(其中超上限的次数)/(采样计算得到的总的电压平均值次数)*100%

功能六:显示电压下限率。

电压下限率=超下限率=(其中超下限的次数)/(采样计算得到的总的电压平均值次数)*100%

功能七:显示电压上限值。

功能八:显示电压下限值。

功能九:显示当前北京时间。

功能十:若当前电压超上限或下限时,蜂鸣器会报警。

 

 

然后再分析下操作:

 

 

首先给键盘各按钮标号如下:

 

 0    1   2   3

 4    5   6   7  

8    9   A   B

C    D    E   F

 

各按钮功能:

 

0:显示当前电压值。

1:显示最大电压值。

2:显示最小电压值。

3:显示电压合格率。

4:显示电压上限率。

5:显示电压下限率。

6:显示电压上限值。

7:显示电压下限值。

8:显示当前北京时间。

9:调整时间,光标闪烁,按一下,光标右移一位;

   调整电压值,光标在电压初始位闪烁。

A:光标所在的时间位的数值加1,到了最大限值后则又从最小限值开始。

B:光标所在的时间位的数值减1,到了最小限值后则又从最大限值开始。

C:确认调整时间完毕。

D:调整电压值,光标所在位的数值加1,到了最大限值后则又从最小限值开始。

E:调整电压值,光标所在位的数值减1,到了最小限值后则又从最大限值开始。

F:确认调整电压完毕。

 

分析完各按钮的功能后,我们就可以开始编写键盘模块的程序了,如下:

 

#include<AD.h>
#include<table.h>
#include<lcd1602.h>
#include<jianpan.h>
#include<DS1307.h>
#include<main.h>

idata uchar id;	           //跳出显示时间界面的标志量,id=0,跳出;否则,继续显示。
idata uchar kcount=0; 	   //按键次数量,亦即光标显示位置的标志量
idata uchar kcount1;	   //当与kcount相等时,说明没按下光标移动键	
uchar ad_flag=0;           //设置上下限值的标志量,上限值对应1,下限值对应2,其他值对应3
bit tflag=0;               //改动时间标志,tflag=1时能改动时间,tflag=0时锁存时间,禁止改动。
uchar ad=0;                //AD显示物理量标志号,各AD物理量对应不同标志号,如当前电压值为1,最大值为2,最小值为3......
      

void delay()         //延时函数
{
	uchar i;
	for(i = 0;i < 100;i++);
}


//光标移动
void move()
{
   if(tflag)
   {

		   if(ad_flag==0) //调节时间时光标移动情况
		   {
				   //超过范围则光标复位
				   if(kcount>16)
				   {
				     kcount=1;
				   }
				   //遇到非数字符号调到下一位有效位
				   if(kcount==3||kcount==6||kcount==11||kcount==14)
				   {
				     kcount++;
				   }    
				
				   lcd_wc(0x0f);//光标显示并闪烁
				
				   //光标闪烁位置
				   if(kcount>8)
				   {
				     lcd_wc(0xC0+kcount-9);	    //当kcount大于8时,光标从第二行开始闪烁
				   }
				   else 
				   {
				     lcd_wc(0x80+kcount-1);	    //当kcount小于8时,光标从第一行开始闪烁
				   }	
				
				  //当不再按键时,光标停留在原位上
				   kcount1=kcount;
				   delay();   
				   while(kcount==kcount1)
				   {
				   	  Keyscan();
				   }
		   }
		   if(ad_flag==1||ad_flag==2)   //调节电压上、下限值时光标移动情况
		   {
				lcd_wc(0x0f);//光标显示并闪烁
		        lcd_wc(0xC0);
		   }  
  } 

  tflag=0;

}


//lcd屏幕显示
void lcd_display(uchar key)
{    
   switch(key)
   {
     case 1:   //当前电压值
		        Check_Busy();
				lcd_wc(lcd_clear);			
				gettable1();
				id=0;
				ad_flag=3;
				setbz_flag(0);
			 
				while(ad)
				{
				  
				  Data_Process(ad);
				  Keyscan();
				}
				
		
				break;
	 case 2:    //最大电压值
		        Check_Busy();
				lcd_wc(lcd_clear);			
				gettable2();
				id=0;
				ad_flag=3;
				setbz_flag(0);
				while(ad)
				{
				  Data_Process(ad);
				  Keyscan();
				}
		
				break;	 
   	 case 3:	//最小电压值
	            Check_Busy();
				lcd_wc(lcd_clear);			
				gettable3();
				id=0;
				ad_flag=3;
				setbz_flag(0);
				while(ad)
				{
				  Data_Process(ad);
				  Keyscan();
				}
		
				break;
	 case 4:	//电压合格率
	            Check_Busy();
				lcd_wc(lcd_clear);			
				gettable4();
				id=0;
				ad_flag=3;
				setbz_flag(1);
				while(ad)
				{
				  Data_Process(ad);
				  Keyscan();
				}
		
				break;
	 case 5:	//超上限率
	            Check_Busy();
				lcd_wc(lcd_clear);			
				gettable5();
				id=0;
				ad_flag=3;
				setbz_flag(2);
				while(ad)
				{
				  Data_Process(ad);
				  Keyscan();
				}
		
				break;
	 case 6:   //超下限率
	            Check_Busy();
				lcd_wc(lcd_clear);			
				gettable6();
				id=0;
				ad_flag=3;
				setbz_flag(3);
				while(ad)
				{
				  Data_Process(ad);
				  Keyscan();
				}
	
				break;
	 case 7:	//电压上限值
	            Check_Busy();
				lcd_wc(lcd_clear);			
				gettable7();
				id=0;
				ad_flag=1;
				tflag=1;
				setbz_flag(0);
				while(ad)
				{
				  Data_Process(ad);
				  Keyscan();
				}
				break;
     case 8:	//电压下限值				 
	            Check_Busy();
				lcd_wc(lcd_clear);			
				gettable8();
				id=0;
				ad_flag=2;
				tflag=1;
				setbz_flag(0);
				while(ad)
				{
				  Data_Process(ad);
				  Keyscan();
				}
				break;
	 case 9:	//显示时间
	            Check_Busy();
				lcd_wc(lcd_clear);
				id=1;
				ad_flag=0;	
				tflag=1;		
	            display(); 				
				break;
	
	 case 10:	//确认
	    		
	            Check_Busy(); 		
				id=1;	
	            makeSure();
				break; 	 

 }



  
} 

//键盘扫描
void Keyscan()
{	    
	unsigned char temp;
	unsigned int j=0;  
		
	P1&=0xf0;      //P1口低四位作为数字输入时应往相应引脚写0
	P2&=0xf0;      //置列扫描信号为0
	temp=P1&0x0f;
    if(temp!=0x0f)   //P1口低四位不全为1,则有键被按下
    {
    	delay();	   //延时消抖
    	if(temp==(P1&0x0f))	  //消抖后再判断键值
    	{
			P2|=0x07;          //P2.3为0
			switch(P1&0x0f)
			{
				case 0x0e://显示电压当前值
				            ad=1;
				            lcd_display(1);
							break;
				case 0x0d:	//显示超上限率
							ad=5;
				            lcd_display(5);							
							break;
				case 0x0b:	//当前时间
							ad=0;
				           lcd_display(9);						   			            
							break;
				case 0x07:	//确认 	
							ad=0;          
						   lcd_display(10);						   
				           break;
				case 0x0f:break;
				default:break;
			}
			P2&=0xf0; 

		    P2|=0x0b;           //P2.2为0
			switch(P1&0x0f)
			{
				case 0x0e: //显示最大电压值
						   ad=2;
						   lcd_display(2);				           						   
						   break;
				case 0x0d://显示超下限率
						   ad=6;
				           lcd_display(6);						   
						   break;
				case 0x0b: //光标移动
							ad=0;
				            kcount++;
						
						    move();									           
				            break;
				case 0x07://增加电压值
						  ad=0;
				          tiaoya_add(ad_flag);
				           break;
				case 0x0f:break;
				default:break;
			}
			P2&=0xf0;

		    P2|=0x0d;            //P2.1为0
			switch(P1&0x0f)
			{
				case 0x0e://显示最小电压值
							ad=3;
                           	lcd_display(3);					   
						    break;
				case 0x0d: //电压上限给定值
						   ad=7;
				           lcd_display(7);
				           break;
				case 0x0b: //加光标所在位置的数值
						   ad=0;
				           addValue(kcount);
				           break;
				case 0x07:
				          //减小电压值
						  ad=0;
						  tiaoya_sub(ad_flag);
				          break;
				case 0x0f:break;
				default:break;
			}
			P2&=0xf0;

		    P2|=0x0e;            //P2.0为0
			switch(P1&0x0f)
			{
				case 0x0e://显示电压合格率
							ad=4;
				            lcd_display(4);					    
							break;
				case 0x0d: //电压下限给定值	
							ad=8;			
				            lcd_display(8);
				            break;
				case 0x0b: //减光标所在位置的数值
							ad=0;
				           subValue(kcount);				           
				           break;
				case 0x07: //电压调整完毕
						   ad=0;
						   lcd_wc(0x0c);
				           break;
				case 0x0f:break;
				default:break;
			}

		}
	}
	  
	  
} 

/*
uchar getk()
{
  return kcount;
} 	 */
//设置按键次数量,主要负责清零重置
void setk(uchar count)
{
	kcount=count;
}
//获得跳出显示时间界面的标志量
uchar getid()
{
  	return id;
}
//获得设置上下限值的标志量
uchar getad_flag()
{
    return ad_flag;
} 
//获得AD显示物理量标志号
uchar getad()
{
    return ad;
}

 ----------------------------------------------------------------------------------------------

 

 

 输出各物理量名的模块

#include<AD.h>
#include<lcd1602.h>	
#include<table.h> 

//当前电压值
void gettable1()
{
            lcd_pos(0);
			lcd_wd(0x43);
			lcd_pos(0x01);
		    lcd_wd(0x75);
			lcd_pos(0x02);
			lcd_wd(0x72);
			lcd_pos(0x03);
			lcd_wd(0x72);
			lcd_pos(0x04);
			lcd_wd(0x65);
			lcd_pos(0x05);
			lcd_wd(0x6E);
			lcd_pos(0x06);
			lcd_wd(0x74);

			lcd_pos(0x07);
			lcd_wd(0x20);

			lcd_pos(0x08);
			lcd_wd(0x56);
			lcd_pos(0x09);
			lcd_wd(0x6F);
			lcd_pos(0x0A);
			lcd_wd(0x6C);
			lcd_pos(0x0B);
			lcd_wd(0x74);
			lcd_pos(0x0C);
			lcd_wd(0x61);
			lcd_pos(0x0D);
			lcd_wd(0x67);
			lcd_pos(0x0E);
			lcd_wd(0x65);
			lcd_pos(0x0F);
			lcd_wd(0x3A);

			lcd_pos(lcd_next);
	
        	

} 

//最大电压值
void gettable2()
{
            lcd_pos(0);
			lcd_wd(0x4D);
			lcd_pos(0x01);
		    lcd_wd(0x61);
			lcd_pos(0x02);
			lcd_wd(0x78);
			
			

			lcd_pos(0x03);
			lcd_wd(0x20);

			lcd_pos(0x04);
			lcd_wd(0x56);
			lcd_pos(0x05);
			lcd_wd(0x6F);
			lcd_pos(0x06);
			lcd_wd(0x6C);
			lcd_pos(0x07);
			lcd_wd(0x74);
			lcd_pos(0x08);
			lcd_wd(0x61);
			lcd_pos(0x09);
			lcd_wd(0x67);
			lcd_pos(0x0A);
			lcd_wd(0x65);

			lcd_pos(0x0B);
			lcd_wd(0x3A);

			lcd_pos(lcd_next);
	


}
//最小电压值
void gettable3()
{		
			lcd_pos(0);
			lcd_wd(0x4D);
			lcd_pos(0x01);
		    lcd_wd(0x69);
			lcd_pos(0x02);
			lcd_wd(0x6E);
			
			lcd_pos(0x03);
			lcd_wd(0x20);

			lcd_pos(0x04);
			lcd_wd(0x56);
			lcd_pos(0x05);
			lcd_wd(0x6F);
			lcd_pos(0x06);
			lcd_wd(0x6C);
			lcd_pos(0x07);
			lcd_wd(0x74);
			lcd_pos(0x08);
			lcd_wd(0x61);
			lcd_pos(0x09);
			lcd_wd(0x67);
			lcd_pos(0x0A);
			lcd_wd(0x65);

			lcd_pos(0x0B);
			lcd_wd(0x3A);

			lcd_pos(lcd_next);
	
		    
}

//电压合格率"Quality Rate"
void gettable4()
{
            lcd_pos(0);
			lcd_wd(0x51);
			lcd_pos(0x01);
		    lcd_wd(0x75);
			lcd_pos(0x02);
			lcd_wd(0x61);
			lcd_pos(0x03);
			lcd_wd(0x6C);
			lcd_pos(0x04);
			lcd_wd(0x69);
			lcd_pos(0x05);
			lcd_wd(0x74);
			lcd_pos(0x06);
			lcd_wd(0x79);
			
			
			lcd_pos(0x07);
			lcd_wd(0x20);

			

			lcd_pos(0x08);
			lcd_wd(0x52);
			lcd_pos(0x09);
			lcd_wd(0x61);
			lcd_pos(0x0A);
			lcd_wd(0x74);
			lcd_pos(0x0B);
			lcd_wd(0x65);

			lcd_pos(0x0C);
			lcd_wd(0x3A);

			lcd_pos(lcd_next);

	        		
}

//超上限率"Upper Limit Rate "
void gettable5()
{
			lcd_pos(0);
			lcd_wd(0x55);
			lcd_pos(0x01);
		    lcd_wd(0x70);
			lcd_pos(0x02);
			lcd_wd(0x70);
			lcd_pos(0x03);
			lcd_wd(0x65);
			lcd_pos(0x04);
			lcd_wd(0x72);
					
			
			lcd_pos(0x05);
			lcd_wd(0x20);

			lcd_pos(0x06);
			lcd_wd(0x4C);
			lcd_pos(0x07);
			lcd_wd(0x69);
			lcd_pos(0x08);
			lcd_wd(0x6D);
			lcd_pos(0x09);
			lcd_wd(0x69);
			lcd_pos(0x0A);
			lcd_wd(0x74);

			lcd_pos(0x0B);
			lcd_wd(0x20);

			lcd_pos(0x0C);
			lcd_wd(0x52);
			lcd_pos(0x0D);
			lcd_wd(0x61);
			lcd_pos(0x0E);
			lcd_wd(0x74);
			lcd_pos(0x0F);
			lcd_wd(0x65);
						

			lcd_pos(lcd_next);
		
}
 
//超下限率"Lower Limit Rate"
void gettable6()  
{
			lcd_pos(0);
			lcd_wd(0x4C);
			lcd_pos(0x01);
		    lcd_wd(0x6F);
			lcd_pos(0x02);
			lcd_wd(0x77);
			lcd_pos(0x03);
			lcd_wd(0x65);
			lcd_pos(0x04);
			lcd_wd(0x72);
					
			
			lcd_pos(0x05);
			lcd_wd(0x20);

			lcd_pos(0x06);
			lcd_wd(0x4C);
			lcd_pos(0x07);
			lcd_wd(0x69);
			lcd_pos(0x08);
			lcd_wd(0x6D);
			lcd_pos(0x09);
			lcd_wd(0x69);
			lcd_pos(0x0A);
			lcd_wd(0x74);

			lcd_pos(0x0B);
			lcd_wd(0x20);

			lcd_pos(0x0C);
			lcd_wd(0x52);
			lcd_pos(0x0D);
			lcd_wd(0x61);
			lcd_pos(0x0E);
			lcd_wd(0x74);
			lcd_pos(0x0F);
			lcd_wd(0x65);
						

			lcd_pos(lcd_next);

} 


//"Upper Limit"
void gettable7()   
{
			lcd_pos(0);
			lcd_wd(0x55);
			lcd_pos(0x01);
		    lcd_wd(0x70);
			lcd_pos(0x02);
			lcd_wd(0x70);
			lcd_pos(0x03);
			lcd_wd(0x65);
			lcd_pos(0x04);
			lcd_wd(0x72);
					
			
			lcd_pos(0x05);
			lcd_wd(0x20);

			lcd_pos(0x06);
			lcd_wd(0x4C);
			lcd_pos(0x07);
			lcd_wd(0x69);
			lcd_pos(0x08);
			lcd_wd(0x6D);
			lcd_pos(0x09);
			lcd_wd(0x69);
			lcd_pos(0x0A);
			lcd_wd(0x74);

			
			lcd_pos(0x0B);
			lcd_wd(0x3A);

			lcd_pos(lcd_next);
	
} 

//超下限值"Lower Limit"
void gettable8()  
{
			lcd_pos(0);
			lcd_wd(0x4C);
			lcd_pos(0x01);
		    lcd_wd(0x6F);
			lcd_pos(0x02);
			lcd_wd(0x77);
			lcd_pos(0x03);
			lcd_wd(0x65);
			lcd_pos(0x04);
			lcd_wd(0x72);
					
			
			lcd_pos(0x05);
			lcd_wd(0x20);

			lcd_pos(0x06);
			lcd_wd(0x4C);
			lcd_pos(0x07);
			lcd_wd(0x69);
			lcd_pos(0x08);
			lcd_wd(0x6D);
			lcd_pos(0x09);
			lcd_wd(0x69);
			lcd_pos(0x0A);
			lcd_wd(0x74); 
			
			lcd_pos(0x0B);
			lcd_wd(0x3A);

			lcd_pos(lcd_next);
		
} 	 

 ------------------------------------------------------------------------------------------------------------------------------------

 主函数所在的模块:

 

 
//ADuC847寄存器地址
/*#ifndef _ADUC847_H_
	#define _ADUC847_H_
	#include <aduc848.h>
#endif */	
//LCD1602驱动
#include <lcd1602.h>
#include <AD.h>	 
#include<DS1307.h>
#include<jianpan.h>
#include<table.h>

#define uchar unsigned char
#define uint  unsigned int

bit a,b;
uchar dat[7];
uchar dispnum[]="0123456789ABCDEF";
idata uchar day[7][4]={"SUN","MON","TUE","WED","THU","FRI","SAT"};


idata uchar kcount2;
uchar dat2[6];	   //存储时分秒等的改变值  
bit zf_flag;       //加减标志位  
  


//改变光标所在位置的数值
void changeValue(uint i)
{


	//设置时间值
	
		  if(zf_flag==0)
		  {
			   if(i==0)
			   {
			     dat[6]+=0x10;
				 lcd_wc(0x80);
				 lcd_wd(dispnum[dat[6]>>4]);
				 lcd_wc(0x0f);
				 lcd_wc(0x80);			 
			   
			   }
			   if(i==1)
			   {
			     dat[6]+=0x01;
				 lcd_wc(0x81);
				 lcd_wd(dispnum[dat[6]&0x0f]);
				 lcd_wc(0x0f);
				 lcd_wc(0x81);
			   
			   }
			   if(i==2)
			   {
			     dat[5]+=0x10;
				 lcd_wc(0x83);
				 lcd_wd(dispnum[dat[5]>>4]);
				 lcd_wc(0x0f);
				 lcd_wc(0x83);
			   
			   }
			   if(i==3)
			   {
			     dat[5]+=0x01;
				 lcd_wc(0x84);
				 lcd_wd(dispnum[dat[5]&0x0f]);
				 lcd_wc(0x0f);
				 lcd_wc(0x84);
			   
			   }
			   if(i==4)
			   {
			     dat[4]+=0x10;
				 lcd_wc(0x86);
				 lcd_wd(dispnum[dat[4]>>4]);
				 lcd_wc(0x0f);
				 lcd_wc(0x86);
			   
			   }
			   if(i==5)
			   {
			     dat[4]+=0x01;
				 lcd_wc(0x87);
				 lcd_wd(dispnum[dat[4]&0x0f]);
				 lcd_wc(0x0f);
				 lcd_wc(0x87);
			   
			   }
			   if(i==6)
			   {
			     dat[2]+=0x10;
	
				 if(dat[2]>0x20)
				 {
				   dat[2]-=0x20;	
				      
				 }	  
				 
	
				 lcd_wc(0xc0);
				 lcd_wd(dispnum[dat[2]>>4]);
				 lcd_wc(0x0f);
				 lcd_wc(0xc0);
			   
				 
			   }
			   if(i==7)
			   {
			     dat[2]+=0x01;
	
				 if(dispnum[dat[2]&0x0f]=='A'||dispnum[dat[2]&0x0f]=='B'||dispnum[dat[2]&0x0f]=='C'||dispnum[dat[2]&0x0f]=='D'||dispnum[dat[2]&0x0f]=='E'||dispnum[dat[2]&0x0f]=='F')
				 {
				   dat[2]-=10;			   
				 }	 
	
				 lcd_wc(0xc1);
				 lcd_wd(dispnum[dat[2]&0x0f]);
				 lcd_wc(0x0f);
				 lcd_wc(0xc1);
			   
			   }
			   if(i==8)
			   {
			     dat[1]+=0x10;
	
				 if(dat[1]>0x60)
				 {
				   dat[1]-=0x60;	
				      
				 }	 
	
				 lcd_wc(0xc3);
				 lcd_wd(dispnum[dat[1]>>4]);
				 lcd_wc(0x0f);
				 lcd_wc(0xc3);
			   
			   }
			   if(i==9)
			   {
			     dat[1]+=0x01;
	
				 if(dispnum[dat[1]&0x0f]=='A'||dispnum[dat[1]&0x0f]=='B'||dispnum[dat[1]&0x0f]=='C'||dispnum[dat[1]&0x0f]=='D'||dispnum[dat[1]&0x0f]=='E'||dispnum[dat[1]&0x0f]=='F')
				 {
				   dat[1]-=10;			   
				 }	 
	
				 lcd_wc(0xc4);
				 lcd_wd(dispnum[dat[1]&0x0f]);
				 lcd_wc(0x0f);
				 lcd_wc(0xc4);
			   
			   }
			   if(i==10)
			   {
			     dat[0]+=0x10;
	
				 if(dat[0]>0x60)
				 {
				   dat[0]-=0x60;	
				      
				 }	 
	
				 lcd_wc(0xc6);
				 lcd_wd(dispnum[dat[0]>>4]);
				 lcd_wc(0x0f);
				 lcd_wc(0xc6);
			   
			   }
			   if(i==11)
			   {
			     dat[0]+=0x01;
	
				 if(dispnum[dat[0]&0x0f]=='A'||dispnum[dat[0]&0x0f]=='B'||dispnum[dat[0]&0x0f]=='C'||dispnum[dat[0]&0x0f]=='D'||dispnum[dat[0]&0x0f]=='E'||dispnum[dat[0]&0x0f]=='F')
				 {
				   dat[0]-=10;			   
				 }	 
	
				 lcd_wc(0xc7);
				 lcd_wd(dispnum[dat[0]&0x0f]);
				 lcd_wc(0x0f);
				 lcd_wc(0xc7);
			   
			   }
	      }

	  else
	  {
		   if(i==0)
		   {
		     dat[6]-=0x10;
			 lcd_wc(0x80);
			 lcd_wd(dispnum[dat[6]>>4]);
			 lcd_wc(0x0f);
			 lcd_wc(0x80);
		   
		   }
		   if(i==1)
		   {
		     dat[6]-=0x01;
			 lcd_wc(0x81);
			 lcd_wd(dispnum[dat[6]&0x0f]);
			 lcd_wc(0x0f);
			 lcd_wc(0x81);
		   
		   }
		   if(i==2)
		   {
		     dat[5]-=0x10;
			 lcd_wc(0x83);
			 lcd_wd(dispnum[dat[5]>>4]);
			 lcd_wc(0x0f);
			 lcd_wc(0x83);
		   
		   }
		   if(i==3)
		   {
		     dat[5]-=0x01;
			 lcd_wc(0x84);
			 lcd_wd(dispnum[dat[5]&0x0f]);
			 lcd_wc(0x0f);
			 lcd_wc(0x84);
		   
		   }
		   if(i==4)
		   {
		     dat[4]-=0x10;
			 lcd_wc(0x86);
			 lcd_wd(dispnum[dat[4]>>4]);
			 lcd_wc(0x0f);
			 lcd_wc(0x86);
		   
		   }
		   if(i==5)
		   {
		     dat[4]-=0x01;
			 lcd_wc(0x87);
			 lcd_wd(dispnum[dat[4]&0x0f]);
			 lcd_wc(0x0f);
			 lcd_wc(0x87);
		   
		   }
		   if(i==6)
		   {
			 if(dat[2]>>4==0)
			 {
			   dat[2]+=0x20;
			 }

		     dat[2]-=0x10;			 

			 lcd_wc(0xc0);
			 lcd_wd(dispnum[dat[2]>>4]);
			 lcd_wc(0x0f);
			 lcd_wc(0xc0);
		   
		   }
		   if(i==7)
		   {
			 if(dispnum[dat[2]&0x0f]=='A'||dispnum[dat[2]&0x0f]=='B'||dispnum[dat[2]&0x0f]=='C'||dispnum[dat[2]&0x0f]=='D'||dispnum[dat[2]&0x0f]=='E'||dispnum[dat[2]&0x0f]=='F')
			 {
			   dat[2]-=0x05;
			 }			  

			   if(dispnum[dat[2]&0x0f]=='0')
			 {
			 	dat[2]+=0x0a;
			 }


		     dat[2]-=0x01;			 

			 if(dispnum[dat[2]&0x0f]=='F')
			 {
			    dat[2]-=0x06;
			 }

			 lcd_wc(0xc1);
			 lcd_wd(dispnum[dat[2]&0x0f]);
			 lcd_wc(0x0f);
			 lcd_wc(0xc1);
		   
		   }
		   if(i==8)
		   {
			 if(dat[1]>>4==0)
			 {
			   dat[1]+=0x60;
			 }

		     dat[1]-=0x10;
			 lcd_wc(0xc3);
			 lcd_wd(dispnum[dat[1]>>4]);
			 lcd_wc(0x0f);
			 lcd_wc(0xc3);
		   
		   }
		   if(i==9)
		   {
			 if(dispnum[dat[1]&0x0f]=='A'||dispnum[dat[1]&0x0f]=='B'||dispnum[dat[1]&0x0f]=='C'||dispnum[dat[1]&0x0f]=='D'||dispnum[dat[1]&0x0f]=='E'||dispnum[dat[1]&0x0f]=='F')
			 {
			   dat[1]-=0x05;
			 }	

			   if(dispnum[dat[1]&0x0f]=='0')
			 {
			 	dat[1]+=0x0a;
			 }

		     dat[1]-=0x01;

			 if(dispnum[dat[1]&0x0f]=='F')
			 {
			    dat[1]-=0x06;
			 }

			 lcd_wc(0xc4);
			 lcd_wd(dispnum[dat[1]&0x0f]);
			 lcd_wc(0x0f);
			 lcd_wc(0xc4);
		   
		   }
		   if(i==10)
		   {
			 if(dat[0]>>4==0)
			 {
			   dat[0]+=0x60;
			 }

		     dat[0]-=0x10;
			 lcd_wc(0xc6);
			 lcd_wd(dispnum[dat[0]>>4]);
			 lcd_wc(0x0f);
			 lcd_wc(0xc6);
		   
		   }
		   if(i==11)
		   {
		     if(dispnum[dat[0]&0x0f]=='A'||dispnum[dat[0]&0x0f]=='B'||dispnum[dat[0]&0x0f]=='C'||dispnum[dat[0]&0x0f]=='D'||dispnum[dat[0]&0x0f]=='E'||dispnum[dat[0]&0x0f]=='F')
			 {
			   dat[0]-=0x05;
			 }	

			   if(dispnum[dat[0]&0x0f]=='0')
			 {
			 	dat[0]+=0x0a;
			 }


		     dat[0]-=0x01;

			 if(dispnum[dat[0]&0x0f]=='F')
			 {
			    dat[0]-=0x06;
			 }
			 lcd_wc(0xc7);
			 lcd_wd(dispnum[dat[0]&0x0f]);
			 lcd_wc(0x0f);
			 lcd_wc(0xc7);
		   
		   }
	  }
		  
		   
  
}

//加值
void addValue(uchar k1)
{
   zf_flag=0;
   
     switch(k1)
	 {
	   	 case 1: 
		  		/*
				 addv[0]++;        
		         lcd_wc(0x80);
		         dat1[0]=(dispnum[dat[6]>>4])+addv[0];
				 lcd_wd(dat1[0]);
				 lcd_wc(0x0f);
				 lcd_wc(0x80); */
				 changeValue(0);
				
				 break;

		 case 2:
				 changeValue(1);	 			 
				 break;
		 case 4:
				 changeValue(2);
		         break;
		 case 5:
				 changeValue(3);
		         break;
		 case 7:
				 changeValue(4);
		         break;
		 case 8:
				 changeValue(5);
		         break;
		 case 9:
				 changeValue(6);
		         break;
		 case 10:
				 changeValue(7);
		         break;
		 case 12:
				 changeValue(8);
		         break;
		 case 13:
				 changeValue(9);
		         break;
		 case 15:
				 changeValue(10);
		         break;
		 case 16:
				 changeValue(11);
		         break;

	 }


}

//减值
void subValue(uchar k1)
{
   
   zf_flag=1;
   	 switch(k1)
	 {
	   	 case 1: 
		  		
				 changeValue(0);
				
				 break;

		 case 2:
				 changeValue(1);	 			 
				 break;
		 case 4:
				 changeValue(2);
		         break;
		 case 5:
				 changeValue(3);
		         break;
		 case 7:
				 changeValue(4);
		         break;
		 case 8:
				 changeValue(5);
		         break;
		 case 9:
				 changeValue(6);
		         break;
		 case 10:
				 changeValue(7);
		         break;
		 case 12:
				 changeValue(8);
		         break;
		 case 13:
				 changeValue(9);
		         break;
		 case 15:
				 changeValue(10);
		         break;
		 case 16:
				 changeValue(11);
		         break;

	 }

}

uchar Decimal_to_BCD(uchar temp)//十进制转换成BCD码 
{ 
uchar a,b,c; 
 a=temp; 
 b=0; 
 if(a>=10) 
 { 
 while(a>=10) 
 { 
 a=a-10; 
 b=b+16; 
 c=a+b; 
 temp=c; 
 } 
 } 
 return temp; 
 } 

//DS1307传输准备,时间初始化
void display_ready()
{
  
	iic_init();
	a=iic_write_address(0xd0,0x00);
	b=iic_write_char(0x30);
	b=iic_write_char(0x26);
	b=iic_write_char(0x16);
	b=iic_write_char(0x01);	  //DS1307只能记录20个小时,每20小时重置。即时最大为19!!
	b=iic_write_char(0x01);
	b=iic_write_char(0x06);
	b=iic_write_char(0x15);
	iic_stop();


} 


//时间显示
void display()

{
   			
	while(1&getid())
	{
		if(iic_write_address(0xd0,0x00)==0)
		{
			iic_start();
			if(iic_write_char(0xd1)==0)
			{
				dat[0]=iic_read_char(0);
				dat[1]=iic_read_char(0);
				dat[2]=iic_read_char(0);
				dat[3]=iic_read_char(0);
				dat[4]=iic_read_char(0);
				dat[5]=iic_read_char(0);
				dat[6]=iic_read_char(1);
			}
			iic_stop();	
		

			lcd_pos(0);
			lcd_wd(dispnum[dat[6]>>4]);
			lcd_wd(dispnum[dat[6]&0x0f]);
			lcd_wd('-');
			lcd_wd(dispnum[dat[5]>>4]);
			lcd_wd(dispnum[dat[5]&0x0f]);
			lcd_wd('-');
			lcd_wd(dispnum[dat[4]>>4]);
			lcd_wd(dispnum[dat[4]&0x0f]);
			lcd_wd(' ');
			lcd_wd(day[dat[3]][0]);
			lcd_wd(day[dat[3]][1]);
			lcd_wd(day[dat[3]][2]);
			
	
			lcd_pos(lcd_next);

			lcd_wd(dispnum[(dat[2]>>4)&0x01]);
			lcd_wd(dispnum[dat[2]&0x0f]);
			lcd_wd(':');
			lcd_wd(dispnum[dat[1]>>4]);
			lcd_wd(dispnum[dat[1]&0x0f]);
			lcd_wd(':');
			lcd_wd(dispnum[(dat[0]>>4)&0x07]);
			lcd_wd(dispnum[dat[0]&0x0f]); 

			
			
	/*		
			//记录按键按下次数并显示
			lcd_pos(lcd_next+0x0C);
			if(getk()>9&&getk()<13)
			{
				  lcd_wd(0x30+1);
	
				 lcd_pos(lcd_next+0x0D); 	
				 lcd_wd(0x30+getk()-10);
			  	
			} 
			else if(getk()>12)
			{
			  	 lcd_wd(0x30+0);

				 lcd_pos(lcd_next+0x0D); 	
				 lcd_wd(0x30+0); 
				 
			}
			else
			{	
				lcd_wd(0x30+0);	
						
				lcd_pos(lcd_next+0x0D); 	
				lcd_wd(0x30+getk());
			}		   				   */
		}
		iic_delay_5us();
	

		Keyscan(); //继续扫描,使能跳出时间显示
		
	}		   
}  

void  makeSure()
{
   //按第一位复位;按第二位除它其他复位;
	uchar i;

    setk(0);						//让kcount复零,光标复位

   	lcd_wc(0x0c);
	lcd_wc(0x02);	


	dat2[0]=Decimal_to_BCD((dispnum[dat[6]>>4]-0x30)*10+(dispnum[dat[6]&0x0f]-0x30));
	dat2[1]=Decimal_to_BCD((dispnum[dat[5]>>4]-0x30)*10+(dispnum[dat[5]&0x0f]-0x30));
	dat2[2]=Decimal_to_BCD((dispnum[dat[4]>>4]-0x30)*10+(dispnum[dat[4]&0x0f]-0x30));
	dat2[3]=Decimal_to_BCD((dispnum[dat[2]>>4]-0x30)*10+(dispnum[dat[2]&0x0f]-0x30));
	dat2[4]=Decimal_to_BCD((dispnum[dat[1]>>4]-0x30)*10+(dispnum[dat[1]&0x0f]-0x30));
	dat2[5]=Decimal_to_BCD((dispnum[dat[0]>>4]-0x30)*10+(dispnum[dat[0]&0x0f]-0x30));
	
 
  
    iic_init();
	a=iic_write_address(0xd0,0x00);		//0xd0为器件写地址
	b=iic_write_char(dat2[5]);
	b=iic_write_char(dat2[4]);
	b=iic_write_char(dat2[3]);
	b=iic_write_char(0x00);
	b=iic_write_char(dat2[2]);
	b=iic_write_char(dat2[1]);
	b=iic_write_char(dat2[0]); 	 
	
    display();	 				 

	
} 



void main()
{	
   	
	PLLCON&=0xf8;	//设置频率为12.582912MHz 		 
	lcd_init();
//	iic_init();		
	display_ready(); 
	Init(); 
//	display();	 	 
	
        while(1)
	  {
	   	
	  	Keyscan();      
			   
	  }	
	   
}

 

 这里说下如何调整显示时间。

 

//DS1307传输准备,时间初始化
void display_ready()
{
  
	iic_init();
	a=iic_write_address(0xd0,0x00);
	b=iic_write_char(0x30);  
	b=iic_write_char(0x26);
	b=iic_write_char(0x16);
	b=iic_write_char(0x01);	  
	b=iic_write_char(0x01);
	b=iic_write_char(0x06);
	b=iic_write_char(0x15);
	iic_stop();


} 

 

30对应的是秒,26对应的是分,16对应的是时,01对应的是星期即星期一,之后分别代表日月年。

 

如果要显示15年6月5日星期四0时42分00秒,可修改为:

 

//DS1307传输准备,时间初始化
void display_ready()
{
  
	iic_init();
	a=iic_write_address(0xd0,0x00);
	b=iic_write_char(0x00);
	b=iic_write_char(0x42);
	b=iic_write_char(0x00);
	b=iic_write_char(0x04);	  
	b=iic_write_char(0x05);
	b=iic_write_char(0x06);
	b=iic_write_char(0x15);
	iic_stop();


} 

 

若再想实现掉电后能继续计时,则下次将程序写入板子前记得把这个函数注释掉,不需要再定义了。

这样效果就会如:掉电前是0时45分00秒,关开关,过10秒后再开开关,时间显示为0时45分10秒!!

 

综合以上,就能实现出一个智能电压测试仪了。下面再给出调整时间或电压上下限值的操作。

 

操作指南

 

操作一:调整北京时间

 

先按下按钮8,然后按下按钮9,通过按动9使光标移动到想要调整的位置,再通过按钮AB改动所在位的时间值,最后再按下按钮C则调整完毕。

 

操作二:调整电压上、下限值

 

以调整电压上限值为例,按下按钮6,然后按下按钮9,通过按钮DE改动电压上限值,最后按下按钮F确定。

 

 

 

 

 

 

 

  • 大小: 14.1 KB
  • 大小: 34.9 KB
  • 大小: 27.6 KB
0
0
分享到:
评论

相关推荐

    aduc848-交你学会ADUC848

    电源模块是系统运行的基础,ADUC848支持多种电压输入,提供稳定的电源供应给各个部分,确保系统稳定工作。 1.4 模数/数模转换 1.4.1 模数转换 内置的12位ADC可实现高速、高精度的模拟信号数字化,支持多种采样速率...

    基于ADI公司ADuC7061的智能压力测量仪.zip

    基于ADI公司ADuC7061的智能压力测量仪.zip基于ADI公司ADuC7061的智能压力测量仪.zip基于ADI公司ADuC7061的智能压力测量仪.zip基于ADI公司ADuC7061的智能压力测量仪.zip基于ADI公司ADuC7061的智能压力测量仪.zip基于...

    ADUC848_AD采集

    2. **分辨率**:ADUC848的ADC分辨率决定了能区分的最小模拟电压差,例如12位ADC可以区分2^12=4096个不同的电压等级。分辨率越高,测量精度越高。 3. **转换速率**:ADUC848的ADC转换速率是指每秒钟可以完成的转换...

    ADUC848_DS1302

    标题中的“ADUC848_DS1302”很可能是指一个基于ADUC848微控制器的项目,其中整合了DS1302时钟芯片。ADUC848是一款由 Analog Devices(亚德诺半导体)制造的8位微控制单元,具有高性能模拟功能,适用于需要混合信号...

    ADUC848_EEPROM

    标题 "ADUC848_EEPROM" 暗示了我们正在探讨一款基于ADUC848微控制器的EEPROM应用。ADUC848是一款集成了模拟和数字功能的微控制器,由Analog Devices(亚德诺半导体)制造。在嵌入式系统设计中,EEPROM(电可擦除可...

    ADUC848_波形发生器

    【ADUC848 波形发生器】是一款基于微控制器ADUC848的电子设备,用于生成各种模拟和数字信号,适用于测试、测量、教育以及科研等用途。ADUC848是一款集成了高性能模拟电路和数字处理能力的微控制器,使其成为构建复杂...

    aduc848资料

    ### ADuC848 资料概览与关键技术知识点 #### 一、产品概述 ADuC848 是 Analog Devices 公司推出的一款高度集成的微控制器单元(MCU),该系列包括 ADuC845、ADuC847 和 ADuC848 三个型号。这些器件结合了高性能的 ...

    ADUC848_DAC

    标题中的“ADUC848_DAC”指的是一款基于ADUC848微控制器的数字模拟转换器(DAC)设计。ADUC848是Analog Devices公司生产的一款集成了微处理器和模拟电路的混合信号微控制器,常用于需要高精度模拟输出的应用。 **...

    ADUC848_ADUC848AD控制程序.zip

    标题中的"ADUC848_ADUC848AD控制程序.zip"暗示了这是一个与ADUC848或ADUC848AD相关的控制程序,它被封装在一个ZIP压缩文件中。ADUC848是Analog Devices公司推出的一款微控制器,集成了模拟和数字功能,常用于数据...

    ADUC848_IIC

    标题中的"ADUC848_IIC"暗示我们主要探讨的是ADI公司生产的微控制器ADUC848在IIC(I²C)通信协议下的应用。IIC,全称为Inter-Integrated Circuit,是由飞利浦(现为NXP半导体)开发的一种多主机、多设备的串行通信...

    PWM.rar_aduc848

    标题中的"PWM.rar_aduc848"表明这是一个与PWM(脉宽调制)技术相关的项目,使用了ADUC848微控制器,并且包含了在Keil uVision4集成开发环境中编写的源代码。这个项目的目标是实现一首乐曲——《绿袖子》的自动播放...

    基于ADuC845单片机的二极管测试仪的设计.pdf

    本文介绍了一种基于ADuC845微控制器的二极管测试仪的设计,该测试仪能够自动显示二极管的极性以及正向电压降,并测试二极管的伏安特性。同时,测试仪具备串行通信功能,便于与计算机通讯并保存不同类型的参数。 ...

    ADUC848_ADUC848AD控制程序_源码.zip

    标题中的“ADUC848_ADUC848AD控制程序_源码.zip”表明这是一个与ADUC848微控制器相关的控制程序源代码。ADUC848是一款由Analog Devices公司生产的混合信号微控制器,它集成了数字处理单元(CPU)和模拟功能,适用于...

    ADuC845 ADuC847 ADuC848

    ### ADuC845 ADuC847 ADuC848: 详析与核心特性 #### 微型转换器(MicroConverter®)多通道24-/16-位ADCs简介 ADuC845、ADuC847及ADuC848是Analog Devices公司推出的一系列高性能微型转换器(MicroConverter®),...

    aduc848rtc参考程序

    ADuC848是一款集成了微控制器(MCU)和模拟功能的混合信号处理器,特别适用于需要高精度测量和控制的应用。本篇文章将围绕"ADuC848 RTC开发参考程序"这一主题,深入探讨相关知识点。 首先,ADuC848是ADI公司生产的...

    基于ADI公司ADuC7061的智能压力测量仪_智能家居物联网开发PCB设计方案.rar

    标题中的“基于ADI公司ADuC7061的智能压力测量仪”指的是使用ADI(Analog Devices, Inc.)公司的微控制器ADuC7061设计的一款智能压力测量设备。这款微控制器集成了模拟和数字功能,适用于高精度、低功耗的物联网应用...

Global site tag (gtag.js) - Google Analytics