51/AVR单片机技术驿站!  <在线翻译>     便利工具    特色网址   无弹窗、无插件的绿色站点...  英才招聘   学历查询  喜欢>>收藏我站 

当前位置:首页 > 单片机技术文章 > AVR单片机 > 详细内容
ATmega8单片机万年历C程序(内部RTC)
发布时间:2009/8/6  阅读次数:3388  字体大小: 【】 【】【
正文
) 调整时间和日期,
只设置了四个按键
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控制模块,无光亮时无法看时间.
等等等等......
我要评论
  • 匿名发表
  • [添加到收藏夹]
  • 发表评论:(匿名发表无需登录,已登录用户可直接发表。) 登录状态:未登录
最新评论
所有评论[0]
    暂无已审核评论!

网站导航 管理登陆 ┊ 免责声明 问题反馈  友链说明
本站部分内容来自网络共享资源,如有冒犯您的权利请来信告之删除或纠正!
不得对本站进行复制、盗链或镜像,转载内容须获得同意或授权;欢迎友情链接、站务合作!

    我要报警 Alexa
 mcusy_cn#126.com (请把#改成@) 交流:522422171
本站学习交流群:138..158(高级群1-)、77930286(高级群2)、61804809(群3)
Copyright© MCUSY All Rights Reserved
本站网警备案号: WZ36040002485
  ICP备案证书号:粤ICP备09034963号