专注电子技术学习与研究
当前位置:单片机教程网 >> MCU设计实例 >> 浏览文章

点阵万年历(带时间、年月日星期调整及闹钟功能)C程序

作者:佚名   来源:本站原创   点击数:  更新时间:2012年06月27日   【字体:

/*此程序是一款用3216点阵屏与DS1302芯片以及
三个按键与STC12C5204AD 4KROM单片机组合成的
万年历电子钟具体功能如下:正常情况下上半屏
(3208)显示主时间。当第1次按下功能键时,下半
屏会左移滚动显示“年、月、日、星期”,当再
次按下时,便进入年、月、日、星期、闹铃等调
整模式,按加与减方便调整,附加功能,当在左
移滚动显示“年、月、日、星期”时,按下加“+”
按键,便可以回到主界面,当在响铃时,按下
“+键”便可以将本次响铃关闭,当按响铃时下“-”
按键时,便可以关闭闹铃功能,再次按下时,可
以恢复闹铃功能*/

视频效果祥见:http://www.tudou.com/programs/view/hQmJSwtHWWc/

完整的源代码下载地址:http://www.51hei.com/f/dzwnl.rar

#include <reg52.h>
#define uchar unsigned char 
#define uint unsigned int
#define LINE P2//定义行线IO口,即74HC154控制端
sbit DATA1=P1^4;//74HC595数据端
sbit CLK=P1^5;//74HC595移位脉冲端
sbit CLKR=P1^6;//74HC595数据锁存端
sbit BBT =P2^7;//蜂鸣器引脚
sbit SCLK=P1^2;//DS1302移位脉冲端
sbit DATA=P1^1;//DS1302数据端
sbit RST=P1^0;//DS1302控制端
sbit key=P3^4;//功能按键
sbit key1=P3^3;//加"+"按键
sbit key2=P3^2;//加"+"按键
uchar line;//行扫描变量
uchar move;//移位次数变量
uchar mov;//年月日时间左移变量,即移8次将1个字移完后加1
uchar yin;//按键计数器变量,一共10次,即功能按键有10种功能
uchar lk;//扫描两行还是1行变量
uchar readvalue;//DS1302转换结果变量
uchar shi,fen,nian,yue,ri,xin;//分别为:小时/分钟/年/月/日/星期变量
uchar shin=12,fenn;//闹钟的小时与分钟变量
bit dian;//主时间小数点位变量
bit shr,a,b,c,d,e,f,g,h,i;//按键对应的10种功能位变量
bit flag;//主程序与调整时间切换变量,即进入调整时间部分就不进入主时间部分
bit flag1;//闹钟标志位变量
bit clockbiao;//闹钟响铃主标志位
uchar BUF[19];//4组缓存数组以便动态更改数据
/******************************************************/
/**************点阵0-9代码(8*6点阵)******************/
/******************************************************/
uchar code table[]={
0x00,0x0E,0x11,0x11,0x11,0x11,0x11,0x0E,//0
0x00,0x04,0x0C,0x04,0x04,0x04,0x04,0x0E,//1
0x00,0x0E,0x11,0x01,0x02,0x04,0x08,0x1F,//2
0x00,0x0E,0x11,0x01,0x06,0x03,0x11,0x0E,//3
0x00,0x06,0x06,0x0A,0x0A,0x12,0x1F,0x02,//4
0x00,0x1F,0x10,0x10,0x1E,0x01,0x01,0x1E,//5
0x00,0x0E,0x11,0x10,0x1E,0x11,0x11,0x0E,//6
0x00,0x1F,0x01,0x02,0x02,0x04,0x04,0x08,//7
0x00,0x0E,0x11,0x11,0x0E,0x11,0x11,0x0E,//8
0x00,0x0E,0x11,0x11,0x0F,0x01,0x01,0x1E,//9
};
/******************************************************/
/**********两个小数黑屏及坚线代码8*6点阵)*************/
/******************************************************/
uchar code table1[]={
0x00,0x0C,0x0C,0x00,0x00,0x0C,0x0C,0x00,//为两个小数点":"
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//为黑屏代码
0x00,0x00,0x00,0x1E,0x1E,0x00,0x00,0x00//为两坚线"-"
};
/******************************************************/
/****此数组为74HC154译码器代码(注也可以不用数组)*****/
/******************************************************/
uchar code table2[]={
0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,//上半屏行代码 0-7行
0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff//下半屏行代码 8-15行
};
/******************************************************/
/*****************延时子程序1**************************/
/******************************************************/
void delaya(uint z)
{
 uint x;
 for(x=z;x>0;x--);   
}
/******************************************************/
/*****************延时子程序2**************************/
/******************************************************/
void delay(uint z)
{
 uint x,y;
 for(x=200;x>0;x--)
 for(y=z;y>0;y--);
}
/******************************************************/
/***************蜂鸣器响一声子程序********************/
/******************************************************/
void bbtsoud()
{
 BBT=0;//打开蜂鸣器
 delay(50);//延时
 BBT=1;//关闭它
}
/**********************************/
//向1302写一个字节数据//
//入口参数:dat
/*********************************/
void write1302xei(uchar dat)
{
 uchar x;
 SCLK=0; delaya(2);
 for(x=0;x<8;x++)
 {
  DATA=dat&0x01;//取出最低位,从而实现一位位传送
  delaya(2);
  SCLK=1;
  delaya(2);
  SCLK=0;
  dat>>=1;//等待传送第二个字节
 }
}

