使用STM32的RTC功能,制作一份私人专属的日历,就SO简单了。不废话,上效果图:
鄙人通过串口输出时间到超级终端的(SecureCRT 5.5这货最好),如果配上TFT就制作一个简易的电子日历了。这个里面主要涉及RTC的初始化,时间数据的初始化输入,串口输出,还有就是公历时间和农历时间的转换处理。通过串口初始化RTC数据,RTC通过串口把时间显示出来,上代码:
工程结构图:
1、main.c如下:
#include"stm32f10x.h"
#include"beep.h"
#include"led.h"
#include"usart1.h"
#include"rtc.h"
int main(void)
{
USART_Config();
Beep_Init();
Beep_State(1,BeepOn);
Led_Init();
Led_Spark(LedAll,1,LedOn);
RTC_NVIC_Config(); //RTC嵌套中断向量初始化
RTC_Display();
}
2、beep led usart这些在博客其他文章里面出现过,这里就不提也罢。
3、RTC.c这是本文的重点了。
C文件如下:
#include"stm32f10x.h"
#include"rtc.h"
#include"usart1.h"
#include"date.h"
#include"calendar.h"
#include
u8 SecondFlag=0;
struct rtc_time systmtime;
u8 const *WEEK_STR[] = {"日", "一", "二", "三", "四", "五", "六"}; //这是一个指针数组的赋值 不是指向一个数组的指针 而是一个数组的每一个元素都是一个指针
//==============================================================================================1-RTC初始化部分
void RTC_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x0000); //起始地址位于FLASH
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //优先级分组方式2
NVIC_InitStructure.NVIC_IRQChannel =RTC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;
NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
static void RTC_Config(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR|RCC_APB1Periph_BKP,ENABLE);
PWR_BackupAccessCmd(ENABLE);
BKP_DeInit();
RCC_LSEConfig(RCC_LSE_ON);
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)==RESET); //等待LSE准备就绪
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForSynchro();
RTC_ITConfig(RTC_IT_SEC,ENABLE);
RTC_WaitForLastTask();
RTC_SetPrescaler(32767);
RTC_WaitForLastTask();
}
//==============================================================================================2--设置时间部分
static u8 RTC_USART_Scanf(uint32_t value)
{
uint32_t index = 0;
uint32_t tmp[2] = {0, 0};
while (index < 2)
{
while (USART_GetFlagStatus(USART, USART_FLAG_RXNE) == RESET)
{}
tmp[index++] = (USART_ReceiveData(USART));
if ((tmp[index - 1] < 0x30) || (tmp[index - 1] > 0x39))
{
if((index == 2) && (tmp[index - 1] == '
')) //第一个输入的是数字,第二个是按的回车键的情况
{
tmp[1] = tmp[0];
tmp[0] = 0x30;
}
else
{
printf("
Please enter valid number between 0 and 9 -->: ");
index--;
}
}
else
{
printf("%c", tmp[index - 1]); //输入一个显示一个数字
}
}
index = (tmp[1] - 0x30) + ((tmp[0] - 0x30) * 10);
if (index > value)
{
printf("
Please enter valid number between 0 and %d -->: ", value);
return 0xFF;
}
return index;
}
[page]
static void RTC_Time_Setting(struct rtc_time *tm)
{
uint32_t DataIn = 0xFF;
printf("
==============请设置时间==================");
printf("
请输入年份(Please Set Years): 20");
while (DataIn == 0xFF)
{
DataIn = RTC_USART_Scanf(99);
}
printf("
年份被设置为: 20%0.2d
", DataIn);
tm->tm_year = DataIn+2000;
DataIn = 0xFF;
printf("
请输入月份(Please Set Months): ");
while (DataIn == 0xFF)
{
DataIn = RTC_USART_Scanf(12);
}
printf("
月份被设置为: %d
", DataIn);
tm->tm_mon= DataIn;
DataIn = 0xFF;
printf("
请输入日期(Please Set Dates): ");
while (DataIn == 0xFF)
{
DataIn = RTC_USART_Scanf(31);
}
printf("
日期被设置为: %d
", DataIn);
tm->tm_mday= DataIn;
DataIn = 0xFF;
printf("
请输入时钟(Please Set Hours): ");
while (DataIn == 0xFF)
{
DataIn = RTC_USART_Scanf(23);
}
printf("
时钟被设置为: %d
", DataIn);
tm->tm_hour= DataIn;
DataIn = 0xFF;
printf("
请输入分钟(Please Set Minutes): ");
while (DataIn == 0xFF)
{
DataIn = RTC_USART_Scanf(59);
}
printf("
分钟被设置为: %d
", DataIn);
tm->tm_min= DataIn;
DataIn = 0xFF;
printf("
请输入秒钟(Please Set Seconds): ");
while (DataIn == 0xFF)
{
DataIn = RTC_USART_Scanf(59);
}
printf("
秒钟被设置为: %d
", DataIn);
tm->tm_sec= DataIn;
}
static void RTC_Time_Adjust(void)
{
RTC_WaitForLastTask();
RTC_Time_Setting(&systmtime); //把输入的年月日时分秒导入到结构体systmtime里面
GregorianDay(&systmtime); //这个会求出tm->tm_wday=day%7 星期
RTC_SetCounter(mktimev(&systmtime)); //根据systmtime里面的内容计算出RTC计数器里面需要装载的数字然后写入计数器里面
RTC_WaitForLastTask();
}
static void RTC_WhetherOrNot_First(void)
{
if(BKP_ReadBackupRegister(BKP_DR1)!=0xa6a6)
{
printf("
第一次进入RTC
");
RTC_Config();
printf("
RTC初始化完成
");
printf("
设置时间
");
RTC_Time_Adjust(); //设置时间
BKP_WriteBackupRegister(BKP_DR1,0xa5a5);
}
else
{
if(RCC_GetFlagStatus(RCC_FLAG_PINRST)!=RESET)
printf("
上次发生了复位引脚复位
");
else if(RCC_GetFlagStatus(RCC_FLAG_PORRST)!=RESET)
printf("
上次发生了上电复位
");
printf("
RTC已经设置
");
}
}
//==============================================================================================3--时间显示部分
static void RTC_TimeHandle(u32 TimeVar)
{
static uint32_t FirstDisplay = 1;
__IO u8 str[15]; // 字符串暂存
to_tm(TimeVar, &systmtime); //TimeVar:RTC的值 把相应的数据填入结构体systmtime(年月日 时分秒 星期)
if((!systmtime.tm_hour && !systmtime.tm_min && !systmtime.tm_sec) || (FirstDisplay)) //天数变更或者是第一次进入此语句
{
GetChinaCalendar((u16)systmtime.tm_year, (u8)systmtime.tm_mon, (u8)systmtime.tm_mday, (u8 *)str); //得到的是农历日期
printf("
今天农历:%0.2d%0.2d,%0.2d,%0.2d", str[0], str[1], str[2], str[3]);
GetChinaCalendarStr((u16)systmtime.tm_year,(u8)systmtime.tm_mon,(u8)systmtime.tm_mday,(u8 *)str); //得到的是甲子年
printf(" %s", str);
if(GetJieQiStr((u16)systmtime.tm_year, (u8)systmtime.tm_mon, (u8)systmtime.tm_mday, (u8 *)str)) //得到的是节气
printf(" %s
", str); // 计算农历节气
FirstDisplay = 0;
}
printf("
当前时间为: %d年 %d月 %d日 (星期%s) %0.2d:%0.2d:%0.2d",
systmtime.tm_year, systmtime.tm_mon, systmtime.tm_mday,
WEEK_STR[systmtime.tm_wday], systmtime.tm_hour,
systmtime.tm_min, systmtime.tm_sec);
}
static void RTC_TimeShow(void)
{
while(1)
{
if(SecondFlag==1)
{
RTC_TimeHandle(RTC_GetCounter());
SecondFlag=0;
}
}
}
void RTC_Display(void)
{
RTC_WhetherOrNot_First();
RTC_WaitForSynchro();
RTC_ITConfig(RTC_IT_SEC,ENABLE);
RTC_WaitForLastTask();
#ifdef RTC_CLK_Output //RTC时钟信号输出
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR|RCC_APB1Periph_BKP,ENABLE);
PWR_BackupAccessCmd(ENABLE);
BKP_DeInit();
BKP_TemperPinCmd(DISABLE);
BKP_RTCOutputConfig(BKP_RTCOutputSource_CalibClock);
#endif
RCC_ClearFlag();
printf("
-------------时间显示如下------------
");
RTC_TimeShow();
}
H文件如下:
#ifndef _RTC_H
#define _RTC_H
#include"stm32f10x.h"
void RTC_NVIC_Config(void); //RTC嵌套中断向量初始化
void RTC_Display(void); //RTC全过程
#endif
以上,注释很给力了,不说了。
至于这两个文件,是通过LINUX移植过来的,网上有现成的代码,读者可以自行下载。由于其代码量相对较大,鄙人这里就不粘贴了。我的QQ380986295 ,免费提供。
还是给这两个文件一个效果图吧:
以上RTC结束了。
使用STM32的RTC功能,制作日历就很简单了,加上一个TFT就很容易做一个电子时钟。作为初学者,还是很有必要做一做提升一下自信心,鼓励自己坚持下去。