51/AVR单片机技术驿站!  <在线翻译>     便利工具    特色网址   无弹窗、无插件的绿色站点...  英才招聘   学历查询  喜欢>>收藏我站 

当前位置:首页 > 单片机源码 > 详细内容
1602液晶万年历汇编和C语言
作者:佚名  发布时间:2008/10/19  阅读次数:2222  字体大小: 【】 【】【

1602液晶万年历汇编和C语言
*日历时钟                                                                                                                                           *
*按K1,进入设置状态                                                                                                                         *
*按k2,停止闹钟声音                                                                                                                         *
*按k3,依次进入闹钟功能是否启用,闹钟时,分秒,年,月,日及时间时,分,秒的设置,           *
*直到退出设置状态                                                                                                                           *
*按k4,调整是否起用闹钟和调节闹钟时,分,秒,年,月,日,时间的时,分,秒的数字                 *
*LCD第二排中间显示小喇叭,表示启用闹钟功能,无则禁止闹钟功能                                     *
*(可在调整状态进行设置)                                                                                                           *
*正常状态,LCD上排最前面显示自定义字符,LCD下排最前面闪动"XUELIN"                               *
*设置状态,LCD上排最前面显示"P",下排最前面在设置闹钟时间时显示"alarm:",                 *
*其它状态显示"time"                                                                                                                       *
*年代变化2000--2099,星期自动转换                                                                                             *
*程序中有自定义字符写入                                                                                                               *


#include
#include
unsigned char code dis_week[]={"SUN,MON,TUE,WED,THU,FRI,SAT"};
unsigned char code para_month[13]={0,0,3,3,6,1,4,6,2,5,0,3,5}; //星期月参变数
unsigned char data dis_buf1[16];   //lcd上排显示缓冲区
unsigned char data dis_buf2[16];   //lcd下排显示缓冲区  
unsigned char data year,month,date,week;//年、月、日、星期
unsigned char data armhour,armmin,armsec;//闹钟时、分、秒
unsigned char data hour,min,sec,sec100; //时、分、秒、百分之一秒
unsigned char data flag,vkey,skey;//设置状态计数标志、按键先前值、按键当前值
bit alarm; //标识是否启用闹钟,1--启用,0--关闭
sbit   rs = P2^0;       //LCD数据/命令选择端(H/L)
sbit   rw = P2^1;       //LCD读/写选择端(H/L)
sbit   ep = P2^2;       //LCD使能控制
sbit PRE = P1^6;       //调整键(k3)
sbit SET = P1^7;       //调整键(k4)
sbit SPK = P3^7;      
void delayms(unsigned char ms); //延时程序
bit   lcd_busy();       //测试LCD忙碌状态程序
void lcd_wcmd(char cmd);   //写入指令到LCD程序
void lcd_wdat(char dat);   //写入数据到LCD程序
void lcd_pos(char pos);     //LCD数据指针位置程序
void lcd_init();       //LCD初始化设定程序
void pro_timedate();     //时间日期处理程序
void pro_display();       //显示处理程序
void pro_key();         //按键处理程序
void time_alarm();       //定时报警功能(闹钟)
unsigned char scan_key();   //按键扫描程序
unsigned char week_proc();   //星期自动计算与显示函数
bit leap_year();       //判断是否为闰年
void lcd_sef_chr();       //LCD自定义字符程序
void update_disbuf(unsigned char t1,unsigned char t2[],unsigned char dis_h,unsigned char dis_m,unsigned char dis_s);    
               //更新显示缓冲区函数
  

// 延时程序
void delay(unsigned char ms)
{ while(ms--)
  { unsigned char i;
   for(i = 0; i< 250; i++)        
   {
     _nop_();           //执行一条_nop_()指令为一个机器周期
     _nop_();
     _nop_();
     _nop_();
   }
  }
}  
  

//测试LCD忙碌状态
bit lcd_busy()
{
  bit result;
  rs = 0;
  rw = 1;
  ep = 1;
  _nop_();
  _nop_();
  _nop_();
  _nop_();
  result =(bit)(P0&0x80); //LCD的D0--D7中,D7=1为忙碌,D7=0为空闲
  ep = 0;
  return result;
}

//写入指令到LCD
void lcd_wcmd(char cmd)
{            
  while(lcd_busy()); //当lcd_busy为1时,再次检测LCD忙碌状态,lcd-busy为0时,开始写指令
  rs = 0;
  rw = 0;
  ep = 0;
  _nop_();
  _nop_();
  P0 = cmd;
  _nop_();
  _nop_();
  _nop_();
  _nop_();
  ep = 1;
  _nop_();
  _nop_();
  _nop_();
  _nop_();
  ep = 0;  
}

//写入数据到LCD
void lcd_wdat(char dat)
{            
  while(lcd_busy()); //当lcd_busy为1时,再次检测LCD忙碌状态,lcd-busy为0时,开始写数据
  rs = 1;
  rw = 0;
  ep = 0;
  P0 = dat;
  _nop_();
  _nop_();
  _nop_();
  _nop_();
  ep = 1;
  _nop_();
  _nop_();
  _nop_();
  _nop_();
  ep = 0;
}

//LCD数据指针位置程序
void lcd_pos(char pos)
{          
  lcd_wcmd(pos|0x80); //数据指针=80+地址码(00H~27H,40H~67H)
}


//设定二个自定义字符,(注意:LCD1602中自定义字符的地址为0x00--0x07,即可定义8个字符)
//这里我们设定把一个自定义字符放在0x00位置(000),另一个放在0x01位子(001)
void lcd_sef_chr()
{ //第一个自定义字符
  lcd_wcmd(0x40); //"01 000 000"   第1行地址 (D7D6为地址设定命令形式D5D4D3为字符存放位置(0--7),D2D1D0为字符行地址(0--7))
     lcd_wdat(0x1f); //"XXX 11111" 第1行数据(D7D6D5为XXX,表示为任意数(一般用000),D4D3D2D1D0为字符行数据(1-点亮,0-熄灭)
  lcd_wcmd(0x41); //"01 000 001"   第2行地址
     lcd_wdat(0x11); //"XXX 10001" 第2行数据
  lcd_wcmd(0x42); //"01 000 010"   第3行地址
     lcd_wdat(0x15); //"XXX 10101" 第3行数据
  lcd_wcmd(0x43); //"01 000 011"   第4行地址
     lcd_wdat(0x11); //"XXX 10001" 第4行数据
  lcd_wcmd(0x44); //"01 000 100"   第5行地址
     lcd_wdat(0x1f); //"XXX 11111" 第5行数据
  lcd_wcmd(0x45); //"01 000 101"   第6行地址
     lcd_wdat(0x0a); //"XXX 01010" 第6行数据
  lcd_wcmd(0x46); //"01 000 110"   第7行地址
     lcd_wdat(0x1f); //"XXX 11111" 第7行数据
  lcd_wcmd(0x47); //"01 000 111"   第8行地址
     lcd_wdat(0x00); //"XXX 00000" 第8行数据
  //第二个自定义字符
  lcd_wcmd(0x48); //"01 001 000"   第1行地址  
     lcd_wdat(0x01); //"XXX 00001" 第1行数据
  lcd_wcmd(0x49); //"01 001 001"   第2行地址
     lcd_wdat(0x1b); //"XXX 11011" 第2行数据
  lcd_wcmd(0x4a); //"01 001 010"   第3行地址
     lcd_wdat(0x1d); //"XXX 11101" 第3行数据
  lcd_wcmd(0x4b); //"01 001 011"   第4行地址
     lcd_wdat(0x19); //"XXX 11001" 第4行数据
  lcd_wcmd(0x4c); //"01 001 100"   第5行地址
     lcd_wdat(0x1d); //"XXX 11101" 第5行数据
  lcd_wcmd(0x4d); //"01 001 101"   第6行地址
     lcd_wdat(0x1b); //"XXX 11011" 第6行数据
  lcd_wcmd(0x4e); //"01 001 110"   第7行地址
     lcd_wdat(0x01); //"XXX 00001" 第7行数据
  lcd_wcmd(0x4f); //"01 001 111"   第8行地址
     lcd_wdat(0x00); //"XXX 00000" 第8行数据

  


}

