当前位置:文档之家› STM32实现万年历

STM32实现万年历

STM32实现万年历
STM32实现万年历

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(igetDays(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(igetDays(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[i]=m_Hour[i]; //保存当前时分秒指针

m_OldMin[i]=m_Min[i];

m_OldSec[i]=m_Sec[i];

}

/* 输出公历时间*/

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编译环境):https://www.doczj.com/doc/bf9886674.html,/file/beo3fygn#UU-Clock-TOUCH.rar

相关主题
文本预览
相关文档 最新文档