正文:
) 调整时间和日期,
只设置了四个按键
a, 复位按键;
b, 调整模态选择按键,切换调整不同参数;
c, 上调按键,调整模式下按此键被调整值上调;
d, 下调按键,调整模式下按此键被调整值下调.
这shi调整年份时de显示状态,LCD第二行末尾显示"yar".
依此类推,调整月份时显示"mth",调整日期时显示"day",小时时显示"hor",分钟时显示"min".
3) 软件部分.
程序中包含一个头文件"LCD1620.h",此文件中包含有关LCDde一些显示函数.
下面shi部分程序原代码---不知道怎么回事,今天网络速度比较慢,无法上传文件.如有需要可与我e-mail联系lhy_radio@yeah.net.
/*******************************************************/
/* Project :Calendar */
/* Compiler :ICCAVR 6.31A */
/* Date :2008,5,31 */
/* Author :lhy */
/* Version :v1.3 */
/* Rework :lhy */
/* Rework Date :2008.6.26 */
/* */
/* Comments : */
/* 1,使用Atmega8内部RTC(实时时钟,32.768KHz) */
/* 2,显示使用LCD1620 */
/* 3,在Timer2中断中刷新显示,精度提高1S@5H */
/* 4,加入星期显示 */
/* 5,加入农历换算 */
/* 6,秒末位大于等于5时,显示公历:Solar 年月日 */
/* 7,SolarYear>2099或SolarYear<1900, */
/* 显示"Out of range!" */
/* 8,加入手动调整日期和时间 */
/*******************************************************/
#i nclude <iom8v.h>
#i nclude <macros.h>
#define DataPortPullup PORTD
#define DataPortDirection DDRD
#define ReadLCDPin PIND
#define CtrlPortPullup PORTC
#define CtrlPortDirection DDRC
#define RS_Bit PC0
#define RW_Bit PC1
#define E_Bit PC2
#i nclude "LCD1620.h"
#define ClkTcnt2 0x80
/****************变量声明********************/
unsigned int Year = 2008;//年变量
unsigned char Month = 6;//月变量
unsigned char Day = 1;
unsigned char Hour = 12;//小时
unsigned char Min = 0;//分钟
unsigned char Sec = 0;//秒
unsigned char YearBit1,YearBit2,YearBit3,YearBit4;
unsigned char MonthBit1,MonthBit2;
unsigned char DayBit1,DayBit2;
unsigned char HourBit1,HourBit2;
unsigned char MinBit1,MinBit2;
unsigned char SecBit1,SecBit2;
unsigned char Week[][4] =
{"Mon","Tue","Wed","Thu","Fri","Sat","Sun"};
unsigned char ChangeSymbol[][5] = {"-Yar","-Mth","-Day","-Hor","-Min"};
unsigned char LeapYearWeekTable[] = {3,6,0,3,5,1,3,6,2,4,0,2};//闰年星期偏差表
unsigned char UnLeapWeekTable[] = {4,0,0,3,5,1,3,6,2,4,0,2};
unsigned char TodayWeek = 0;
unsigned char LeapYearBit = 0;//为0时,平年
unsigned char LunarData[] = {0,0,0,0};
unsigned char LunarYear1,LunarYear2,LunarYear3,LunarYear4,LunarMonth1,LunARMonth2,LunarDay1,LunarDay2;
unsigned char LunarConvertBit;//0,农历转换成功
unsigned char CalendarStopBit;//1,时钟暂停
unsigned char OldKeyNum = 0;
unsigned char NewKeyNum = 0;
unsigned char ModeSelect = 0;
unsigned char ChangeModeBit = 0;//ModeSelect != 0时,为1,标志现在处于更改时间状态
unsigned char SecOddBit = 0;//秒为偶数时,此为0,否则为1
static unsigned char const LunarDayCode1[9]=
{0x0,0x1f,0x3b,0x5a,0x78,0x97,0xb5,0xd4,0xf3};
static unsigned short const LunarDayCode2[3]={0x111,0x130,0x14e};
/**************************
***********子函数**********
*************************/
void PortInit(void) //端口初始化
{
DDRC &= ~((1<<PC3)|(1<<PC4)|(1<<PC5));
PORTC |= (1<<PC3)|(1<<PC4)|(1<<PC5);
}
void Timer2Init(void) //timer2初始化
{
TCCR2 = 0x00; //stop
ASSR = 0x08; //set async mode
TCNT2 = ClkTcnt2; //setup
TCCR2 = 0x06; //start
}
void Timer2Ovf(void)//timer2中断函数
{
TCNT2 = ClkTcnt2;//reload counter value
Sec += 1;
AskLeapYear();
SolarCount();
AskLeapYear();
CountWeek();
LunarCount();//先判断shi否转换成功,然后再计算各位显示数值
if(ModeSelect == 0)
{
LCDispClear();
DispUpdate();
}
}
void AskLeapYear(void)
{
if ( ( (Year%4 == 0) && (Year % 100!=0) ) || Year%400 == 0)//判断shi否为闰年
{
LeapYearBit = 1;
}
else
{
LeapYearBit = 0;
}
}
void SolarCount(void)//计算各位显示值
{
if (Sec>59)
{
Sec = 0;
Min ++;
}
if (Min>59)
{
Min = 0;
Hour ++;
}
if (Hour>23)
{
Hour = 0;
Day ++;
}
if ( ( (Month==1) || (Month==3) || (Month==5) || (Month==7) ||(Month==8) || (Month==10) || (Month==12) ) && (Day>31) )
{
Month ++;
Day = 1;
}
else if ( ( (Month==4) || (Month==6) || (Month==9) || (Month==11) ) && (Day>30) )
{
Month ++;
Day = 1;
}
else if (Month==2)
{
if (LeapYearBit == 1)//如果shi闰年
{
if (Day>29)
{
Month ++;
Day = 1;
}
}
else if (Day > 28)//平年
{
Month ++;
Day = 1;
}
}
if (Month > 12)
{
Month = 1;
Year ++;
}
//计算各位de值
YearBit1 = Year /1000;
YearBit2 = Year %1000/100;
YearBit3 = Year %100/10;
YearBit4 = Year %10;
MonthBit1 = Month /10;
MonthBit2 = Month %10;
DayBit1 = Day /10;
DayBit2 = Day %10;
HourBit1 = Hour /10;
HourBit2 = Hour %10;
MinBit1 = Min /10;
MinBit2 = Min %10;
SecBit1 = Sec /10;
SecBit2 = Sec %10;
}
void DeviceInit(void)//MCU初始化
{
CLI();
PortInit();
Timer2Init();
MCUCR = 0x00;
GICR = 0x00;
TIMSK = 0x40;
LCD_Init();
SEI();
}
//更新显示
void DispUpdate(void)
{
if((SecBit2 >= 5) || (ModeSelect != 0))//秒末位大于5时,显示公历
{
PutStringLCD(0,0,"Solar");
PutNumberLCD(0,6,YearBit1);
PutNumberLCD(0,7,YearBit2);
PutNumberLCD(0,8,YearBit3);
PutNumberLCD(0,9,YearBit4);
PutNumberLCD(0,11,MonthBit1);
PutNumberLCD(0,12,MonthBit2);
PutNumberLCD(0,14,DayBit1);
PutNumberLCD(0,15,DayBit2);
}
else if(LunarConvertBit == 1)//秒末位小于5并且农历转换成功时,显示农历
{
PutStringLCD(0,0,"Lunar");
PutNumberLCD(0,6,LunarYear1);
PutNumberLCD(0,7,LunarYear2);
PutNumberLCD(0,8,LunarYear3);
PutNumberLCD(0,9,LunarYear4);
PutNumberLCD(0,11,LunARMonth1);
PutNumberLCD(0,12,LunARMonth2);
PutNumberLCD(0,14,LunarDay1);
PutNumberLCD(0,15,LunarDay2);
}
else
{
PutStringLCD(0,0,"Out of range!");
}
PutNumberLCD(1,0,HourBit1);
PutNumberLCD(1,1,HourBit2);
if(SecOddBit)
{
PutOneCharLCD(1,2,":");
}
PutNumberLCD(1,3,MinBit1);
PutNumberLCD(1,4,MinBit2);
if(SecOddBit)
{
PutOneCharLCD(1,5,":");
}
PutNumberLCD(1,6,SecBit1);
PutNumberLCD(1,7,SecBit2);
PutStringLCD(1,9,Week[TodayWeek]);
if(ChangeModeBit && SecOddBit)
{
PutStringLCD(1,12,ChangeSymbol[ModeSelect - 1]);
}
}
void CountWeek(void)
{
if(LeapYearBit == 1)
{
TodayWeek = ((Year/100%4*5) + (Year%100/4*5) + (Year%4) + 1 + Day + LeapYearWeekTable[Month - 1])%7;
}
else
{
TodayWeek = ((Year/100%4*5) + (Year%100/4*5) + (Year%4) + 1 + Day + UnLeapWeekTable[Month - 1])%7;
}
}
void KeyScan(void)
{if((PINC&(1<<PC5)) == 0)
{
OldKeyNum = 1;
}
else if((PINC&(1<<PC4)) == 0)
{
OldKeyNum = 2;
}
else if((PINC&(1<<PC3)) == 0)
{
OldKeyNum = 3;
}
if((PINC & (1<<PC5)) && (PINC & (1<<PC4)) && (PINC & (1<<PC3)))//判断shi否有按键按下
{
NewKeyNum = OldKeyNum;
OldKeyNum = 0;
}
}
void TimeChange(void)
{
switch(ModeSelect)
{
case 0:
{
if(NewKeyNum == 2)
{
ModeSelect += 1;
}
}break;
case 1://更改年变量
{
switch (NewKeyNum)
{
case 1: Year --; break;
case 2: ModeSelect ++; break;
case 3: Year ++; break;
default:break;
}
}break;
case 2://更改月变量
{
switch (NewKeyNum)
{
case 1: Month --; break;
case 2: ModeSelect ++; break;
case 3: Month ++; break;
default:break;
}
}break;
case 3://更改日变量
{
switch (NewKeyNum)
{
case 1: Day --; break;
case 2: ModeSelect ++; break;
case 3: Day ++; break;
default:break;
}
}break;
case 4://更改小时变量
{
switch (NewKeyNum)
{
case 1: Hour --; break;
case 2: ModeSelect ++; break;
case 3: Hour ++; break;
default:break;
}
}break;
case 5:
{
switch (NewKeyNum)
{
case 1: Min --; break;
case 2: ModeSelect = 0; break;
case 3: Min ++; break;
default:break;
}
}break;
default : break;
}
}
/***********************
**********主函数********
***********************/
void main()
{
DeviceInit();
SEI();
for (;;)
{
if(ModeSelect != 0)//判断现在shi否处于更改时间日期状态
{
ChangeModeBit = 1;
}
else
{
ChangeModeBit = 0;
}
if(SecBit2 % 2 == 0)//如果秒末位shi偶数,SecSymbol=0
{
SecOddBit = 0;
}
else
{
SecOddBit = 1;
}
KeyScan();
TimeChange();
if(ChangeModeBit == 1)
{
CLI();
DispUpdate();
SEI();
}
}
}
此万年历程序不足,未尽完善之处:
1) 未设置闹钟,只能显示阴历阳历和星期等信息.
2) 后续应加入温度显示,以测定日气温
3) 没有与计算机或其他设备通讯接口
4) 液晶显示处于常亮状态,影响寿命.应当设置如果一定时间未操作,显示屏应关闭.待有按键操作时再打开.这样才能使LCD寿命更为长久.
5) 程序和硬件中未加入对于LCD背光de控制模块,无光亮时无法看时间.
等等等等......