//LCD初始化设定
void lcd_init()
{          
  lcd_wcmd(0x38);   //设置LCD为16X2显示,5X7点阵,八位数据借口
  delay(1);
  lcd_wcmd(0x0c);   //LCD开显示及光标设置(光标不闪烁,不显示"-")
  delay(1);
  lcd_wcmd(0x06);   //LCD显示光标移动设置(光标地址指针加1,整屏显示不移动)
  delay(1);
  lcd_wcmd(0x01);   //清除LCD的显示内容
  delay(1);
}

//闰年的计算
bit leap_year()
{
  bit leap;
  if((year%4==0&&year%100!=0)||year%400==0)//闰年的条件
   leap=1;
  else
   leap=0;
  return leap;
}

//星期的自动运算和处理
unsigned char week_proc()
{ unsigned char num_leap;
  unsigned char c;
  num_leap=year/4-year/100+year/400;//自00年起到year所经历的闰年数
  if( leap_year()&& month<=2 )     //既是闰年且是1月和2月
   c=5;
  else
   c=6;
  week=(year+para_month[month]+date+num_leap+c)%7;//计算对应的星期
  return week;
}

//更新显示缓冲区
void update_disbuf(unsigned char t1,unsigned char t2[],unsigned char dis_h,unsigned char dis_m,unsigned char dis_s)
{ dis_buf1[0]=t1;       //
  dis_buf1[1]=0x20;       //空格
  dis_buf1[2]=50;       //'2'
  dis_buf1[3]=48;                         //'0'
  dis_buf1[4]=year/10+48;
  dis_buf1[5]=year%10+48;
  dis_buf1[6]=0x2d;
  dis_buf1[7]=month/10+48;
  dis_buf1[8]=month%10+48;
  dis_buf1[9]=0x2d;       //'-'
  dis_buf1[10]=date/10+48;
  dis_buf1[11]=date%10+48;
  dis_buf1[12]=0x20;
  dis_buf1[13]=dis_week[4*week];
  dis_buf1[14]=dis_week[4*week+1];
  dis_buf1[15]=dis_week[4*week+2];

  dis_buf2[0]=t2[0];
  dis_buf2[1]=t2[1];
  dis_buf2[2]=t2[2];
  dis_buf2[3]=t2[3];
  dis_buf2[4]=t2[4];
  dis_buf2[5]=t2[5];
  dis_buf2[6]=0x20;     //空格
   if (alarm)
   dis_buf2[7]=0x01;   //alarm=1,显示闹钟启用标致(第二个自定义字符)
  else
   dis_buf2[7]=0x20;   //alarm=0,不显示闹钟启用标致
  dis_buf2[8]=dis_h/10+48;
  dis_buf2[9]=dis_h%10+48;
  dis_buf2[10]=0x3a;     //':'
  dis_buf2[11]=dis_m/10+48;
  dis_buf2[12]=dis_m%10+48;
  dis_buf2[13]=0x3a;
  dis_buf2[14]=dis_s/10+48;
  dis_buf2[15]=dis_s%10+48;

}

//时间和日期处理程序
void pro_timedate()
{
  sec++;
  if(sec > 59)
   {sec = 0;
     min++;
     if(min>59)
     {min=0;
       hour++;
       if(hour>23)
       {hour=0;
         date++;
         if (month==1||month==3||month==5||month==7||month==8||month==10||month==12)
           if (date>31) {date=1;month++;}         //大月31天
         if (month==4||month==6||month==9||month==11)  
             if (date>30) {date=1;month++;}         //小月30天
         if (month==2)    
           {if( leap_year())               //闰年的条件
           {if (date>29) {date=1;month++;}}     //闰年2月为29天
           else
           {if (date>28) {date=1;month++;}}     //平年2月为28天
           }      
         if (month>12) {month=1;year++;}
         if (year>99) year="0";
       }
     }
   }
  week_proc();
  if (sec==armsec && min==armmin && hour==armhour)      
   {if (alarm)
     TR1=1;         //闹钟启用时,报警时间到,启动Timer1
   }

}

//显示处理程序
void pro_display()
{ unsigned char i;
  lcd_pos(0x00);
  for (i=0;i<=15;i++)
   {lcd_wdat(dis_buf1[i]);}

  lcd_pos(0x40);
  for (i=0;i<=15;i++)
   {lcd_wdat(dis_buf2[i]);}
}

//Timer0中断处理程序,秒的产生
void timer0() interrupt 1
{
  TH0=0xdc;     //Timer0置10ms定时初值dc00H(2^16=65536D,dc00H=56320D)
  TL0=0x00;     //定时时间=(65536-56320)*(1/11.0592)*12=10ms (f0=11.0592Mhz)
  sec100++;
  if(sec100 >= 100) //1秒时间 (100*10ms=1000ms=1s)
   {sec100 = 0;
     pro_timedate();//调用时间和日期处理程序
   }
  if (sec&0x01)                   //"XUELIN"闪一秒,停一秒
   update_disbuf(0x00,"           ",hour,min,sec);       //0x00表示显示00位置的自定义字符  
  else
   update_disbuf(0x00,"XUELIN",hour,min,sec);
  pro_display();   //调用显示处理函数


}
  
//按键扫描程序
unsigned char   scan_key()
{
  skey=0x00;                 //给变量vkey置初值
  skey|=PRE;                 //读取PRE键的状态
  skey=skey<<1;               //将PRE键的状态存于skey的B1位
  skey|=SET;                 //读取SET键的状态,并存于skey的B0位
  return skey;               //返回skey的键值(即PRE,SET的状态)

}

