GD32F10X ----RTC

 1. RTC的简介 

STM32 的实时时钟(RTC)是一个独立的定时器。STM32 的 RTC 模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。
        RTC 模块和时钟配置系统(RCC_BDCR 寄存器)是在后备区域,即在系统复位或从待机模式唤醒后 RTC 的设置和时间维持不变。但是在系统复位后,会自动禁止访问后备寄存器和 RTC,以防止对后备区域(BKP)的意外写操作。所以在要设置时间之前, 先要取消备份区域(BKP)写保护。


 2. RTC的框图

这里用的是STM32其实与GD都是差不多。

 RTC 由两个主要部分组成 第一部分(APB1 接口),第二部分是后备区域。

 RT_DIV寄存器设置可编程产生 1 秒的 RTC 时间基准 TR_CLK。每一秒到来RTC_CNT

寄存器的值就会加1。RTC_CNT是32位的寄存器。1秒到还可以产生中断。以及溢出中断。以及闹钟中断。(当RTC_ALR寄存器与RTC_CNT一样)。

我们通过读取RTC_CNT的大小(多少秒)然后转换成实时时钟(年,月,日,时,分,秒)

如果我要设置一个实时时钟转成秒然后设置到RTC_CNT。

不管是设置与获取都是操作RTC_CNT并且单位是秒。具体怎么转成实时时钟要自己写逻辑。

实时时钟都是以1970年1月1日00 :00:00为开始。(红色字是重点)

由于RTC_CNT是32位的,可被初始化为当前的系统时间,一个 32 位的时钟计数器,按秒钟计算,可以记录 4294967296 秒,约合 136 年左右。所以最大:1970 + 136。如果大于这个年就会溢出。

3. 代码实现

 RTC.h

#ifndef _RTC_H
#define _RTC_H#include "gd32f10x.h"
#include <stdio.h>//日期时间结构体
typedef struct{//时间uint8_t hour;uint8_t min;uint8_t sec;//日期uint16_t w_year;uint8_t w_month;uint8_t w_day;
}_calender_obj;extern _calender_obj calender;  //日期、时间结构体变量
extern uint8_t const month_table[12];void RTC_Config(void);  //RTC配置
uint8_t RTC_Init(void);    //RTC初始化
void RTC_NVIC_Config(void); //配置RTC中断uint8_t RTC_Set(uint16_t syear, uint8_t smonth, uint8_t sday, uint8_t shour, uint8_t smin, uint8_t ssec); //将设置时间转化为秒数,给到RTC_CNT
uint8_t RTC_Get(void);  //得到RTC_CNT的值并转换为日期时间
uint8_t Is_Leap_Year(uint16_t year); //判断year是否闰年
uint8_t RTC_Get_Week(uint16_t year,uint8_t month,uint8_t day);
#endif

RTC.c

