找回密码
 立即注册

QQ登录

只需一步,快速开始

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

基于DS1302的万年历(含proteus仿真与代码)

[复制链接]
跳转到指定楼层
楼主
ID:524667 发表于 2020-6-29 20:07 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
#include <reg51.h>
#include <stdio.h>
#include <intrins.h>
typedef unsigned int u16;
typedef unsigned char u8;
sbit lcden=P2^5;//液晶使能
sbit lcdrw=P2^4;//液晶读写
sbit lcdrs=P2^3;//液晶命令/数据
sbit ds1302rst=P2^0;//1302复位端
sbit ds1302clk=P2^1;//1302时钟输入
sbit ds1302io=P2^2;//1302IO口
sbit key1=P1^2;//功能选择键
sbit key2=P1^3;//数值增加键
sbit key3=P1^4;//数值减少键
sbit key4=P1^5;//启动确认键
sbit key5=P1^6;//12/24小时切换键
sbit key6=P1^7;
sbit key7=P1^1;//闹钟设置
sbit beep=P1^0;
char year=10,mon=9,day=8;hou=14,min=33,sec=12;
char naohou=20,naomin=25;
u8 key1pushflag,key2pushflag,key3pushflag,key4pushflag,key5pushflag=0,key6pushflag=0;//定义按键1,2,3,4,5标志位
u8 countkey1,runmode=1,naomode=0,countkey2=0;//按键1标志,运行标志位
u8 init_display1[]="2010-09-08";
u8 init_display2[]="14:33:12";


void delay(u16 ms){
u8 i,j;
   for(i=ms;i>0;i--)
      for(j=110;j>0;j--);
   }


//液晶显示模块
  void write_com(u8 com){//写命令
     lcdrs=0;
     lcden=0;
     lcdrw=0;
     P0=com;
     delay(5);
     lcden=1;
     delay(5);
     lcden=0;
     }

      void write_date(u8 date){//写数据
       lcdrs=1;
         lcden=0;
         lcdrw=0;
     P0=date;
     delay(5);
     lcden=1;
     delay(5);
     lcden=0;
      }

      void init_lcd(){//初始化显示函数
        u8  num;
         lcden=0;
        write_com(0x38); //设置16*2行显示,5*7点阵,8位数据口
         write_com(0x0c); //开显示,不显示光标
         write_com(0x06); //写一个字符后地址自动加一
         write_com(0x01); //显示清零,数据指针清零
         write_com(0x80+0x03); //第一行起始地址
         for(num=0;num<10;num++){
         write_date(init_display1[num]);
            delay(5);
            }
            write_com(0x80+0x42); //第二行起始地址
         for(num=0;num<9;num++){
         write_date(init_display2[num]);
            delay(5);
            }
            }