//外部中断INT0中断处理程序
void int0() interrupt 0
{  
   TR0=0;                 //禁止Timer0
   IE=0;                 //禁止中断
   lcd_wcmd(0x0e);             //显示光标"_",整个光标不闪烁
   alarm=1;
   update_disbuf(0x50,"alarm:",armhour,armmin,armsec); //更新显示数据,0x50表示要显示"P"
   pro_display();             //调用显示处理程序
   lcd_pos(0x47);                   //使光标位于第一个调整项下          
   flag=0;                
   vkey=0x03;
   while(flag^0x0a)
     {skey = scan_key();         //扫描按键状态
     if (skey^vkey)           //若skey与vkey相同,跳出循环,相异执行循环体
       { delay(10);         //去按键抖动
         skey = scan_key();     //转回扫描按键状态    
         if (skey^vkey)       //若skey与vkey相同,跳出循环,相异执行循环体  
             { vkey=skey;     //将skey的值付给vkey
             if (skey==0x01)   //PRE键按下
               {   flag++; //调整标志位加1
                   switch (flag) //将光标置于相应调整位置
                   {
                          
                     case 1: lcd_pos(0x49);break;   //光标置小时报警设置位置            
                     case 2: lcd_pos(0x4c);break;   //光标置分钟报警设置位置        
                     case 3: lcd_pos(0x4f);break;   //光标置秒时报警设置位置
                    
                     case 4: update_disbuf(0x50,"time: ",hour,min,sec);
                         pro_display();
                         lcd_pos(0x05);break;   //光标置年调整位置                        
                     case 5: lcd_pos(0x08);break;   //光标置月调整位置
                     case 6: lcd_pos(0x0b);break;   //光标置日调整位置
                    
                     case 7: lcd_pos(0x49);break;   //光标置时调整位置
                     case 8: lcd_pos(0x4c);break;   //光标置分调整位置
                     case 9: lcd_pos(0x4f);break;   //光标置秒调整位置
                      
                     default:break;
                   }
               }
             if (skey==0x02)           //SET键按下
               { pro_key();   //转设置按键处理程序
               }
           }
       }                
     }                
   lcd_wcmd(0x0c);             //设置LCD开显示及光标不闪烁,不显示"-"
   lcd_wcmd(0x01);                   //清除LCD的显示内容
   IE=0x8f;                         //CPU开中断,INT0,INT1,开中断
   TR0=1;                 //Timer0启动
}


//主程序,初始化及初值设定
void main()
{
  lcd_init();                                           //初始化LCD
  lcd_sef_chr();           //写入自定义字符号
  hour=0;min=0;sec=0;               //开机时的时,分,秒显示
  armhour=0;armmin=0;armsec=0;   //开机时的时,分,秒报警初值
  year= 5; month="1";date=1;             //开机时的年,月,日,星期显示
  week_proc();
  alarm=1;             //初始开机,启用闹钟
  IE = 0x8f;             //CPU开中断,INT0,INT1,Timer0,Timer1开中断
  IP = 0x04;             //设置INT0为中断最高优先级
  IT0=0;IT1=0;           //外部INT0,INT1设置为电平触发方式(注意,触发不要选边沿方式,易误动)
  TMOD = 0x11;           //Timer0,Timer1工作于模式1, 16位定时方式
  TH0 = 0xdc;TL0 = 0x00;       //Timer0置10ms定时初值  
  TH1 = 0xff;TL1 = 0x00;       //Timer1置初值  
  TR0 = 1;             //Timer0启动
  TR1 = 0;
  while(1);
}

//设置按键处理程序
void pro_key()
{
  switch (flag)
   {
   case 0:alarm=!alarm;     //启用或关闭闹钟(alarm=1:启用,alarm=0:关闭)
       update_disbuf(0x50,"alarm:",armhour,armmin,armsec); //更新显示数据
       pro_display();                   //调用显示处理
       lcd_pos(0x47);break;               //光标回到原调整位置
   case 1:armhour++;
       if (armhour>23) armhour="0";
       update_disbuf(0x50,"alarm:",armhour,armmin,armsec); //更新显示数据
       pro_display();                   //调用显示处理
       lcd_pos(0x49);break;               //光标回到原调整位置
   case 2:armmin++;
       if (armmin>59) armmin="0";
       update_disbuf(0x50,"alarm:",armhour,armmin,armsec);
       pro_display();
       lcd_pos(0x4c);break;
   case 3:armsec++;
       if (armsec>59) armsec="0";
       update_disbuf(0x50,"alarm:",armhour,armmin,armsec);
       pro_display();
       lcd_pos(0x4f);break;

   case 4:year++;
       if (year> 99) year= 0;
       week_proc();                                               //星期自动运算
       update_disbuf(0x50,"time: ",hour,min,sec);
       pro_display();
       lcd_pos(0x05);break;
     case 5:month++;
       if (month>12) month="1";
       week_proc();           //星期自动运算
       update_disbuf(0x50,"time: ",hour,min,sec);
       pro_display();
       lcd_pos(0x08);break;
   case 6:date++;
       if (month==1||month==3||month==5||month==7||month==8||month==10||month==12)
         if (date>31) date="1";     //大月31天
       if (month==4||month==6||month==9||month==11)  
           if (date>30) date="1";     //小月30天
       if (month==2)    
         {if(leap_year())       //闰年的条件
           {if (date>29) date="1";}   //闰年2月为29天
           else
           {if (date>28) date="1";}}   //平年2月为28天
       week_proc();                 //星期自动运算
       update_disbuf(0x50,"time: ",hour,min,sec);
       pro_display();
       lcd_pos(0x0b);break;
  
   case 7:hour++;
       if (hour>23) hour="0";
       update_disbuf(0x50,"time: ",hour,min,sec);
       pro_display();
       lcd_pos(0x49);break;
   case 8:min++;
       if (min>59) min="0";
       update_disbuf(0x50,"time: ",hour,min,sec);
       pro_display();
       lcd_pos(0x4c);break;
   case 9:sec++;
       if (sec>59) sec="0";
       update_disbuf(0x50,"time: ",hour,min,sec);
       pro_display();
       lcd_pos(0x4f);break;
   default: break ;                        
   }
}

//Timer1中断处理程序,产生报警的声音
void timer1() interrupt 3
{
  TH1=0xff;      
  TL1=0x00;
  SPK=~SPK;
  
      
}

//外部中断INT1中断处理程序,停止报警声音
void int1() interrupt 2
{
  if(TR1)
   TR1=0;      

}


汇编的:

  

;********************************************************************************
;按K1,依次进入闹钟功能,闹钟时间,年,月,日和时,分,秒模式,直致退出设置状态           *
;按K2,调整是否起用闹钟和调节闹钟时,分,秒,年,月,日,时间的时,分,秒的数字                   *
;闹钟响时,按K2即可停止闹钟的声响                                                                                             *
;正常状态,上排最前面显示一自定义字符,下排最前面闪动"willar"                                       *
;设置状态,LCD上排最前面显示"P",下排最前面设置闹钟时显示"alarm:",其他显示"time:"*
;闹钟启用时,在LCD下排中间显示一小喇叭,闹钟禁用时,无此小喇叭                                   *
;年代变化2000--2099,星期自动转换                                                                                               *


