《最新STM32实现万年历.doc》由会员分享,可在线阅读,更多相关《最新STM32实现万年历.doc(20页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、精品资料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得到计数的天数,根据这个得到年月
2、日。Count%86400得到时分秒。2、一些根据1中得到的年月日时分秒,进行计算的程序有:阳历转阴历,闰年判断,节气判断,星期几计算,当前月有多少天等等。3、模拟时钟的绘制:时钟指针运动算法、屏幕重绘方法、RTC消息、画笔/画刷等。指针运动算法和屏幕重绘方法是本程序主要难点所在。(以下参照百度文库之模拟时钟)不论何种指针,每次转动均以/30弧度(一秒的角度)为基本单位,且都以表盘中心为转动圆心。计算指针端点(x, y)的公式如下:x =圆心x坐标 + 指针长度 * cos (指针方向角)y =圆心y坐标 + 指针长度 * sin (指针方向角)注意,指针长度是指自圆心至指针一个端点的长度(是
3、整个指针的一部分),由于指针可能跨越圆心,因此一个指针需要计算两个端点。由于屏幕的重绘1秒钟一次,如果采用全屏删除式重绘则闪烁十分明显,显示效果不佳。本程序采用非删除式重绘,假定指针将要移动一格,则先采用背景色(这里是白色)重绘原来指针以删除原来位置的指针,再采用指针的颜色在当前位置绘制指针(如果指针没有动,则直接绘制指针,此句在程序中被我删除,具体原因,为数据截断导致一些误差)。另外,秒表为RTC一秒钟定时计数。程序分析: uCGUI+uCOS,一共三个任务:主处理任务、触摸屏任务、秒更新任务。void App_UCGUI_TaskCreate (void) CPU_INT08U os_er
4、r;os_err = os_err; Clock_SEM=OSSemCreate(1); /建立秒更新中断的信号量 /硬件平台初始化 BSP_Init(); /主处理任务- os_err = OSTaskCreateExt(AppTaskUserIF,(void *)0,(OS_STK *)&AppTaskUserIFStkAPP_TASK_USER_IF_STK_SIZE-1,APP_TASK_USER_IF_PRIO,APP_TASK_USER_IF_PRIO,(OS_STK *)&AppTaskUserIFStk0,APP_TASK_USER_IF_STK_SIZE,(void *)0,
5、OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR); /触摸屏任务- os_err = OSTaskCreateExt(AppTaskKbd, (void *)0, (OS_STK *)&AppTaskKbdStkAPP_TASK_KBD_STK_SIZE-1, APP_TASK_KBD_PRIO, APP_TASK_KBD_PRIO, (OS_STK *)&AppTaskKbdStk0, APP_TASK_KBD_STK_SIZE, (void *)0, OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR); /秒更新任务 os_er
6、r = OSTaskCreateExt(Clock_Updata,(void *)0,(OS_STK *)&Clock_Updata_StkClock_Updata_STK_SIZE-1,Clock_Updata_PRIO,Clock_Updata_PRIO,(OS_STK *)&Clock_Updata_Stk0,Clock_Updata_STK_SIZE,(void *)0,OS_TASK_OPT_STK_CHK|OS_TASK_OPT_STK_CLR);万年历中的时间用的是STM32自带的RTC实时时钟。1、主处理任务:界面背景初始化,并根据当前时间,画出图1的数据。static voi
7、d 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_D
8、ispStringAt(二,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_SetF
9、ont(&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
10、 );/设置英文字体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 2099)/超过范围处理s_time.tm_year=1970;else if(key=41)/年数减小按钮s_time.tm_
11、year-; /F2if(s_time.tm_year12)/超过范围处理s_time.tm_mon=1;else if(key=43) /月数减小按钮s_time.tm_mon-; /F4if(s_time.tm_mongetDays(s_time.tm_year,s_time.tm_mon)/超过范围处理s_time.tm_mday=1;else if(key=45) /日数减小按钮s_time.tm_mday-; /F6if(s_time.tm_mday0)/超过范围处理s_time.tm_mday=getDays(s_time.tm_year,s_time.tm_mon);GUI_Se
12、tFont(&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_md
13、ay,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);/阳历转阴历/见下面子程序1GUI_DispString(str); /显示阴历GUI_SetColor(GUI_RED); /字体颜色GUI_DispString(竹天笑万年历); k=getWeekDay(s_time.tm_year,
14、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)/如果为星期六和星期天,字体设置为红色
15、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);/
16、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)/如果为节气/见子程序4GUI_SetColo
17、r(GUI_MAGENTA);/设置字体为橙色elseGUI_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(); /刷新屏
18、幕#defineDEG2RAD (3.1415926f / 180) GUI_POINT m_Hour2,m_Sec2,m_Min2;/时分秒两个端点static GUI_POINT m_OldHour2,m_OldMin2,m_OldSec2;/时分秒之前的两个端点 m_Hour0.x=-20*cos(systmtime.tm_hour*30+90)*DEG2RAD)+264;/时钟指针端点计算,每一时旋转30 m_Hour0.y=-20*sin(systmtime.tm_hour*30+90)*DEG2RAD)+170;/度,逆时针旋转,当前时钟*30得旋 m_Hour1.x=-2*cos
19、(systmtime.tm_hour*30+270)*DEG2RAD)+264;/转的度数, 时钟另一端加上180度 m_Hour1.y=-2*sin(systmtime.tm_hour*30+270)*DEG2RAD)+170; /将极坐标形式转换成直角坐标GUI_SetColor(GUI_WHITE);/重绘上一次时钟指针覆盖的背景 GUI_DrawLine(m_OldHour0.x,m_OldHour0.y, m_OldHour1.x,m_OldHour1.y);GUI_SetColor(GUI_RED);/画新的时钟指针 GUI_DrawLine(m_Hour0.x,m_Hour0.y
20、, m_Hour1.x,m_Hour1.y); m_Min0.x=-30*cos(systmtime.tm_min*6+90)*DEG2RAD)+264;/分钟指针端点计算,每一分旋转6 m_Min0.y=-30*sin(systmtime.tm_min*6+90)*DEG2RAD)+170;/度,逆时针旋转,当前分钟*6得旋 m_Min1.x=-4*cos(systmtime.tm_min*6+270)*DEG2RAD)+264;/转的度数, 时钟另一端加上180度 m_Min1.y=-4*sin(systmtime.tm_min*6+270)*DEG2RAD)+170; /将极坐标形式转换
21、成直角坐标 GUI_SetColor(GUI_WHITE);/重绘上一次分钟指针覆盖的背景 GUI_DrawLine(m_OldMin0.x,m_OldMin0.y, m_OldMin1.x,m_OldMin1.y); GUI_SetColor(GUI_BLUE);/画新的分钟指针 GUI_DrawLine(m_Min0.x,m_Min0.y, m_Min1.x,m_Min1.y); m_Sec0.x=-35*cos(systmtime.tm_sec*6+90)*DEG2RAD)+264;/分钟指针端点计算,每一秒旋转6 m_Sec0.y=-35*sin(systmtime.tm_sec*6+
22、90)*DEG2RAD)+170;/度,逆时针旋转,当前秒钟*6得旋 m_Sec1.x=-8*cos(systmtime.tm_sec*6+270)*DEG2RAD)+264;/转的度数, 时钟另一端加上180度 m_Sec1.y=-8*sin(systmtime.tm_sec*6+270)*DEG2RAD)+170;/将极坐标形式转换成直角坐标 GUI_SetColor(GUI_WHITE); GUI_DrawLine(m_OldSec0.x,m_OldSec0.y, m_OldSec1.x,m_OldSec1.y); GUI_SetColor(GUI_BLACK); GUI_DrawLin
23、e(m_Sec0.x,m_Sec0.y, m_Sec1.x,m_Sec1.y); for(i=0;i10) StrCopy(&str10,(u8 *)nonglidayNLyear3/10,2);elseStrCopy(&str10,(u8 *)初,2);StrCopy(&str12,(u8 *)monthcode(NLyear3-1)%10,2);子程序2u8 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) /
24、 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,表示你调用该函数时传递了不正确的年份值或月份值.*/
25、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 公历年/