当前位置: 首页 > article >正文

RTC 案例2 :实时时钟 (掉电不丢失)

需求描述:

显示时间。通过串口把时间发送给电脑显示。即使关机很多天,再启动后也能正确显示时间。

思考:

1 通过时间戳设置初始时间

2 可视化的展示:年月日

实现:

1 时间戳

    /* 在windows的powshell获取unix时间戳命令: [int][double]::Parse((Get-Date -UFormat %s)) */
    /* 设置一次就行了,以后时钟就可以正常运行了 */
    //RTC_SetUnixTimestampSecond(1700478670);

三种方式:

第一种:获得从1970 年 1 月 1 日 00:00:00 UTC(协调世界时)开始计算的秒钟

[int][double]::Parse((Get-Date -UFormat %s))

第二种:获得计时

Get-Date

第三种:获得精准的秒数

Get-Date -UFormat %s

2 可视化

C语言中有一个time.h的库提供一个tm的类型------函数:localtime();返回一个tm的类型的函数。

rtc.h

#ifndef __RTC_H
#define __RTC_H

#include "stm32f10x.h"
#include <time.h>

// 自定义日历时间结构体类型
typedef struct
{
    uint16_t year;
    uint8_t month;
    uint8_t day;
    uint8_t hour;
    uint8_t minute;
    uint8_t second;
} DateTime;

// 初始化
void RTC_Init(void);

// 设置闹钟,s秒之后唤醒
void RTC_SetAlarm(uint32_t s);

// 设置当前时间(UNIX时间戳)
void RTC_SetTimestamp(uint32_t ts);

// 获取日历时间(年月日时分秒)
void RTC_GetDateTime(DateTime * dateTime);

#endif

rtc.c

#include "rtc.h"

// 初始化
void RTC_Init(void)
{
    // 1. 后备域统一配置
    // 1.1 开启PWR时钟
    RCC->APB1ENR |= RCC_APB1ENR_PWREN;

    // 1.2 放开后备域的写保护
    PWR->CR |= PWR_CR_DBP;

    // // 1.3 软件复位整个备份域
    // RCC->BDCR |= RCC_BDCR_BDRST;

    // // 1.4 解除备份域复位
    // RCC->BDCR &= ~RCC_BDCR_BDRST;

    // 2. 配置RTC时钟源以及开启RTC
    // 2.1 开启RTC时钟
    RCC->BDCR |= RCC_BDCR_RTCEN;

    // 2.2 打开LSE并等待启动完成
    RCC->BDCR |= RCC_BDCR_LSEON;
    while (!(RCC->BDCR & RCC_BDCR_LSERDY))
    {
    }

    // 2.3 选择LSE作为RTC的时钟源
    RCC->BDCR &= ~RCC_BDCR_RTCSEL;
    RCC->BDCR |= RCC_BDCR_RTCSEL_0;

    // 3. RTC寄存器的配置
    // 3.1 查询RTOFF位,直到变为1
    while (!(RTC->CRL & RTC_CRL_RTOFF))
    {
    }

    // 3.2 进入配置模式
    RTC->CRL |= RTC_CRL_CNF;

    // 3.3 设置预分频系数 32767,产生秒脉冲
    RTC->PRLH = 0;
    RTC->PRLL = 0x7fff;

    // 3.4 退出配置模式
    RTC->CRL &= ~RTC_CRL_CNF;

    // 3.5 查询RTOFF位,直到变为1
    while (!(RTC->CRL & RTC_CRL_RTOFF))
    {
    }
}

// 设置闹钟,s秒之后唤醒
void RTC_SetAlarm(uint32_t s)
{
    // 0. 先清除闹钟标志
    RTC->CRL &= ~RTC_CRL_ALRF;

    // 1. 查询RTOFF位,直到变为1
    while (!(RTC->CRL & RTC_CRL_RTOFF))
    {
    }

    // 2. 进入配置模式
    RTC->CRL |= RTC_CRL_CNF;

    // 3. 设置寄存器
    // 3.1 计数器 CNT = 0
    RTC->CNTH = 0;
    RTC->CNTL = 0;

    // 3.2 闹钟 ALR = s - 1
    s -= 1;
    RTC->ALRH = (s >> 16) & 0xffff;
    RTC->ALRL = (s >> 0) & 0xffff;

    // 4. 退出配置模式
    RTC->CRL &= ~RTC_CRL_CNF;

    // 5. 查询RTOFF位,直到变为1
    while (!(RTC->CRL & RTC_CRL_RTOFF))
    {
    }
}