void LCD_Write_Char(unsigned char x,unsigned char y,unsigned char Data)
{     
if (y == 0)
{     
write_com(0x80 + x);     
        }   
else
{     
write_com(0xC0 + x);     
}        
write_date( Data);  
}

   void write_dat_to_lcd(u8 add,u8 dat){
      u8 ge,shi;
      ge=dat%10;
      shi=dat/10;
      write_com(0x0c);
      write_com(0x80+add);
      write_date(0x30+shi);   
      write_date(0x30+ge);   
   }


   void ds1302_write_byte(u8 dat){//1302写一字节函数
   u8 temp,num1;
      temp=dat;
      ds1302rst=1;
      for(num1=0;num1<8;num1++){
      ds1302io=temp&0x01;
         ds1302clk=0;
         ds1302clk=1;
         temp=temp>>1;
         }
      }

     u8 ds1302_read_byte(){//1302读一字节函数
     u8 num,temp;
        ds1302rst=1;
        for(num=0;num<8;num++){
        if(ds1302io)
           temp=temp|0x80;
        else
           temp=temp&0x7f;
         ds1302clk=1;
         ds1302clk=0;
        temp=temp>>1;
           }
           return temp;
        }

        void ds1302_write_add_dat(u8 address,u8 dat){//向ds1302特定地址写入一字节数据
        ds1302rst=0;
           ds1302clk=0;
           ds1302rst=1;
          ds1302_write_byte(address);
          ds1302_write_byte(dat);
          ds1302clk=1;
           ds1302rst=0;
           }
          
         u8 ds1302_read_add_dat(u8 address,u8 dat){//向ds1302特定地址读入一字节数据
            u8 temp;
        ds1302rst=0;
           ds1302clk=0;
           ds1302rst=1;
          ds1302_write_byte(address);//先写地址再读数据
          temp=ds1302_read_byte();
          ds1302clk=1;
           ds1302rst=0;
            return temp;
           }
          
           u8 BCD_Decimal(u8 bcd){//BCD码转十进制
           u8 Decimal;
              Decimal=bcd>>4;
              return (Decimal=Decimal*10+(bcd&=0x0f));
              }
             
           void init_ds1302(){
           ds1302rst=0;
           ds1302clk=0;
              ds1302_write_add_dat(0x8e,0x00);
              }
   //按键模块
   void keyscan(){
   if(key1==0){//加速键
   delay(5);
      if(key1==0){//功能按键
      while(!key1);
        runmode=0;
      key1pushflag=1;//功能按键按下,万年历设置状态
      countkey1++;//年月日时分秒设置
      if(countkey1>6)
         countkey1=1;
         }
      }
      if(key7==0){//闹钟模式
      delay(5);
         if(key7==0){
         while(!key7);
            naomode=1;
         key6pushflag=1;
      countkey2++;
     if(countkey2>1)
     countkey2=0;
       }  
            }
    if(key1pushflag==1||key6pushflag==1){
       if(key2==0){//加键
   delay(5);
      if(key2==0){
      while(!key2);
        key2pushflag=1;
         }
      }
      if(key3==0){//减键
   delay(5);
      if(key3==0){
      while(!key3);
        key3pushflag=1;
         }
      }
      if(key4==0){
   delay(5);
      if(key4==0){
      while(!key4);
      key4pushflag=1;
      key1pushflag=0;
      key6pushflag=0;
         }
      }
      }
      if(key5==0){//12/24小时切换键
      delay(5);
         if(key5==0){
         while(!key5);
         key5pushflag=1;         
            }
         }
      if(key6==0){//12/24小时切换键
      delay(5);
         if(key6==0){
         while(!key6);
         key5pushflag=0;         
            }
         }
       
            
         }