#include "RTC.h"_calender_obj calender;uint8_t const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表
uint8_t const month_table[12]={31,28,31,30,31,30,31,31,30,31,30,31};//平年月份的天数uint32_t timecount = 0;//RTC配置
void RTC_Config(void){rcu_periph_clock_enable(RCU_BKPI); //备份区域的时钟要先使能rcu_periph_clock_enable(RCU_PMU);  //电源管理时钟使能pmu_backup_write_enable();         //使能备份域访问允许bkp_deinit();                      //备份域复位rcu_osci_on(RCU_LXTAL);            //使能外部低速时钟rcu_osci_stab_wait(RCU_LXTAL);     //等待外部低速时钟稳定rcu_rtc_clock_config(RCU_RTCSRC_LXTAL); //时钟源选择rcu_periph_clock_enable(RCU_RTC); //使能RTC时钟rtc_register_sync_wait();         //等待寄存器与APB1时钟同步rtc_lwoff_wait();   //等待RTC的最后一次操作完成rtc_interrupt_enable(RTC_INT_SECOND);//使能RTC的秒中断rtc_lwoff_wait();   //等待RTC的最后一次操作完成rtc_prescaler_set(32767); /* 配置RTC_PRL的值(时钟分频) */rtc_lwoff_wait();   //等待RTC的最后一次操作完成
}//RTC初始化
uint8_t RTC_Init(void){RTC_Config();RTC_Set(2023, 8, 21, 23, 13, 15);RTC_NVIC_Config();//配置中断的优先级return 0;
}// 配置RTC的中断优先级
void RTC_NVIC_Config(void){nvic_irq_enable(RTC_IRQn, 2, 0);
}//RTC的中断服务函数
void RTC_IRQHandler(void){if(rtc_flag_get(RTC_FLAG_SECOND) != RESET){ //判断是否为秒中断rtc_flag_clear(RTC_FLAG_SECOND);RTC_Get();printf("Now time is: %d-%d-%d %d:%d:%d\r\n", calender.w_year, calender.w_month, calender.w_day, calender.hour, calender.min, calender.sec);}
}//将设置时间转化为秒数,给到RTC_CNT
uint8_t RTC_Set(uint16_t syear, uint8_t smonth, uint8_t sday, uint8_t shour, uint8_t smin, uint8_t ssec){uint32_t seccounts = 0;uint16_t temp_year = 1970;uint8_t temp_month;if(syear<1970 || syear>2099){  //设置的时间不合理return 1;}//整年的秒数while(temp_year < syear){if(Is_Leap_Year(temp_year))seccounts += 31622400; //闰年,一年的秒数  366* 24 * 60 *60else seccounts += 31536000;  //平年,一年的秒数  365* 24 * 60 *60temp_year++;}//整月的秒数smonth--;for(temp_month = 0; temp_month<smonth; temp_month++){seccounts += (uint32_t)month_table[temp_month]*86400;if(Is_Leap_Year(syear)&&temp_month==1)seccounts += 86400; //如果设置的年份是闰年,在二月这个月份要加多一天}//日、时、分、秒的处理seccounts += (uint32_t)(sday-1)*86400; //整日的秒数  24 * 60 * 60seccounts += (uint32_t)shour*3600;//小时seccounts += (uint32_t)smin*60;   //分seccounts += ssec;      //秒rtc_lwoff_wait();rtc_counter_set(seccounts);return 0;
}//得到RTC_CNT的值并转换为日期时间
uint8_t RTC_Get(void){//把timecount转换为日期时间,并赋给calenderuint32_t temp_days = timecount/86400;uint16_t temp_year = 1970;uint16_t temp_month;uint32_t temp_seconds;timecount = rtc_counter_get();//读取RTC_CNT寄存器的值//处理天数中的整年,if(temp_days>0){while(temp_days>=365){if(Is_Leap_Year(temp_year)){//如果是闰年if(temp_days>365){temp_days -= 366;}else{break;}}else{temp_days -= 365;}temp_year++;}calender.w_year = temp_year;//剩下不足一年的,再处理整月temp_month = 1; //用来临时存放月份while(temp_days >= 28){ //超过了一个月if(Is_Leap_Year(calender.w_year) && temp_month == 2){if(temp_days>=29){ //闰年的2月是29天temp_days -= 29;}else{break;}}else{if(temp_days >= month_table[temp_month-1]){//剩余的天数是不是大于temp_month这个月整月的天数temp_days -= month_table[temp_month-1];}else{break;}}temp_month++;}}calender.w_month = temp_month;calender.w_day = temp_days+1;//处理剩下的不足一天的秒数,时:分:秒temp_seconds = timecount%86400; //不足一天的秒数calender.hour = temp_seconds/3600;calender.min = (temp_seconds%3600)/60;calender.sec = temp_seconds%60;return 0;
}uint8_t Is_Leap_Year(uint16_t year){ //判断year是否闰年if(year%4 == 0){if(year%100 == 0){if(year%400 == 0)return 1;elsereturn 0;}else{return 1;}}else{return 0;}
}//获得现在是星期几
//功能描述:输入公历日期得到星期(只允许1901-2099年)
//year,month,day:公历年月日 
//返回值:星期号																						 
uint8_t RTC_Get_Week(uint16_t year,uint8_t month,uint8_t day)
{	uint16_t temp2;uint8_t yearH,yearL;yearH=year/100;	yearL=year%100; // 如果为21世纪,年份数加100  if (yearH>19)yearL+=100;// 所过闰年数只算1900年之后的  temp2=yearL+yearL/4;temp2=temp2%7; temp2=temp2+day+table_week[month-1];if (yearL%4==0&&month<3)temp2--;return(temp2%7);
}

main.c

#include "gd32f10x_eval.h"#include "LED.h"
#include "SYSTICK_DELAY.h"
#include "RTC.h"int main(){gd_eval_com_init(EVAL_COM0);    // 初始化USART0LED_Init();my_systick_config();printf("This is a RTC DEMO test.\r\n");RTC_Init();while(1){LED1_Toggle();my_systick_delay_ms(1000);	//delay 1000 ms}
}/*重写fputc*/
int fputc(int ch, FILE *f)
{usart_data_transmit(EVAL_COM0,ch);  //通过串口把ch给发送出去while(RESET == usart_flag_get(EVAL_COM0, USART_FLAG_TBE));return ch;
}

通过串口工具来显示实时时钟。先设置然后在读取通过串口显示出来。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/146353.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

详解Avast Driver Updater:电脑驱动更新工具的利器还是多余的软件?

亲爱的读者朋友们&#xff0c;你是不是经常为电脑的驱动问题而烦恼&#xff1f;如果是的话&#xff0c;你可能会对这款软件——Avast Driver Updater 电脑驱动更新工具感兴趣。但在你决定尝试之前&#xff0c;不妨先和我一起深入探讨一下它的优点、缺点以及它适用的使用场景。 …

【夏虫语冰】测试服务器端口是否打开(命令行、Python)

文章目录 1、简介2、命令行2.1 telnet2.1.1 工具简介2.1.2 工具配置2.1.3 工具使用 2.2 curl2.2.1 工具简介2.2.1 工具下载2.2.1 工具使用 2.3 wget2.3.1 工具简介2.3.2 工具下载2.3.2 工具使用 2.4 nc2.4.1 工具简介2.4.2 工具安装2.4.3 工具使用 2.5 ssh2.5.1 工具简介2.5.2 …

动态规划算法(1)--矩阵连乘和凸多边形剖分

目录 一、动态数组 1、创建动态数组 2、添加元素 3、删除修改元素 4、访问元素 5、返回数组长度 6、for each遍历数组 二、输入多个数字 1、正则表达式 2、has.next()方法 三、矩阵连乘 1、什么是矩阵连乘&#xff1f; 2、动态规划思路 3、手推m和s矩阵 4、完…

番外4:VMware安装

step4: 安装过程中&#xff0c;有些选项不需要点&#xff08;安装地址建议选C盘或默认&#xff0c;装载在其他盘后续会报错&#xff09;&#xff0c;如&#xff1a; may error&#xff08;本人猜测安装虚拟机完整版需要C盘的一些桥插件支持&#xff09;: step5: 安装虚拟机成功…

给奶牛做直播之三

​一、前言 上一篇给牛奶做直播之二 主要讲用RTMP搭建点播服务器&#xff0c;整了半天直播还没上场&#xff0c;今天不讲太多理论的玩意&#xff0c;奶牛今天放假了也不出场&#xff0c;就由本人亲自上场来个直播首秀&#xff0c;见下图&#xff0c;如果有兴趣的话&#xff0…

Android修行手册 - Activity 在 Java 和 Kotlin 中怎么写构造参数

点击跳转>Unity3D特效百例点击跳转>案例项目实战源码点击跳转>游戏脚本-辅助自动化点击跳转>Android控件全解手册点击跳转>Scratch编程案例点击跳转>软考全系列 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&…

大喜国庆,聊聊我正式进入职场的这三个月...

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…

实现三栏布局的十种方式

本文节选自我的博客&#xff1a;实现三栏布局的十种方式 &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是MilesChen&#xff0c;偏前端的全栈开发者。&#x1f4dd; CSDN主页&#xff1a;爱吃糖的猫&#x1f525;&#x1f4e3; 我的博客&#xff1a;爱吃糖的猫&…

02-Zookeeper实战

上一篇&#xff1a;01-Zookeeper特性与节点数据类型详解 1. zookeeper安装 Step1&#xff1a; 配置JAVA环境&#xff0c;检验环境&#xff1a; java -versionStep2: 下载解压 zookeeper wget https://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.5.8/apache-zookeepe…

番外5:下载+安装+配置Linux

任务前期工作&#xff1a; 01. 电脑已安装好VMware Workstation软件&#xff1b; 02.提前下载好Rhel-8.iso映像文件&#xff08;文件较大一般在9.4GB&#xff0c;建议采用迅雷下载&#xff09;&#xff0c;本人使用的以下版本&#xff08;地址ed2k://|file|rhel-8.4-x86_64-dvd…

C++-哈希Hash

本期我们来学习哈希 目录 unordered系列关联式容器 unordered_map unordered_set 性能比较 哈希概念 哈希冲突 哈希函数 哈希冲突解决 闭散列 模拟实现 开散列 模拟实现 全部代码 unordered系列关联式容器 在 C98 中&#xff0c; STL 提供了底层为红黑树结构的一…

【算法基础】一文掌握十大排序算法,冒泡排序、插入排序、选择排序、归并排序、计数排序、基数排序、希尔排序和堆排序

目录 1 冒泡排序&#xff08;Bubble Sort&#xff09; 2 插入排序&#xff08;Insertion Sort&#xff09; 3 选择排序&#xff08;Selection Sort&#xff09; 4. 快速排序&#xff08;Quick Sort&#xff09; 5. 归并排序&#xff08;Merge Sort&#xff09; 6 堆排序 …

【day10.01】使用select实现服务器并发

用select实现服务器并发&#xff1a; linuxlinux:~/study/1001$ cat server.c #include <myhead.h>#define ERR_MSG(msg) do{\printf("%d\n",__LINE__);\perror(msg);\ }while(0)#define PORT 8880#define IP "192.168.31.38"int main(int argc, c…

11链表-迭代与递归

目录 LeetCode之路——206. 反转链表 分析&#xff1a; 解法一&#xff1a;迭代 解法二&#xff1a;递归 LeetCode之路——206. 反转链表 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 1&#xff1a; 输入&#xff1a;head […

开绕组电机零序Bakc EMF-based无感控制以及正交锁相环inverse Park-based

前言 最近看论文遇到了基于反Park变换的锁相环&#xff0c;用于从开绕组永磁同步电机零序电压信号中提取转子速度与位置信息&#xff0c;实现无感控制。在此记录 基于零序Back EMF的转子估算 开绕组电机的零序反电动势 e 0 − 3 ω e ψ 0 s i n 3 θ e e_0-3\omega_e\psi_…

SoloX:Android和iOS性能数据的实时采集工具

SoloX&#xff1a;Android和iOS性能数据的实时采集工具 github地址&#xff1a;https://github.com/smart-test-ti/SoloX 最新版本&#xff1a;V2.7.6 一、SoloX简介 SoloX是开源的Android/iOS性能数据的实时采集工具&#xff0c;目前主要功能特点&#xff1a; 无需ROOT/越狱…

直播协议 python 常见直播协议

1. 推流、直播 和 点播分别是什么意思&#xff1f; 推流 主播将本地视频源和音频源推送到云服务器&#xff0c;也被称为“RTMP发布”。 直播 即直接观看主播实时推送过来的音视频数据。 点播 视频源已经事先存储于云服务器之上的音视频文件&#xff0c;观众随时可以观看。 目…

STM32晶振的选择与计算

目录 1、石英晶体特性和型号2、振荡器理论2.1负电阻2.2跨导2.3负阻振荡器原理 3、皮尔斯振荡器设计3.1 皮尔斯振荡器简介3.2反馈电阻器3.3负载电容3.4振荡器跨导3.5驱动电平和外部电阻计算3.5.1计算驱动电平3.5.2另一种驱动电平测量方法3.5.3计算外部电阻 3.6启动时间3.7晶体拉…

八个不可不知的SQL高级方法

结构化查询语言&#xff08;SQL&#xff09;是一种广泛使用的工具&#xff0c;用于管理和操作数据库。基本的SQL查询简单易学&#xff0c;但掌握高级SQL技术可以将您的数据分析和管理能力提升到新的高度。 高级SQL技术是指一系列功能和函数&#xff0c;使您能够对数据执行复杂…

记录:Unity脚本的编写

目录 前言添加脚本到unity编写c#脚本查看效果 前言 在学习软件构造这门课的时候&#xff0c;对unity和c#进行了 一定程度的学习&#xff0c;包括简单的建立地形&#xff0c;添加对象&#xff0c;添加材质等&#xff0c;前不久刚好学习了如何通过c#脚本对模型进行操控&#xff…