// 设置当前时间(UNIX时间戳)
void RTC_SetTimestamp(uint32_t ts)
{
    // 1. 查询RTOFF位,直到变为1
    while (!(RTC->CRL & RTC_CRL_RTOFF))
    {
    }

    // 2. 进入配置模式
    RTC->CRL |= RTC_CRL_CNF;

    // 3. 设置CNT寄存器
    RTC->CNTH = (ts >> 16) & 0xffff;
    RTC->CNTL = (ts >> 0) & 0xffff;

    // 4. 退出配置模式
    RTC->CRL &= ~RTC_CRL_CNF;

    // 5. 查询RTOFF位,直到变为1
    while (!(RTC->CRL & RTC_CRL_RTOFF))
    {
    }
}

// 获取日历时间(年月日时分秒)
void RTC_GetDateTime(DateTime *dateTime)
{
    // 1. 等待寄存器同步
    while ( !(RTC->CRL & RTC_CRL_RSF) )
    {}
    
    // 2. 读取当前计数值(秒数)
    uint32_t second = RTC->CNTH << 16 | RTC->CNTL;

    // 3. 将秒数转换成tm结构体对象
    struct tm* ptm = localtime(&second);

    // 4. 基于tm构建自定义的结构体对象
    dateTime->year = ptm->tm_year + 1900;
    dateTime->month = ptm->tm_mon + 1;
    dateTime->day = ptm->tm_mday;
    dateTime->hour = ptm->tm_hour;
    dateTime->minute = ptm->tm_min;
    dateTime->second = ptm->tm_sec;
}

main.c

#include "usart.h"
#include "delay.h"
#include "rtc.h"

int main(void)
{
	// 初始化
	USART_Init();
	RTC_Init();

	printf("RTC实验:RTC实时时钟...\n");

	// 设置一次当前的时间戳
	// RTC_SetTimestamp(1736160789);

	DateTime dateTime;

	while (1)
	{
		// 每隔1s获取当前时间打印输出一次
		RTC_GetDateTime(&dateTime);

		printf("%04d年%02d月%02d日 %02d:%02d:%02d\n",
			dateTime.year, dateTime.month, dateTime.day, dateTime.hour, dateTime.minute, dateTime.second);
		
		Delay_ms(1000);
	}
}


http://www.kler.cn/a/469919.html

相关文章:

  • 信息系统管理师试题-人力资源
  • 新一代智能工控系统网络安全合规解决方案
  • thinkphp通过html生成pdf
  • UWB实操:用信号分析仪(频谱分析仪)抓取UWB频域的图像
  • JMeter + Grafana +InfluxDB性能监控 (二)
  • 数据挖掘教学指南:从基础到应用
  • QT实现 端口扫描暂停和继续功能 3
  • 算法解析-经典150(图论、回溯法)
  • websocket在各主流浏览器中默认的请求头是如何设置的?
  • SQL语言的语法糖
  • 【MySQL】表的基本操作
  • MYSql------视图
  • 基于transformer的目标检测:DETR
  • KAGGLE竞赛实战2-捷信金融违约预测竞赛-part1-数据探索及baseline建立
  • 结构型模式2.桥接模式
  • springboot配置线程池
  • 今日总结 2025-01-06
  • 软件工程大复习之(四)——面向对象与UML
  • win32汇编环境,在窗口程序中画五边形与六边形
  • Unity3D PBR光照计算公式推导详解
  • 土建施工员考试题库及答案
  • 社交新零售下开源 AI 智能名片 2+1 链动模式 S2B2C 商城小程序的促单策略研究
  • MR20强抗干扰一体式IO模块的革新力量
  • KACL:Knowledge-Adaptive Contrastive Learning for Recommendation
  • C++ 原子变量
  • Bash语言的函数实现