//按键处理
void keyhandle(){
u8 temp;
    switch(countkey1){
    case 1:  //功能按键按一次,年数据处理
    write_com(0x80+0x05);//光标处于年的位置
    write_com(0x0f);//光标闪烁
    if(key2pushflag==1){//增加按键按下
    year++;
       if(year>99)
          year=0;
      key2pushflag=0;//清除按键标志,放置按1次该键,数值一直减少
    write_dat_to_lcd(0x05,year);//显示增加数字
    write_com(0x80+0x05);   //光标回到年起始位置
       }
       else if(key3pushflag==1){
    year--;
       if(year<0)
          year=99;
      key3pushflag=0;//清除按键标志,放置按1次该键,数值一直增加
    write_dat_to_lcd(0x05,year);//显示减少数字
    write_com(0x80+0x05);   //光标回到年起始位置
       }
       break;
       case 2:
          write_com(0x80+0x08);//光标处于月的位置
    write_com(0x0f);//光标闪烁
    if(key2pushflag==1){//增加按键按下
    mon++;
       if(mon>12)
          mon=1;
      key2pushflag=0;//清除按键标志,放置按1次该键,数值一直增加
    write_dat_to_lcd(0x08,mon);//显示增加数字
    write_com(0x80+0x08);   //光标回到月起始位置
       }
       else if(key3pushflag==1){
    mon--;
       if(mon<0)
          mon=12;
      key3pushflag=0;//清除按键标志,放置按1次该键,数值一直减少
    write_dat_to_lcd(0x08,mon);//显示减少数字
    write_com(0x80+0x08);   //光标回到月起始位置
       }
       break;  
       case 3:
            write_com(0x80+0x0b);//光标处于日的位置
    write_com(0x0f);//光标闪烁
    if(key2pushflag==1){//增加按键按下
    day++;
       if(day>30)
          day=0;
      key2pushflag=0;//清除按键标志,放置按1次该键,数值一直增加
    write_dat_to_lcd(0x0b,day);//显示增加数字
    write_com(0x80+0x0b);   //光标回到日起始位置
       }
       else if(key3pushflag==1){
    day--;
       if(day<1)
          day=30;
      key3pushflag=0;//清除按键标志,放置按1次该键,数值一直减少
    write_dat_to_lcd(0x0b,day);//显示减少数字
    write_com(0x80+0x0b);   //光标回到日起始位置
       }
       break;

       case 4:
        write_com(0x80+0x42);//光标处于时的位置
    write_com(0x0f);//光标闪烁
    if(key2pushflag==1){//增加按键按下
    hou++;
       if(hou>23)
          hou=0;
      key2pushflag=0;//清除按键标志,放置按1次该键,数值一直增加
    write_dat_to_lcd(0x42,hou);//显示增加数字
    write_com(0x80+0x42);   //光标回到时起始位置
       }
    else if(key3pushflag==1){
    hou--;
       if(hou<0)
          hou=23;
      key3pushflag=0;//清除按键标志,放置按1次该键,数值一直减少
    write_dat_to_lcd(0x42,hou);//显示减少数字
    write_com(0x80+0x42);   //光标回到时起始位置
       }
       break;
       case 5:
           write_com(0x80+0x45);//光标处于分的位置
    write_com(0x0f);//光标闪烁
    if(key2pushflag==1){//增加按键按下
    min++;
       if(min>59)
          min=0;
      key2pushflag=0;//清除按键标志,放置按1次该键,数值一直增加
    write_dat_to_lcd(0x45,hou);//显示增加数字
    write_com(0x80+0x45);   //光标回到分起始位置
       }
       else if(key3pushflag==1){
    min--;
       if(min<0)
          min=59;
      key3pushflag=0;//清除按键标志,放置按1次该键,数值一直减少
    write_dat_to_lcd(0x45,min);//显示减少数字
    write_com(0x80+0x45);   //光标回到分起始位置
       }
       break;  

       case 6:
         write_com(0x80+0x48);//光标处于秒的位置
    write_com(0x0f);//光标闪烁
    if(key2pushflag==1){//增加按键按下
    sec++;
       if(sec>59)
          sec=0;
      key2pushflag=0;//清除按键标志,放置按1次该键,数值一直增加
    write_dat_to_lcd(0x48,sec);//显示增加数字
    write_com(0x80+0x48);   //光标回到秒起始位置
       }
       else if(key3pushflag==1){
    sec--;
       if(sec<0)
          sec=59;
      key3pushflag=0;//清除按键标志,放置按1次该键,数值一直减少
    write_dat_to_lcd(0x48,sec);//显示减少数字
    write_com(0x80+0x48);   //光标回到秒起始位置
       }
       break;
     }  
       if(key4pushflag==1){
         temp=sec/10*16+sec%10;//秒钟数据变成BCD码
        ds1302_write_add_dat(0x8e,0x00);//禁止DS1302写保护
        ds1302_write_add_dat(0x80,temp);  //将秒钟数据写入1302秒钟寄存器
          
          temp=min/10*16+min%10;//分钟数据变成BCD码
        ds1302_write_add_dat(0x8e,0x00);//禁止DS1302写保护
        ds1302_write_add_dat(0x82,temp);  //将秒钟数据写入1302秒钟寄存器
          
          temp=hou/10*16+hou%10;//时钟数据变成BCD码
        ds1302_write_add_dat(0x8e,0x00);//禁止DS1302写保护
        ds1302_write_add_dat(0x84,temp);  //将秒钟数据写入1302秒钟寄存器
          
          temp=day/10*16+day%10;//日数据变成BCD码
        ds1302_write_add_dat(0x8e,0x00);//禁止DS1302写保护
        ds1302_write_add_dat(0x86,temp);  //将秒钟数据写入1302秒钟寄存器
          
          temp=mon/10*16+mon%10;//月数据变成BCD码
        ds1302_write_add_dat(0x8e,0x00);//禁止DS1302写保护
        ds1302_write_add_dat(0x88,temp);  //将秒钟数据写入1302秒钟寄存器
          
          temp=year/10*16+year%10;//年数据变成BCD码
        ds1302_write_add_dat(0x8e,0x00);//禁止DS1302写保护
        ds1302_write_add_dat(0x8c,temp);  //将秒钟数据写入1302秒钟寄存器
       
        write_com(0x0c);
        key4pushflag=0;
        runmode=1;

       }
    }  

  void naozhongmozhi(void){
     u8 temp;
        switch(countkey2){
        case 0:
        write_com(0x80+0x42);//光标处于时的位置
        write_com(0x0f);//光标闪烁
        if(key2pushflag==1){//增加按键按下
        naohou++;
       if(naohou>23)
          naohou=0;
      key2pushflag=0;//清除按键标志,放置按1次该键,数值一直增加
    write_dat_to_lcd(0x42,naohou);//显示增加数字
    write_com(0x80+0x42);   //光标回到时起始位置
       }
    else if(key3pushflag==1){
    naohou--;
       if(naohou<0)
          naohou=23;
      key3pushflag=0;//清除按键标志,放置按1次该键,数值一直减少
    write_dat_to_lcd(0x42,naohou);//显示减少数字
    write_com(0x80+0x42);   //光标回到时起始位置
       }
       break;
       case 1:
    write_com(0x80+0x45);//光标处于分的位置
    write_com(0x0f);//光标闪烁
    if(key2pushflag==1){//增加按键按下
    naomin++;
       if(naomin>59)
          naomin=0;
      key2pushflag=0;//清除按键标志,放置按1次该键,数值一直增加
    write_dat_to_lcd(0x45,naomin);//显示增加数字
    write_com(0x80+0x45);   //光标回到分起始位置
       }
       else if(key3pushflag==1){
    naomin--;
       if(naomin<0)
          naomin=59;
      key3pushflag=0;//清除按键标志,放置按1次该键,数值一直减少
    write_dat_to_lcd(0x45,naomin);//显示减少数字
    write_com(0x80+0x45);   //光标回到分起始位置
       }
       break;  
           }
           if(key4pushflag==1){
           write_com(0x0c);
        key4pushflag=0;
        naomode=0;
              }
        }
       
  void shijianmoshiqiehuan(void){
  if(key5pushflag==1){
        if(hou>12){
          hou=hou-12;
          LCD_Write_Char(10,1,'P');
          LCD_Write_Char(11,1,'M');
           }
           else{
           hou=hou;
          LCD_Write_Char(10,1,'A');
          LCD_Write_Char(11,1,'M');  
              }
        write_dat_to_lcd(0x48,sec);//把秒送入液晶
        write_dat_to_lcd(0x45,min);
        write_dat_to_lcd(0x42,hou);
        write_dat_to_lcd(0x0b,day);
        write_dat_to_lcd(0x08,mon);
        write_dat_to_lcd(0x05,year);
           }
           else{
        write_dat_to_lcd(0x48,sec);//把秒送入液晶
        write_dat_to_lcd(0x45,min);
        write_dat_to_lcd(0x42,hou);
        write_dat_to_lcd(0x0b,day);
        write_dat_to_lcd(0x08,mon);
        write_dat_to_lcd(0x05,year);
          LCD_Write_Char(10,1,' ');
          LCD_Write_Char(11,1,' ');  
              }
     }


void main(void)
{

   init_lcd();
    init_ds1302();

   while (1){
      keyscan();
      if(runmode==1){
         sec=BCD_Decimal(ds1302_read_add_dat(0x81));//读1302秒钟寄存器数据,并转化为十进制
          min=BCD_Decimal(ds1302_read_add_dat(0x83));
          hou=BCD_Decimal(ds1302_read_add_dat(0x85));
          day=BCD_Decimal(ds1302_read_add_dat(0x87));
          mon=BCD_Decimal(ds1302_read_add_dat(0x89));
          year=BCD_Decimal(ds1302_read_add_dat(0x8d));
         write_com(0x0c);
         if(naomode==0){
         shijianmoshiqiehuan();
         }
         if(naomode==1){
        write_dat_to_lcd(0x45,naomin);
        write_dat_to_lcd(0x42,naohou);
           naozhongmozhi();
            }
            
            if(hou==naohou&&min==naomin){
           beep=0;
               }
               else{
               beep=1;
                  }
         }
         else{//万年历参数设置模式
         keyhandle();
            }
      }

}


基于ds1302的万年历设计.rar

136.04 KB, 下载次数: 44, 下载积分: 黑币 -5

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

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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