📄 dateandtime.c
字号:
/***********************************************************************************
************************************************************************************
********************************
基于MSC-51单片机的万年历程序
********************************
文件名称:DataAndTime.c
设 计 者: 黄开坤
***********************************************************************************/
#include <reg51.h>
#include <LCD1602.h>
#include <DS18B20.h>
sbit led =P3^7 ; //LCD屏背光灯控制线
sbit Play =P3^0 ; //启到发音
/***全局变量************************************************************************/
unsigned char year =7 ; //年变量,初始值为2007年
unsigned char month =4 ; //月娈量,初始值为4月
unsigned char day =20 ; //日变量,初始值为20日
unsigned char week =5 ; //周 ,初始值为周5
unsigned char hour =12 ; //时 ,初始值为12
unsigned char minute =0 ; //分 ,初始值为0
unsigned char second =0 ; //秒 ,初始值为0
unsigned char Timer_hour =12 ; //定时器的时变量
unsigned char Timer_minute =0 ; //定时器的分变量
unsigned char days =30 ; //用于存放每月的天数,初使值为30天
unsigned char Timer_Ring =1 ; //定时器提示音编号
unsigned char led_on =15 ; //LCD显示屏背光灯亮的时间
unsigned char Number =0 ; //用于指定报第几个音
bit Temperature_sin =1 ; //温度转换标志,为1,则启动温度转换并刷新
bit LeapYear_sin =0 ; //润年标志,1为润年,0为非润年
bit Timer_sin =0 ; //定时器响应标志,为1表示定时已到,正在响应
bit Timer_ON_OFF ; //定时器开/关标志。1开;0为关
bit Timer_Show_sin ; //定时器显示标志。为1表示正处于定时器显示状态
bit Speak_sin ; //报时标志,为1表示正在报时
unsigned char DATA[3] ; //存放两位十进制数的ASCII码
unsigned char Week_Str[4] ; //用于存放3个字符,表示星期,如Mon表示星期一
unsigned char Voice[4] ; //存放两位十进数的语音地址
unsigned char Speak[11] ; //存放将要报出的语音
/***0-10语音地址表******************************************************************/
unsigned char code VoiceTab[]={0x00,0x04,0x08,0x0c,0x10,0x14,0x18,0x1c,0x20,0x24};
/***2000--2099年中的润年表**********************************************************/
unsigned char code Leap_YearTAB[]={4 ,8 ,12,16,20,24,28,32,36,40,44,48,
52,56,60,64,68,72,76,80,84,88,92,96};
/***计算润年************************************************************************/
void Leap_Year(unsigned char Years)
{
unsigned char i;
for(i=0;i<24;i++)
{
if(Years==Leap_YearTAB[i]) //用查表的方法确定是否为润年
{LeapYear_sin=1;break;}
else
LeapYear_sin=0;
}
}
/***计算每月的天数******************************************************************/
unsigned char Momth_Days(unsigned char Months)
{
switch(Months)
{ case 2 :{if(LeapYear_sin==1) //二月份天数,润年为29天,非润年为28天
days=29;
else
days=28;
};break;
case 4 : //四、六、九、十一月份为30天
case 6 :
case 9 :
case 11 :days=30 ;break;
default :days=31 ; //其余月份为31天
}
days=days+1 ;
return(days); //返回值=某月的实际天数+1。
}
/***星期转换************************************************************************/
void WeekToStr( char n)
{
switch(n)
{ case 1 :{Week_Str[0]='M' ; //星期一,Mon
Week_Str[1]='o' ;
Week_Str[2]='n' ;
Week_Str[3]='\0';
};break ;
case 2 :{Week_Str[0]='T' ; //星期二,Tue
Week_Str[1]='u' ;
Week_Str[2]='e' ;
Week_Str[3]='\0';
};break ;
case 3 :{Week_Str[0]='W' ; //星期三,Wen
Week_Str[1]='e' ;
Week_Str[2]='n' ;
Week_Str[3]='\0';
};break ;
case 4 :{Week_Str[0]='T' ; //星期四,Thu
Week_Str[1]='h' ;
Week_Str[2]='u' ;
Week_Str[3]='\0';
};break ;
case 5 :{Week_Str[0]='F' ; //星期五,Fri
Week_Str[1]='r' ;
Week_Str[2]='i' ;
Week_Str[3]='\0';
};break ;
case 6 :{Week_Str[0]='S' ; //星期六,Sat
Week_Str[1]='a' ;
Week_Str[2]='t' ;
Week_Str[3]='\0';
};break ;
case 7 :{Week_Str[0]='S' ; //星期日,Sun
Week_Str[1]='u' ;
Week_Str[2]='n' ;
Week_Str[3]='\0';
};break ;
}
}
/***类型转换(将字符型数据转换成相应的ASCII码****************************************/
void CharToStr(unsigned char t)
{
DATA[0]=(t/10)%10+'0' ; //取十位,并转换成相应的ASCII码
DATA[1]=t%10+'0' ; //取个位,并转换成相应的ASCII码
DATA[2]='\0' ; //字符串结束符
}
/***延时程序************************************************************************/
void Delay1ms(unsigned char n) //延时时间≈(4*n+996*n)us=n ms
{
unsigned char k=166;
while(--n)
{ while(--k)
;
}
}
/***键盘扫描程序********************************************************************/
unsigned char Key_Scan(void)
{
if((P2&0x0f)!=0x0f) //判断P.4--P2.7是否有键按下
{ Delay1ms(10) ; //延时10ms,消抖动
if((P2&0x0f)!=0x0f)
{ led_on=15 ; //LCD屏的背光灯亮的时间重新赋值
led=1 ; //只要有键按下,LCD屏的背光灯就亮
Timer_sin=0 ; //只要有键按下,闹铃停止
switch(P2&0x0f)
{case 0x0e :{while((P2&0x0f)!=0x0f) //等待按键释放
;
return 1; //P2.4上的键按下,1号键
};break;
case 0x0d :{while((P2&0x0f)!=0x0f) //等待按键释放
;
return 2; //P2.5上的键按下,2号键
};break;
case 0x0b :{while((P2&0x0f)!=0x0f) //等待按键释放
;
return 3; //P2.6上的键按下,3号键
};break;
case 0x07 :{while((P2&0x0f)!=0x0f) //等待按键释放
;
return 4; //P2.7上的键按下,4号键
};break;
default :return 0;
}
}
}
else
return 0;
}
/***数字——语音变换****************************************************************/
void NumberToVoice(unsigned char number)//将数字转换成相应的读音。(0≤number<60)
{
unsigned char a,b;
a=(number/10)%10 ; //取十位值
b=number%10 ; //取个位值
if(a==0) //0≤number<10时的读音,(一个音)
{ Voice[0]=VoiceTab[b]; //
Voice[1]=0xff ; //
}
if(a!=0&&b==0) //number的个位为0,十位不为0时的读音
{if(a==1) //10的读音
{Voice[0]=0x28 ; //
Voice[1]=0xff ; //
}
Voice[0]=VoiceTab[a] ; //个位为0,十位不为0和1时的读音
Voice[1]=0x28 ; //
Voice[2]=0xff ; //
}
if(a==1&&b!=0) //10<number<20时的读音,(两个音)
{Voice[0]=0x28 ; //
Voice[1]=VoiceTab[b] ; //
Voice[2]=0xff ; //
}
if((a!=0&&a!=1)&&b!=0) //number的个位不为0,十位不为0和1时的读音
{Voice[0]=VoiceTab[a]; //
Voice[1]=0x28 ; //
Voice[2]=VoiceTab[b]; //
Voice[3]=0xff ; //
}
}
/***语音报时************************************************************************/
void SpeakTime(void) //语音报时函数
{
unsigned char j,i=0 ;
Speak[i]=0x3c ; //报时前凑音
i++ ;
Speak[i]=0x2c ; //“现在时刻”
NumberToVoice(hour) ; //“小时”
for(j=0;j<5;j++)
{ i++ ;
if(Voice[j]==0xff)
{ Speak[i]=0x34 ; //“点”
break;
}
Speak[i]=Voice[j];
}
NumberToVoice(minute) ; //“分钟”
for(j=0;j<5;j++)
{ i++ ;
if(Voice[j]==0xff)
{ Speak[i]=0x38 ; //“分”
break ;
}
Speak[i]=Voice[j] ;
}
i++ ;
Speak[i]=0xff ; //报时结束标志
EX0=1 ; //INT0开中
IE0=1 ; //启动报时
Speak_sin=1 ; //报时标志置1
}
/***闹铃****************************************************************************/
void Ring(void)
{
if(Timer_Ring==1) //铃声1
P1=0x44 ;
if(Timer_Ring==2) //铃声2
P1=0x58 ;
if(Timer_Ring==3) //铃声3
P1=0x70 ;
Timer_sin=1 ; //表示进入闹铃状态
EX0=1 ; //INT0开中
IE0=1 ; //启动闹铃
}
/***日历和时间调整******************************************************************/
void Set_TimeAndDate(void)
{
unsigned char key;
EX1=0; //关闭INT1中断,停止计时
LCD_ShowMode(LCD_SHOW|LCD_CORSOR|LCD_FLASH); //开光标,光标闪烁
Year_set: LCD_GoToXY(2,1) ; //年校正
key=Key_Scan() ; //键盘扫描
if(key==1) goto Month_set ; //如果按下的是功能键(1号键),转月校正
if(key==2) year++ ; //如果按下的是加1 键(2号键),年加1
if(year==100) //年上限循环
year=0 ;
if(key==3) year-- ; //如果按下的是减1 键(3号键),年减1
if(year==-1) //年下限循环
year=99 ;
Leap_Year(year) ; //判断润年
LCD_GoToXY(2,1) ;
CharToStr(year) ; //将校正后的年数据转换成相对应的ASCII码
Delay1ms(50) ; //延时100ms
LCD_Print(DATA) ; //年显示刷新
goto Year_set ; //年校正循环
Month_set: LCD_GoToXY(5,1) ; //月校正
key=Key_Scan() ; //键盘扫描
if(key==1) goto Day_set ; //如果按下的是功能键(1号键),转日校正
if(key==2) month++ ; //如果按下的是加1 键(2号键),月加1
if(month==13) //月上限循环
month=1 ;
if(key==3) month-- ; //如果按下的是减1 键(3号键),月减1
if(month==0) //月下限循环
month=12 ;
CharToStr(month) ; //将校正后的月数据转换成相对应的ASCII码
Delay1ms(50) ; //延时100ms
LCD_Print(DATA) ; //月显示刷新
Momth_Days(month) ; //确定校正后,月的天数
goto Month_set ; //月校正循环
Day_set: LCD_GoToXY(8,1) ; //日校正
key=Key_Scan() ; //键盘扫描
if(key==1) goto Week_set ; //如果按下的是功能键(1号键),转时校正
if(key==2) day++ ; //如果按下的是加1 键(2号键),日加1
if(day==days) //日上限循环
day=1 ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -