RTC -

RTC

目录

RTC

回顾

RTC

如何实现RTC制作一个时钟日历

代码编写

rtc.c完整代码



模块开发的步骤:

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();
  }
}
相关推荐
yutian06062 小时前
Keil MDK下载程序后MCU自动重启设置
单片机·嵌入式硬件·keil
析木不会编程5 小时前
【小白51单片机专用教程】protues仿真独立按键控制LED
单片机·嵌入式硬件·51单片机
枯无穷肉9 小时前
stm32制作CAN适配器4--WinUsb的使用
stm32·单片机·嵌入式硬件
不过四级不改名6779 小时前
基于HAL库的stm32的can收发实验
stm32·单片机·嵌入式硬件
嵌入式大圣9 小时前
单片机UDP数据透传
单片机·嵌入式硬件·udp
云山工作室10 小时前
基于单片机的视力保护及身姿矫正器设计(论文+源码)
stm32·单片机·嵌入式硬件·毕业设计·毕设
嵌入式-老费10 小时前
基于海思soc的智能产品开发(mcu读保护的设置)
单片机·嵌入式硬件
qq_3975623111 小时前
MPU6050 , 设置内部低通滤波器,对于输出数据的影响。(简单实验)
单片机
艺术家天选12 小时前
STM32点亮LED灯
stm32·单片机·嵌入式硬件
向阳逐梦12 小时前
基于STM32F4单片机实现ROS机器人主板
stm32·单片机·机器人