;**************变量的定义*****************
RS   BIT P2.0   ;LCD数据/命令选择端(H/L)
RW   BIT         P2.1         ;LCD读/写选择端(H/L)
EP   BIT   P2.2   ;LCD使能控制
PRE   BIT     P1.4   ;调整键(K1)
ADJ   BIT P1.5   ;调整键(K2)
SPK   BIT         P3.7   ;闹钟声音输出口

YEAR     DATA 18H   ;年,月,日变量
MONTH   DATA 19H
DATE   DATA   1AH
WEEK   DATA   1BH

HOUR   DATA   1CH   ;时,分,秒,百分之一秒变量
MIN   DATA 1DH
SEC   DATA 1EH
SEC100   DATA 1FH

HOUR_ARM DATA   20H   ;闹钟时,分,秒,变量
MIN_ARM   DATA 21H
SEC_ARM   DATA 22H

STATE   DATA 23H
ALARM   BIT STATE.0   ;闹钟是否启用标志1--启用,0--禁止
LEAP   BIT STATE.1   ;是否闰年标志1--闰年,0--平年

KEY_S   DATA 24H   ;当前扫描键值
KEY_V   DATA 25H   ;上次扫描键值

DIS_BUF_U0 DATA 26H   ;LCD上排显示缓冲区
DIS_BUF_U1 DATA 27H
DIS_BUF_U2 DATA 28H
DIS_BUF_U3 DATA 29H
DIS_BUF_U4 DATA 2AH
DIS_BUF_U5 DATA 2BH
DIS_BUF_U6 DATA 2CH
DIS_BUF_U7 DATA 2DH
DIS_BUF_U8 DATA 2EH
DIS_BUF_U9 DATA 2FH
DIS_BUF_U10 DATA 30H
DIS_BUF_U11 DATA 31H
DIS_BUF_U12 DATA 32H
DIS_BUF_U13 DATA 33H
DIS_BUF_U14 DATA 34H
DIS_BUF_U15 DATA 35H


DIS_BUF_L0 DATA 36H   ;LCD下排显示缓冲区
DIS_BUF_L1 DATA 37H
DIS_BUF_L2 DATA 38H
DIS_BUF_L3 DATA 39H
DIS_BUF_L4 DATA 3AH
DIS_BUF_L5 DATA 3BH
DIS_BUF_L6 DATA 3CH
DIS_BUF_L7 DATA 3DH
DIS_BUF_L8 DATA 3EH
DIS_BUF_L9 DATA 3FH
DIS_BUF_L10 DATA 40H
DIS_BUF_L11 DATA 41H
DIS_BUF_L12 DATA 42H
DIS_BUF_L13 DATA 43H
DIS_BUF_L14 DATA 44H
DIS_BUF_L15 DATA 45H

FLAG   DATA 46H   ;标识调整状态 0-闹钟功能,1-闹钟时,2-闹钟分,3-闹钟秒
         ;4-年,5-月,6-日,7-时,8-分,9-秒,10-退出调整。
DIS_H   DATA 47H
DIS_M   DATA 48H
DIS_S   DATA 49H

DIS_S0   DATA 4AH
DIS_S1   DATA 4BH
DIS_S2   DATA 4CH
DIS_S3   DATA 4DH
DIS_S4   DATA 4EH
DIS_S5   DATA 4FH


;******************初始化***********************
   ORG 0000H
   LJMP START
   ORG 000BH
   LJMP TIMER0
   ORG 001BH
   LJMP TIMER1
   ORG 0100H
START:   MOV SP,#60H
   MOV R0,#18H
   MOV A,#00H