/**************************************/
//根据控制字向1302写一个字节数据//
//入口参数:控制参数kong,实际参数can
/*************************************/
void write1302(uchar kong,uchar can)
{
 SCLK=0;
 RST=0;
 RST=1;
 delaya(2);
 write1302xei(kong);
 write1302xei(can);
 SCLK=1;
 RST=0;  
}
/**************************************/
//向1302读一个字节数据//
//入口参数:dat,x
/*************************************/
uchar read1302du()
{
 uchar dat,x;
 SCLK=0;
 for(x=0;x<8;x++)
 {
  dat>>=1;
  if(DATA==1)
  dat|=0x80;
  SCLK=1;
  delaya(2);
  SCLK=0;
  delaya(2); 
 }
 return dat;
}
/**************************************/
//根据控制字向1302读一个字节数据//
//入口参数:控制参数kong  实际参:dat
/*************************************/
uchar read1302(uchar kong)
{
 uchar dat;
 RST=0;
 SCLK=0;
 RST=1;
 write1302xei(kong);
 dat=read1302du();
 SCLK=1;
 RST=0;
 return dat;
}
/**************************************/
//根据控制字向1302读一个字节数据//
//入口参数:分别写入:日期:2010-03-07 时间:23:59:54 星期天
/*************************************/
void init1302()
{
 /*以下是掉电保护函数通过判断标志位是否为1来判断*/
  uchar flag;
 flag=read1302(0x81);//读秒数据
 if(flag&0x80==1)//判断最高位是否为1,若为1则说明芯片停止工作了,若为0则说明没有停止
 {
 write1302(0x8e,0x00);//去掉保护
 write1302(0x80,((12/10)<<4)|(12%10));/*显示54秒/*先将BCD码求模得到高位,然后左移四位,
 得到了高四位,然后将BCD码求余这样就得到了低四位,然后相或就转换成了二进制代码了*/
 write1302(0x82,((59/10)<<4)|(59%10));//显示59分
 write1302(0x84,((23/10)<<4)|(23%10));//显示23点
 write1302(0x86,((7/10)<<4)|(7%10));//显示07日
 write1302(0x88,((3/10)<<4)|(3%10));//显示03月
 write1302(0x8c,((10/10)<<4)|(10%10));//显示10年
 write1302(0x8a,((7/10)<<4)|(7%10));//显示星期天
 write1302(0x90,0xa5);//打开充电方式,选择一个二极管2K电阻
 write1302(0x8e,0x80);//打开保护
 }

 /*以下是开机复位函数*/
 /*
 write1302(0x8e,0x00);//去掉保护
 write1302(0x80,((12/10)<<4)|(12%10));/*显示54秒/*先将BCD码求模得到高位,然后左移四位,
 //得到了高四位,然后将BCD码求余这样就得到了低四位,然后相或就转换成了二进制代码了
 write1302(0x82,((59/10)<<4)|(59%10));//显示59分
 write1302(0x84,((23/10)<<4)|(23%10));//显示23点
 write1302(0x86,((7/10)<<4)|(7%10));//显示07日
 write1302(0x88,((3/10)<<4)|(3%10));//显示03月
 write1302(0x8c,((10/10)<<4)|(10%10));//显示10年
 write1302(0x8a,((7/10)<<4)|(7%10));//显示星期天
 write1302(0x90,0xa5);//打开充电方式,选择一个二极管2K电阻
 write1302(0x8e,0x80);//打开保护
 */
}
/******************************************************/
/***************DS1302转换结果子程序********************/
/******************************************************/
void value()
{
 readvalue=read1302(0x83);//读入分地址
 fen=((readvalue&0x70)>>4)*10+(readvalue&0x0f);//将分16进制转换成10进制 
 readvalue=read1302(0x85);//读入小时地址
 shi=((readvalue&0x70)>>4)*10+(readvalue&0x0f);//将小时16进制转换成10进制
 readvalue=read1302(0x87);//读入日地址
 ri=((readvalue&0x70)>>4)*10+(readvalue&0x0f);//将分日进制转换成10进制 
 readvalue=read1302(0x89);//读入月地址
 yue=((readvalue&0x70)>>4)*10+(readvalue&0x0f);//将分月进制转换成10进制 
 readvalue=read1302(0x8d);//读入年地址
 nian=((readvalue&0xf0)>>4)*10+(readvalue&0x0f);//将分年进制转换成10进制 
 readvalue=read1302(0x8b);//读入星期地址
 xin=((readvalue&0x70)>>4)*10+(readvalue&0x0f);//将分星期进制转换成10进制 
}
/********************************/
/**74HC595移位寄存器送数子函数***/
/********************************/
void song(uchar dat)//带参数函数
{
 uchar num;//定义变量
 for(num=0;num<6;num++)//移动6次将数据发送完毕
 {
  dat>>=1;//将数移走一位
  DATA1=CY;//为1就将74HC595数据端置1
  CLK=0;//上升沿送走数据
  CLK=1;//高电平形成上升沿
 }
}
/******************************************************/
/***装一线数据子函数(即一行数据)主时间装数函数********/
/******************************************************/
void yixian(uchar shi,uchar ge,uchar z)
{
 BUF[0]=table[(8*(shi/10))+line];//显示小时十位
 BUF[1]=table[(8*(shi%10))+line];//显示小时个位
 BUF[2]=table1[z*8+line];//显示两个小数点,注意是不同的数组内哟
 BUF[3]=table[(8*(ge/10))+line];//显示分十位 
 BUF[4]=table[(8*(ge%10))+line];//显示分个位
}
/******************************************************/
/***装一线数据子函数(即一行数据)显示黑屏子程序********/
/******************************************************/
void yixianhei()
{
 uchar linee,i;
 if(line>8)//如果是显示下半屏,就会大于8
 linee=line-8;
 else
 linee=line;//否则直接给数
 for(i=0;i<5;i++)//循环5次得到5个数组的数
 BUF[i]=table1[8+linee];//查表得到数,注意是数组1中的数
}
/******************************************************/
/*******主程序显示子程序(包括上半屏与下半屏)********/
/******************************************************/
void xianzhu(uchar nia,uchar ye,uchar rii,uchar xi)
{
 uchar temp;//左移数值变量
 char i;//有符号变量
 for(move=0;move<8;move++)//左移8次让下半屏形成左移
 {
  for(line=0;line<8+lk;line++)//lk变量为选择上半屏还是全屏变量,当它等于0时,只显示上半屏时间,否则全屏显示
  {
   if(line<8)//如果它小于8则说明lk变量为0,只让它显示上半屏的主时间
   {
    yixian(shi,fen,dian);//调用主时间一线数值装载子函数
    for(i=4;i>=0;i--)
    song(~BUF[i]);//循环5次,将数组4-0的数全部发数到显示屏上
   }
   else//如果大于16则就循环左移显示下半屏的"年月日星期等信息"
   { 
    uchar movee;//局部变量
    movee=line-8;//line大于16,此时用它减去8就得到实际要显示的值
    BUF[0]=table[16+movee];//显示数字"2"字
    BUF[1]=table[movee];//显示数字"0"字
    BUF[2]=table[(8*(nia/10))+movee];//显示年十位
    BUF[3]=table[(8*(nia%10))+movee];//显示年个位
    BUF[4]=table1[16+movee];//显示横线"-"
    BUF[5]=table[(8*(ye/10))+movee];//显示月份十位
    BUF[6]=table[(8*(ye%10))+movee];//显示月份个位
    BUF[7]=table1[16+movee];//显示横线"-"
    BUF[8]=table[(8*(rii/10))+movee];//显示日十位 
    BUF[9]=table[(8*(rii%10))+movee];//显示日个位
    BUF[10]=table1[16+movee];//显示横线"-"
    BUF[11]=table[(8*(xi%10))+movee];//显示星期几
    for(i=4;i>=0;i--)//循环5次将数发送给下半屏
    {
     temp=((BUF[i+mov]<<move)|(BUF[(i+1)+mov]>>(6-move)));//将左半屏数左移x位,然后将右
     //半屏数右移6-x位,然后或一下就得到在左移了,此句是左移关键!
     song(~temp);//送数出去
    }
    delaya(1000);//延时一下
   }
   LINE=table2[line];//打开行线,即174HC154行线端
   CLKR=1;//在74HC595处锁存起来
   CLKR=0;
   CLKR=1;
   delaya(800);//延时一下
  }
 
 }
  mov++;//显示完一屏后,将移1个字变量加1,这样就完成下一字显示。原理是:显示下一个数组
  if(mov>13)//移完14次,就将它清0。原因是,程序全部定了19个数组,前面显示数用了5个加现在14次,刚好19个数组
  mov=0;//清0,重新开始显示
}
/******************************************************/
/**********闪烁间断显示子程序(包括下半屏)************/
/******************************************************/
void xianshan()
{
 char ii;//有符号变量
 for(line=0;line<8;line++)//扫描8次,即完成一个字的移动
 {
  if(flag1==0)//如果标志位为0,则以0.5秒速度显示时分钟主界面
  yixian(shi,fen,dian);//调用时分秒主界面子程序
  if(flag1==1)//如果标志位为1,则以0.5秒速度显示黑屏界面,形成闪烁效果
  yixianhei();//调用黑屏子程序
  for(ii=4;ii>=0;ii--)//循环5次将数发往显示屏
  song(~BUF[ii]);//送数
  LINE=table2[line];//打开行线,即174HC154行线端
  CLKR=1;//在74HC595处锁存起来
  CLKR=0;
  CLKR=1;
  delaya(800);
 }  
}
/******************************************************/
/**********年调整界面显示子程序(包括下半屏)************/
/******************************************************/
void xiannian(uchar nia)//变量年
{
 uchar movee;
 char ii;
 for(line=8;line<16;line++)//扫描8次,即完成一个字的移动,line等于8,表示在下半屏显示
 {
  if(flag1==0)//如果标志位为1,则执行显示部分
  {
   movee=line-8;
   BUF[0]=table[16+movee];//显示数字2
   BUF[1]=table[movee];//显示数字0
   BUF[2]=table[(8*(nia/10))+movee];//显示年十位
   BUF[3]=table[(8*(nia%10))+movee];
   BUF[4]=table1[16+movee];//显示横线
  }
  if(flag1==1)
  yixianhei();//否则显示黑屏
  for(ii=4;ii>=0;ii--)//循环5次将数发往显示屏
  song(~BUF[ii]);//送数
  LINE=table2[line];//打开行线,即174HC154行线端
  CLKR=1;//在74HC595处锁存起来
  CLKR=0;
  CLKR=1;
  delaya(800);
 }  
}
/******************************************************/
/*********月/日调整界面显示子程序(包括下半屏)********/
/******************************************************/
void xianriyue(uchar ye,uchar rii)//月与日变量
{
 uchar movee;
 char ii;
 for(line=8;line<16;line++)//扫描8次,即完成一个字的移动,line等于8,表示在下半屏显示
 {
  if(flag1==0)//同上如果为0就显示,为1就黑屏,形成闪烁
  {
   movee=line-8;
   BUF[0]=table[(8*(ye/10))+movee];//显示月十位
   BUF[1]=table[(8*(ye%10))+movee];//月个位
   BUF[2]=table1[16+movee];//显示横线
   BUF[3]=table[(8*(rii/10))+movee];//显示日十位 
   BUF[4]=table[(8*(rii%10))+movee];//显示横线
  }
  if(flag1==1)//为1就黑屏显示
  yixianhei();
  for(ii=4;ii>=0;ii--)//循环5次将数发往显示屏
  song(~BUF[ii]);//送数
  LINE=table2[line];//打开行线,即174HC154行线端
  CLKR=1;//在74HC595处锁存起来
  CLKR=0;
  CLKR=1;
  delaya(800);
 }  
}
/******************************************************/
/*********星期调整界面显示子程序(包括下半屏)********/
/******************************************************/
void xi(uchar xi)
{
 uchar movee;
 char ii;
 for(line=8;line<16;line++)//扫描8次,即完成一个字的移动,line等于8,表示在下半屏显示
 {
  if(flag1==0)//0.5秒显示
  {
   movee=line-8;
   BUF[0]=table1[16+movee];//显示横线"-"
   BUF[1]=table1[16+movee];//显示横线"-"
   BUF[2]=table[(8*(xi%10))+movee];//显示出星期个位
   BUF[3]=table1[16+movee];//显示横线"-"
   BUF[4]=table1[16+movee];//显示横线"-"
  }
  if(flag1==1)
  yixianhei();
  for(ii=4;ii>=0;ii--)//循环5次将数发往显示屏
  song(~BUF[ii]);//送数
  LINE=table2[line];//打开行线,即174HC154行线端
  CLKR=1;//在74HC595处锁存起来
  CLKR=0;
  CLKR=1;
  delaya(800);
 }  
}
/******************************************************/
/***************闹钟时间调整显示子程序*****************/
/******************************************************/
void xianniao(uchar shi,uchar ge,uchar z)
{
 char ii;
 for(line=0;line<8;line++)//扫描8次,即完成一个字的移动
 {
  if(flag1==0)//同样0.5秒显示时间
  {
   BUF[0]=table[(8*(shi/10))+line];//显示小时十位
   BUF[1]=table[(8*(shi%10))+line];
   BUF[2]=table1[z*8+line];//显示横线
   BUF[3]=table[(8*(ge/10))+line]; //显示分钟十位
   BUF[4]=table[(8*(ge%10))+line];
  }
  if(flag1==1)//同样0.5秒显示黑屏
  yixianhei();
  for(ii=4;ii>=0;ii--)//循环5次将数发往显示屏
  song(~BUF[ii]);//送数
  LINE=table2[line];//打开行线,即174HC154行线端
  CLKR=1;//在74HC595处锁存起来
  CLKR=0;
  CLKR=1;
  delaya(800);
 }  
}
/******************************************************/
/***************按键按下后处理子程序*******************/
/******************************************************/
void skey()
{
 if(shr!=0)//如果标志位shr不为0,则执行以下内容------如果按下了加按键则程序复位
 {
  if(key1==0)
  {
   delay(10);
   if(key1==0)//如果加按键按下了,则全部复位
   {
    yin=0;//将按键计数器清0
    shr=0;//标志位清0
    lk=0;//显示上半屏,此变量是全屏与半屏控制变量,当它为8时,就执行全屏,否则半屏
    clockbiao=~clockbiao;
    bbtsoud();//蜂鸣器响一声子程序
    while(!key1);//按键释放
   }   
  }
 }
 if(a!=0)//如果标志位不为0,则执行以下内容-------闪烁进入调整模式
 xianshan(); //闪烁 
 if(b!=0)//如果标志位不为0,则执行以下内容,进行主时间小时调整
 {
  xianshan();//调用主时间显示子程序
  if(key1==0)
  {
   delay(10);
   if(key1==0)
   {
    xianshan();
    shi++;
    if(shi==24)//小时等于24?
    shi=0;//清0
    write1302(0x8e,0x00);//去掉保护
    write1302(0x84,((shi/10)<<4)|(shi%10));//时数据写入
    write1302(0x8e,0x80);//打开保护 
    readvalue=read1302(0x85);
    shi=((readvalue&0xf0)>>4)*10+(readvalue&0x0f);//将小时转换出来
    while(!key1);
   }   
  }
  if(key2==0)//以下是处理主时间小时减部分
  {
   delay(10);
   if(key2==0)
   {
    shi--;
    if(shi==(0-1))
    shi=23;
    write1302(0x8e,0x00);//去掉保护
    write1302(0x84,((shi/10)<<4)|(shi%10));//时数据写入
    write1302(0x8e,0x80);//打开保护 
    readvalue=read1302(0x85);
    shi=((readvalue&0xf0)>>4)*10+(readvalue&0x0f); 
    while(!key2);
   }   
  }
 }
 if(c!=0)//如果标志位不为0,则执行以下内容------以下是处理主时间分钟调整部分
 {
  xianshan(); 
  if(key1==0)//加分钟部分
  {
   delay(10);
   if(key1==0)
   {
    xianshan();//调用主时间显示子程序
    fen++;
    if(fen==60)
    fen=00;
    write1302(0x8e,0x00);//去掉保护
    write1302(0x82,((fen/10)<<4)|(fen%10));//分数据写入
    write1302(0x8e,0x80);//打开保护
    readvalue=read1302(0x83);
    fen=((readvalue&0xf0)>>4)*10+(readvalue&0x0f);//将它转换出来
    while(!key1);
   }
  }
  if(key2==0)//减分钟部分
  {
   delay(10);
   if(key2==0)
   {
    xianshan(); 
    fen--;
    if(fen==(0-1))
    fen=59;
    write1302(0x8e,0x00);//去掉保护
    write1302(0x82,((fen/10)<<4)|(fen%10));//分数据写入
    write1302(0x8e,0x80);//打开保护
    readvalue=read1302(0x83);
    fen=((readvalue&0xf0)>>4)*10+(readvalue&0x0f); 
    while(!key2);
   }
  
  }
 }
 if(d!=0)//如果标志位不为0,则执行以下内容-----调整年
 {
  xiannian(nian);//调用年显示子程序
  if(key1==0)//年时间加部分处理
  {
   delay(10);
   if(key1==0)
   {
    xiannian(nian);
    nian++;
    if(nian==99)//年到了99吗?
    nian=0;
    write1302(0x8e,0x00);//去掉保护
    write1302(0x8c,((nian/10)<<4)|(nian%10));//年数据写入
    write1302(0x8e,0x80);//打开保护
    readvalue=read1302(0x8d);
    nian=((readvalue&0xf0)>>4)*10+(readvalue&0x0f);//年数据转换
    while(!key1);
   }
  }
  if(key2==0)//年时间减部分处理
  {
   delay(10);
   if(key2==0)
   {
    xiannian(nian); 
    nian--;
    if(nian==(0-1))
    nian=99;
    write1302(0x8e,0x00);//去掉保护
    write1302(0x8c,((nian/10)<<4)|(nian%10));//年数据写入
    write1302(0x8e,0x80);//打开保护
    readvalue=read1302(0x8d);
    nian=((readvalue&0xf0)>>4)*10+(readvalue&0x0f);//年数据转换 
    while(!key2);
   }
  
  }
 }
 if(e!=0)//如果标志位不为0,则执行以下内容-----处理月
 {
  xianriyue(yue,ri);
  if(key1==0)//月加部分处理
  {
   delay(10);
   if(key1==0)
   {
    xianriyue(yue,ri);
    yue++;
    if(yue==13)
    yue=1;
    write1302(0x8e,0x00);//去掉保护
    write1302(0x88,((yue/10)<<4)|(yue%10));//月数据写入
    write1302(0x8e,0x80);//打开保护
    readvalue=read1302(0x89);
    yue=((readvalue&0xf0)>>4)*10+(readvalue&0x0f); 
    while(!key1);
   }
  }
  if(key2==0)//月减部分处理
  {
   delay(10);
   if(key2==0)
   {
    xianriyue(yue,ri);
    yue--;
    if(yue==(1-1))
    yue=12;
    write1302(0x8e,0x00);//去掉保护
    write1302(0x88,((yue/10)<<4)|(yue%10));//月数据写入
    write1302(0x8e,0x80);//打开保护
    readvalue=read1302(0x89);
    yue=((readvalue&0xf0)>>4)*10+(readvalue&0x0f);//月转换
    while(!key2);
   }
  
  }
 }
 if(f!=0)//如果标志位不为0,则执行以下内容-------调整日
 {
  xianriyue(yue,ri);
  if(key1==0)//加日部分
  {
   delay(10);
   if(key1==0)
   {
    xianriyue(yue,ri);
    ri++;
    if(ri==32)
    ri=1;
    write1302(0x8e,0x00);//去掉保护
    write1302(0x86,((ri/10)<<4)|(ri%10));//日数据写入
    write1302(0x8e,0x80);//打开保护
    readvalue=read1302(0x87);
    ri=((readvalue&0xf0)>>4)*10+(readvalue&0x0f); 
    while(!key1);
   }
  }
  if(key2==0)//减日部分
  {
   delay(10);
   if(key2==0)
   {
    xianriyue(yue,ri);
    ri--;
    if(ri==(1-1))
    ri=31;
    write1302(0x8e,0x00);//去掉保护
    write1302(0x86,((ri/10)<<4)|(ri%10));//日数据写入
    write1302(0x8e,0x80);//打开保护 
    readvalue=read1302(0x87);
    ri=((readvalue&0xf0)>>4)*10+(readvalue&0x0f); 
    while(!key2);
   }
  
  }
 }
 if(g!=0)//如果标志位不为0,则执行以下内容-----星期调整部分
 {
  xi(xin);
  if(key1==0)//星期加部分
  {
   delay(10);
   if(key1==0)
   {
    xi(xin);
    xin++;//将星期+1
    if(xin==8)//如果星期到了8就清它清1
    xin=1;//清1
    write1302(0x8e,0x00);//去掉保护
    write1302(0x8a,((xin/10)<<4)|(xin%10));//显示星期天
    write1302(0x8e,0x80);//打开保护
    readvalue=read1302(0x8b);//读星期
    xin=((readvalue&0xf0)>>4)*10+(readvalue&0x0f);//将星期值还原 
    while(!key1);
   }
  }
  if(key2==0)//星期减部分
  {
   delay(10);
   if(key2==0)
   {
    xi(xin);
    xin--;//减1 
    if(xin==(1-1))//如果到了(1-1)就给它7,因为星期只1---7
    xin=7;//将它给7
    write1302(0x8e,0x00);//去掉保护
    write1302(0x8a,((xin/10)<<4)|(xin%10));//显示星期天
    write1302(0x8e,0x80);//打开保护
    readvalue=read1302(0x8b);
    xin=((readvalue&0xf0)>>4)*10+(readvalue&0x0f);//读星期值  
    while(!key2);
   }
  
  }
 }
 if(h!=0)////如果标志位不为0,则执行以下内容------------以下是闹钟小时调整部分
 {
  xianniao(shin,fenn,2);//调整闹钟小时与分钟显示子程序
  if(key1==0)//闹钟小时加处理
  {
   delay(10);
   if(key1==0)
   {
    xianniao(shin,fenn,2);
    shin++;//将星期+1
    if(shin==24)//如果星期到了8就清它清1
    shin=0;//清1
    while(!key1);
   }
  }
  if(key2==0)//闹钟小时减处理
  {
   delay(10);
   if(key2==0)
   {
    xianniao(shin,fenn,2);
    shin--;
    if(shin==(0-1))
    shin=23;  
    while(!key2);
   }
  
  }
 } 
 if(i!=0)//如果标志位不为0,则执行以下内容----------闹钟分钟调整
 {
  xianniao(shin,fenn,2);
  if(key1==0)//闹钟分钟加处理
  {
   delay(10);
   if(key1==0)
   {
    xianniao(shin,fenn,2);
    fenn++;//将星期+1
    if(fenn==60)//如果星期到了8就清它清1
    fenn=0;//清1
    while(!key1);
   }
  }
  if(key2==0)//闹钟分钟减处理
  {
   delay(10);
   if(key2==0)
   {
    xianniao(shin,fenn,2);
    fenn--;
    if(fenn==(0-1))
    fenn=59;  
    while(!key2);
   }
  
  }
 } 
}
/******************************************************/
/*******************响闹子程序*************************/
/******************************************************/
void xiangniao()
{
 bit clock;//定义一个标志位
 if(clockbiao==0)//闹钟总标志为0时才可以执行闹钟处理程序
 {
  if(clock==0)//如果标志位为0,就执行下面内容
  {
   if(shin==shi)//主时间小时与闹钟小时相等吗?
   {
    if(fenn==fen)//主时间分钟与闹钟分钟相等吗?
    bbtsoud();//相等了就执行闹钟响一声子程序,即小时与分钟都相等了就执行闹铃
   }
  }
  if(fenn!=fen)//如果分钟不等
  clock=0;//将标志位清0,以便下次再响铃
  if(key1==0)//判断加"+"按键有没有被按下,如果按下了,就让闹铃停止响
  {
   delay(10);
   if(key1==0)
   {
    clock=1;//将标志位清0,让闹钟在响铃时立马停下来
    while(!key1);
   }
  }
 }
 if(key2==0)//如果减按键按下了,则则关闭闹铃全部功能
 {
  delay(10);
  if(key2==0)//如果加按键按下了,则全部复位
  {
   clockbiao=~clockbiao;
   bbtsoud();//蜂鸣器响一声子程序
   while(!key2);//按键释放
  }   
 }   

/******************************************************/
/******************************************************/
/**********主程序(包括主显示/闹钟/按键处理)************/
/******************************************************/
/******************************************************/ 
void main()
{
 init1302();
 TMOD=0X11;//寄存器工作方式
 EA=1;//开总中断
 TR0=1;//开定时器
 ET0=1;//开定时器中断
 TH0=(65536-20000)/256;//赋值给高位
 TL0=(65536-20000)%256;//赋值给低位
 TR1=1;//开定时器
 ET1=1;//开定时器中断
 TH1=(65536-50000)/256;//赋值给高位
 TL1=(65536-50000)%256;//赋值给低位
 while(1)
 {
  if(flag==0)//如果标志位为0,就让它执行主程序,不让它读按键处理部分,省资源
  {
   value();//调用DS1302时间转换子程序
   xianzhu(nian,yue,ri,xin);//调用主显示
   xiangniao();//调用响闹子程序
  }
  skey();//调用按键处理子程序
 } 
}
/******************************************************/
/*******************定时中断0子程序********************/
/******************************************************/
void zhong() interrupt 3
{
 uchar ding;
 TH1=(65536-50000)/256;
 TL1=(65536-50000)%256;
 ding++;
 if(ding>=10)//模拟普通闹钟小数闪烁处理部分
 {
  ding=0;
  dian=~dian;//0.5秒闪一次,它不参与具体计时,具体计时只是DS1302内部
 }
}
/******************************************************/
/*******************定时中断1子程序********************/
/******************************************************/
void zhong1() interrupt 1//T1中断服务程序
{  
 uchar ding1,ding2;
 TH0=(65536-10000)/256;//赋值给高位
 TL0=(65536-10000)%256;//赋值给低位
 ding1++;
 ding2++;
 if(ding2>=50)//进入调整模式时闪烁标志位处理
 {
  ding2=0;
  flag1=~flag1;
 }
 switch(yin)//以下是主功能按键处理子程序
 {
  case 0:if(ding1>=250)//长按功能按键进入调整模式,否则怕误按-------------进入查看年月日功能
  {
   ding1=0;//将定时器清0
   if(key==0)
   {
    delay(100);
    if(key==0)
    {
     yin++;//将标志位加1
     lk=8;//些句是调用"年月日星期"显示的关键一步,即打开下屏显示
     shr=1;//将标志位置1
     bbtsoud();//蜂鸣器响一声
     while(!key);//按键释放
    }
   }
  }
  break;
  case 1:if(key==0)//-----------------------------进入调整模式闪烁功能
  {
   delay(100);
   if(key==0)
   {
    yin++;//以便进入一个功能
    a=1;//标志位置1,以便进入按键功能
    shr=0;//将上次标志位清0,以免与现在的键值产生冲突
    lk=0;//将下半屏清掉
    flag=1;//将主程序中的标志位置1
    bbtsoud();//蜂鸣器响一声
    TR1=0;//将定时器关掉
    dian=0;//将主时间中的两位小数点标志位打开
    write1302(0x8e,0x00);//去掉DS1302保护
    write1302(0x80,0x80);//当它等于0X80时,让DS1302时间停下来,以便调整
    write1302(0x8e,0x80);//让DS1302保护
    while(!key);
   } 
  }
  break;
  case 2: if(key==0)//-----------------------------进入主时间小时调整功能
  {
   delay(100);
   if(key==0)
   {
    yin++;//以下便进行下一功能
    b=1;//标志位置1
    a=0;
    bbtsoud();
    while(!key);
   } 
  }
  break;
  case 3: if(key==0)//---------------------------进入主时间分钟时调整功能
  {
   delay(100);
   if(key==0)
   {
    yin++;
    b=0;
    c=1;
    bbtsoud();
    while(!key);
   }
  }
  break;
  case 4: if(key==0)//---------------------------------进入日期年调整功能
  {
   delay(100);
   if(key==0)
   {
    yin++;
    c=0;
    d=1;
    bbtsoud();
    while(!key);
   }
  }
  break; 
  case 5:if(key==0)//-----------------------------------进入日期月调整功能
  {
   delay(100);
   if(key==0)
   {
    yin++;
    d=0;
    e=1;
    bbtsoud();
    while(!key);
   } 
  }
  break;
  case 6: if(key==0)//-----------------------------------进入日期日调整功能
  {
   delay(100);
   if(key==0)
   {
    yin++;
    e=0;
    f=1;
    bbtsoud();
    while(!key);
   } 
  }
  break;
  case 7:if(key==0)//---------------------------------进入日期星期调整功能
  {
   delay(100);
   if(key==0)
   {
    yin++;
    f=0;
    g=1;
    bbtsoud();
    while(!key);
   }
  }
  break;
  case 8: if(key==0)//------------------------------进入闹钟小时调整功能
  {
   delay(100);
   if(key==0)
   {
    yin++;
    g=0;
    h=1;
    bbtsoud();
    while(!key);
   }
  }
  break; 
  case 9:if(key==0)//------------------------------进入闹钟分钟调整功能
  {
   delay(100);
   if(key==0)
   {
    yin++;
    h=0;
    i=1;
    bbtsoud();
    while(!key);
   } 
  }
  break;
  case 10:if(key==0)//----------------------将系统全部复位,即回到主程序
  {
   delay(100);
   if(key==0)
   {
    yin=0;//总计数器复位为0
    i=0;//上次功能标志位清0
    flag=0;//主程序标志位清0
    TR1=1;//打开定时器
    write1302(0x8e,0x00);//去掉DS1302保护
    write1302(0x80,0x00);//当它等于0X00时,让时间就开始走 即0X00就让时间开始走,0X80让时停
    write1302(0x8e,0x80);//让时间停下来
    bbtsoud();
    while(!key);
   } 
  }
  break;
 }
}  

关闭窗口

相关文章