找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1793|回复: 0
收起左侧

51单片机+3按键,带闹钟+DS1302+LCM1602源程序

[复制链接]
ID:1016115 发表于 2022-6-2 17:53 | 显示全部楼层 |阅读模式
新手勿喷,打了个实物板,验证了一下功能正常。
1.实现功能 开机时正常显示时间并读取DS1302ROM 闹钟时间 进行初始化,
2.时间设置:按KEY1 1次进入时间设置画面 在按KEY3进入时间设置状态 秒设置,然后按key1 key2进行时间加减,在按KEY3分设置 key1 key2进行时间加减......
3.闹钟:按key1 俩次后进入闹钟画面  在按KEY3进入闹钟设置状态分设置,然后按key1 key2进行时间加减 ...最后设置完后退出之前写入DS1302ROM。

仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
51hei.gif

仿真

仿真


单片机源程序如下:
#include<reg52.h>
#include"lcd1602.h"
#include "DS1302.h"
#include "mues.h"
void showsit();
void showsec();
void showmin();
void showhour();
void showbit();
void showyear();
void showmon();
void showday();
void ak();
void alarmclock();
void alarmclocksit();
void alarmclockmin();
void alarmclockhour();
void alarmclockshowbit();
sbit pwm=P3^0;
sbit key1=P2^7;
unsigned char flag,bits,count,sitcount,secdata,mindata,hourdata,keyone,yeardata,mondata,daydata
,alarmclockcount;
unsigned char alarmhourdata,alarmmindata,nudata,nudatas,t_H,t_L,da=1,db=0,dbtwo=3;
//延时函数
void DelayMS1(unsigned int  x)
{
    unsigned char  t;
     while(x--) for(t=0;t<120;t++);
}
void initEx0() { //KEY3
  EA = 1;         //开启总中断
  EX0 = 1;         //开启0号外部中断
  IT0 = 1;         //设置外部中断触发方式
             //0 - 低电平触发
             //1 - 负跳变触发
}
void ex0_intr() interrupt 0 //外部0中断处理函数
{  
    if(keyone==0){ //实现一键多意,只有3个按键不够用
     flag++;
        if(flag>=3){flag=0;}
  }
  if(flag==1&&sitcount==1&&keyone==1){if(secdata<=0){secdata=60;}secdata--;}
  if(flag==1&&sitcount==2&&keyone==1){if(mindata<=0){mindata=60;}mindata--;}
  if(flag==1&&sitcount==3&&keyone==1){if(hourdata<=0){hourdata=24;}hourdata--;}
  if(flag==1&&sitcount==4&&keyone==1){if(yeardata<=0){yeardata=22;}yeardata--;}
  if(flag==1&&sitcount==5&&keyone==1){if(mondata<=0){mondata=11;}mondata--;}
  if(flag==1&&sitcount==6&&keyone==1){if(daydata<=0){daydata=31;}daydata--;}
  if(flag==2&&alarmclockcount==1&&keyone==1){if(alarmmindata<=0){alarmmindata=60;}alarmmindata--;}
  if(flag==2&&alarmclockcount==2&&keyone==1){if(alarmhourdata<=0){alarmhourdata=24;}alarmhourdata--;}  
}
void initEx1() { //KEY2
  EA = 1;         //开启总中断
  EX1 = 1;         //开启0号外部中断
  IT1 = 1;         //设置外部中断触发方式
             //0 - 低电平触发
            //1 - 负跳变触发
}
void ex1_intr() interrupt 2 //外部1中断处理函数处理按键/切换
{
        
if(flag==1&&sitcount==1){
        secdata++;
  if(secdata>=60){secdata=0;}
}
if(flag==1&&sitcount==2){
        mindata++;
  if(mindata>=60){mindata=0;}
}
if(flag==1&&sitcount==3){
        hourdata++;
  if(hourdata>=24){hourdata=0;}
}
if(flag==1&&sitcount==4){
        yeardata++;
  if(yeardata>=24){yeardata=0;}
}
if(flag==1&&sitcount==5){
        mondata++;
  if(mondata>=12){mondata=0;}
}
if(flag==1&&sitcount==6){
        daydata++;
  if(daydata>=31){daydata=0;}
}
if(flag==2&&alarmclockcount==1){
        alarmmindata++;
  if(alarmmindata>=60){alarmmindata=0;}
}
if(flag==2&&alarmclockcount==2){
        alarmhourdata++;
  if(alarmhourdata>=24){alarmhourdata=0;}
}
}
void INIT_T0()                //KEY1 //1毫秒@12.000MHz
{
    TMOD = 0x01;        //设置定时器模式
           TL0 = t_L;                //设置定时初值
        TH0 = t_H;                //设置定时初值
        TR0 = 1;                //定时器0开始计时
        EA = 1;         
    ET0 = 1;   
}
void lcd1602T0() interrupt 1 //监听按键3切换功能
{        
     if(nudatas==1){        //开始蜂鸣器
          if(db<dbtwo){
                   pwm=0;
           }else{
                   pwm=1;
           }
           db++;
           db=db%10;        
          TL0 = t_L;                //设置定时初值
          TH0 = t_H;                //设置定时初值
}  
    if(nudata==0){
                   if(key1==0&&bits==0){
                 bits=1;           
  }
   if( key1==1&&bits==1){
           if(flag==0&&keyone==0){ TR1=1;}
       if(flag==1){sitcount++;bits=0;if( sitcount>=8){sitcount=0;}
           if(flag==1&&sitcount==1){ keyone=1;}}
           if(flag==2){alarmclockcount++;bits=0;if(alarmclockcount>=4){alarmclockcount=0;}
           if(flag==2&&alarmclockcount==1){keyone=1;}}
       bits=0;        
   }
  t_H = (65535 - 30000) / 256;   
  t_L = (65535 - 30000) % 256;
}
}
//上面是三个按键中断


