找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2194|回复: 4
打印 上一主题 下一主题
收起左侧

求帮忙把如下程序改成可以在普中开发板上使用

[复制链接]
跳转到指定楼层
楼主
ID:255209 发表于 2017-11-29 15:12 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
#include <reg51.h>
#include <intrins.h>
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 = P3^3;                                //调整键(AN3)
sbit        SET = P3^4;                                //调整键(AN4)
sbit        SPK = P3^6;                               
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]=t2[6];                        //空格
        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);}
        lcd_pos(0x40);
        for (i=0;i<=15;i++)
                {lcd_wdat(dis_buf2);}
}
//Timer0中断处理程序,秒的产生
void timer0() interrupt 1
{
        TH0=0xD8;                       
        TL0=0xF0;               
        sec100++;
        if(sec100 >= 100)        //1秒时间 (100*10ms=1000ms=1s)
                {sec100 = 0;
                pro_timedate();//调用时间和日期处理程序
                }
        if (sec&0x01)                                                                                //"__run__"闪一秒,停一秒
                update_disbuf(0x00,"       ",hour,min,sec);           //0x00表示显示00位置的自定义字符               
        else
  update_disbuf(0x00,"__run__",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=0x80;                               
        TL1=0x00;
        SPK=~SPK;
        t++;
                               
}
//外部中断INT1中断处理程序,停止报警声音
void int1() interrupt 2
{
        if(TR1)
                TR1=0;                               
}

这个程序代码怎么改啊,求大神指教

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:240626 发表于 2017-11-29 15:34 | 只看该作者
很简单的,你先把你的开发板的原理图找到,然后改最上面的sbit特殊寄存器的位地址就可以使用了。
回复

使用道具 举报

板凳
ID:157238 发表于 2017-11-29 20:15 | 只看该作者
把这个程序的硬件连接官谢对应到你的开发板上的硬件连接就应该可以了
回复

使用道具 举报

地板
ID:155507 发表于 2017-11-29 20:56 | 只看该作者
这个程序代码改了


  1. #include <reg51.h>
  2. #include <intrins.h>

  3. unsigned char code dis_week[]={"SUN,MON,TUE,WED,THU,FRI,SAT"};
  4. unsigned char code para_month[13]={0,0,3,3,6,1,4,6,2,5,0,3,5};        //星期月参变数
  5. unsigned char data dis_buf1[16];                //lcd上排显示缓冲区
  6. unsigned char data dis_buf2[16];                //lcd下排显示缓冲区               
  7. unsigned char data year,month,date,week; //年、月、日、星期
  8. unsigned char data armhour,armmin,armsec; //闹钟时、分、秒
  9. unsigned char data hour,min,sec,sec100;        //时、分、秒、百分之一秒
  10. unsigned char data flag,vkey,skey;//设置状态计数标志、按键先前值、按键当前值      
  11. bit        alarm;        //标识是否启用闹钟,1--启用,0--关闭
  12. sbit        rs = P2^6;  //P2^0;        //LCD数据/命令选择端(H/L)
  13. sbit        rw = P2^5; //P2^1;         //LCD读/写选择端(H/L)
  14. sbit        ep = P2^7; //P2^2;          //LCD使能控制
  15. sbit        PRE = P3^2; //P3^3;         //调整键(AN3)
  16. sbit        SET = P3^3; //P3^4;         //调整键(AN4)
  17. sbit        SPK = P1^5;    //P3^6;                              
  18. void delayms(unsigned char ms);        //延时程序
  19. bit  lcd_busy();                       //测试LCD忙碌状态程序
  20. void lcd_wcmd(char cmd);                //写入指令到LCD程序
  21. void lcd_wdat(char dat);                //写入数据到LCD程序
  22. void lcd_pos(char pos);                  //LCD数据指针位置程序
  23. void lcd_init();                         //LCD初始化设定程序
  24. void pro_timedate();                     //时间日期处理程序
  25. void pro_display();                      //显示处理程序
  26. void pro_key();                          //按键处理程序
  27. void time_alarm();                       //定时报警功能(闹钟)
  28. unsigned char scan_key();                //按键扫描程序
  29. unsigned char week_proc();               //星期自动计算与显示函数
  30. bit leap_year();                         //判断是否为闰年
  31. void lcd_sef_chr();                      //LCD自定义字符程序
  32. void update_disbuf(unsigned char t1, unsigned char t2[], unsigned char dis_h, unsigned char dis_m, unsigned char dis_s);                       
  33. //更新显示缓冲区函数
  34. // 延时程序
  35. void delay(unsigned char ms)
  36. {
  37.   while(ms--)
  38.         {        unsigned char i;
  39.                 for(i = 0; i< 250; i++)     
  40.                 {
  41.                         _nop_();         //执行一条_nop_()指令为一个机器周期
  42.                         _nop_();
  43.                         _nop_();
  44.                         _nop_();
  45.                 }
  46.         }
  47. }               

  48. //测试LCD忙碌状态
  49. bit lcd_busy()
  50. {      
  51.         bit result;
  52.         rs = 0;
  53.         rw = 1;
  54.         ep = 1;
  55.         _nop_();
  56.         _nop_();
  57.         _nop_();
  58.         _nop_();
  59.         result =(bit)(P0&0x80);        //LCD的D0--D7中,D7=1为忙碌,D7=0为空闲
  60.         ep = 0;
  61.         return result;      
  62. }
  63. //写入指令到LCD
  64. void lcd_wcmd(char cmd)
  65. {                                                      
  66.         while(lcd_busy());        //当lcd_busy为1时,再次检测LCD忙碌状态,lcd-busy为0时,开始写指令
  67.         rs = 0;
  68.         rw = 0;
  69.         ep = 0;
  70.         _nop_();
  71.         _nop_();      
  72.         P0 = cmd;
  73.         _nop_();
  74.         _nop_();
  75.         _nop_();
  76.         _nop_();
  77.         ep = 1;
  78.         _nop_();
  79.         _nop_();
  80.         _nop_();
  81.         _nop_();
  82.         ep = 0;               
  83. }
  84. //写入数据到LCD
  85. void lcd_wdat(char dat)      
  86. {                                                      
  87.         while(lcd_busy());        //当lcd_busy为1时,再次检测LCD忙碌状态,lcd-busy为0时,开始写数据
  88.         rs = 1;
  89.         rw = 0;
  90.         ep = 0;
  91.         P0 = dat;
  92.         _nop_();
  93.         _nop_();
  94.         _nop_();
  95.         _nop_();
  96.         ep = 1;
  97.         _nop_();
  98.         _nop_();
  99.         _nop_();
  100.         _nop_();
  101.         ep = 0;      
  102. }
  103. //LCD数据指针位置程序
  104. void lcd_pos(char pos)
  105. {                                               
  106.         lcd_wcmd(pos|0x80);        //数据指针=80+地址码(00H~27H,40H~67H)
  107. }
  108. //设定二个自定义字符,(注意:LCD1602中自定义字符的地址为0x00--0x07,即可定义8个字符)
  109. //这里我们设定把一个自定义字符放在0x00位置(000),另一个放在0x01位子(001)
  110. void lcd_sef_chr()
  111. {        //第一个自定义字符
  112.         lcd_wcmd(0x40);        //"01 000 000"  第1行地址 (D7D6为地址设定命令形式D5D4D3为字符存放位置(0--7),D2D1D0为字符行地址(0--7))
  113.         lcd_wdat(0x1f);        //"XXX 11111"        第1行数据(D7D6D5为XXX,表示为任意数(一般用000),D4D3D2D1D0为字符行数据(1-点亮,0-熄灭)
  114.         lcd_wcmd(0x41);        //"01 000 001"         第2行地址
  115.         lcd_wdat(0x11);        //"XXX 10001"        第2行数据
  116.         lcd_wcmd(0x42);        //"01 000 010"         第3行地址
  117.         lcd_wdat(0x15);        //"XXX 10101"        第3行数据
  118.         lcd_wcmd(0x43);        //"01 000 011"         第4行地址
  119.         lcd_wdat(0x11);        //"XXX 10001"        第4行数据
  120.         lcd_wcmd(0x44);        //"01 000 100"         第5行地址
  121.         lcd_wdat(0x1f);        //"XXX 11111"        第5行数据
  122.         lcd_wcmd(0x45);        //"01 000 101"         第6行地址
  123.         lcd_wdat(0x0a);        //"XXX 01010"        第6行数据
  124.         lcd_wcmd(0x46);        //"01 000 110"         第7行地址
  125.         lcd_wdat(0x1f);        //"XXX 11111"        第7行数据
  126.         lcd_wcmd(0x47);        //"01 000 111"         第8行地址
  127.         lcd_wdat(0x00);        //"XXX 00000"        第8行数据
  128.         //第二个自定义字符
  129.         lcd_wcmd(0x48);        //"01 001 000"  第1行地址  
  130.         lcd_wdat(0x01);        //"XXX 00001"        第1行数据
  131.         lcd_wcmd(0x49);        //"01 001 001"         第2行地址
  132.         lcd_wdat(0x1b);        //"XXX 11011"        第2行数据
  133.         lcd_wcmd(0x4a);        //"01 001 010"         第3行地址
  134.         lcd_wdat(0x1d);        //"XXX 11101"        第3行数据
  135.         lcd_wcmd(0x4b);        //"01 001 011"         第4行地址
  136.         lcd_wdat(0x19);        //"XXX 11001"        第4行数据
  137.         lcd_wcmd(0x4c);        //"01 001 100"         第5行地址
  138.         lcd_wdat(0x1d);        //"XXX 11101"        第5行数据
  139.         lcd_wcmd(0x4d);        //"01 001 101"         第6行地址
  140.         lcd_wdat(0x1b);        //"XXX 11011"        第6行数据
  141.         lcd_wcmd(0x4e);        //"01 001 110"         第7行地址
  142.         lcd_wdat(0x01);        //"XXX 00001"        第7行数据
  143.         lcd_wcmd(0x4f);        //"01 001 111"         第8行地址
  144.         lcd_wdat(0x00);        //"XXX 00000"        第8行数据
  145. }
  146. //LCD初始化设定
  147. void lcd_init()
  148. {                                               
  149.         lcd_wcmd(0x38);                //设置LCD为16X2显示,5X7点阵,八位数据借口
  150.         delay(1);
  151.         lcd_wcmd(0x0c);                //LCD开显示及光标设置(光标不闪烁,不显示"-")
  152.         delay(1);
  153.         lcd_wcmd(0x06);                //LCD显示光标移动设置(光标地址指针加1,整屏显示不移动)
  154.         delay(1);
  155.         lcd_wcmd(0x01);                //清除LCD的显示内容
  156.         delay(1);
  157. }
  158. //闰年的计算
  159. bit leap_year()
  160. {
  161.         bit leap;
  162.         if((year%4==0&&year%100!=0)||year%400==0)//闰年的条件
  163.         leap=1;
  164.         else
  165.         leap=0;
  166.         return leap;
  167. }
  168. //星期的自动运算和处理
  169. unsigned char week_proc()
  170. {        unsigned char num_leap;      
  171.         unsigned char c;
  172.         num_leap=year/4-year/100+year/400;//自00年起到year所经历的闰年数
  173.         if( leap_year()&& month<=2 )          //既是闰年且是1月和2月      
  174.         c=5;
  175.         else
  176.         c=6;
  177.         week=(year+para_month[month]+date+num_leap+c)%7;//计算对应的星期
  178.         return week;
  179. }      
  180. //更新显示缓冲区
  181. void update_disbuf(unsigned char t1,unsigned char t2[],unsigned char dis_h,unsigned char dis_m,unsigned char dis_s)      
  182. {        dis_buf1[0]=t1;        //
  183.         dis_buf1[1]=0x20;           //空格
  184.         dis_buf1[2]=50;             //'2'
  185.         dis_buf1[3]=48;             //'0'
  186.         dis_buf1[4]=year/10+48;
  187.         dis_buf1[5]=year%10+48;
  188.         dis_buf1[6]=0x2d;
  189.         dis_buf1[7]=month/10+48;
  190.         dis_buf1[8]=month%10+48;
  191.         dis_buf1[9]=0x2d;           //'-'
  192.         dis_buf1[10]=date/10+48;
  193.         dis_buf1[11]=date%10+48;
  194.         dis_buf1[12]=0x20;
  195.         dis_buf1[13]=dis_week[4*week];
  196.         dis_buf1[14]=dis_week[4*week+1];
  197.         dis_buf1[15]=dis_week[4*week+2];
  198.         dis_buf2[0]=t2[0];
  199.         dis_buf2[1]=t2[1];
  200.         dis_buf2[2]=t2[2];
  201.         dis_buf2[3]=t2[3];
  202.         dis_buf2[4]=t2[4];
  203.         dis_buf2[5]=t2[5];
  204.         dis_buf2[6]=t2[6];           //空格
  205.         if (alarm)
  206.         dis_buf2[7]=0x01;                //alarm=1,显示闹钟启用标致(第二个自定义字符)
  207.         else
  208.         dis_buf2[7]=0x20;                //alarm=0,不显示闹钟启用标致
  209.         dis_buf2[8]=dis_h/10+48;
  210.         dis_buf2[9]=dis_h%10+48;
  211.         dis_buf2[10]=0x3a;                        //':'
  212.         dis_buf2[11]=dis_m/10+48;
  213.         dis_buf2[12]=dis_m%10+48;
  214.         dis_buf2[13]=0x3a;
  215.         dis_buf2[14]=dis_s/10+48;
  216.         dis_buf2[15]=dis_s%10+48;
  217. }
  218. //时间和日期处理程序
  219. void pro_timedate()
  220. {      
  221.         sec++;
  222.         if(sec > 59)
  223.         {sec = 0;
  224.                 min++;
  225.                 if(min>59)
  226.                 {min=0;
  227.                         hour++;
  228.                         if(hour>23)
  229.                         {hour=0;
  230.                                 date++;
  231.                                 if (month==1||month==3||month==5||month==7||month==8||month==10||month==12)
  232.                                 if (date>31) {date=1;month++;}                                        //大月31天
  233.                                 if (month==4||month==6||month==9||month==11)               
  234.                                 if (date>30) {date=1;month++;}                                        //小月30天
  235.                                 if (month==2)                       
  236.                                 {if( leap_year())                                                                //闰年的条件
  237.                                         {if (date>29) {date=1;month++;}}                        //闰年2月为29天
  238.                                         else
  239.                                         {if (date>28) {date=1;month++;}}                        //平年2月为28天      
  240.                                 }                              
  241.                                 if (month>12) {month=1;year++;}
  242.                                 if (year>99) year=0;
  243.                         }
  244.                 }
  245.         }
  246.         week_proc();
  247.         if (sec==armsec && min==armmin && hour==armhour)                              
  248.         {if (alarm)
  249.                 TR1=1;                                        //闹钟启用时,报警时间到,启动Timer1
  250.         }
  251. }
  252. //显示处理程序
  253. void pro_display()
  254. {        
  255.   unsigned char i;
  256.         lcd_pos(0x00);
  257.         for (i=0;i<=15;i++)
  258.         {lcd_wdat(dis_buf1[i]);}
  259.         lcd_pos(0x40);
  260.         for (i=0;i<=15;i++)
  261.         {lcd_wdat(dis_buf2[i]);}
  262. }
  263. //Timer0中断处理程序,秒的产生
  264. void timer0() interrupt 1
  265. {
  266.         TH0=0xD8;                       
  267.         TL0=0xF0;               
  268.         sec100++;
  269.         if(sec100 >= 100)        //1秒时间 (100*10ms=1000ms=1s)
  270.         {sec100 = 0;
  271.                 pro_timedate();//调用时间和日期处理程序
  272.         }
  273.         if (sec&0x01)                                                                                //"__run__"闪一秒,停一秒
  274.         update_disbuf(0x00,"       ",hour,min,sec);           //0x00表示显示00位置的自定义字符               
  275.         else
  276.         update_disbuf(0x00,"__run__",hour,min,sec);
  277.         pro_display();  //调用显示处理函数
  278. }      

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

  288. //外部中断INT0中断处理程序
  289. void int0() interrupt 0
  290. {               
  291.         TR0=0;                                                                        //禁止Timer0
  292.         IE=0;                                                                        //禁止中断
  293.         lcd_wcmd(0x0e);                                                        //显示光标"_",整个光标不闪烁
  294.         alarm=1;
  295.         update_disbuf(0x50,"alarm_",armhour,armmin,armsec);        //更新显示数据,0x50表示要显示"P"      
  296.         pro_display();                                                        //调用显示处理程序
  297.         lcd_pos(0x47);                                                    //使光标位于第一个调整项下                                               
  298.         flag=0;                                                                       
  299.         vkey=0x03;
  300.         while(flag^0x0a)
  301.         {skey = scan_key();          //扫描按键状态
  302.                 if (skey^vkey)                                                //若skey与vkey相同,跳出循环,相异执行循环体
  303.                 {        delay(10);                                        //去按键抖动      
  304.                         skey = scan_key();                        //转回扫描按键状态                       
  305.                         if (skey^vkey)                                //若skey与vkey相同,跳出循环,相异执行循环体               
  306.                         {        vkey=skey;                        //将skey的值付给vkey      
  307.                                 if (skey==0x01)                //PRE键按下
  308.                                 {        flag++;        //调整标志位加1
  309.                                         switch (flag)        //将光标置于相应调整位置
  310.                                         {      
  311.                                                
  312.                                         case 1: lcd_pos(0x49);break;                //光标置小时报警设置位置                                               
  313.                                         case 2:        lcd_pos(0x4c);break;                //光标置分钟报警设置位置                  
  314.                                         case 3:        lcd_pos(0x4f);break;                //光标置秒时报警设置位置
  315.                                                
  316.                                         case 4:        update_disbuf(0x50,"time_ ",hour,min,sec);
  317.                                                 pro_display();
  318.                                                 lcd_pos(0x05);break;  //光标置年调整位置                                                                                         
  319.                                         case 5:        lcd_pos(0x08);break;                //光标置月调整位置
  320.                                         case 6:        lcd_pos(0x0b);break;                //光标置日调整位置
  321.                                                
  322.                                         case 7: lcd_pos(0x49);break;      //光标置时调整位置
  323.                                         case 8:        lcd_pos(0x4c);break;                //光标置分调整位置
  324.                                         case 9:        lcd_pos(0x4f);break;                //光标置秒调整位置
  325.                                                
  326.                                         default:break;
  327.                                         }
  328.                                 }
  329.                                 if (skey==0x02)                    //SET键按下
  330.                                 {
  331.           pro_key();                //转设置按键处理程序
  332.                                 }
  333.                         }
  334.                 }                                                               
  335.         }                                                               
  336.         lcd_wcmd(0x0c);                                                        //设置LCD开显示及光标不闪烁,不显示"-"
  337.         lcd_wcmd(0x01);                                                    //清除LCD的显示内容
  338.         IE=0x8f;                                                              //CPU开中断,INT0,INT1,开中断
  339.         TR0=1;                                                                        //Timer0启动
  340. }
  341. //主程序,初始化及初值设定
  342. void main()
  343. {      
  344.         lcd_init();                   //初始化LCD
  345.         lcd_sef_chr();                 //写入自定义字符号
  346.         hour=0;min=0;sec=0;           //开机时的时,分,秒显示
  347.         armhour=0;armmin=0;armsec=0;    //开机时的时,分,秒报警初值
  348.         year= 5; month=1;date=1;         //开机时的年,月,日,星期显示
  349.         week_proc();
  350.         alarm=1;                                                        //初始开机,启用闹钟
  351.         IE = 0x8f;                                                        //CPU开中断,INT0,INT1,Timer0,Timer1开中断
  352.         IP = 0x04;                                                        //设置INT0为中断最高优先级
  353.         IT0=0;IT1=0;                                                //外部INT0,INT1设置为电平触发方式(注意,触发不要选边沿方式,易误动)
  354.         TMOD = 0x11;                                                //Timer0,Timer1工作于模式1, 16位定时方式
  355.         TH0 = 0xdc;TL0 = 0x00;                                //Timer0置10ms定时初值        
  356.         TH1 = 0xff;TL1 = 0x00;                                //Timer1置初值        
  357.         TR0 = 1;                                                        //Timer0启动
  358.         TR1 = 0;
  359.         while(1);
  360. }
  361. //设置按键处理程序
  362. void pro_key()
  363. {
  364.         switch (flag)
  365.         {
  366.         case 0:alarm=!alarm;                        //启用或关闭闹钟(alarm=1:启用,alarm=0:关闭)
  367.                 update_disbuf(0x50,"alarm_",armhour,armmin,armsec); //更新显示数据
  368.                 pro_display();                                                                                //调用显示处理
  369.                 lcd_pos(0x47);break;                                                                //光标回到原调整位置
  370.         case 1:armhour++;
  371.                 if (armhour>23) armhour=0;
  372.                 update_disbuf(0x50,"alarm_",armhour,armmin,armsec); //更新显示数据
  373.                 pro_display();                                                                                //调用显示处理
  374.                 lcd_pos(0x49);break;                                                                //光标回到原调整位置
  375.         case 2:armmin++;
  376.                 if (armmin>59) armmin=0;
  377.                 update_disbuf(0x50,"alarm_",armhour,armmin,armsec);
  378.                 pro_display();
  379.                 lcd_pos(0x4c);break;
  380.         case 3:armsec++;
  381.                 if (armsec>59) armsec=0;
  382.                 update_disbuf(0x50,"alarm_",armhour,armmin,armsec);
  383.                 pro_display();
  384.                 lcd_pos(0x4f);break;
  385.         case 4:year++;
  386.                 if        (year> 99) year= 0;
  387.                 week_proc();                        //星期自动运算
  388.                 update_disbuf(0x50,"time_ ",hour,min,sec);
  389.                 pro_display();
  390.                 lcd_pos(0x05);break;
  391.         case 5:month++;
  392.                 if (month>12) month=1;
  393.                 week_proc();                                                //星期自动运算
  394.                 update_disbuf(0x50,"time_ ",hour,min,sec);
  395.                 pro_display();
  396.                 lcd_pos(0x08);break;
  397.         case 6:date++;
  398.                 if (month==1||month==3||month==5||month==7||month==8||month==10||month==12)
  399.                 if (date>31) date=1;                        //大月31天
  400.                 if (month==4||month==6||month==9||month==11)               
  401.                 if (date>30) date=1;                        //小月30天
  402.                 if (month==2)                       
  403.                 {if(leap_year())                                //闰年的条件
  404.                         {if (date>29) date=1;}                //闰年2月为29天
  405.                         else
  406.                         {if (date>28) date=1;}}                //平年2月为28天      
  407.                 week_proc();                                            //星期自动运算
  408.                 update_disbuf(0x50,"time_ ",hour,min,sec);
  409.                 pro_display();
  410.                 lcd_pos(0x0b);break;
  411.                
  412.         case 7:hour++;
  413.                 if (hour>23) hour=0;
  414.                 update_disbuf(0x50,"time_ ",hour,min,sec);
  415.                 pro_display();
  416.                 lcd_pos(0x49);break;      
  417.         case 8:min++;
  418.                 if (min>59) min=0;
  419.                 update_disbuf(0x50,"time_ ",hour,min,sec);
  420.                 pro_display();
  421.                 lcd_pos(0x4c);break;
  422.         case 9:sec++;
  423.                 if (sec>59) sec=0;
  424.                 update_disbuf(0x50,"time_ ",hour,min,sec);
  425.                 pro_display();
  426.                 lcd_pos(0x4f);break;
  427.         default: break ;                                                                                               
  428.         }
  429. }      

  430. //Timer1中断处理程序,产生报警的声音
  431. void timer1() interrupt 3
  432. {
  433.         TH1=0x80;                              
  434.         TL1=0x00;
  435.         SPK=~SPK;
  436.         //t++;
  437.        
  438. }

  439. //外部中断INT1中断处理程序,停止报警声音
  440. void int1() interrupt 2
  441. {
  442.         if(TR1)
  443.         TR1=0;                              
  444. }

复制代码
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表