MEM_INI: MOV @R0,A
   INC R0
   CJNE R0,#5FH,MEM_INI
   LCALL DELAY_5ms ;初始化LCD
   MOV R0,#38H   ;设置LCD为16X2显示,5X7点阵,八位数据接口
   LCALL LCD_WCMD
   LCALL DELAY_5ms
   MOV R0,#0CH   ;设置LCD开显示及光标形式(光标不闪烁,不显示"-")
   LCALL LCD_WCMD
   LCALL DELAY_5ms
   MOV R0,#06H   ;LCD显示光标移动设置(光标地址指针加1,整屏显示不移动)
   LCALL LCD_WCMD
   LCALL DELAY_5ms
   MOV R0,#01H   ;清除LCD的显示内容
   LCALL LCD_WCMD
   LCALL DELAY_5ms


         ;第一自定义字符:
   MOV R0,#40H
   LCALL lcd_wcmd ;"01 000 000"第1行地址 (D7D6为地址设定命令形式D5D4D3为字符存放位置(0--7),D2D1D0为字符行地址(0--7))
   MOV R0,#1FH
   LCALL lcd_wdat ;"XXX 11111"第1行数据(D7D6D5为XXX,表示为任意数(一般用000),D4D3D2D1D0为字符行数据(1-点亮,0-熄灭)
   MOV R0,#41H
   LCALL lcd_wcmd   ;"01 000 001"第2行地址
   MOV R0,#11H
   LCALL lcd_wdat   ;"XXX 10001"第2行数据
   MOV R0,#42H
   LCALL lcd_wcmd ;"01 000 010"第3行地址
   MOV R0,#15H
   LCALL lcd_wdat   ;"XXX 10101"第3行数据
   MOV R0,#43H
   LCALL lcd_wcmd   ;"01 000 011"第4行地址
   MOV R0,#11H
   LCALL lcd_wdat ;"XXX 10001"第4行数据
   MOV R0,#44H
   LCALL lcd_wcmd ;"01 000 100"第5行地址
   MOV R0,#1FH
   LCALL lcd_wdat ;"XXX 11111"第5行数据
   MOV R0,#45H
   LCALL lcd_wcmd ;"01 000 101"第6行地址
   MOV R0,#0AH
   LCALL     lcd_wdat ;"XXX 01010"第6行数据
   MOV R0,#46H
   LCALL lcd_wcmd ;"01 000 110"第7行地址
   MOV R0,#1FH
   LCALL     lcd_wdat ;"XXX 11111"第7行数据
   MOV R0,#47H
   LCALL lcd_wcmd ;"01 000 111"第8行地址
   MOV R0,#00H
   LCALL     lcd_wdat ;"XXX 00000"第8行数据

         ;第二个自定义字符:
   MOV R0,#48H
   LCALL lcd_wcmd ;"01 001 000"第1行地址
   MOV R0,#01H
   LCALL     lcd_wdat ;"XXX 00001"第1行数据
   MOV R0,#49H
   LCALL lcd_wcmd ;"01 001 001"第2行地址
   MOV R0,#1BH
   LCALL     lcd_wdat ;"XXX 11011"第2行数据
   MOV R0,#4AH
   LCALL lcd_wcmd ;"01 001 010"第3行地址
   MOV R0,#1DH
   LCALL     lcd_wdat ;"XXX 11101"第3行数据
   MOV R0,#4BH
   LCALL lcd_wcmd ;"01 001 011"第4行地址
   MOV R0,#19H
   LCALL     lcd_wdat ;"XXX 11001"第4行数据
   MOV R0,#4CH
   LCALL lcd_wcmd ;"01 001 100"第5行地址
   MOV R0,#1DH
   LCALL     lcd_wdat ;"XXX 11101"第5行数据
   MOV R0,#4DH
   LCALL lcd_wcmd ;"01 001 101"第6行地址
   MOV R0,#1BH
   LCALL     lcd_wdat ;"XXX 11011"第6行数据
   MOV R0,#4EH
   LCALL lcd_wcmd ;"01 001 110"第7行地址
   MOV R0,#01H
   LCALL lcd_wdat ;"XXX 00001"第7行数据
   MOV R0,#4FH
   LCALL lcd_wcmd ;"01 001 111"第8行地址
   MOV R0,#00H
   LCALL     lcd_wdat ;"XXX 00000"第8行数据

   MOV YEAR,#5   ;置年初值
   MOV MONTH,#1 ;置月初值
   MOV DATE,#1   ;置日初值
   MOV DIS_S0,#35H ;"8"
   MOV DIS_S1,#31H ;"9"
   MOV DIS_S2,#43H ;"s"
   MOV DIS_S3,#35H ;"5"
   MOV DIS_S4,#31H ;"1"
   MOV DIS_S5,#20H ;" "
   MOV R1,#00H   ;显示一自定义字符
   LCALL WEEK_PRO
   LCALL UPDATE_BUF
   LCALL DISPLAY_PRO ;屏显初始化

;*********************主程序*********************
MAIN:   MOV IE,#8AH   ;CPU开中断,Timer0,Timer1开中断
   MOV TMOD,#11H   ;Timer0,Timer1工作于模式1, 16位定时方式
   MOV TH0,#0DCH ;Timer0置10ms定时初值
   MOV TL0,#00H
   MOV TH1,#0FFH ;Timer1置闹钟声音初值
   MOV TL1,#00H
   SETB ALARM   ;初始启动闹钟功能
   CLR TR1     ;Timer1禁止
   SETB TR0                     ;Timer0启动
   MOV KEY_V,#03H

MAIN_1:   LCALL KEY_SCAN
   MOV A,KEY_S
   XRL A,KEY_V
   JZ MAIN_1
   LCALL DELAY_5ms
   LCALL DELAY_5ms
   LCALL KEY_SCAN
   MOV A,KEY_S
   XRL A,KEY_V
   JZ MAIN_1
   MOV KEY_V,KEY_S
   MOV A,KEY_V
   XRL A,#01H
   JNZ MAIN_2
   CLR TR0   ;进入调整状态,禁止Timer0
   MOV IE,#00H   ;CPU禁止中断
   LCALL KEY_PRE_PRO ;PRE按键按下,调用PRE按键处理程序
   SJMP MAIN_1
MAIN_2:   MOV A,KEY_V
   XRL A,#02H
   JNZ MAIN_1
   LCALL KEY_ADJ_PRO ;ADJ按键按下,调用PRE按键处理程序
   SJMP MAIN_1

;*******************按键扫描程序******************
KEY_SCAN: CLR A
   MOV P1,#0FFH
   MOV C,PRE
   MOV ACC.1,C
   MOV C,ADJ
   MOV ACC.0,C
   MOV KEY_S,A     ;本次扫描键值存入KEY_S

   RET

;**************PRE按键处理程序*******************
KEY_PRE_PRO: INC FLAG
   MOV R4,FLAG
   CJNE R4,#1,KEY_PRE_1 ;注意,该指令不改变操作
   MOV R0,#0EH
   LCALL LCD_WCMD ;显示光标"_",整个光标不闪烁
   MOV DIS_S0,#61H ;"a"
   MOV DIS_S1,#6cH ;"l"
   MOV DIS_S2,#61H ;"a"
   MOV DIS_S3,#72H ;"r"
   MOV DIS_S4,#6dH ;"m"
   MOV DIS_S5,#3aH ;":"
   MOV R1,#50H   ;"P"
   MOV DIS_H,HOUR_ARM
   MOV DIS_M,MIN_ARM
   MOV DIS_S,SEC_ARM
   LCALL UPDATE_BUF
   LCALL DISPLAY_PRO ;更新屏显内容
   MOV R0,#47H
   LCALL LCD_POS   ;使光标位于第一个调整项下
   JMP KEY_PRE_E
KEY_PRE_1: CJNE R4,#2,KEY_PRE_2
   MOV R0,#49H
   LCALL LCD_POS   ;光标置小时报警设置位置
   JMP KEY_PRE_E
KEY_PRE_2: CJNE R4,#3,KEY_PRE_3
   MOV R0,#4CH
   LCALL LCD_POS   ;光标置分钟报警设置位置
   JMP KEY_PRE_E
KEY_PRE_3: CJNE R4,#4,KEY_PRE_4
   MOV R0,#4FH
   LCALL LCD_POS   ;光标置秒时报警设置位置
   JMP KEY_PRE_E
KEY_PRE_4: CJNE R4,#5,KEY_PRE_5
   MOV DIS_S0,#74H ;"t"
   MOV DIS_S1,#69H ;"i"
   MOV DIS_S2,#6dH ;"m"
   MOV DIS_S3,#65H ;"e"
   MOV DIS_S4,#3aH ;":"
   MOV DIS_S5,#20H ;" "
   MOV R1,#50H   ;"P"
   MOV DIS_H,HOUR
   MOV DIS_M,MIN
   MOV DIS_S,SEC
   LCALL UPDATE_BUF
   LCALL DISPLAY_PRO ;更新屏显内容
   MOV R0,#05H
   LCALL LCD_POS   ;光标置年调整位置
   JMP KEY_PRE_E
KEY_PRE_5: CJNE R4,#6, KEY_PRE_6
   MOV R0,#08H
   LCALL LCD_POS   ;光标置月调整位置
   JMP KEY_PRE_E
KEY_PRE_6: CJNE R4,#7,KEY_PRE_7
   MOV R0,#0bH
   LCALL LCD_POS   ;光标置日调整位置
   JMP KEY_PRE_E
KEY_PRE_7: CJNE R4,#8,KEY_PRE_8
   MOV R0,#49H
   LCALL LCD_POS   ;光标置时调整位置
   JMP KEY_PRE_E
KEY_PRE_8: CJNE R4,#9,KEY_PRE_9
   MOV R0,#4cH
   LCALL LCD_POS   ;光标置分调整位置
   JMP KEY_PRE_E
KEY_PRE_9: CJNE R4,#10,KEY_PRE_10
   MOV R0,#4fH
   LCALL LCD_POS   ;光标置秒调整位置
   JMP KEY_PRE_E
KEY_PRE_10: MOV FLAG,#0   ;FLAG到11,就清零
   MOV R0,#0CH
   LCALL LCD_WCMD ;设置LCD开显示及光标不闪烁,不显示"-"
   MOV R0,#01H
   LCALL LCD_WCMD ;清除LCD的显示内容
   MOV IE,#8AH   ;CPU开中断,TIMER0,TIMER1开中断
   SETB TR0   ;启动TIMER0
KEY_PRE_E:
   RET

;**************ADJ按键处理程序*******************
KEY_ADJ_PRO: MOV R5,FLAG
   CJNE R5,#0,KEY_ADJ_0   ;FLAG=0,如果有闹钟声音,就停止闹钟声音
   MOV C,TR1
   JNC KEY_ADJ_A
   CLR TR1
KEY_ADJ_A: JMP KEY_ADJ_E
KEY_ADJ_0: CJNE R5,#1,KEY_ADJ_1   ;FLAG=1,调整是否启用闹钟
   CPL ALARM
   LCALL UPDATE_BUF
   LCALL DISPLAY_PRO
   MOV R0,#47H
   LCALL LCD_POS
   JMP KEY_ADJ_E
KEY_ADJ_1: CJNE R5,#2,KEY_ADJ_2   ;FLAG=2,调整闹钟时
   INC HOUR_ARM
   MOV A,HOUR_ARM
   CJNE A,#24,KEY_ADJ_1_1
   MOV HOUR_ARM,#0
KEY_ADJ_1_1: MOV DIS_H,HOUR_ARM
   LCALL UPDATE_BUF
   LCALL DISPLAY_PRO
   MOV R0,#49H
   LCALL LCD_POS
   JMP KEY_ADJ_E
KEY_ADJ_2: CJNE R5,#3,KEY_ADJ_3   ;FLAG=3,调整闹钟分
   INC MIN_ARM
   MOV A,MIN_ARM
   CJNE A,#60,KEY_ADJ_2_1
   MOV MIN_ARM,#0
KEY_ADJ_2_1: MOV DIS_M,MIN_ARM
   LCALL UPDATE_BUF
   LCALL DISPLAY_PRO
   MOV R0,#4CH
   LCALL LCD_POS
   JMP KEY_ADJ_E
KEY_ADJ_3: CJNE R5,#4,KEY_ADJ_4   ;FLAG=4,调整闹钟秒
   INC SEC_ARM
   MOV A,SEC_ARM
   CJNE A,#60,KEY_ADJ_3_1
   MOV SEC_ARM,#0
KEY_ADJ_3_1: MOV DIS_S,SEC_ARM
   LCALL UPDATE_BUF
   LCALL DISPLAY_PRO
   MOV R0,#4FH
   LCALL LCD_POS
   JMP KEY_ADJ_E
KEY_ADJ_4: CJNE R5,#5,KEY_ADJ_5   ;FLAG=5,调整年
   INC YEAR
   MOV A,YEAR
   CJNE A,#100,KEY_ADJ_4_1
   MOV YEAR,#0
KEY_ADJ_4_1: LCALL WEEK_PRO
   LCALL UPDATE_BUF
   LCALL DISPLAY_PRO
   MOV R0,#05H
   LCALL LCD_POS
   JMP KEY_ADJ_E
KEY_ADJ_5: CJNE R5,#6,KEY_ADJ_6   ;FLAG=6,调整月
   INC MONTH
   MOV A,MONTH
   CJNE A,#13,KEY_ADJ_5_1
   MOV MONTH,#1
KEY_ADJ_5_1: LCALL WEEK_PRO
   LCALL UPDATE_BUF
   LCALL DISPLAY_PRO
   MOV R0,#08H
   LCALL LCD_POS
   JMP KEY_ADJ_E
KEY_ADJ_6: CJNE R5,#7,KEY_ADJ_7   ;FLAG=7,调整日
   INC DATE
   MOV A,MONTH
   XRL A,#2
   JNZ KEY_ADJ_6_2   ;不是二月跳转
   MOV A,DATE     ;
   MOV C,LEAP     ;判断是否闰年
   JC KEY_ADJ_6_1
   XRL A,#29     ;平年二月日期28天
   JNZ KEY_ADJ_6_5
   JMP KEY_ADJ_6_4
KEY_ADJ_6_1: XRL A,#30     ;闰年二月日期29天
   JNZ KEY_ADJ_6_5
   JMP KEY_ADJ_6_4   ;跳转到月处理
KEY_ADJ_6_2: MOV A,MONTH
   XRL A,#4
   JZ KEY_ADJ_6_3
   MOV A,MONTH
   XRL A,#6
   JZ KEY_ADJ_6_3
   MOV A,MONTH
   XRL A,#9
   JZ KEY_ADJ_6_3
   MOV A,MONTH
   XRL A,#11
   JZ KEY_ADJ_6_3
   MOV A,DATE
   XRL A,#32     ;大月日期31天
   JNZ KEY_ADJ_6_5
   JMP KEY_ADJ_6_4
KEY_ADJ_6_3: MOV A,DATE
   XRL A,#31     ;小月日期30天
   JNZ KEY_ADJ_6_5
KEY_ADJ_6_4: MOV DATE,#1
KEY_ADJ_6_5: LCALL WEEK_PRO
   LCALL UPDATE_BUF
   LCALL DISPLAY_PRO
   MOV R0,#0BH
   LCALL LCD_POS
   JMP KEY_ADJ_E
KEY_ADJ_7: CJNE R5,#8,KEY_ADJ_8   ;FLAG=8,调整时
   INC HOUR
   MOV A,HOUR
   CJNE A,#24,KEY_ADJ_7_1
   MOV HOUR,#0
KEY_ADJ_7_1: MOV DIS_H,HOUR
   LCALL UPDATE_BUF
   LCALL DISPLAY_PRO
   MOV R0,#49H
   LCALL LCD_POS
   JMP KEY_ADJ_E
KEY_ADJ_8: CJNE R5,#9,KEY_ADJ_9   ;FLAG=9,调整分
   INC MIN
   MOV A,MIN
   CJNE A,#60,KEY_ADJ_8_1
   MOV MIN,#0
KEY_ADJ_8_1: MOV DIS_M,MIN
   LCALL UPDATE_BUF
   LCALL DISPLAY_PRO
   MOV R0,#4CH
   LCALL LCD_POS
   JMP KEY_ADJ_E
KEY_ADJ_9: CJNE R5,#10,KEY_ADJ_E ;FLAG=10,调整秒
   INC SEC
   MOV A,SEC
   CJNE A,#60,KEY_ADJ_9_1
   MOV SEC,#0
KEY_ADJ_9_1: MOV DIS_S,SEC
   LCALL UPDATE_BUF
   LCALL DISPLAY_PRO
   MOV R0,#4FH
   LCALL LCD_POS
   JMP KEY_ADJ_E
KEY_ADJ_E:
   RET

;***************Timer0定时中断程序*****************
TIMER0:   MOV     TH0,#0DCH
   MOV TL0,#00H
   INC     SEC100
   MOV     A,SEC100
   CJNE A,#100,TIMER0_E
   MOV SEC100,#0
   LCALL TIME_PRO
   MOV A,SEC     ;"51C51显示1秒钟,消失一秒种,形成闪动
   ANL A,#01
   JZ TIMER0_1
   MOV DIS_S0,#20H   ;" "
   MOV DIS_S1,#20H   ;" "
   MOV DIS_S2,#20H   ;" "
   MOV DIS_S3,#20H   ;" "
   MOV DIS_S4,#20H   ;" "
   MOV DIS_S5,#20H   ;" "
   SJMP TIMER0_2
TIMER0_1: MOV DIS_S0,#35H   ;"5"
   MOV DIS_S1,#31H   ;"1"
   MOV DIS_S2,#43H   ;"C"
   MOV DIS_S3,#35H   ;"5"
   MOV DIS_S4,#31H   ;"1"
   MOV DIS_S5,#20H   ;" "
TIMER0_2: MOV R1,#00H
   MOV DIS_H,HOUR
   MOV DIS_M,MIN
   MOV DIS_S,SEC
   LCALL UPDATE_BUF
   LCALL DISPLAY_PRO
TIMER0_E:
   RETI


;***********Timer1定时中断程序******************
TIMER1:   MOV TH1,#0FFH
   MOV TL1,#00H
   CPL SPK
   RETI

;**************时间日期处理函数******************
TIME_PRO: INC SEC     ;秒处理
   MOV A,SEC
   CJNE A,#60,TIME_PRO_A
   MOV SEC,#0
   INC MIN     ;分处理
   MOV A,MIN
   CJNE A,#60,TIME_PRO_A
   MOV MIN,#0
   INC HOUR     ;时处理
   MOV A,HOUR
   CJNE A,#24,TIME_PRO_A
   MOV HOUR,#0
   INC DATE     ;日处理(日处理要考虑是否闰年,大月,小月)
   MOV A,MONTH
   XRL A,#2
   JNZ TIME_PRO_D2   ;不是二月,转TIME_PRO_D2
   MOV A,DATE     ;
   MOV C,LEAP     ;判断是否闰年
   JC TIME_PRO_D1
   XRL A,#29     ;平年二月日期28天
   JNZ TIME_PRO_W
   SJMP TIME_PRO_M   ;跳转到月处理
TIME_PRO_D1: XRL A,#30     ;闰年二月日期29天
   JNZ TIME_PRO_W
   SJMP TIME_PRO_M   ;跳转到月处理
TIME_PRO_D2: MOV A,MONTH
   XRL A,#4
   JZ TIME_PRO_D3
   MOV A,MONTH
   XRL A,#6
   JZ TIME_PRO_D3
   MOV A,MONTH
   XRL A,#9
   JZ TIME_PRO_D3
   MOV A,MONTH
   XRL A,#11
   JZ TIME_PRO_D3
   MOV A,DATE
   XRL A,#32     ;大月日期31天
   JNZ TIME_PRO_W
   SJMP TIME_PRO_M   ;跳转到月处理
TIME_PRO_D3: MOV A,DATE
   XRL A,#31     ;小月日期30天
   JNZ TIME_PRO_W
TIME_PRO_M: MOV DATE,#1
   INC MONTH     ;月处理
   MOV A,MONTH
   CJNE A,#13,TIME_PRO_W
   MOV MONTH,#1
   INC YEAR     ;年处理
   MOV A,YEAR
   CJNE A,#100,TIME_PRO_W
   MOV YEAR,#0
TIME_PRO_W: LCALL WEEK_PRO   ;星期处理

TIME_PRO_A: JNB ALARM,TIME_PRO_E ;alarm=0,闹钟功能禁用,不判断闹钟时间是否到
   MOV A,SEC
   CJNE A,SEC_ARM,TIME_PRO_E   ;alarm=1,闹钟功能启用,判断秒
   MOV A,MIN
   CJNE A,MIN_ARM,TIME_PRO_E   ;alarm=1,闹钟功能启用,判断分
   MOV A,HOUR
   CJNE A,HOUR_ARM,TIME_PRO_E ;alarm=1,闹钟功能启用,判断时
   SETB TR1       ;闹钟时间到,启动Timer1(TR1=1)
TIME_PRO_E:

   RET

;**********星期自动运算函数*********************
;星期运算常数W(5或6)
;闰年的数目L(0--99年:L=YEAR/4 整除)
;年数YEAR
;月参变数MONTH_TAB(0,3,3,6,1,4,6,2,5,0,3,5)
;日期DATE
;星期数=(W+L+YEAR+MONTH_TAB+DATE)%7 (求余)

WEEK_PRO: MOV A,MONTH     ;确定星期运算常数W
   XRL A,#1
   JZ WEEK_PRO_1
   MOV A,MONTH
   XRL A,#2
   JZ WEEK_PRO_1
   SJMP WEEK_PRO_2
WEEK_PRO_1: LCALL LEAP_PRO
   MOV C,LEAP
   JNC WEEK_PRO_2
   MOV R3,#5
   SJMP WEEK_PRO_3
WEEK_PRO_2: MOV R3,#6
WEEK_PRO_3: MOV A,YEAR     ;计算闰年的数目L
   MOV B,#4
   DIV AB
   ADD A,R3     ;W+L
   MOV R3,A
   MOV A,YEAR
   ADD A,R3     ;(W+L)+YEAR
   MOV R3,A
   MOV DPTR,#MONTH_TAB
   MOV A,MONTH
   MOVC A,@A+DPTR
   ADD A,R3     ;(W+L+YEAR)+MONTH_TAB
   MOV R3,A
   MOV A,DATE
   ADD A,R3     ;(W+L+YEAR+MONTH_TAB+DATE)
   MOV B,#7
   DIV AB     ;余数即为星期数
   MOV WEEK,B
   RET

;**********闰年的判断函数*********************
;闰年的条件:年(YEAR)能被4整除、但不能被100整除;或者被400整除。
;如果我们只考虑(00--99),则只需考虑年(YEAR)能被4整除即可。
LEAP_PRO: MOV A,YEAR
   MOV B,#4
   DIV AB
   MOV A,B
   JZ LEAP_PRO_1 ;能被4整除
   CLR LEAP   ;平年,清零LEAP
   LJMP LEAP_PRO_E
LEAP_PRO_1: SETB LEAP   ;闰年,置位LEAP
LEAP_PRO_E:
   RET

;**********更新显示缓冲区********************
;入口R1,
UPDATE_BUF: MOV DIS_BUF_U0,R1 ;调整时,"P",正常工作,显示一自定义字符
   MOV DIS_BUF_U1,#20H ;空格
   MOV DIS_BUF_U2,#32H ;"2"
   MOV DIS_BUF_U3,#30H ;"0"
   MOV A,YEAR   ;更新年数据
   MOV B,#10
   DIV AB
   ADD A,#48   ;二进制转换为ASCMA码
   MOV DIS_BUF_U4,A
   MOV A,B
   ADD A,#48
   MOV DIS_BUF_U5,A
   MOV DIS_BUF_U6,#2DH ;"-"
   MOV A,MONTH   ;更新月数据
   MOV B,#10
   DIV AB
   ADD A,#48
   MOV DIS_BUF_U7,A
   MOV A,B
   ADD A,#48
   MOV DIS_BUF_U8,A
   MOV DIS_BUF_U9,#2DH ;"-"
   MOV A,DATE   ;更新日数据
   MOV B,#10
   DIV AB
   ADD A,#48
   MOV DIS_BUF_U10,A
   MOV A,B
   ADD A,#48
   MOV DIS_BUF_U11,A
   MOV DIS_BUF_U12,#20H;空格
   MOV B,WEEK   ;更新星期数据
   MOV A,#3
   MUL AB
   MOV B,A
   MOV DPTR,#WEEK_TAB
   MOVC A,@A+DPTR
   MOV DIS_BUF_U13,A
   MOV A,B
   INC A
   MOVC A,@A+DPTR
   MOV DIS_BUF_U14,A
   MOV A,B
   INC A
   INC A
   MOVC A,@A+DPTR
   MOV DIS_BUF_U15,A

   MOV A,DIS_S0
   MOV DIS_BUF_L0,A
   MOV A,DIS_S1
   MOV DIS_BUF_L1,A
   MOV A,DIS_S2
     MOV DIS_BUF_L2,A
   MOV A,DIS_S3
   MOV DIS_BUF_L3,A
   MOV A,DIS_S4
   MOV DIS_BUF_L4,A
   MOV A,DIS_S5
   MOV DIS_BUF_L5,A
   MOV DIS_BUF_L6,#20H ;空格
   MOV C,ALARM
   JC UPDATE_BUF_1
   MOV DIS_BUF_L7,#20H ;闹钟禁用时,显示空格
   SJMP UPDATE_BUF_2
UPDATE_BUF_1: MOV DIS_BUF_L7,#01H ;闹钟启用时,显示小喇叭
UPDATE_BUF_2: MOV A,DIS_H
   MOV B,#10
   DIV AB
   ADD A,#48
   MOV DIS_BUF_L8,A
   MOV A,B
   ADD A,#48
   MOV DIS_BUF_L9,A
   MOV DIS_BUF_L10,#3AH;":"
   MOV A,DIS_M
   MOV B,#10
   DIV AB
   ADD A,#48
   MOV DIS_BUF_L11,A
   MOV A,B
   ADD A,#48
   MOV DIS_BUF_L12,A
   MOV DIS_BUF_L13,#3AH;":"
   MOV A,DIS_S
   MOV B,#10
   DIV AB
   ADD A,#48
   MOV DIS_BUF_L14,A
   MOV A,B
   ADD A,#48
   MOV DIS_BUF_L15,A
   RET

;************显示处理程序*********************
DISPLAY_PRO: MOV R0,#00H
   LCALL LCD_POS
   MOV R0,DIS_BUF_U0
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_U1
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_U2
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_U3
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_U4
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_U5
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_U6
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_U7
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_U8
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_U9
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_U10
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_U11
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_U12
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_U13
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_U14
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_U15
   LCALL LCD_WDAT

   MOV R0,#40H
   LCALL LCD_POS
   MOV R0,DIS_BUF_L0
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_L1
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_L2
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_L3
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_L4
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_L5
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_L6
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_L7
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_L8
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_L9
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_L10
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_L11
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_L12
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_L13
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_L14
   LCALL LCD_WDAT
   MOV R0,DIS_BUF_L15
   LCALL LCD_WDAT
   RET

;**********LCD忙标志BF测试程序**************
BF_TEST: PUSH   ACC   ;保护ACC数据
                 CLR         RS                           ;RS=0
                 SETB       RW                   ;RW=1
                 SETB       EP                           ;E=高电平
   NOP
   NOP
   NOP
   NOP
   MOV P0,#0FFH                 ;将p0口置1,保证后面数据正确读入(由 P0口结构决定)
WT_BF:                   NOP                                           ;
                 JB           P0.7,WT_BF             ;DB7=0   LCD控制器空闲,DB7=1   LCD控制器忙
                 CLR EP
   POP   ACC                           ;释放ACC数据
                 RET

;**********LCD指令写入程序******************
;程序入口:R0
LCD_WCMD: LCALL BF_TEST   ;检测忙标志
   CLR RS
   CLR RW
   CLR EP
   NOP
   NOP
   MOV P0,R0
   NOP
   NOP
   NOP
   NOP
   SETB EP
   NOP
   NOP
   NOP
   NOP
   CLR   EP
   RET

;**********LCD数据写入程序****************
;程序入口:R0
LCD_WDAT: LCALL BF_TEST   ;检测忙标志
   SETB RS
   CLR RW
   CLR EP
   NOP
   NOP
   MOV P0,R0
   NOP
   NOP
   NOP
   NOP
   SETB EP
   NOP
   NOP
   NOP
   NOP
   CLR EP
   RET

;**********LCD数据指针位置子程序**************
;程序入口:R0
LCD_POS: MOV A,R0
   ORL A,#80H
   MOV R0,A
   LCALL LCD_WCMD
   RET

;**********延时约5ms子程序********************
;晶振f=11.0592Mhz
;延时时间=(1+(1+2*100+2)*25)*12/11.0592=5507us(约5ms)
DELAY_5ms: MOV R7,#25
DELAY1:   MOV R6,#100
DELAY2:   DJNZ R6,DELAY2
   DJNZ R7,DELAY1
   RET

;***********星期自动运算月参变数**************
MONTH_TAB: DB 0
   DB 0
   DB 3
   DB 3
   DB 6

我要评论
  • 匿名发表
  • [添加到收藏夹]
  • 发表评论:(匿名发表无需登录,已登录用户可直接发表。) 登录状态:未登录
最新评论
  • 评论人:[匿名] 时间: [2012/3/16 23:26:51] IP:[118.183.194.*]
  • ***更新显示缓冲区****第36步 MOV DPTR,#WEEK_TAB 去掉_TAP 程序最后加上 END 完全可以编译。好强!
  • 评论人:[匿名] 时间: [2012/3/16 23:25:48] IP:[118.183.194.*]
  • ***更新显示缓冲区****第36步 MOV DPTR,#WEEK_TAB 去掉_TAP 程序最后加上 END 完全可以编译。好强!

网站导航 管理登陆 ┊ 免责声明 问题反馈  友链说明
本站部分内容来自网络共享资源,如有冒犯您的权利请来信告之删除或纠正!
不得对本站进行复制、盗链或镜像,转载内容须获得同意或授权;欢迎友情链接、站务合作!

    我要报警 Alexa
 mcusy_cn#126.com (请把#改成@) 交流:522422171
本站学习交流群:138..158(高级群1-)、77930286(高级群2)、61804809(群3)
Copyright© MCUSY All Rights Reserved
本站网警备案号: WZ36040002485
  ICP备案证书号:粤ICP备09034963号