void INIT_T1(){           //开启定时器1定时读DS1302时间显示出来
        TMOD = 0x20;        //设置定时器模式
    TL1 = 0x88;                //设置定时初值
        TH1 = 0x88;                //设置定时重载值
        TR1 = 0;                //定时器1开始计时  
        EA = 1;         
    ET1 = 1;   
}
void SEGT1() interrupt 3
{
  unsigned char nums;
    nums++;
   if(nums>=200){
    nums=0;
           DS1302redinit();//定时器每200MS取一次时间然后显示到1602
           tab1[12]=((TIME[0]&0x0f)+'0'); //秒
        tab1[11]=((TIME[0] >> 4)+'0');
        tab1[10]='-';
        tab1[9]=((TIME[1]&0x0f)+'0');  //分
        tab1[8]=((TIME[1] >> 4)+'0');
        tab1[7]='-';
        tab1[6]=((TIME[2]&0x0f)+'0');
        tab1[5]=((TIME[2] >> 4)+'0');
        tab2[6]=((TIME[6]&0x0f)+'0');
        tab2[5]=((TIME[6] >> 4)+'0');
        tab2[7]='-';
        tab2[9]=((TIME[4]&0x0f)+'0');
        tab2[8]=((TIME[4] >> 4)+'0');
        tab2[10]='-';
        tab2[12]=((TIME[3]&0x0f)+'0');
        tab2[11]=((TIME[3] >> 4)+'0');
    if((alarmmindata%10)==((TIME[1]&0x0f))
        &&(alarmhourdata%10)==((TIME[2]&0x0f))
        &&(alarmhourdata/10)==((TIME[2]>> 4))
        &&(alarmmindata/10)==((TIME[1]>>4))
        &&('0'==((TIME[0]&0x0f)+'0'))
        &&('0'==((TIME[0] >> 4)+'0')))
        {//闹钟
           nudata=1;
           TR1=0;
        }
    start();
   }
}
void  ak(){
   unsigned char  t,k;
    for(k=0;k<20;k++){
          if(key1==0){
                            break;
                   }
            for(t=0;t<42;t++)
        {
                   if(key1==0){
                            break;
                   }
            t_H=toneH[soundtone[t]];     //提取音调对应的定时器初始值
            t_L=toneL[soundtone[t]];
                TH0=t_H;                  //给TH0和TL0赋值
                TL0=t_L;
                        nudatas=1;
            TR0=1;//打开定时器,蜂鸣器发声
            DelayMS1(soundlong[t]*300);    //延时soundlong[t]指定的时间长度
        }
        }  
        nudata=0;//关闭闹钟
        nudatas=0;//关闭闹钟
}
void alarmclock(){
        switch(alarmclockcount){
        case 0:alarmclocksit();break;
                case 1:alarmclockmin();break;
                case 2:alarmclockhour();break;
                case 3:alarmclockshowbit();break;
           }
}
void alarmclockshowbit(){
   ramTIME[1]=((alarmmindata/10*16)|(alarmmindata%10));//BCD码转换
   ramTIME[0]=((alarmhourdata/10*16)|(alarmhourdata%10));
   ram();//写闹钟时间到DS1302RAM
   keyone=0;flag=0;flag=bits=count=sitcount=alarmclockcount=0; //设置好后还原
}
void alarmclockmin(){//调闹钟分
    Whiteorder(0x80|0x49);
    Whitedata(((alarmmindata%10)+'0'));
        Whiteorder(0x80|0x48);
    Whitedata(((alarmmindata/10)+'0'));   
}
void alarmclockhour(){//调闹钟时
    Whiteorder(0x80|0x46);
    Whitedata(((alarmhourdata%10)+'0'));
        Whiteorder(0x80|0x45);
    Whitedata(((alarmhourdata/10)+'0'));   
}
void alarmclocksit(){//进入闹钟初始化第一个页面
        Whiteorder(0x80|0x00);//setting
        Whitedata((0x00));
        Whitedata((0x00));
        Whitedata((0x00));
        Whitedata(('a'));
        Whitedata(('l'));
        Whitedata(('a'));
        Whitedata(('r'));
        Whitedata(('m'));
        Whitedata(('c'));
        Whitedata(('l'));
        Whitedata(('o'));
        Whitedata(('c'));
        Whitedata(('k'));
    Whiteorder(0x80|0xc0);//setting
        Whitedata((0x00));
        Whitedata((0x00));
        Whitedata((0x00));
        Whitedata((0x00));
        Whitedata((0x00));
        Whitedata(((alarmhourdata/10)+'0'));
        Whitedata(((alarmhourdata%10)+'0'));
        Whitedata(('-'));
        Whitedata(((alarmmindata/10)+'0'));
        Whitedata(((alarmmindata%10)+'0'));
        Whitedata((0x00));
        Whitedata((0x00));
        Whitedata((0x00));

}
void showclock(){
           switch(count){
        case 0:        TR1 = 1;break;
           }
}
void sitclock(){//时间设置
           switch(sitcount){
        case 0:showsit();break;
                case 1:showsec();break;
                case 2:showmin();break;
                case 3:showhour();break;
                case 4:showyear();break;
                case 5:showmon();break;
                case 6:showday();break;
                case 7:showbit();break;
           }
}
void showbit(){         //设置好时间后写到DS1302
        INIT_TIME[0]=((secdata/10*16)+(secdata%10));
    INIT_TIME[1]=(mindata/10*16)+(mindata%10);
        INIT_TIME[2]=(hourdata/10*16)+(hourdata%10);
        INIT_TIME[3]=(daydata/10*16)+(daydata%10);
        INIT_TIME[4]=(mondata/10*16)+(mondata%10);
        INIT_TIME[6]=(yeardata/10*16)+(yeardata%10);
        DS1302init();
    keyone=0;flag=0;flag=bits=count=sitcount=0;        //设置好后还原
                     
}
void showyear(){  //设置年
        Whiteorder(0x80|0x46);
    Whitedata(((yeardata%10)+'0'));
        Whiteorder(0x80|0x45);
    Whitedata(((yeardata/10)+'0'));
}
void showmon(){         //设置月
        Whiteorder(0x80|0x49);
    Whitedata(((mondata%10)+'0'));
        Whiteorder(0x80|0x48);
    Whitedata(((mondata/10)+'0'));
}
void showday(){         //设置日
        Whiteorder(0x80|0x4c);
    Whitedata(((daydata%10)+'0'));
        Whiteorder(0x80|0x4b);
    Whitedata(((daydata/10)+'0'));
}
void showsec(){         //设置秒
        Whiteorder(0x80|0x0c);
    Whitedata(((secdata%10)+'0'));
        Whiteorder(0x80|0x0b);
    Whitedata(((secdata/10)+'0'));
}
void showmin(){         //设置分
        Whiteorder(0x80|0x09);
    Whitedata(((mindata%10)+'0'));
        Whiteorder(0x80|0x08);
    Whitedata(((mindata/10)+'0'));
}
void showhour(){//设置时
        Whiteorder(0x80|0x06);
    Whitedata(((hourdata%10)+'0'));
        Whiteorder(0x80|0x05);
    Whitedata(((hourdata/10)+'0'));
}
void showsit(){         //设置时间第一个界面
    Whiteorder(0x80|0x00);//setting
        Whitedata(('S'));
        Whitedata(('e'));
        Whitedata(('t'));
        Whitedata((0x00));
        Whiteorder(0x80|0xc0);//setting
        Whitedata((0x00));
        Whitedata((0x00));
        Whitedata((0x00));
        Whitedata((0x00));
}
void main(){
   RSTintit();
   initEx1();
   INIT_T0();
   initEx0();
   INIT_T1();
   ramread();
   alarmmindata = (((((ramreadTIME[0])&0xF0)>>4)*10)+(ramreadTIME[0])&0x0F);
   alarmhourdata = (((((ramreadTIME[1])&0xF0)>>4)*10)+((ramreadTIME[1])&0x0F)); //开机就读取DS1302保存的闹钟
   while(1){
     if(nudata==1){
             ak();
   }
       switch(flag){   
                            case 0:showclock();break; //正常显示
                        case 1:TR1=0;sitclock();nudata=0;break;//设置时间        /闹钟关闭nudata=0;pwm=1;
                                case 2:TR1=0;alarmclock();break;//设置闹钟
                        }
  }
}

51hei.png
Keil5代码与Proteus8.8仿真下载:
da13021602-02.7z (109.43 KB, 下载次数: 68)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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