一、前言
本章节承接上期的【Mini-F5265-OB开发板试用测评】硬件SPI方式驱动LCD屏帖子上。灵动微官方提供的“LibSamples_MM32F5260_V0.10.2”SDK中包含一个RTC日历的参考例程,因此将该功能移植到上期工程中,即可达成在LCD屏上显示RTC日历时钟。
官方提供的参考示例,基本上都是采用PA2复用为串口2的TX端,方便用户外接USB转TTL调试模块打印串口输出信息,上期咱使用PA2作为控制LCD的背光输出脚,因此如果想要工程既支持串口打印RTC日历时钟信息,又能将数据同步到LCD屏上,必须将PA2改成其它通用GPIO口。
二、移植说明
参考“RTC_Calendar”例程,将“rtc_calendar.c”与“rtc_calendar.h”添加到原工程路径中,并在“mm32f5260_it.c”中添加RTC_IRQHandler()中断函数。
由于这里使用LCD做为数据显示端,因此可将printf串口打印输出替换成LCD相关显示接口函数。
三、工程源码
main.c
#include "platform.h"
#include "gpio_led_toggle.h"
#include "main.h"
#include "lcd.h"
#include "rtc_calendar.h"
int main(void)
{
PLATFORM_Init();
GPIO_LED_Toggle_Sample();
LCDInit();
RTC_Configure();
PLATFORM_DelayMS(200U);
LcdFill(0,0,LCD_W,LCD_H,WHITE);
while (1)
{
LCDTest();
}
}
rtc_calendar.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "platform.h"
#include "rtc_calendar.h"
#include "lcd.h"
const uint8_t RTC_DayOfMonth[12] =
{
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
RTC_CalendarTypeDef RTC_Calendar;
uint8_t RTC_LeapYear(uint16_t Year)
{
if (
(((Year % 400) == 0)) || /* Century Leap Year */
(((Year % 100) != 0) && ((Year % 4) == 0)) /* Normal Leay Year */
)
{
return (1);
}
else
{
return (0);
}
}
uint8_t RTC_GetWeek(uint16_t Year, uint8_t Month, uint8_t Day)
{
int w, c, y;
/* Month 1 Or 2 of This Year Must Be As Last Month 13 Or 14 */
if ((Month == 1) || (Month == 2))
{
Month += 12;
Year -= 1;
}
w = 0; /* Weekday */
c = Year / 100; /* Century */
y = Year % 100; /* Year */
w = y + (y / 4) + (c / 4) - (2 * c) + (26 * (Month + 1) / 10) + Day - 1;
while (w < 0)
{
w += 7;
}
w %= 7;
return (w);
}
void RTC_UpdateCalendar(void)
{
static uint32_t PreTotalDay = 0;
uint32_t TotalSecond = 0;
uint32_t TotalDay = 0;
uint16_t Year = 1970;
uint8_t Month = 0;
TotalSecond = RTC_GetCounter();
TotalDay = TotalSecond / 86400;
if (PreTotalDay != TotalDay)
{
PreTotalDay = TotalDay;
while (TotalDay >= 365)
{
if (RTC_LeapYear(Year) == 1)
{
if (TotalDay >= 366)
{
TotalDay -= 366;
}
else
{
break;
}
}
else
{
TotalDay -= 365;
}
Year++;
}
RTC_Calendar.year = Year;
while (TotalDay >= 28)
{
if ((Month == 1) && (RTC_LeapYear(RTC_Calendar.year) == 1))
{
if (TotalDay >= 29)
{
TotalDay -= 29;
}
else
{
break;
}
}
else
{
if (TotalDay >= RTC_DayOfMonth[Month])
{
TotalDay -= RTC_DayOfMonth[Month];
}
else
{
break;
}
}
Month++;
}
RTC_Calendar.month = Month + 1;
RTC_Calendar.day = TotalDay + 1;
RTC_Calendar.week = RTC_GetWeek(RTC_Calendar.year, RTC_Calendar.month, RTC_Calendar.day);
}
RTC_Calendar.hour = (TotalSecond % 86400) / 3600;
RTC_Calendar.minute = ((TotalSecond % 86400) % 3600) / 60;
RTC_Calendar.second = ((TotalSecond % 86400) % 3600) % 60;
}
void RTC_SetDateTime(uint16_t Year, uint8_t Month, uint8_t Day, uint8_t Hour, uint8_t Minute, uint8_t Second)
{
uint32_t TotalSecond = 0;
uint16_t y = 0;
uint8_t m = 0;
if ((Year >= 1970) && (Year <= 2099))
{
for (y = 1970; y < Year; y++)
{
if (RTC_LeapYear(y) == 1)
{
TotalSecond += 31622400; /* Total Seconds Of Leap Year */
}
else
{
TotalSecond += 31536000; /* Total Seconds Of Normal Year */
}
}
for (m = 0; m < (Month - 1); m++)
{
TotalSecond += RTC_DayOfMonth[m] * 86400; /* Total Seconds Of Month */
if ((RTC_LeapYear(Year) == 1) && (m == 1))
{
TotalSecond += 86400;
}
}
TotalSecond += (uint32_t)(Day - 1) * 86400; /* Total Seconds Of Day */
TotalSecond += (uint32_t)Hour * 3600; /* Total Seconds Of Hour */
TotalSecond += (uint32_t)Minute * 60; /* Total Seconds Of Minute */
TotalSecond += Second;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWRDBG | RCC_APB1Periph_BKP, ENABLE);
PWR_BackupAccessCmd(ENABLE);
RTC_SetCounter(TotalSecond);
RTC_WaitForLastTask();
RTC_UpdateCalendar();
}
else
{
printf("\r\nError Date & Time!!!\r\n");
}
}
void RTC_PrintDateTime(void)
{
LcdShowIntNum(8,118,RTC_Calendar.year,4,WHITE,RED,16);
LcdShowString(40,118,"-",WHITE,RED,16);
if(RTC_Calendar.month < 10)
{
LcdShowIntNum(48,118,0,1,WHITE,RED,16);
LcdShowIntNum(56,118,RTC_Calendar.month,1,WHITE,RED,16);
}
else
{
LcdShowIntNum(48,118,RTC_Calendar.month,2,WHITE,RED,16);
}
LcdShowString(64,118,"-",WHITE,RED,16);
if(RTC_Calendar.day < 10)
{
LcdShowIntNum(72,118,0,1,WHITE,RED,16);
LcdShowIntNum(80,118,RTC_Calendar.day,1,WHITE,RED,16);
}
else
{
LcdShowIntNum(72,118,RTC_Calendar.day,2,WHITE,RED,16);
}
switch (RTC_Calendar.week)
{
case 0:
LcdShowString(88,118," SUN ",WHITE,RED,16);
break;
case 1:
LcdShowString(88,118," MON ",WHITE,RED,16);
break;
case 2:
LcdShowString(88,118," TUE ",WHITE,RED,16);
break;
case 3:
LcdShowString(88,118," WED ",WHITE,RED,16);
break;
case 4:
LcdShowString(88,118," THU ",WHITE,RED,16);
break;
case 5:
LcdShowString(88,118," FRI ",WHITE,RED,16);
break;
case 6:
LcdShowString(88,118," SAT ",WHITE,RED,16);
break;
default:
break;
}
if(RTC_Calendar.hour < 10)
{
LcdShowIntNum(8,140,0,1,WHITE,RED,16);
LcdShowIntNum(16,140,RTC_Calendar.hour,1,WHITE,RED,16);
}
else
{
LcdShowIntNum(8,140,RTC_Calendar.hour,2,WHITE,RED,16);
}
LcdShowString(24,140,":",WHITE,RED,16);
if(RTC_Calendar.minute < 10)
{
LcdShowIntNum(32,140,0,1,WHITE,RED,16);
LcdShowIntNum(40,140,RTC_Calendar.minute,1,WHITE,RED,16);
}
else
{
LcdShowIntNum(32,140,RTC_Calendar.minute,2,WHITE,RED,16);
}
LcdShowString(48,140,":",WHITE,RED,16);
if(RTC_Calendar.second < 10)
{
LcdShowIntNum(56,140,0,1,WHITE,RED,16);
LcdShowIntNum(64,140,RTC_Calendar.second,1,WHITE,RED,16);
}
else
{
LcdShowIntNum(56,140,RTC_Calendar.second,2,WHITE,RED,16);
}
}
void RTC_LoadDefault(void)
{
char Date[20], Time[20];
char Text[6][5];
uint8_t i = 0, Index = 0, Month = 0;
char *MonthTable[12] =
{
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
};
char *str;
memset(Date, 0, sizeof(Date));
memset(Time, 0, sizeof(Time));
memset(Text, 0, sizeof(Text));
memcpy(Date, __DATE__, sizeof(__DATE__));
memcpy(Time, __TIME__, sizeof(__TIME__));
str = strtok(Date, " ");
while (str != NULL)
{
memcpy(Text[Index++], str, strlen(str));
str = strtok(NULL, " ");
}
str = strtok(Time, ":");
while (str != NULL)
{
memcpy(Text[Index++], str, strlen(str));
str = strtok(NULL, ":");
}
for (i = 0; i < 12; i++)
{
if (0 == strcmp(Text[0], MonthTable[i]))
{
Month = i + 1;
}
}
RTC_Calendar.day = atoi(Text[1]);
RTC_Calendar.month = Month;
RTC_Calendar.year = atoi(Text[2]);
RTC_Calendar.hour = atoi(Text[3]);
RTC_Calendar.minute = atoi(Text[4]);
RTC_Calendar.second = atoi(Text[5]);
RTC_SetDateTime(RTC_Calendar.year, RTC_Calendar.month, RTC_Calendar.day, RTC_Calendar.hour, RTC_Calendar.minute, RTC_Calendar.second);
}
void RTC_Configure(void)
{
NVIC_InitTypeDef NVIC_InitStruct;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWRDBG | RCC_APB1Periph_BKP, ENABLE);
PWR_BackupAccessCmd(ENABLE);
BKP_DeInit();
if (BKP_ReadBackupRegister(BKP_DR1) != 0x5D5D)
{
RCC_LSEConfig(RCC_LSE_ON);
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
{
}
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForSynchro();
RTC_WaitForLastTask();
RTC_ITConfig(RTC_IT_SEC, ENABLE);
RTC_WaitForLastTask();
RTC_SetPrescaler(32767);
RTC_WaitForLastTask();
printf("\r\n%s", __FUNCTION__);
BKP_WriteBackupRegister(BKP_DR1, 0x5D5D);
}
else
{
printf("\r\nNeed't to configure RTC...");
RTC_WaitForSynchro();
RTC_ITConfig(RTC_IT_SEC, ENABLE);
RTC_WaitForLastTask();
}
NVIC_InitStruct.NVIC_IRQChannel = RTC_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
RTC_LoadDefault();
}
函数LCDTest更改成如下:
uint8_t number = 0;
void LCDTest(void)
{
LcdShowIntNum(8,10,2025,4,BLUE,GREEN,16);
LcdShow16x16Hz(40,10,0, BLUE,GREEN);
LcdShow16x16Hz(56,10,1, BLUE,GREEN);
LcdShow16x16Hz(72,10,2, BLUE,GREEN);
LcdShow16x16Hz(88,10,3, BLUE,GREEN);
LcdShow16x16Hz(104,10,4,BLUE,GREEN);
LcdShow16x16Hz(8,30,5, BLUE,GREEN);
LcdShow16x16Hz(24,30,6, BLUE,GREEN);
LcdShowString(40,30," ",BLUE,GREEN,16);
LcdShowString(44,30,"MM32F5260",BLUE, GREEN,16);
LcdShow16x16Hz(8,50,7, BLUE,GREEN);
LcdShow16x16Hz(24,50,8, BLUE,GREEN);
LcdShow16x16Hz(40,50,9, BLUE,GREEN);
LcdShowImage(0,70, 128, 40, gImage_2);
number++;
if(number > 100)
number = 0;
LcdShowIntNum(80,140,number,3,WHITE,RED,16);
}
mm32f5260_it.c文件中增加RTC_IRQHandler()中断函数如下:
void RTC_IRQHandler(void)
{
if (RESET != RTC_GetITStatus(RTC_IT_SEC))
{
RTC_UpdateCalendar();
RTC_PrintDateTime();
RTC_ClearITPendingBit(RTC_IT_SEC);
RTC_WaitForLastTask();
}
}
四、日历时钟显示
由上述源码可知,RTC的初始值是由工程编译时产生的Text文本时间属性所定义的,因此无需手动输入,编译完下载自动重启后便与电脑端同步时钟了。这里为了显示更标准化,将月份、日期、时、分、秒固定输出两位数字,采用24小时制,显示的效果呈现如下视频。
https://www.youku.com/video/X...