RTC
目录
模块开发的步骤:
1、找文档
2、 在文档里面找通信方式,通信过程(协议)
3、代码>
-- 前面学的是模块的开发,串口类,IO类,ADC类设备,从这章开始,依然学习模块开发,但是方式不一样,之前代码都是自己写的,现在要学的是库开发,代码都是现成的
- 今天用库开发方式
-- 什么叫库开发,代码都是现成的
-- 那么我们还做什么呢?
- 三件事:移植,修改,使用
移植:把代码拿过来,放到工程里面
修改:修改错误或者修改一些参数配置
使用:应用
这三步都很重要
-- 在库开发阶段,可能会出现这些问题:
- 可能会出现代码看不明白,具体是代码的细节看不明白(不需要深入纠结代码 )
在库开发阶段,核心就是应用
回顾
- DMA的本质是数据传输的快速通道,特点:无需CPU干预
DMA 一般不会单独出现,他一定和其他外设一块使用。
比如说:dma 去实现 printf (dma 和 usart1 TX)
RTC
-
首先查找参考手册,了解RTC
-
看核心框图
-- 单片机的时钟源有四个(外部高速(HSE),内部高速(HSI),外部低速(LSE),内部低速(LSI))
-- RTC的是时钟源有三个:外部低速(32.768khz),内部低速(40khz),外部高速(72M)/128(=562500)
如何实现RTC制作一个时钟日历
1、时钟芯片 DS1302.
2、单片机内部的 RTC
时间相关:定时器
计数器:16 位
分频系数:16 位 2^16 如果单片机的频率是72MHZ,那么经过2^16次分频后,频率为72MHZ/2^16 = 1098hz
最大的计时时间? 2^16/1098 = 59.6 S 1min
所以经过上面的计算,tim 能实现时钟日历吗? 不太行 (最大的计时时间才1min)
单片机上有一个专门用来制作时钟日历的定时器:RTC
-- RTC的特点:
- 1.计数时间长
计数器:32 位 2^32
最大的计数时间大概 136 年
分频:20 位 2^20 1hz/s
时钟源:外部低速(32.768K) 内部低速(40K) 外部高速/128(562500hz)
- 2.RTC 在单片机处于后备区域
后备区域:一般情况,单片机上电之后,禁止访问的区域,有单独供电(和单片机的供电不是同一个)
所有时钟芯片,都会存在一个问题:时间长了,就会不准。
解决问题:联网定期更新时间(获取的是世界标准时间,和北京时间有 8 个小时时差)
代码编写
-
先找到固件库
-
打开main.c文件,找到RTC的初始化函数
-
看参考手册中,找到RTC的配置过程
-
在main.c文件中找到相应的配置代码,找到配置函数,跳到相应的函数定义。
-
RTC的配置
-
选择我们用到的加到我们的工程中
cs
if (BKP_ReadBackupRegister(BKP_DR1) != 0x1234){
//1、使能访问
/* Enable PWR and BKP clocks */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);//时钟
/* Allow access to BKP Domain */
PWR_BackupAccessCmd(ENABLE); //电源 //前两行开启访问
//2、时钟源和分频
/* Enable LSE */
RCC_LSEConfig(RCC_LSE_ON);
/* Wait till LSE is ready */
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
{}
/* Select LSE as RTC Clock Source */
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
/* Enable RTC Clock */
RCC_RTCCLKCmd(ENABLE);
/* Wait for RTC registers synchronization */
RTC_WaitForSynchro();
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
/* Set RTC prescaler: set RTC period to 1sec */
RTC_SetPrescaler(32767); /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) */
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
- 设置计数初值
cs
//3、计数初值
/* Change the current time */
RTC_SetCounter(1728444875);//赋一个初值,一个秒数
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
BKP_WriteBackupRegister(BKP_DR1, 0x1234);
- 读取时间
cs
struct tm a = {0};
void get_time(void)
{
uint32_t sec = RTC_GetCounter();
//struct tm *p = &a;
a = *(localtime((time_t*)&sec));
printf("%04d/%02d/%02d %02d:%02d:%02d\r\n",a.tm_year+1900,a.tm_mon+1,a.tm_mday,a.tm_hour+8,a.tm_min,a.tm_sec);
}
- 更新时间,因为该单片机没有纽扣电池,断电后数值就会丢失,重新上电后就会从初始值开始计数
cs
//用来更新RTC时间的
void updata_time(uint32_t sec)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);//时钟
/* Allow access to BKP Domain */
PWR_BackupAccessCmd(ENABLE); //电源
/* Change the current time */
RTC_SetCounter(sec);//赋一个初值,一个秒数
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
}
- main.c
cs
rtc_init();
while(1)
{
if(rtctime >=999)
{
rtctime = 0;
get_time();
}
if(keytime>=50)//50ms执行一次
{
keyflag = get_key();
switch(keyflag)
{
case 1:
updata_time(1728455609);
break;
case 2: break;
}
}
}
-- tip:
-
如果要修改时钟源
-
计数的初值是什么(是一个时间戳,我们只需要将当前时间的时间戳赋值进去即可)
rtc.c完整代码
cs
#include "rtc.h"
#include "time.h"
void rtc_init(void)
{
if (BKP_ReadBackupRegister(BKP_DR1) != 0x1234){
//1、使能访问
/* Enable PWR and BKP clocks */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);//时钟
/* Allow access to BKP Domain */
PWR_BackupAccessCmd(ENABLE); //电源 //前两行开启访问
//2、时钟源和分频
/* Enable LSE */
RCC_LSEConfig(RCC_LSE_ON);
/* Wait till LSE is ready */
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
{}
/* Select LSE as RTC Clock Source */
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
/* Enable RTC Clock */
RCC_RTCCLKCmd(ENABLE);
/* Wait for RTC registers synchronization */
RTC_WaitForSynchro();
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
/* Set RTC prescaler: set RTC period to 1sec */
RTC_SetPrescaler(32767); /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) */
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
//3、计数初值
/* Change the current time */
RTC_SetCounter(1728444875);//赋一个初值,一个秒数
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
BKP_WriteBackupRegister(BKP_DR1, 0x1234);
}
// //4、中断或者闹钟(需要就写,不需要就不写)
//
// //中断----------------------------------------------
//
// RTC_ITConfig(RTC_IT_SEC, ENABLE); //使能RTC秒中断
// /* Wait until last write operation on RTC registers has finished */
// RTC_WaitForLastTask();
//
// NVIC_InitTypeDef NVIC_InitStructure;
// /* Configure one bit for preemption priority */
// NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
// /* Enable the RTC Interrupt */
// 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);
//
// //---------------------------------------------------
}
//中断服务函数
//void RTC_IRQHandler(void)
//{
// if (RTC_GetITStatus(RTC_IT_SEC) != RESET)
// {
// /* Clear the RTC Second interrupt */
// RTC_ClearITPendingBit(RTC_IT_SEC);
// /* Wait until last write operation on RTC registers has finished */
// RTC_WaitForLastTask();
//
// }
//}
struct tm a = {0};
void get_time(void)
{
uint32_t sec = RTC_GetCounter();
//struct tm *p = &a;
a = *(localtime((time_t*)&sec));
printf("%04d/%02d/%02d %02d:%02d:%02d\r\n",a.tm_year+1900,a.tm_mon+1,a.tm_mday,a.tm_hour+8,a.tm_min,a.tm_sec);
}
//因为该单片机没有纽扣电池,断电后数值就会丢失,重新上电后就会从初始值开始计数
//用来更新RTC时间的
void updata_time(uint32_t sec)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);//时钟
/* Allow access to BKP Domain */
PWR_BackupAccessCmd(ENABLE); //电源
/* Change the current time */
RTC_SetCounter(sec);//赋一个初值,一个秒数
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
}
用RTC实现闹钟功能
- 这里要使用闹钟中断
-- 1、在初始化函数中加入中断和闹钟的初始化
-- 2、写中断服务函数,这里用RTC的中断服务函数即可,不用专门用闹钟的中断服务函数
-- 3、在主函数中只要将初始化函数写入main函数中,就可以达到闹钟的效果
-- 主要代码
cs
#include "rtc.h"
#include "relay.h"
#include "delay.h"
uint16_t naozhong = 0;
void rtc_init(void)
{
//if (BKP_ReadBackupRegister(BKP_DR1) != 0x1233)
{
//1、使能访问
/* Enable PWR and BKP clocks */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);//时钟
/* Allow access to BKP Domain */
PWR_BackupAccessCmd(ENABLE); //电源 //前两行开启访问
//2、时钟源和分频
/* Enable LSE */
RCC_LSEConfig(RCC_LSE_ON);
/* Wait till LSE is ready */
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
{}
/* Select LSE as RTC Clock Source */
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
/* Enable RTC Clock */
RCC_RTCCLKCmd(ENABLE);
/* Wait for RTC registers synchronization */
RTC_WaitForSynchro();
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
/* Set RTC prescaler: set RTC period to 1sec */
RTC_SetPrescaler(32768); /* RTC period = RTCCLK/RTC_PR = (32.768 KHz)/(32767+1) */
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
//3、计数初值
/* Change the current time */
RTC_SetCounter(1728444875);//赋一个初值,一个秒数
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
BKP_WriteBackupRegister(BKP_DR1, 0x1233);
}
//4、中断或者闹钟(需要就写,不需要就不写)
//中断----------------------------------------------
RTC_ITConfig(RTC_IT_ALR | RTC_IT_SEC, ENABLE); //使能RTC秒中断
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
RTC_SetAlarm(1728444875+10);
RTC_WaitForLastTask();
NVIC_InitTypeDef NVIC_InitStructure={0};
/* Configure one bit for preemption priority */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
/* Enable the RTC Interrupt */
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);
//---------------------------------------------------
}
//中断服务函数
void RTC_IRQHandler(void)
{
if (RTC_GetITStatus(RTC_IT_SEC) != RESET)
{
/* Clear the RTC Second interrupt */
RTC_ClearITPendingBit(RTC_IT_SEC);//秒中断
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
}
if (RTC_GetITStatus(RTC_IT_ALR) != RESET)//闹钟中断
{
uint32_t aa = RTC_GetCounter();
RTC_SetAlarm(aa+10);
RTC_WaitForLastTask();
relay_init();
relay_on();
Delay_nms(100);
relay_off();
RTC_WaitForLastTask();
/* Clear the RTC Second interrupt */
RTC_ClearITPendingBit(RTC_IT_ALR);
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
}
}