万年历的单片机实现.docx
《万年历的单片机实现.docx》由会员分享,可在线阅读,更多相关《万年历的单片机实现.docx(43页珍藏版)》请在冰豆网上搜索。
万年历的单片机实现
实验题目:
万年历的单片机实现
一、实验内容
用单片机实现万年历
二、实验要求
(1)平时显示实时时钟与日历
(2)输入任意日子可显示对应的星期和阴历
(3)可设置的闹钟功能
三、实验器件
DP-51PRO.NET综合实验箱
微机一台(Keil软件)
四、设计任务分析
本实验是基于51单片机的电子万年历的设计,其中包括当前时间与日期的显示,当前时间与日期的调整,闹铃的设置,任意日期的阴历查询以及星期查询的功能。
可以依据功能,将显示分为三个界面,分别为当前时间与日期显示界面,闹铃设置界面,综合查询界面,可通过三个按键进行切换,按键时需要软件“去抖”。
显示器件为型号为LCM12864的LCD液晶显示屏。
具体实现过程如下:
五、具体实现过程
可以依据功能,将显示分为三个界面,分别为当前时间与日期显示与设置界面,闹铃设置界面,综合查询界面。
由于LCM12864的配置文件中自带一个函数LCM_DispStr,可以直接将指定字符串显示于指定行列,故为了方便起见,也为了减少变量,将本实验中所需的时间与日期全部定义为字符串形式。
事实证明,这样反而加大了程序代码的冗余。
(一)、当前时间与日期显示与设置
本界面中包含当前的时间与日期显示及设置功能,为主界面,即初始界面。
1、当前时间与日期显示
由于时间具有同步性,故时间应该是可以动态刷新的,又为了不被其它功能影响计时的准确性,可以用一个定时器中断予以实现。
采用定时方式1,由于定时器无法计时1S,故可以设置一个变量从而使其为2ms*500,不太清楚具体晶振频率,取TH=-2000/256,TL=-2000%256,即作12MHz处理,经测试平均约每分钟2s的误差。
之所以设置值不大,也是为了后期的闹铃部分的闹钟能稍微响亮一些。
同时每次更新完时间后,若秒钟达到了60秒,则会引起相应的时间甚至日期的进位。
同时在日期的进位中,需要注意的是平闰年的2月只有28/29天,以及大月31天与小月30天。
2、当前时间与日期修改
在此过程中,需要有按键可以进入修改界面,以及退出界面,同时,在修改时需要移位以及数字的加减功能,为了方便表明修改的哪位,设置了一个周期约为0.2s的闪烁功能。
另在修改时,由于时间与日期有最大值限制,需要设置一个允许修改的范围。
为了实用性,除年份可以4位都设置外,其它部分定义为只能设置个位,并因个位的变化而引起十位的进位或退位。
调整时,不再计时。
(二)、闹铃设置
本界面包括闹铃的时间显示与设置,以及闹铃的开关,闹铃的执行。
1、闹铃时间设置
闹铃的时间设置类似于主界面中的时间设置功能,不同的是,增加了在每次时间更新后会与设定时间对比,若时间完全符合,且开关为On,即开启状态,会由定时器赋予蜂鸣器一个周期约为0.2s的方波,从而使其发出声音,闹铃执行过程中,其它功能正常进行,不影响计时,按下指定键后闹铃停止。
2、闹铃开关
闹铃的开关设置为仅可在设置闹铃时进行设置,其中闹铃的开关标识符为一个全局变量,可通过指定按键修改,显示界面中会根据全局变量的值显示闹铃的开关状态。
(三)、综合查询
1、输入查询日期
输入查询日期的过程与主界面中设置日期的过程类似,只是输入后会使查询的星期与阴历动态变化,而不需要确定键。
2、显示查询的星期与阴历
在输入查询的日期后,需要获得查询的星期几可以通过在网上查询到的一个公式:
W = (Y-1) + [(Y-1)/4] - [(Y-1)/100] + [(Y-1)/400] + D
其中Y是年份,D为累计的天数,然后WMod7即是当前星期几,若为0,则为星期天,即Sunday。
阴历换算我确实不太懂,但经过网上搜索资料后,可以找到一个关于从1901年到2099年每年各阴历月份的大小,春节所在的公历以及有无闰月等的表,则可以通过累计日期求出农历的日期,为了方便,未采用传统的天干地支计法,而直接采用了数字计法。
六、连线及实验配置准备
1、软件设置:
给出的拓展名.c的文件全部加入到Keil安装目录下的LIB文件夹里;给出的拓展名为.h的文件全部加入到INC文件夹里,并添加所有的c文件至工程中
因为用到了外部I/O(RAM),所以调试时,要开放系统总线。
点击工具栏的Project->Optionfortarget‘target1’->debug->Settings,然后开放总线,即选择ALLBUS或者XBUS(推荐)。
2、硬件连接
a.将A2区J65的A0-A3分别连接到B3区J75的A0-A2及/CS。
b.将A2区J56的/WR、/RD分别连接到B3区J75的WR,WD。
c.将A2区J51的P1.0连接到B3区J75的RST
d.将P1.4,P3.5,P3.4,P3.0,P3.1分别连接至D1区的K1-K5,P1.7连接至D4区的蜂鸣器
七、实验总结
此次实验目的为设计一个电子万年历,并要求有一些指定功能。
经过了好几天的编程,最后能实现一个基本没BUG的作品,看见自己的万年历可以正常运行了,还是挺欣慰的。
通过这次实验给我最大的感受就是,不要着急写程序,架构最重要。
因为我图一时方便用了字符串存储日期与时间,致使后面的程序复杂了不少,虽然最后还是达到了一定的精确度,但是代码非常冗余。
如果开始架构好,完全可以用单纯的数字存储,并通过编写通用的子函数来大大简化函数。
如果在以后工作中,这点必须注意,不然代码维护性很差。
另外,在实验过程中,有一个花了不少时间的在于,我不太懂LCM的内部连接,并且执意不采用周立功键盘而自行采用普通按键,致使花了很长时间才找出了可以正常用于与单片机交互可输入的I/O口。
同时在实验中,我也学会了一些计算星期及阴历的算法,这样可以方便以后。
另外,还有点很重要,只要自己愿意花时间去研究,在复杂的问题都可以解决。
此次试验中,比较遗憾的一点,就是为图简单,未利用LCD的扫描函数,而使其完全为英文界面。
八、程序代码
Code:
#include"LCM_config.h"
#include
#defineucharunsignedchar
#defineuintunsignedint
voidwindow_now();
voidwindow_alarm();
voidwindow_search();
voidDelayms(uintms);
voidT_delay();
voidTimeUpdate();
voidTimeShow();
voidDateUpdate();
voidDateShow();
voidAlarmShow();
voidSearchShow();
voidAlarmChanged();
voidTimeDateChanged();
voidSearchDateChanged();
voidSound();
voidLunarConversion(ucharYear[]);
intJudgeRun(ucharYear[]);
intJudgeWeek(ucharYear[]);
intLunarBigOrSmall(ucharmonth_n,uinttable_addr);
ucharDate[]="2014-07-10";
ucharTime[]="12:
15:
00";
ucharAlarm[]="13:
27:
40";
ucharInput[]="2014-07-09";
ucharLunar[]="2014-02-08";
ucharcodeWeek[7][10]={"Monday","Tuesday","Wednesday","Thursday",
"Friday","Saturday","Sunday"};
ucharcodeyear_code[]={
//1901-2099
//第一字节BIT7-4位表示闰月月份,值为0为无闰月,
//BIT3-0对应农历第1-4月的大小
//第二字节BIT7-0对应农历第5-12月大小,
//第三字节BIT7表示农历第13个月大小
//月份对应的位为1表示本农历月大(30天),为0表示小(29天)
//BIT6-5表示春节的公历月份,BIT4-0表示春节的公历日期
0x04,0xAe,0x53,//19010
0x0A,0x57,0x48,//19023
0x55,0x26,0xBd,//19036
0x0d,0x26,0x50,//19049
0x0d,0x95,0x44,//190512
0x46,0xAA,0xB9,//190615
0x05,0x6A,0x4d,//190718
0x09,0xAd,0x42,//190821
0x24,0xAe,0xB6,//1909
0x04,0xAe,0x4A,//1910
0x6A,0x4d,0xBe,//1911
0x0A,0x4d,0x52,//1912
0x0d,0x25,0x46,//1913
0x5d,0x52,0xBA,//1914
0x0B,0x54,0x4e,//1915
0x0d,0x6A,0x43,//1916
0x29,0x6d,0x37,//1917
0x09,0x5B,0x4B,//1918
0x74,0x9B,0xC1,//1919
0x04,0x97,0x54,//1920
0x0A,0x4B,0x48,//1921
0x5B,0x25,0xBC,//1922
0x06,0xA5,0x50,//1923
0x06,0xd4,0x45,//1924
0x4A,0xdA,0xB8,//1925
0x02,0xB6,0x4d,//1926
0x09,0x57,0x42,//1927
0x24,0x97,0xB7,//1928
0x04,0x97,0x4A,//1929
0x66,0x4B,0x3e,//1930
0x0d,0x4A,0x51,//1931
0x0e,0xA5,0x46,//1932
0x56,0xd4,0xBA,//1933
0x05,0xAd,0x4e,//1934
0x02,0xB6,0x44,//1935
0x39,0x37,0x38,//1936
0x09,0x2e,0x4B,//1937
0x7C,0x96,0xBf,//1938
0x0C,0x95,0x53,//1939
0x0d,0x4A,0x48,//1940
0x6d,0xA5,0x3B,//1941
0x0B,0x55,0x4f,//1942
0x05,0x6A,0x45,//1943
0x4A,0xAd,0xB9,//1944
0x02,0x5d,0x4d,//1945
0x09,0x2d,0x42,//1946
0x2C,0x95,0xB6,//1947
0x0A,0x95,0x4A,//1948
0x7B,0x4A,0xBd,//1949
0x06,0xCA,0x51,//1950
0x0B,0x55,0x46,//1951
0x55,0x5A,0xBB,//1952
0x04,0xdA,0x4e,//1953
0x0A,0x5B,0x43,//1954
0x35,0x2B,0xB8,//1955
0x05,0x2B,0x4C,//1956
0x8A,0x95,0x3f,//1957
0x0e,0x95,0x52,//1958
0x06,0xAA,0x48,//1959
0x7A,0xd5,0x3C,//1960
0x0A,0xB5,0x4f,//1961
0x04,0xB6,0x45,//1962
0x4A,0x57,0x39,//1963
0x0A,0x57,0x4d,//1964
0x05,0x26,0x42,//1965
0x3e,0x93,0x35,//1966
0x0d,0x95,0x49,//1967
0x75,0xAA,0xBe,//1968
0x05,0x6A,0x51,//1969
0x09,0x6d,0x46,//1970
0x54,0xAe,0xBB,//1971
0x04,0xAd,0x4f,//1972
0x0A,0x4d,0x43,//1973
0x4d,0x26,0xB7,//1974
0x0d,0x25,0x4B,//1975
0x8d,0x52,0xBf,//1976
0x0B,0x54,0x52,//1977
0x0B,0x6A,0x47,//1978
0x69,0x6d,0x3C,//1979
0x09,0x5B,0x50,//1980
0x04,0x9B,0x45,//1981
0x4A,0x4B,0xB9,//1982
0x0A,0x4B,0x4d,//1983
0xAB,0x25,0xC2,//1984
0x06,0xA5,0x54,//1985
0x06,0xd4,0x49,//1986
0x6A,0xdA,0x3d,//1987
0x0A,0xB6,0x51,//1988
0x09,0x37,0x46,//1989
0x54,0x97,0xBB,//1990
0x04,0x97,0x4f,//1991
0x06,0x4B,0x44,//1992
0x36,0xA5,0x37,//1993
0x0e,0xA5,0x4A,//1994
0x86,0xB2,0xBf,//1995
0x05,0xAC,0x53,//1996
0x0A,0xB6,0x47,//1997
0x59,0x36,0xBC,//1998
0x09,0x2e,0x50,//1999294
0x0C,0x96,0x45,//2000297
0x4d,0x4A,0xB8,//2001
0x0d,0x4A,0x4C,//2002
0x0d,0xA5,0x41,//2003
0x25,0xAA,0xB6,//2004
0x05,0x6A,0x49,//2005
0x7A,0xAd,0xBd,//2006
0x02,0x5d,0x52,//2007
0x09,0x2d,0x47,//2008
0x5C,0x95,0xBA,//2009
0x0A,0x95,0x4e,//2010
0x0B,0x4A,0x43,//2011
0x4B,0x55,0x37,//2012
0x0A,0xd5,0x4A,//2013
0x95,0x5A,0xBf,//2014
0x04,0xBA,0x53,//2015
0x0A,0x5B,0x48,//2016
0x65,0x2B,0xBC,//2017
0x05,0x2B,0x50,//2018
0x0A,0x93,0x45,//2019
0x47,0x4A,0xB9,//2020
0x06,0xAA,0x4C,//2021
0x0A,0xd5,0x41,//2022
0x24,0xdA,0xB6,//2023
0x04,0xB6,0x4A,//2024
0x69,0x57,0x3d,//2025
0x0A,0x4e,0x51,//2026
0x0d,0x26,0x46,//2027
0x5e,0x93,0x3A,//2028
0x0d,0x53,0x4d,//2029
0x05,0xAA,0x43,//2030
0x36,0xB5,0x37,//2031
0x09,0x6d,0x4B,//2032
0xB4,0xAe,0xBf,//2033
0x04,0xAd,0x53,//2034
0x0A,0x4d,0x48,//2035
0x6d,0x25,0xBC,//2036
0x0d,0x25,0x4f,//2037
0x0d,0x52,0x44,//2038
0x5d,0xAA,0x38,//2039
0x0B,0x5A,0x4C,//2040
0x05,0x6d,0x41,//2041
0x24,0xAd,0xB6,//2042
0x04,0x9B,0x4A,//2043
0x7A,0x4B,0xBe,//2044
0x0A,0x4B,0x51,//2045
0x0A,0xA5,0x46,//2046
0x5B,0x52,0xBA,//2047
0x06,0xd2,0x4e,//2048
0x0A,0xdA,0x42,//2049
0x35,0x5B,0x37,//2050
0x09,0x37,0x4B,//2051
0x84,0x97,0xC1,//2052
0x04,0x97,0x53,//2053
0x06,0x4B,0x48,//2054
0x66,0xA5,0x3C,//2055
0x0e,0xA5,0x4f,//2056
0x06,0xB2,0x44,//2057
0x4A,0xB6,0x38,//2058
0x0A,0xAe,0x4C,//2059
0x09,0x2e,0x42,//2060
0x3C,0x97,0x35,//2061
0x0C,0x96,0x49,//2062
0x7d,0x4A,0xBd,//2063
0x0d,0x4A,0x51,//2064
0x0d,0xA5,0x45,//2065
0x55,0xAA,0xBA,//2066
0x05,0x6A,0x4e,//2067
0x0A,0x6d,0x43,//2068
0x45,0x2e,0xB7,//2069
0x05,0x2d,0x4B,//2070
0x8A,0x95,0xBf,//2071
0x0A,0x95,0x53,//2072
0x0B,0x4A,0x47,//2073
0x6B,0x55,0x3B,//2074
0x0A,0xd5,0x4f,//2075
0x05,0x5A,0x45,//2076
0x4A,0x5d,0x38,//2077
0x0A,0x5B,0x4C,//2078
0x05,0x2B,0x42,//2079
0x3A,0x93,0xB6,//2080
0x06,0x93,0x49,//2081
0x77,0x29,0xBd,//2082
0x06,0xAA,0x51,//2083
0x0A,0xd5,0x46,//2084
0x54,0xdA,0xBA,//2085
0x04,0xB6,0x4e,//2086
0x0A,0x57,0x43,//2087
0x45,0x27,0x38,//2088
0x0d,0x26,0x4A,//2089
0x8e,0x93,0x3e,//2090
0x0d,0x52,0x52,//2091
0x0d,0xAA,0x47,//2092
0x66,0xB5,0x3B,//2093
0x05,0x6d,0x4f,//2094
0x04,0xAe,0x45,//2095
0x4A,0x4e,0xB9,//2096
0x0A,0x4d,0x4C,//2097
0x0d,0x15,0x41,//2098
0x2d,0x92,0xB5,//2099
};
sbitRST=P1^0;
sbitk1=P1^4;
sbitk2=P3^5;
sbitk3=P3^4;
sbitk4=P3^0;
sbitk5=P3^1;
sbitsoundOn=P1^7;
inttimeCount=0;
intAlarmSwitch=0;
intflag=0;
intSoundFlag=0;
intTimeSwitch=1;
//月份数据表
codeucharday_code1[9]={0x0,0x1f,0x3b,0x5a,0x78,0x97,0xb5,0xd4,0xf3};
codeuintday_code2[3]={0x111,0x130,0x14e};
timer0()interrupt1{
//定时器中断
TH0=-2000/256;
TL0=-2000%256;
if(TimeSwitch){
timeCount++;
if(SoundFlag){
soundOn=!
soundOn;
Delayms
(1);
}
if(timeCount==500){
TimeUpdate();
timeCount=0;
Sound();
}
}
}//timer0
voidSound(){
//判断是否到达所设置的闹钟时间
if(!
SoundFlag&&AlarmSwitch==1
&&Time[0]==Alarm[0]&&Time[1]==Alarm[1]
&&Time[3]==Alarm[3]&&Time[4]==Alarm[4]
&&Time[6]==Alarm[6]&&Time[7]==Alarm[7]){
SoundFlag=1;
}elseif(SoundFlag){
if(!
k5){
T_delay();
if(!
k5){
SoundFlag=0;
}
}
}
}//Sound
voidmain(){
//主函数
intchangeFlag=0;
TMOD=0x01;
TH0=-2000/256;
TL0=-2000%256;
EA=1;ET0=1;
TR0=1;
LCM_DispIni();
window_now();
while
(1){
k1=k2=k3=k4=k5=1;
changeFlag=0;
if(!
k1){
T_delay();
if(!
k1){
changeFlag=1;
flag=0;
}
}elseif(k2==0){
T_delay();
if(!
k2){
changeFlag=1;
flag=1;
}
}elseif(k3==0){
T_delay();
if