【Mini-F5265-OB开发板试用测评】显示RTC日历时钟

一、前言

本章节承接上期的【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/XNjQ1MDM3OTU2NA==

相关推荐
Lay_鑫辰20 小时前
西门子诊断-状态和错误位(“轴”工艺对象 V1...3)
服务器·网络·单片机·嵌入式硬件·自动化
无垠的广袤1 天前
【工业树莓派 CM0 NANO 单板计算机】本地部署 EMQX
linux·python·嵌入式硬件·物联网·树莓派·emqx·工业物联网
雲烟1 天前
嵌入式设备EMC安规检测参考
网络·单片机·嵌入式硬件
泽虞1 天前
《STM32单片机开发》p7
笔记·stm32·单片机·嵌入式硬件
田甲1 天前
【STM32】 数码管驱动
stm32·单片机·嵌入式硬件
up向上up1 天前
基于51单片机垃圾箱自动分类加料机快递物流分拣器系统设计
单片机·嵌入式硬件·51单片机
纳祥科技1 天前
Switch快充方案,内置GaN,集成了多个独立芯片
单片机
单片机日志1 天前
【单片机毕业设计】【mcugc-mcu826】基于单片机的智能风扇系统设计
stm32·单片机·嵌入式硬件·毕业设计·智能家居·课程设计·电子信息
松涛和鸣2 天前
从零开始理解 C 语言函数指针与回调机制
linux·c语言·开发语言·嵌入式硬件·排序算法
小曹要微笑2 天前
STM32F7 时钟树简讲(快速入门)
c语言·stm32·单片机·嵌入式硬件·算法