打印
[AVR单片机]

ATmega8万年历程序

[复制链接]
3226|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Karlshen|  楼主 | 2010-2-20 09:59 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
程序中包含一个头文件"LCD1620.h",此文件中包含有关LCD的一些显示函数.
下面是部分程序原代码---不知道怎么回事,今天网络速度比较慢,无法上传文件.如有需要可与我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();//先判断是否转换成功,然后再计算各位显示数值
if(ModeSelect == 0)
   {
   LCDispClear();
   DispUpdate();
   }
}

void AskLeapYear(void)
{
  if ( ( (Year%4 == 0) && (Year % 100!=0) ) || Year%400 == 0)//判断是否为闰年
    {
    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)//如果是闰年
    {
    if (Day>29)
     {
      Month ++;
      Day = 1;
     }
    }
   else if (Day > 28)//平年
    {
     Month ++;
     Day = 1;
    }
  }
  
if (Month > 12)
  {
   Month = 1;
   Year ++;
  }
  
//计算各位的值  
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)))//判断是否有按键按下
    {
    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;
    }
}

相关帖子

沙发
Karlshen|  楼主 | 2010-2-20 10:00 | 只看该作者
/***********************
**********主函数********
***********************/
void main()
{
DeviceInit();
SEI();
for (;;)
  {
  if(ModeSelect != 0)//判断现在是否处于更改时间日期状态
    {
    ChangeModeBit = 1;
    }
  else
    {
    ChangeModeBit = 0;
    }
   
  if(SecBit2 % 2 == 0)//如果秒末位是偶数,SecSymbol=0
    {
    SecOddBit = 0;
    }
  else
    {
    SecOddBit = 1;
    }
   
  KeyScan();
  TimeChange();
  if(ChangeModeBit == 1)
    {
    CLI();
    DispUpdate();
    SEI();
    }
  }
}


此万年历程序不足,未尽完善之处:
1) 未设置闹钟,只能显示阴历阳历和星期等信息.
2) 后续应加入温度显示,以测定日气温
3) 没有与计算机或其他设备通讯接口
4) 液晶显示处于常亮状态,影响寿命.应当设置如果一定时间未操作,显示屏应关闭.待有按键操作时再打开.这样才能使LCD寿命更为长久.
5) 程序和硬件中未加入对于LCD背光的控制模块,无光亮时无法看时间.
等等等等......

使用特权

评论回复
板凳
lovelyegle| | 2010-2-22 19:22 | 只看该作者
这么多未完善之处啊:lol

使用特权

评论回复
地板
guiliang| | 2011-3-15 16:08 | 只看该作者
值得借鉴

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

81

主题

734

帖子

1

粉丝