日志档案

发表于 2008-4-10 15:54:40

9

标签: 1602  液晶  万年历  汇编  C语言  

1602液晶万年历汇编和C语言

1602液晶万年历汇编和C语言

好的就顶,相互帮助是我们的传统美德哦~~~~

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
  DB 1
  DB 4
  DB 6
  DB 2
  DB 5
  DB  0
  DB 3
  DB 5

WEEK_TAB: DB 'S','U','N'
  DB 'M','O','N'
  DB 'T','U','E'
  DB 'W','E','D'
  DB 'T','H','U'
  DB 'F','R','I'
  DB 'S','A','T'


  END

 

下载区:

rar

系统分类: 单片机   |   用户分类: 单片机   |   来源: 原创   |   【推荐给朋友】

    阅读(1076)    回复(13)  

投一票您将和博主都有获奖机会!

  • hnjztyx

    2008-4-11 19:40:13

    自己想写个12864液晶的时钟日历程序,拿边个回去学习一下!!

  • wujianhua

    2008-4-12 22:13:30

    如果有原理图,请发一份到我邮箱,谢谢!atarlic@163.com

  • ahai0306

    2008-4-17 12:47:26

    学习学习,用我的开发板体验一下

  • yjc99

    2008-4-17 18:25:12

    支持一下

  • pw308167510

    2008-4-22 18:15:48

    dddddddddddddddddddd

  • mianyang

    2008-4-22 19:12:24

    DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD

  • dhaichen

    2008-4-22 21:59:53

    支持

  • wsmwbx

    2008-4-25 8:16:53

    我想要个用VHDL语言编的,能帮忙吗? wsmwbx@163.com

  • dzcz88

    2008-5-3 22:39:52

    在给出汇编语言的同时,不知道有时间可以给出,它的设计图和设计思路不,我也是刚学单片机的,

  • zkhailang

    2008-5-5 12:40:25

    很不赖! 支持呀!!

  • linlaser

    2008-5-5 22:27:46

    太棒了!!

  • lina0404

    2008-5-6 16:28:18

    能把原理图给我吗,拜托了。毕业设计需要。ysl02_04@hotmail.com

  • lina0404

    2008-5-6 16:29:00

    能把原理图给我吗,拜托了。毕业设计需要。ysl02_04@hotmail.com