搜索
bottom↓
回复: 55

STM32实现万年历

  [复制链接]

出0入0汤圆

发表于 2012-6-23 13:00:44 | 显示全部楼层 |阅读模式
本帖最后由 akwkevin2011 于 2012-6-23 13:07 编辑

                        STM32学习笔记一   竹天笑
实现的功能:
1、日历功能。
2、数字和模拟时钟功能。


图1(为LCD截屏保存在SD卡中的图像)
最终界面如下,但还存在不少漏洞。1、没有更改时间的设置;2、只有节气显示没有节假日显示3、背景不是用uCGUI画的,是在PS中画好然后存在SD卡中,然后显示的BMP格式图像。
要点分析:
1、STM32自带了RTC时钟计数器,从0开始计数到232。每一个计数代表秒计数,每六十个计数代表分计数,以此类推。24(小时)*60(分钟)*60(秒钟)=86400代表一天的计数时间。假设当前计数为count,count/86400得到计数的天数,根据这个得到年月日。Count%86400得到时分秒。
2、一些根据1中得到的年月日时分秒,进行计算的程序有:阳历转阴历,闰年判断,节气判断,星期几计算,当前月有多少天等等。
3、模拟时钟的绘制:时钟指针运动算法、屏幕重绘方法、RTC消息、画笔/画刷等。指针运动算法和屏幕重绘方法是本程序主要难点所在。(以下参照百度文库之模拟时钟)
不论何种指针,每次转动均以π/30弧度(一秒的角度)为基本单位,且都以表盘中心为转动圆心。计算指针端点(x, y)的公式如下:
x =圆心x坐标 + 指针长度 * cos (指针方向角)
y =圆心y坐标 + 指针长度 * sin (指针方向角)
注意,指针长度是指自圆心至指针一个端点的长度(是整个指针的一部分),由于指针可能跨越圆心,因此一个指针需要计算两个端点。
由于屏幕的重绘1秒钟一次,如果采用全屏删除式重绘则闪烁十分明显,显示效果不佳。本程序采用非删除式重绘,假定指针将要移动一格,则先采用背景色(这里是白色)重绘原来指针以删除原来位置的指针,再采用指针的颜色在当前位置绘制指针(如果指针没有动,则直接绘制指针,此句在程序中被我删除,具体原因,为数据截断导致一些误差)。
另外,秒表为RTC一秒钟定时计数。
程序分析:
uCGUI+uCOS,一共三个任务:主处理任务、触摸屏任务、秒更新任务。
void  App_UCGUI_TaskCreate (void)
{
    CPU_INT08U  os_err;
        os_err = os_err;
        Clock_SEM=OSSemCreate(1);                         //建立秒更新中断的信号量
         //硬件平台初始化
           BSP_Init();                                             
        //主处理任务---------------------------------------------------------   
        os_err =    OSTaskCreateExt(AppTaskUserIF,
                                                                (void *)0,
                                                                (OS_STK *)&AppTaskUserIFStk[APP_TASK_USER_IF_STK_SIZE-1],
                                                                APP_TASK_USER_IF_PRIO,
                                                                APP_TASK_USER_IF_PRIO,
                                                                (OS_STK *)&AppTaskUserIFStk[0],
                                                                APP_TASK_USER_IF_STK_SIZE,
                                                                (void *)0,
                                                                OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR);       

   
     //触摸屏任务---------------------------------------------------------                 
           os_err = OSTaskCreateExt(AppTaskKbd,
                                                         (void *)0,
                                                         (OS_STK *)&AppTaskKbdStk[APP_TASK_KBD_STK_SIZE-1],
                                                         APP_TASK_KBD_PRIO,
                                                         APP_TASK_KBD_PRIO,
                                                         (OS_STK *)&AppTaskKbdStk[0],
                                                         APP_TASK_KBD_STK_SIZE,
                                                         (void *)0,
                                                         OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR);
       
         //秒更新任务
   os_err = OSTaskCreateExt(Clock_Updata,
                                                        (void *)0,
                                                        (OS_STK *)&Clock_Updata_Stk[Clock_Updata_STK_SIZE-1],
                                                        Clock_Updata_PRIO,
                                                        Clock_Updata_PRIO,
                                                        (OS_STK *)&Clock_Updata_Stk[0],
                                                        Clock_Updata_STK_SIZE,
                                                        (void *)0,
                                                        OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR);               
}       
万年历中的时间用的是STM32自带的RTC实时时钟。
1、主处理任务:界面背景初始化,并根据当前时间,画出图1的数据。
static  void  AppTaskUserIF (void *p_arg)
{
        (void)p_arg;
        INT8U err;
        //界面初始化
          GUI_Init();                                                        //ucgui 初始化
        _ExecCalibration();                                  /* 触摸屏校准   */
        GUI_SetBkColor(GUI_WHITE);                //设置背景色
        GUI_SetColor(GUI_GRAY);             //设置前景色
            GUI_Clear();                                                //清屏
           Lcd_show_bmp(0, 0,"/RTC.bmp");                //显示万年历背景
        GUI_SetFont(&GUI_FontHZ_SimSun_16);
        GUI_DispStringAt("一",15,47);       //显示星期一
        GUI_DispStringAt("二",44,47);                //显示星期二
        GUI_DispStringAt("三",73,47);                //显示星期三
        GUI_DispStringAt("四",102,47);                //显示星期四
        GUI_DispStringAt("五",131,47);                //显示星期五
        GUI_SetColor(GUI_RED);                                //用红字显示周末
        GUI_DispStringAt("六",160,47);                //显示星期六
        GUI_DispStringAt("日",189,47);                //显示星期日
       

to_tm(RTC_GetCounter(), &s_time);  //根据RTC时钟得到万年历时间的初值,注意,这个值是根据用户查询万年历变化
        GUI_SetFont(&GUI_Font16_1 );                //设置英文字体
        GUI_DispDecAt(s_time.tm_year,4,13,4);//显示万年历的年份
        GUI_SetFont(&GUI_FontHZ_SimSun_16);  //设置中文字体
        GUI_DispString("年");                                //显示年
        GUI_SetFont(&GUI_Font16_1 );                //设置英文字体
        GUI_DispDec(s_time.tm_mon,2);                //显示万年历的月份
        GUI_SetFont(&GUI_FontHZ_SimSun_16);        //设置中文字体
        GUI_DispString("月");                                //显示月
        GUI_SetFont(&GUI_Font16_1 );                //设置英文字体
        GUI_DispDec(s_time.tm_mday,2);                //显示万年历的日子
        GUI_SetFont(&GUI_FontHZ_SimSun_16);//设置中文字体
        GUI_DispString("日");                                //显示日
        //画模拟时钟界面
        u16 index,x,y;
        GUI_SetPenSize(1);
        GUI_SetColor(GUI_RED);
        GUI_DrawCircle(264,170, 45);                //画时钟最外层的圆,
    for( index = 0; index < 60; index++ )//画时钟的刻度
    {
          x = -(40* cos(( index * 6 ) * DEG2RAD)) + 264;
          y = -(40* sin(( index * 6 ) * DEG2RAD)) + 170;
          if( index % 5 == 0 )
          {                                                                                                                                         
             GUI_SetPenSize(4);                                //指示为小时的刻度用粗点画
          }
          else
          {
             GUI_SetPenSize(2);                                //其它刻度用西点画
          }
          GUI_DrawPoint( x, y );
    }
         while(1)
        {
           RTC_Show(RTC_GetCounter());                //主任务执行程序,接下来分析
           OSTimeDlyHMSM(0,0,0,10);                 
        }                        
}
//主任务执行程序
void RTC_Show(uint32_t TimeVar)
{
           u8 str[15]; // 字符串暂存
           u8 i,k;
           static flag=0;
          
             
  #if (GUI_SUPPORT_CURSOR|GUI_SUPPORT_TOUCH)
    GUI_CURSOR_Show();                                                //鼠标显示
  #endif
           WM_SetCreateFlags(WM_CF_MEMDEV);  /* Automatically use memory devices on all windows */   
  if(flag==0)                //初始化按键,只执行一次。
  {
//建立按键F1-F5   
_ahButton[0] =BUTTON_Create(5, 0, 32,13, GUI_KEY_F1 , WM_CF_SHOW | WM_CF_STAYONTOP | WM_CF_MEMDEV);
_ahButton[1]=BUTTON_Create(5, 29, 32,13, GUI_KEY_F2 , WM_CF_SHOW | WM_CF_STAYONTOP | WM_CF_MEMDEV);
_ahButton[2]=BUTTON_Create(53, 0, 16,13, GUI_KEY_F3 , WM_CF_SHOW | WM_CF_STAYONTOP | WM_CF_MEMDEV);
_ahButton[3]=BUTTON_Create(53,29,16,13, GUI_KEY_F4 , WM_CF_SHOW | WM_CF_STAYONTOP | WM_CF_MEMDEV);
_ahButton[4]=BUTTON_Create(85, 0, 16,13, GUI_KEY_F5, WM_CF_SHOW | WM_CF_STAYONTOP | WM_CF_MEMDEV);
_ahButton[5]=BUTTON_Create(85,29, 16,13, GUI_KEY_F6, WM_CF_SHOW | WM_CF_STAYONTOP | WM_CF_MEMDEV);
   //按键字体设置
   BUTTON_SetFont(_ahButton[0],&GUI_Font6x8);//GUI_Font16_ASCII
   BUTTON_SetFont(_ahButton[1],&GUI_Font6x8);//GUI_Font16_ASCII
   BUTTON_SetFont(_ahButton[2],&GUI_Font6x8);//GUI_Font16_ASCII
   BUTTON_SetFont(_ahButton[3],&GUI_Font6x8);//GUI_Font16_ASCII
   BUTTON_SetFont(_ahButton[4],&GUI_Font6x8);//GUI_Font16_ASCII
BUTTON_SetFont(_ahButton[5],&GUI_Font6x8);//GUI_Font16_ASCII
   //按键背景色设置
        BUTTON_SetBkColor(_ahButton[0],0,GUI_DARKMAGENTA);                                  //按键背景颜色
        BUTTON_SetBkColor(_ahButton[1],0,GUI_DARKMAGENTA);  
        BUTTON_SetBkColor(_ahButton[2],0,GUI_DARKMAGENTA);  
        BUTTON_SetBkColor(_ahButton[3],0,GUI_DARKMAGENTA);  
        BUTTON_SetBkColor(_ahButton[4],0,GUI_DARKMAGENTA);  
        BUTTON_SetBkColor(_ahButton[5],0,GUI_DARKMAGENTA);
   //按键前景色设置
        BUTTON_SetTextColor(_ahButton[0],0,GUI_WHITE);
        BUTTON_SetTextColor(_ahButton[1],0,GUI_WHITE);
        BUTTON_SetTextColor(_ahButton[2],0,GUI_WHITE);
        BUTTON_SetTextColor(_ahButton[3],0,GUI_WHITE);
        BUTTON_SetTextColor(_ahButton[4],0,GUI_WHITE);
        BUTTON_SetTextColor(_ahButton[5],0,GUI_WHITE);
                //按键显示字符
        BUTTON_SetText(_ahButton[0], "+");   
        BUTTON_SetText(_ahButton[1], "-");
        BUTTON_SetText(_ahButton[2], "+");
        BUTTON_SetText(_ahButton[3], "-");
        BUTTON_SetText(_ahButton[4], "+");
        BUTTON_SetText(_ahButton[5], "-");
        flag=1;
  }
                u8 key = GUI_GetKey();                                               //实时获得触摸按键的值
                if(key==40)                                                  //年数增加按钮
                {
                        s_time.tm_year++;                                                                //F1
                        if(s_time.tm_year>2099)                                                        //超过范围处理
                                s_time.tm_year=1970;
                }
                else if(key==41)                                                                        //年数减小按钮
                {
                        s_time.tm_year--;                                                                   //F2
                        if(s_time.tm_year<1900)                                                        //超过范围处理
                                s_time.tm_year=2099;
                }
                else if(key==42)                                                                         //月数增加按钮
                {
                        s_time.tm_mon++;                                                                   //F3
                        if(s_time.tm_mon>12)                                                        //超过范围处理
                        {
                                s_time.tm_mon=1;
                        }
                }
                else if(key==43)                                                                          //月数减小按钮
                {
                        s_time.tm_mon--;                                                                   //F4
                        if(s_time.tm_mon<0)                                                        //超过范围处理
                        {
                                s_time.tm_mon=12;
                               
                        }
                }
                else if(key==44)                                                                         //日数增加按钮
                {
                        s_time.tm_mday++;                                                                   //F5
                        if(s_time.tm_mday>getDays(s_time.tm_year,s_time.tm_mon))                //超过范围处理
                        {
                                s_time.tm_mday=1;
                        }
                }
                else if(key==45)                                                                         //日数减小按钮
                {
                        s_time.tm_mday--;                                                                   //F6
                        if(s_time.tm_mday<0)                                                        //超过范围处理
                        {
                                s_time.tm_mday=getDays(s_time.tm_year,s_time.tm_mon);
                        }
                }
        GUI_SetFont(&GUI_Font16_1 );
        GUI_DispDecAt(s_time.tm_year,4,13,4);                //显示万年历的年数
        GUI_SetFont(&GUI_FontHZ_SimSun_16);
        GUI_DispString("年");                                //显示年       
        GUI_SetFont(&GUI_Font16_1 );
        GUI_DispDec(s_time.tm_mon,2);                        //显示万年历的月数
        GUI_SetFont(&GUI_FontHZ_SimSun_16);
        GUI_DispString("月");                                //显示月
        GUI_SetFont(&GUI_Font16_1 );
        GUI_DispDec(s_time.tm_mday,2);                //显示万年历的日数
        GUI_SetFont(&GUI_FontHZ_SimSun_16);
        GUI_DispString("日");                                //显示日
        GUI_DispString("   ");       
        GetChinaCalendarStr((u16)systmtime.tm_year,(u8)systmtime.tm_mon,(u8)systmtime.tm_mday,str);        //阳历转阴历
//见下面子程序1
        GUI_DispString(str);                                 //显示阴历
        GUI_SetColor(GUI_RED);                                 //字体颜色
        GUI_DispString("竹天笑万年历");
           k=getWeekDay(s_time.tm_year,s_time.tm_mon,1);                //得到某年某月的第一天的星期数        //见下面子程序2
           GUI_GotoXY(18,69);                                .//位置设定
           GUI_SetFont(&GUI_Font6x8);   

//万年历日子显示
           for(i=1;i<=40;i++)                        //第一行最少显示一个,第六行最多显示二个,i的上限只需要大于37即可
           {
                   if(i<k+1||i>getDays(s_time.tm_year,s_time.tm_mon)+k)                //本月1号前和最后一天后的格子显示清零
                   {                                                                                //见子程序3
                           GUI_DispString("  ");                                                //显示空格,用于清除之前数据
                   }
                   else
                   {
                                   if((i+1)%7==0||i%7==0)                                        //如果为星期六和星期天,字体设置为红色
                                   {
                                           GUI_SetColor(GUI_RED);
                                   }
                                   else                                                                //否则为黑色
                                   {
                                                GUI_SetColor(GUI_BLACK);
                                   }
                                if(i==s_time.tm_mday+k)                                        //如果该天为所选日期,设置背景为黄色
                                {
                                        GUI_SetBkColor(GUI_YELLOW);                 
                                }
                                   GUI_DispDecSpace(i-k,2);                                        //显示日子
                                GUI_SetBkColor(GUI_WHITE);                                //恢复之前背景色
                   }
                   GUI_GotoXY(GUI_GetDispPosX()+17,GUI_GetDispPosY());        //光标移动到下一个格子         
                   if(i%7==0)
                   {
                           GUI_GotoXY(18,GUI_GetDispPosY()+27);                        //7天换行显示
                   }
           }
           GUI_GotoXY(12,79);                                                                 //光标移动到下一行首行       
           GUI_SetFont(&GUI_FontHZ_SimSun_11);
//显示为初几,若为节气则显示节气
           for(i=1;i<=40;i++)
           {
                    if(i<k+1||i>getDays(s_time.tm_year,s_time.tm_mon)+k)                //本月1号前和最后一天后的格子显示清零
                   {
                           GUI_DispString("  ");                                        //显示两个中文空格,占两个中文字符
                   }
                   else
                   {
                                   if(GetJieQiDay((u16)s_time.tm_year, (u8)s_time.tm_mon, i-k, str)==1)        //如果为节气
                                {                                                                                        //见子程序4
                                        GUI_SetColor(GUI_MAGENTA);                                                //设置字体为橙色
                                }
                                else
                                {
                                        GUI_SetColor(GUI_BLUE);                                                //正常显示蓝色
                                }
                                if(i==s_time.tm_mday+k)                                        //如果该天为所选日期,设置背景为黄色
                                {
                                        GUI_SetBkColor(GUI_YELLOW);
                                }
                                   GUI_DispString(str);                                        //显示阴历号
                                GUI_SetBkColor(GUI_WHITE);                                //恢复背景色
                   }
                        GUI_GotoXY(GUI_GetDispPosX()+7,GUI_GetDispPosY());                 
                   if(i%7==0)
                   {
                           GUI_GotoXY(12,GUI_GetDispPosY()+27);
                   }
           }
           WM_ExecIdle();                                                                          //刷新屏幕
                                                                                                        #defineDEG2RAD (3.1415926f / 180)
           GUI_POINT m_Hour[2],m_Sec[2],m_Min[2];                                        //时分秒两个端点
        static GUI_POINT m_OldHour[2],m_OldMin[2],m_OldSec[2];                        //时分秒之前的两个端点
         m_Hour[0].x=-20*cos((systmtime.tm_hour*30+90)*DEG2RAD)+264;                //时钟指针端点计算,每一时旋转30
         m_Hour[0].y=-20*sin((systmtime.tm_hour*30+90)*DEG2RAD)+170;                //度,逆时针旋转,当前时钟*30得旋
         m_Hour[1].x=-2*cos((systmtime.tm_hour*30+270)*DEG2RAD)+264;                //转的度数, 时钟另一端加上180度
         m_Hour[1].y=-2*sin((systmtime.tm_hour*30+270)*DEG2RAD)+170;                 //将极坐标形式转换成直角坐标
                GUI_SetColor(GUI_WHITE);                                                        //重绘上一次时钟指针覆盖的背景
                 GUI_DrawLine(m_OldHour[0].x,m_OldHour[0].y, m_OldHour[1].x,m_OldHour[1].y);
                GUI_SetColor(GUI_RED);                                                                //画新的时钟指针
                 GUI_DrawLine(m_Hour[0].x,m_Hour[0].y, m_Hour[1].x,m_Hour[1].y);

         m_Min[0].x=-30*cos((systmtime.tm_min*6+90)*DEG2RAD)+264;                        //分钟指针端点计算,每一分旋转6
         m_Min[0].y=-30*sin((systmtime.tm_min*6+90)*DEG2RAD)+170;                        //度,逆时针旋转,当前分钟*6得旋
         m_Min[1].x=-4*cos((systmtime.tm_min*6+270)*DEG2RAD)+264;                        //转的度数, 时钟另一端加上180度
         m_Min[1].y=-4*sin((systmtime.tm_min*6+270)*DEG2RAD)+170;                         //将极坐标形式转换成直角坐标
                 GUI_SetColor(GUI_WHITE);                                                        //重绘上一次分钟指针覆盖的背景
                  GUI_DrawLine(m_OldMin[0].x,m_OldMin[0].y, m_OldMin[1].x,m_OldMin[1].y);
                 GUI_SetColor(GUI_BLUE);                                                        //画新的分钟指针
                 GUI_DrawLine(m_Min[0].x,m_Min[0].y, m_Min[1].x,m_Min[1].y);

         m_Sec[0].x=-35*cos((systmtime.tm_sec*6+90)*DEG2RAD)+264;                        //分钟指针端点计算,每一秒旋转6
         m_Sec[0].y=-35*sin((systmtime.tm_sec*6+90)*DEG2RAD)+170;                        //度,逆时针旋转,当前秒钟*6得旋
         m_Sec[1].x=-8*cos((systmtime.tm_sec*6+270)*DEG2RAD)+264;                        //转的度数, 时钟另一端加上180度
         m_Sec[1].y=-8*sin((systmtime.tm_sec*6+270)*DEG2RAD)+170;                        //将极坐标形式转换成直角坐标
                 GUI_SetColor(GUI_WHITE);
                 GUI_DrawLine(m_OldSec[0].x,m_OldSec[0].y, m_OldSec[1].x,m_OldSec[1].y);
                 GUI_SetColor(GUI_BLACK);
                 GUI_DrawLine(m_Sec[0].x,m_Sec[0].y, m_Sec[1].x,m_Sec[1].y);
         for(i=0;i<2;i++)
        {          
                   m_OldHour=m_Hour;                                                           //保存当前时分秒指针
                   m_OldMin=m_Min;          
                   m_OldSec=m_Sec;
        }
                  /* 输出公历时间 */
         
                GUI_SetFont(&GUI_Font16_1 );
                GUI_DispDecAt(systmtime.tm_year, 240, 60,4);                                        //显示当前年                  
                GUI_DispString("-");
                GUI_DispDec(systmtime.tm_mon,2);                                                //显示当前月
                GUI_DispString("-");
                GUI_DispDec(systmtime.tm_mday,2);                                                //显示当前日       
                  GUI_DispDecAt(systmtime.tm_hour,240,76,2);                                        //显示当前时       
                GUI_DispString(":");
                GUI_DispDec(systmtime.tm_min,2);                                                //显示当前分       
                GUI_DispString(":");
                GUI_DispDec(systmtime.tm_sec,2);                                                //显示当前秒       
                GUI_SetFont(&GUI_FontHZ_SimSun_16);
                GUI_DispStringAt("星期",240,92);                                                //显示当前星期       
                  GUI_DispString(WEEK_STR[systmtime.tm_wday]);
}
子程序1
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// 函数名称:GetChinaCalendarStr
// 功能描述:输入公历日期得到农历字符串       
//          如:GetChinaCalendarStr(2007,02,06,str) 返回str="丙戌年腊月十九"
// 输 入:  year        公历年
//          month       公历月
//          day         公历日
//          str         储存农历日期字符串地址   15Byte
// 输 出:  无                                                                                                                                  
/////////////////////////////////////////////////////////////////////////////////////////////////////////
void GetChinaCalendarStr(u16 year,u8 month,u8 day,u8 *str)
{
        u8 NLyear[4];
        u8 SEyear;
        StrCopy(&str[0],(u8 *)"甲子年正月初一",15);
        if(GetChinaCalendar(year,month,day,(u8 *)NLyear)==0)        return;        //GetChinaCalendar见子程序5,转化为阴历
        GetSkyEarth(NLyear[0]*100+NLyear[1],&SEyear);
        StrCopy(&str[0],(u8 *)  sky[SEyear%10],2);        //  甲
        StrCopy(&str[2],(u8 *)earth[SEyear%12],2);        //  子       
        if(NLyear[2]==1)        StrCopy(&str[6],(u8 *)"正",2);
        else                                StrCopy(&str[6],(u8 *)monthcode[NLyear[2]-1],2);               
        if(NLyear[3]>10)         StrCopy(&str[10],(u8 *)nongliday[NLyear[3]/10],2);       
        else                                StrCopy(&str[10],(u8 *)"初",2);
        StrCopy(&str[12],(u8 *)monthcode[(NLyear[3]-1)%10],2);
}
子程序2
u8 getWeekDay(u16 y, u8 m, u8 d)                  //得到指定年月日的星期数  
{        
        if (m == 1) m = 13;        
        if (m == 2) m = 14;        
        u8 week = (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400) % 7 + 1;        
        return week;   
}
子程序3
/*
*判断是否闰年
*参数:   y 整型, 接收年份值
*返回值: 整型, 只为0或1, 0代表假, 1代表真
*/
u8 isRunNian(u16 y)
{
return (y % 4 == 0 && y % 100 != 0 || y % 400 == 0) ? 1 : 0;
}
/*
*计算某个月的天数
*参数:   y 整型,接收年份值; m 整型,接收月份值;
*返回值: 整型, 是0, 28, 29, 30, 31之间的一个数
*注意:   返回值为0,表示你调用该函数时传递了不正确的年份值或月份值.
*/
u8 getDays(u16 y, u8 m)
{
u8 days = 0;
switch(m)
{
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
  days = 31; break;
case 4:
case 6:
case 9:
case 11:
  days = 30; break;
case 2:
  days = isRunNian(y) ? 29 : 28; break;
default:;
}
return days;
}
子程序4
//////////////////////////////////////////////////////////////////////////////////////////////////////////
// 函数名称:GetJieQiDay
// 功能描述:输入公历日期得到24节气字符串       
//          是否为节气
// 输 入:  year        公历年
//          month       公历月
//          day         公历日
//          str         储存24节气字符串地址   5Byte
// 输 出:  1           成功
//          0           失败                                                                                                                                                          
/////////////////////////////////////////////////////////////////////////////////////////////////////////
u8 GetJieQiDay(u16 year,u8 month,u8 day,u8 *str)
{
        u8 JQdate,JQ;
        u8 NLyear[4];
        StrCopy(&str[0],(u8 *)"初一",5);
        if(GetJieQi(year,month,day,&JQdate)==0)        return 0;
        JQ = (month-1) *2 ;                             //获得节气顺序标号(0~23
        if(day >= 15) JQ++;                             //判断是否是上半月
        if(day==JQdate)                                 //今天正是一个节气日
        {
                StrCopy(str,(u8 *)JieQiStr[JQ],5);
                return 1;
        }                                            //今天不是一个节气日
        else
        {       
                GetChinaCalendar(year,month,day,(u8 *)NLyear);
                if(NLyear[3]>10)         StrCopy(&str[0],(u8 *)nongliday[NLyear[3]/10],2);       
                else                                StrCopy(&str[0],(u8 *)"初",2);
                StrCopy(&str[2],(u8 *)monthcode[(NLyear[3]-1)%10],2);
                return 0;
        }
}
子程序5
/////////////////////////////////////////////////////////////////////////////////////////////////////////
// 函数名称:GetChinaCalendar
//功能描述:公农历转换(只允许1901-2099年)
// 输 入:  year        公历年
//          month       公历月
//          day         公历日
//          p           储存农历日期地址
// 输 出:  1           成功
//          0           失败                                                                                                                                                         
/////////////////////////////////////////////////////////////////////////////////////////////////////////
u8 GetChinaCalendar(u16  year,u8 month,u8 day,u8 *p)
{
        u8 temp1,temp2,temp3,month_p,yearH,yearL;       
        u8 flag_y;
        unsigned short temp4,table_addr;

        yearH=year/100;        yearL=year%100;//年份的高低两个字节
        if((yearH!=19)&&(yearH!=20))return(0);//日期不在19xx ~ 20xx 范围内,则退出
       
        // 定位数据表地址  
        if(yearH==20)        table_addr=(yearL+100-1)*3;
        else                          table_addr=(yearL-1)*3;

        // 取当年春节所在的公历月份  
        temp1=year_code[table_addr+2]&0x60;       
        temp1>>=5;

        // 取当年春节所在的公历日  
        temp2=year_code[table_addr+2]&31;

        // 计算当年春年离当年元旦的天数,春节只会在公历1月或2月  
        if(temp1==1)         temp3=temp2-1;
        else                         temp3=temp2+31-1;

        // 计算公历日离当年元旦的天数  
        if (month<10)         temp4=day_code1[month-1]+day-1;
        else                          temp4=day_code2[month-10]+day-1;
        // 如果公历月大于2月并且该年的2月为闰月,天数加1  
        if ((month>2)&&(yearL%4==0))         temp4++;

        // 判断公历日在春节前还是春节后  
        if (temp4>=temp3)
        {                                                
                temp4-=temp3;
                month=1;
                month_p=1;
                                                       
                flag_y=0;
                if(GetMoonDay(month_p,table_addr)==0)        temp1=29; //小月29天
                else                                                                         temp1=30; //大小30天
                // 从数据表中取该年的闰月月份,如为0则该年无闰月  
                temp2=year_code[table_addr]/16;        
                while(temp4>=temp1)
                {
                        temp4-=temp1;
                        month_p++;
                        if(month==temp2)
                        {
                                flag_y=~flag_y;
                                if(flag_y==0)month++;
                        }
                        else month++;
                        if(GetMoonDay(month_p,table_addr)==0)        temp1=29;
                        else                                                                         temp1=30;
                }
                day=temp4+1;
        }
        // 公历日在春节前使用下面代码进行运算  
        else
        {                                                
                temp3-=temp4;
                if (yearL==0)
                {
                        yearL=100-1;
                        yearH=19;
                }
                else yearL--;
                table_addr-=3;
                month=12;
                temp2=year_code[table_addr]/16;        
                if (temp2==0)        month_p=12;
                else                         month_p=13;

                flag_y=0;
                if(GetMoonDay(month_p,table_addr)==0)        temp1=29;
                else                                                                         temp1=30;
                while(temp3>temp1)
                {
                        temp3-=temp1;
                        month_p--;
                        if(flag_y==0)                month--;
                        if(month==temp2)        flag_y=~flag_y;
                        if(GetMoonDay(month_p,table_addr)==0)        temp1=29;
                        else                                                                         temp1=30;
                }
                day=temp1-temp3+1;
        }

        *p++=yearH;
        *p++=yearL;
        *p++=month;
        *p=day;       
        return(1);
}
2、触摸屏任务:处理触摸屏按键任务,更改要查询的年月日。
static  void  AppTaskKbd (void *p_arg)
{  
   (void)p_arg;
   TP_Init();        //触摸初始化
   while(1)
   {
      OSTimeDlyHMSM(0,0,0,10);
          GUI_TOUCH_Exec(); //触摸执行程序,详细请阅读ucgui教程
}
}
3、秒更新任务:秒更新任务中一直等待一个OS_EVENT(信号量),RTC闹钟一秒钟中断一次,闹钟中断程序中发送信号量,秒更新任务接到OS_EVENT(信号量)便执行一次,更新当前的时间。(如果没有不用uCOS中的信号量的话,直接设置一个全局变量也可,在中断函数中将其置1,秒更新任务中判断其为1执行,然后将其置零,等待下一次为1。
void  Clock_Updata(void *p_arg)
{   
        INT8U err;
        (void)p_arg;       
        while(1)
        {
           OSSemPend(Clock_SEM,0,&err);                   //等待 时钟更新信号量
           RTC_Get(RTC_GetCounter());               
        }
}
void RTC_Get(uint32_t TimeVar)
{             
//根据RTC时钟得到时钟的初值,注意,这个值是根据系统自动变化
        to_tm(TimeVar, &systmtime);                          //使用野火RTC例程中的date.c
}
//时间结构体
struct rtc_time {
        int tm_sec;
        int tm_min;
        int tm_hour;
        int tm_mday;
        int tm_mon;
        int tm_year;
        int tm_wday;
};
//RTC计数转化为年月日时分秒,储存在systmtime
void to_tm(u32 tim, struct rtc_time * tm)
{
        register u32    i;
        register long   hms, day;
        day = tim / SECDAY;                        //#define SECDAY                        86400L        得到天数
        hms = tim % SECDAY;                        //余下的为时分秒
        /* Hours, minutes, seconds are easy */
        tm->tm_hour = hms / 3600;           //时
        tm->tm_min = (hms % 3600) / 60;                //分
        tm->tm_sec = (hms % 3600) % 60;        //秒
/* Number of years in days */ /*算出当前年份,起始的计数年份为1970年,总天数减去从1970开始递增的每年天数,当天数小于365/366时,得到当前的年份*/
        for (i = STARTOFTIME; day >= days_in_year(i); i++)                //#define        STARTOFTIME                1970
{                                                               
                day -= days_in_year(i);                                        //#define        days_in_year(a)         (leapyear(a) ? 366 : 365)
        }                                                                     .//#define        leapyear(year)                ((year) % 4 == 0)
        tm->tm_year = i;
        /* Number of months in days left */ /*计算当前的月份*/
        if (leapyear(tm->tm_year))                                                //如果为闰年,二月为29天
{
                days_in_month(FEBRUARY) = 29;                         //#define FEBRUARY                2
        }                                                                       
for (i = 1; day >= days_in_month(i); i++)        //剩下的总天数减去从1月开始递增的每月天数,当天数小于当前月天数时,得到当前的月份。
{                                                //static int month_days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
                day -= days_in_month(i);                                        //#define        days_in_month(a)         (month_days[(a) - 1])
        }
        days_in_month(FEBRUARY) = 28;                                //还原二月的天数为28天
        tm->tm_mon = i;

        /* Days are what is left over (+1) from all that. *//*计算当前日期*/       
        tm->tm_mday = day + 1;                                                //剩下的天数加一为日。
        /*
         * Determine the day of week
         */
        GregorianDay(tm);
}
/*得到星期几*/
void GregorianDay(struct rtc_time * tm)
{
        int leapsToDate;
        int lastYear;
        int day;
        int MonthOffset[] = { 0,31,59,90,120,151,181,212,243,273,304,334 };
        lastYear=tm->tm_year-1;
        /*计算从公元元年到计数的前一年之中一共经历了多少个闰年*/
        leapsToDate = lastYear/4 - lastYear/100 + lastYear/400;      
     /*如若计数的这一年为闰年,且计数的月份在2月之后,则日数加1,否则不加1*/
        if((tm->tm_year%4==0) &&((tm->tm_year%100!=0) || (tm->tm_year%400==0)) && (tm->tm_mon>2)) {
                day=1;
        } else {
                day=0;
        }
        day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + tm->tm_mday; /*计算从公元元年元旦到计数日期一共有多少天*/
        tm->tm_wday=day%7;                                                //得到今天为星期几
}
程序包下载地址(IAR编译环境):http://115.com/file/beo3fygn#UU_Clock_TOUCH.rar
word文件下载地址http://115.com/file/c25m7acc#STM32实现万年历.doc

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2012-6-23 13:04:42 | 显示全部楼层
不错,。。

出0入0汤圆

发表于 2012-6-23 13:05:06 | 显示全部楼层
万一火了呢?

出0入0汤圆

发表于 2012-6-23 13:45:57 | 显示全部楼层
不错,mark

出0入0汤圆

发表于 2012-6-23 14:25:17 | 显示全部楼层
我这些天就在搞万年历呢,楼主的思路值得借鉴啊

出0入0汤圆

发表于 2012-6-23 15:16:20 | 显示全部楼层
先收藏吧!!

出0入0汤圆

发表于 2012-6-23 15:18:34 | 显示全部楼层
收藏了,界面做到好看~~~

出0入0汤圆

 楼主| 发表于 2012-6-23 15:26:17 | 显示全部楼层
renpeng009 发表于 2012-6-23 13:05
万一火了呢?

呵呵,只是学习过程中写下来的,火了就再接再厉。

出0入0汤圆

 楼主| 发表于 2012-6-23 15:27:38 | 显示全部楼层
wuguoyan 发表于 2012-6-23 15:18
收藏了,界面做到好看~~~

我先百度到百度的小工具万年历,但是做不到那么好的界面,然后就删减成这样了。

出0入0汤圆

 楼主| 发表于 2012-6-23 15:28:31 | 显示全部楼层
sure220 发表于 2012-6-23 14:25
我这些天就在搞万年历呢,楼主的思路值得借鉴啊

是参照野火的教程写的。

出0入0汤圆

发表于 2012-6-24 22:52:44 | 显示全部楼层
强烈支持楼主!~~

出0入0汤圆

发表于 2012-6-24 23:22:11 | 显示全部楼层
可以学习一下。

出0入0汤圆

发表于 2012-6-24 23:25:38 | 显示全部楼层
不错,mark

出0入0汤圆

发表于 2012-6-25 20:00:05 | 显示全部楼层
留名 三克油

出0入0汤圆

发表于 2012-12-3 11:24:22 | 显示全部楼层

出0入0汤圆

发表于 2012-12-3 11:56:41 | 显示全部楼层
嗯,很好,很有借鉴价值

出0入0汤圆

发表于 2013-2-4 01:17:17 | 显示全部楼层
漂亮

出0入0汤圆

发表于 2013-2-4 07:31:45 来自手机 | 显示全部楼层
留个脚印

出0入0汤圆

发表于 2013-2-5 00:03:32 | 显示全部楼层
mark

出0入0汤圆

发表于 2013-2-5 00:21:36 | 显示全部楼层
明种是 清明 + 芒种 吗?

出0入0汤圆

发表于 2013-2-23 15:07:20 | 显示全部楼层
mark stm32 万年历

出0入0汤圆

 楼主| 发表于 2013-2-25 09:58:12 | 显示全部楼层
hyz_avr 发表于 2013-2-5 00:21
明种是 清明 + 芒种 吗?

那个是盲种,不是明种,因为是12*12大小的字体,比较像明字而已.

出0入0汤圆

发表于 2013-2-25 15:02:06 | 显示全部楼层
akwkevin2011 发表于 2013-2-25 09:58
那个是盲种,不是明种,因为是12*12大小的字体,比较像明字而已.

怎么看都不像"盲"...

出0入0汤圆

 楼主| 发表于 2013-2-25 16:25:26 | 显示全部楼层
hyz_avr 发表于 2013-2-25 15:02
怎么看都不像"盲"...

我当初也是这么认为的,还特意查了下.可就是这样.

出0入0汤圆

发表于 2013-2-25 17:16:59 | 显示全部楼层
谢谢楼主分享

出0入0汤圆

发表于 2013-2-25 17:18:05 | 显示全部楼层
二十四节气里的是:芒种

出0入0汤圆

发表于 2013-2-25 19:48:03 | 显示全部楼层
akwkevin2011 发表于 2013-2-25 16:25
我当初也是这么认为的,还特意查了下.可就是这样.

再查下...

出0入0汤圆

发表于 2013-2-26 09:31:31 来自手机 | 显示全部楼层
不错,正好用ucos

出0入0汤圆

 楼主| 发表于 2013-2-27 17:11:23 | 显示全部楼层
hyz_avr 发表于 2013-2-25 19:48
再查下...

不要纠结单个字嘛

出0入0汤圆

发表于 2013-2-27 17:59:48 | 显示全部楼层
mark,顶一下

出0入0汤圆

发表于 2013-2-28 13:21:50 | 显示全部楼层
楼主强人呀

出0入0汤圆

发表于 2013-3-1 18:13:55 来自手机 | 显示全部楼层
谢谢分享!

出0入0汤圆

发表于 2013-8-24 17:13:30 | 显示全部楼层
前辈的RTC时钟是在uC上进行的吧?晚辈最近在学习RTC写时钟到stm32的lcd上,可是LCD始终没有显示时间出来(LCD可以显示其他数据,图片,就差时间不能实现)。。请问前辈初始化时间是在GUI进行的吗??
我那具体问题有劳前辈看这里:http://www.amobbs.com/forum.php? ... page%3D1#pid6916159
不胜感激!

出0入0汤圆

发表于 2013-8-24 17:30:35 | 显示全部楼层
标记。方便查找。

出0入0汤圆

发表于 2013-8-25 14:11:54 | 显示全部楼层
不错啊,用到再细看

出0入0汤圆

发表于 2013-8-26 16:34:55 | 显示全部楼层
界面千奇百怪个人喜欢,关键亮点是STM32的RTC秒计数器到日历的转换。

出0入0汤圆

发表于 2013-8-26 23:02:30 | 显示全部楼层
标记学习一下!

出0入0汤圆

 楼主| 发表于 2013-9-20 20:31:38 | 显示全部楼层
崆峒 发表于 2013-8-24 17:13
前辈的RTC时钟是在uC上进行的吧?晚辈最近在学习RTC写时钟到stm32的lcd上,可是LCD始终没有显示时间出来(L ...

呵呵,不好意思,好久没来,不过去看了你的贴,你已经解决了啊.

出0入0汤圆

发表于 2013-9-21 14:30:19 | 显示全部楼层
研究一下算法

出0入0汤圆

发表于 2013-9-21 14:52:49 | 显示全部楼层
感谢楼主奉献

出0入0汤圆

发表于 2013-9-22 07:40:44 来自手机 | 显示全部楼层
谢谢分享

出0入10汤圆

发表于 2013-9-22 10:06:37 | 显示全部楼层
LZ头像不错

出0入8汤圆

发表于 2013-9-22 11:03:00 | 显示全部楼层

谢谢楼主分享

出0入0汤圆

发表于 2014-7-22 17:19:21 | 显示全部楼层
mark一下,很好参考

出0入0汤圆

发表于 2014-7-23 14:59:24 | 显示全部楼层
mark                  

出0入0汤圆

发表于 2014-8-26 15:18:48 | 显示全部楼层
谢谢LZ分享。正要用到

出0入0汤圆

发表于 2014-8-26 15:29:45 | 显示全部楼层
给楼主点个赞~

出0入0汤圆

发表于 2014-8-26 19:36:37 | 显示全部楼层
源码编译后,几十个错误,上百个警告

出0入0汤圆

发表于 2014-8-26 20:01:40 | 显示全部楼层
楼主好用心呀

出0入0汤圆

发表于 2015-1-28 23:24:26 | 显示全部楼层
很好的东西,我喜欢

出0入0汤圆

发表于 2015-1-28 23:58:53 来自手机 | 显示全部楼层
帮顶一下

出0入0汤圆

发表于 2015-1-29 09:11:23 | 显示全部楼层
后面的字体让人看得很头痛

出0入0汤圆

发表于 2015-1-29 10:08:48 | 显示全部楼层
字体太小了点

出0入0汤圆

发表于 2015-1-30 08:54:46 | 显示全部楼层
不错,挺好看的!

出0入0汤圆

发表于 2015-1-30 10:53:52 | 显示全部楼层
楼主厉害,赞,强大啊

出0入0汤圆

发表于 2017-3-23 22:05:08 | 显示全部楼层
农历部分的呢???
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-26 02:59

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表