[STM32F1] STM32F103C8T6配置RTC显示年月日时分秒(日历)

[复制链接]
2284|38
 楼主| g36xcv 发表于 2023-11-24 00:13 | 显示全部楼层 |阅读模式
RTC介绍一、主要框图
82252655f7a32f393f.png

55553655f7a3b5193b.png

 楼主| g36xcv 发表于 2023-11-24 00:14 | 显示全部楼层
二、介绍
RTC模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。
RTC 模块和时钟配置系统 (RCC_BDCR 寄存器 ) 处于后备区域,即在系统复位或从待机模式唤醒
后, RTC 的设置和时间维持不变。
系统复位后,对后备寄存器和 RTC 的访问被禁止,这是为了防止对后备区域 (BKP) 的意外写操
作。执行以下操作将使能对后备寄存器和 RTC 的访问:
● 设置寄存器RCC_APB1ENR的PWREN和BKPEN位,使能电源和后备接口时钟
● 设置寄存器PWR_CR的DBP位,使能对后备寄存器和RTC的访问。
● 可以选择以下三种 RTC 的时钟源:
─ HSE 时钟除以 128 ;
─ LSE振荡器时钟;
─ LSI 振荡器时钟 ( 详见 6.2.8
308/754
节 RTC 时钟 ) 。
● 2 个独立的复位类型:
─ APB1 接口由系统复位;
─ RTC 核心 ( 预分频器、闹钟、计数器和分频器 ) 只能由后备域复位 。
● 3 个专门的可屏蔽中断:
─ 闹钟中断,用来产生一个软件可编程的闹钟中断。
─ 秒中断 ,用来产生一个可编程的周期性中断信号 ( 最长可达 1 秒 ) 。
─ 溢出中断,指示内部可编程计数器溢出并回转为 0 的状态。
 楼主| g36xcv 发表于 2023-11-24 00:14 | 显示全部楼层
2、主要模块
一、rtc文件
RTC初始化配置
RTC_NVIC配置
备份区域识别--BKP
设置时间
将时间放进Setcounter()---Time_Adjust()函数
获取时间
把参数放进时间结构体
显示时间
判断闰年
RTC中断服务函数
printf重定向,重写fputc函数
 楼主| g36xcv 发表于 2023-11-24 00:15 | 显示全部楼层
系统文件
系统文件system 34801655f7a9c84d09.png
 楼主| g36xcv 发表于 2023-11-24 00:15 | 显示全部楼层
库文件 38177655f7aba8d0a2.png
 楼主| g36xcv 发表于 2023-11-24 00:16 | 显示全部楼层
用户文件 38893655f7ad675cb5.png
 楼主| g36xcv 发表于 2023-11-24 00:16 | 显示全部楼层
自编程序 21386655f7ae01707c.png
 楼主| g36xcv 发表于 2023-11-24 00:16 | 显示全部楼层
3、代码框架
4个,主函数,延时,串口,rtc
4个.h文件中实现函数的声明,定义
将printf重写函数写进rtc.c中
主函数只有初始化函数调用和时间显示函数,时间显示函数在while(1)里
 楼主| g36xcv 发表于 2023-11-24 00:17 | 显示全部楼层
4、RTC配置
如果忘记如何配置查看STM32f103固件库参考手册和数据手册实例,有详细的步骤

使能电源PWR,后备区域BKP
允许访问备份区域
备份域复位
使能外部低速时钟LSE
等待LSE稳定(这里while循环可能会被卡死)
选择LSE作为RTC时钟源
使能RTC时钟
等待上一次操作完成
等待寄存器与APB1时钟同步,因为RTC时钟是低速的,内环时钟是高速的,所以要同步(这里很可能会卡死)
等待上一次操作完成
使能RTC秒中断
等待上一次操作完成
设置预分配寄存器周期1s
等待上一次操作完成
 楼主| g36xcv 发表于 2023-11-24 00:17 | 显示全部楼层
5、重写printf
  1. #include <stdio.h>
  2. #if 1
  3. //关闭半主机模式
  4. #pragma import(__use_no_semihosting)
  5. //标准库需要的支持函数
  6. struct __FILE{
  7. int handle;
  8. };
  9. FILE __stdin, __stdout, __stderr;
  10. //FILE __stdin;
  11. //避免使用半主机模式
  12. void _sys_exit(int x)
  13. {
  14. x=x;
  15. }


  16. /*重写fputc*/
  17. int fputc(int ch, FILE *f)
  18. {
  19.        
  20.         while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);  //通过串口把ch给发送出去
  21.         USART_SendData(USART1,ch);
  22.         return ch;
  23. }
 楼主| g36xcv 发表于 2023-11-24 00:18 | 显示全部楼层
6、时间设置Set
时间是从1970年1月1日00:00: 00开始

1970-到现在经过的天数,一天60*60*24=86400秒

不足一天的按,时*3600+分*60+秒=second

second+经过的天数*86400=所有的秒

?那一年经过多少天呢 ?是365还是366?             答:就需要一个判断年是不是闰年的函数

用一个临时自增变量记录年份,每判断一个年份就自增,直到2023

剩下不足一年的按照月份统计天数

?二月 ?是28还是29于是又一次用判断闰年函数,每一次加数字太繁琐,使用数组装下每个月的天数,用一个for循环方便。month_table[12]={31,28,31,30,31,30,31,31,30,31,30,31}

返回类型uint32_t,将此函数放于RTC_SetCounter(时间设置函数Set) ,后面请看代码
 楼主| g36xcv 发表于 2023-11-24 00:18 | 显示全部楼层
7、时间Get获取
通过RTC_GetCounter()获得放在寄存器的秒,将所有秒/86400得到所有的天数days,从1970判断是不是闰年直到2023,是闰年days-366不是就days-365。不足一天的秒如何得到?答:所有秒%86400.一天中的时就(秒%86400)/3600=时,((秒%86400)%3600)/60=分,(秒%86400)%3600)%60=second,将获得的年月日放进我们设置的结构体时间里
 楼主| g36xcv 发表于 2023-11-24 00:18 | 显示全部楼层
8、核心代码
1、rtc.h
  1. #ifndef _RTC_H
  2. #define _RTC_H
  3. #include <stm32f10x.h>
  4. #include <stdio.h>

  5. //时间结构体
  6. typedef struct{
  7.      uint16_t year;
  8.            uint8_t month;
  9.            uint8_t day;
  10.            uint8_t hour;
  11.            uint8_t minute;
  12.            uint8_t second;

  13. }cal;
  14. extern cal calendar;
  15. extern int const month_table[12] ;


  16. void clockinit_RTC(void);
  17. void RTC_NVIC_Config(void);
  18. void rtc_init(void);
  19. uint32_t rtc_timeSet(uint16_t syear,uint8_t smonth,uint8_t sdays,uint8_t shour,uint8_t sminute,uint8_t ssecond);
  20. void Time_Adjust(void);
  21. uint8_t rtc_timeGet(void);
  22. int IS_temp_year(uint16_t year);
  23. void Time_Show(void);
  24. void Time_Display(uint32_t time);
  25. void Time_Display2(void);
  26. #endif
 楼主| g36xcv 发表于 2023-11-24 00:18 | 显示全部楼层
2、rtc.c
  1. #include "rtc.h"
  2. #if 1
  3. //关闭半主机模式
  4. #pragma import(__use_no_semihosting)
  5. //标准库需要的支持函数
  6. struct __FILE{
  7. int handle;
  8. };
  9. FILE __stdin, __stdout, __stderr;
  10. //FILE __stdin;
  11. //避免使用半主机模式
  12. void _sys_exit(int x)
  13. {
  14. x=x;
  15. }


  16. /*重写fputc*/
  17. int fputc(int ch, FILE *f)
  18. {
  19.        
  20.         while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);  //通过串口把ch给发送出去
  21.         USART_SendData(USART1,ch);
  22.         return ch;
  23. }

  24. int fgetc(FILE *f){
  25.    char ch;
  26.          while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==RESET);
  27.    ch=USART_ReceiveData(USART1);
  28.          return (int)ch;
  29. }
  30. int ferror(FILE * f){
  31.   return EOF;
  32. }
  33. void _ttywrch(int ch){
  34.    while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
  35.          USART_SendData(USART1,ch);
  36. }
  37. //void _sys_exit(int return_code){
  38. //  while(1);
  39. //}
  40. #endif

  41. cal calendar;
  42. int const month_table[12] ={31,28,31,30,31,30,31,31,30,31,30,31};
  43. __IO uint8_t TimeDisplay;
  44. //RTC内设配置
  45. void rtc_init(){
  46.           uint32_t t;
  47.     //使能rcu_bkpi时钟,pwr电源,bkp后备区域
  48.           RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP,ENABLE);
  49.           //使能备份区域,允许访问备份(Backup)区域
  50.           PWR_BackupAccessCmd(ENABLE);
  51.        
  52.     //备份域复位
  53.           BKP_DeInit();
  54.           //使能外部低速时钟,32.768k
  55.           RCC_LSEConfig(RCC_LSE_ON);       
  56.           //等待外部低速时钟稳定  
  57.           while((RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)&& (t<10)){
  58.                    t++;
  59.                 }
  60.           //选择LSE作为RTC的时钟源       
  61.           RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);       
  62.           //使能RTC时钟
  63.           RCC_RTCCLKCmd(ENABLE);
  64.                
  65.           //等待RTC最后一次操作完成
  66.     RTC_WaitForLastTask();       
  67.                
  68.           //等待寄存器与APB1时钟同步,因为RTC时钟是低速的,内环时钟是高速的,所以要同步
  69.           RTC_WaitForSynchro();
  70.           //等待RTC最后一次操作完成
  71.     RTC_WaitForLastTask();       
  72.           //使能RTC的秒中断
  73.                 RTC_ITConfig(RTC_IT_SEC,ENABLE);
  74.                 //等待RTC最后一次操作完成
  75.                 RTC_WaitForLastTask();
  76.                 //设置预分频寄存器,时间周期是1秒 = 32.768k/32768+1--------(RTCCLK/RTC_PR)
  77.                 RTC_SetPrescaler(32768-1);
  78.                 //等待RTC最后一次操作完成
  79.                 RTC_WaitForLastTask();
  80. }

  81. void RTC_NVIC_Config(void){
  82.         NVIC_InitTypeDef NVIC_InitStructure;
  83.         //设置优先级组为1,抢占1位(0-1),从3位(0-7)
  84.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
  85.         //设置优先级通道
  86.         NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
  87.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  88.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  89.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  90.         NVIC_Init(&NVIC_InitStructure);
  91. }

  92. void clockinit_RTC(){
  93.         RTC_NVIC_Config();
  94.   RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP,ENABLE);
  95.         PWR_BackupAccessCmd(ENABLE);
  96.         //识别是不是后背备份区域
  97.   if(BKP_ReadBackupRegister(BKP_DR1)!=0XA5A5){
  98.                 //通过判断后背寄存器的值来判断是否是系统第一次上电
  99.                 printf("RTC没有被配置过");
  100.                 //是的话就进行RTC配置,设置初试时间
  101.           rtc_init();
  102.                 printf("RTC正在配置");
  103.                 Time_Adjust();
  104.                 BKP_WriteBackupRegister(BKP_DR1,0xA5A5);

  105.         }else{
  106.                 //看是否是系统掉电
  107.                 if(RCC_GetFlagStatus(RCC_FLAG_PORRST)!=RESET){
  108.                   printf("Power On Resetm occurred...");
  109.                 }
  110.                 //看是否是复位引脚引起的复位
  111.                 else if(RCC_GetFlagStatus(RCC_FLAG_PINRST)!=RESET){
  112.                   printf("External Reset occured...");
  113.                 }
  114.                 printf("No need to configure RTC...");
  115.           RTC_WaitForSynchro();
  116.                 RTC_ITConfig(RTC_IT_SEC,ENABLE);
  117.                 RTC_WaitForLastTask();
  118.         }
  119.                 RCC_ClearFlag();
  120.                 Time_Show();       
  121. }
  122. //RTC初始化(配置函数,Set引参,Get获得时间)

  123. //设置时间函数
  124. void Time_Adjust(void){
  125.    //等待RTC最后一次操作完成
  126.     RTC_WaitForLastTask();
  127.                  //将秒数存取寄存器
  128.           RTC_SetCounter(rtc_timeSet(2023,9,22,14,30,0));
  129.           //等待RTC最后一次操作完成
  130.     RTC_WaitForLastTask();
  131. }
  132. //用设置的时间去获得秒,我们使用秒中断       
  133. uint32_t rtc_timeSet(uint16_t syear,uint8_t smonth,uint8_t sdays,uint8_t shour,uint8_t sminute,uint8_t ssecond){
  134.                          
  135.     uint16_t old_year=1970;
  136.          //uint32_t all_second=0;
  137.           uint16_t days=0;
  138.           uint8_t month=0;
  139.           uint32_t second=0;
  140.         //时间大于一年的计算
  141.         while(old_year<syear){
  142.           if(IS_temp_year(old_year)){
  143.             days +=        366;                       
  144.           }else{
  145.             days +=365;
  146.           }       
  147.                 old_year++;
  148.         }
  149.         //时间不足一年的计算
  150.   for(;month<smonth;month++){
  151.                 if(!IS_temp_year(syear)){
  152.                    days += month_table[month];
  153.                 }else{
  154.                    if(month==1){
  155.                             days = days + month_table[month]+1;
  156.                          }else{
  157.                             days += month_table[month];
  158.                          }
  159.                 }   
  160.         }
  161.         days += sdays;
  162.         //得到年月日的秒数,一天有86400秒
  163.         second = days * 86400;
  164.         //不足一天的秒数--时
  165.         second +=shour * 3600;
  166.   //不足一天的秒数--分
  167.         second += sminute * 60;
  168.         //不足一天的秒数--秒
  169.         second += ssecond;
  170.   return second;
  171.        
  172. }
  173. //用得到的秒数去计算现在的日期
  174. uint8_t rtc_timeGet(){
  175.   uint32_t getsecond = RTC_GetCounter();
  176.         uint16_t gyear = 1970;
  177.         uint16_t gdays = 0;
  178.         uint8_t gmonth = 0;
  179.         uint8_t ghour = 0;
  180.         uint8_t gminute = 0;
  181.         uint16_t gsecond = 0;
  182.        
  183.         gdays = getsecond / 86400;
  184.         while(gdays < 365){
  185.            if(IS_temp_year(gyear)){
  186.                     gdays -= 366;
  187.                  }else{
  188.                     gdays -= 365;
  189.                  }
  190.                  gyear++ ;
  191.         }
  192.        
  193.         while(gdays >= 28){
  194.                         if(IS_temp_year(gyear)){
  195.                            gdays = gdays - month_table[gmonth]-1;
  196.                         }else{
  197.                            gdays -= month_table[gmonth];
  198.                         }
  199.             gmonth++ ;
  200.          }
  201.         calendar.year = gyear;
  202.         calendar.month = gmonth;
  203.         calendar.day = (uint8_t)gdays;
  204.         //不足一天的秒数
  205.         gsecond = getsecond % 86400 ;
  206.         ghour = gsecond / 3600;
  207.         gminute = (gsecond % 3600) / 60;
  208.         gsecond = (gsecond % 3600) %60 ;
  209.   calendar.hour = ghour;
  210.         calendar.minute = gminute;
  211.         calendar.second = (uint8_t)gsecond;
  212.         return 0;

  213. }
  214. //判断现在的年份是不是闰年
  215. int IS_temp_year(uint16_t year){
  216.    if(year%4==0){
  217.             if(year%100!=0){
  218.                             return 1;
  219.                         }else{
  220.                             return 0;
  221.                         }
  222.          
  223.          }else{
  224.            if(year%400==0){
  225.                     return 1;
  226.                  }else{
  227.                     return 0;
  228.                  }
  229.          }
  230. }
  231. void Time_Show(void){
  232.         printf("\n\r");
  233.    while(1){
  234.                  //秒标志位
  235.            if(TimeDisplay == 1){
  236.                          //Time_Display(RTC_GetCounter());
  237.                          Time_Display2();
  238.                          TimeDisplay = 0;
  239.                  }
  240.          
  241.          }

  242. }

  243. void Time_Display(uint32_t time){
  244.     uint32_t hh=0,mm=0,ss=0;
  245.         /*当时间走到23:59:59,RTC复位,计数值清零*/
  246.         if(RTC_GetCounter() == 0x0001517f){  //(23*3600=82800)+(59*60=3540)+(59)=86399变十六进制是0x0001517f
  247.            RTC_SetCounter(0x0);
  248.                 RTC_WaitForLastTask();
  249.         }
  250.         hh=time/3600;
  251.         mm=(time%3600)/60;
  252.         ss=(time%3600)%60;
  253. }
  254. void RTC_IRQHandler(void){
  255.         //秒中断是否开启
  256.    if(RTC_GetITStatus(RTC_IT_SEC)==SET){
  257.                  /*清除秒中断标识位*/
  258.                  RTC_ClearITPendingBit(RTC_IT_SEC);
  259.                  /*置1s标志位*/
  260.                  TimeDisplay=1;
  261.                  RTC_WaitForLastTask();
  262. //                 //显示时间
  263. //                 Time_Display2();
  264.                  
  265.          }
  266.          RTC_WaitForLastTask();

  267. }
  268. void Time_Display2(void){
  269.    rtc_timeGet();
  270.    printf("Now time is: %d-%d-%d %d:%d:%d\r\n", calendar.year, calendar.month, calendar.day, calendar.hour, calendar.minute, calendar.second);
  271. }
 楼主| g36xcv 发表于 2023-11-24 00:19 | 显示全部楼层
2、rtc.c
  1. #include "rtc.h"
  2. #if 1
  3. //关闭半主机模式
  4. #pragma import(__use_no_semihosting)
  5. //标准库需要的支持函数
  6. struct __FILE{
  7. int handle;
  8. };
  9. FILE __stdin, __stdout, __stderr;
  10. //FILE __stdin;
  11. //避免使用半主机模式
  12. void _sys_exit(int x)
  13. {
  14. x=x;
  15. }


  16. /*重写fputc*/
  17. int fputc(int ch, FILE *f)
  18. {
  19.        
  20.         while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);  //通过串口把ch给发送出去
  21.         USART_SendData(USART1,ch);
  22.         return ch;
  23. }

  24. int fgetc(FILE *f){
  25.    char ch;
  26.          while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==RESET);
  27.    ch=USART_ReceiveData(USART1);
  28.          return (int)ch;
  29. }
  30. int ferror(FILE * f){
  31.   return EOF;
  32. }
  33. void _ttywrch(int ch){
  34.    while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
  35.          USART_SendData(USART1,ch);
  36. }
  37. //void _sys_exit(int return_code){
  38. //  while(1);
  39. //}
  40. #endif

  41. cal calendar;
  42. int const month_table[12] ={31,28,31,30,31,30,31,31,30,31,30,31};
  43. __IO uint8_t TimeDisplay;
  44. //RTC内设配置
  45. void rtc_init(){
  46.           uint32_t t;
  47.     //使能rcu_bkpi时钟,pwr电源,bkp后备区域
  48.           RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP,ENABLE);
  49.           //使能备份区域,允许访问备份(Backup)区域
  50.           PWR_BackupAccessCmd(ENABLE);
  51.        
  52.     //备份域复位
  53.           BKP_DeInit();
  54.           //使能外部低速时钟,32.768k
  55.           RCC_LSEConfig(RCC_LSE_ON);       
  56.           //等待外部低速时钟稳定  
  57.           while((RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)&& (t<10)){
  58.                    t++;
  59.                 }
  60.           //选择LSE作为RTC的时钟源       
  61.           RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);       
  62.           //使能RTC时钟
  63.           RCC_RTCCLKCmd(ENABLE);
  64.                
  65.           //等待RTC最后一次操作完成
  66.     RTC_WaitForLastTask();       
  67.                
  68.           //等待寄存器与APB1时钟同步,因为RTC时钟是低速的,内环时钟是高速的,所以要同步
  69.           RTC_WaitForSynchro();
  70.           //等待RTC最后一次操作完成
  71.     RTC_WaitForLastTask();       
  72.           //使能RTC的秒中断
  73.                 RTC_ITConfig(RTC_IT_SEC,ENABLE);
  74.                 //等待RTC最后一次操作完成
  75.                 RTC_WaitForLastTask();
  76.                 //设置预分频寄存器,时间周期是1秒 = 32.768k/32768+1--------(RTCCLK/RTC_PR)
  77.                 RTC_SetPrescaler(32768-1);
  78.                 //等待RTC最后一次操作完成
  79.                 RTC_WaitForLastTask();
  80. }

  81. void RTC_NVIC_Config(void){
  82.         NVIC_InitTypeDef NVIC_InitStructure;
  83.         //设置优先级组为1,抢占1位(0-1),从3位(0-7)
  84.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
  85.         //设置优先级通道
  86.         NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
  87.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  88.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  89.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  90.         NVIC_Init(&NVIC_InitStructure);
  91. }

  92. void clockinit_RTC(){
  93.         RTC_NVIC_Config();
  94.   RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP,ENABLE);
  95.         PWR_BackupAccessCmd(ENABLE);
  96.         //识别是不是后背备份区域
  97.   if(BKP_ReadBackupRegister(BKP_DR1)!=0XA5A5){
  98.                 //通过判断后背寄存器的值来判断是否是系统第一次上电
  99.                 printf("RTC没有被配置过");
  100.                 //是的话就进行RTC配置,设置初试时间
  101.           rtc_init();
  102.                 printf("RTC正在配置");
  103.                 Time_Adjust();
  104.                 BKP_WriteBackupRegister(BKP_DR1,0xA5A5);

  105.         }else{
  106.                 //看是否是系统掉电
  107.                 if(RCC_GetFlagStatus(RCC_FLAG_PORRST)!=RESET){
  108.                   printf("Power On Resetm occurred...");
  109.                 }
  110.                 //看是否是复位引脚引起的复位
  111.                 else if(RCC_GetFlagStatus(RCC_FLAG_PINRST)!=RESET){
  112.                   printf("External Reset occured...");
  113.                 }
  114.                 printf("No need to configure RTC...");
  115.           RTC_WaitForSynchro();
  116.                 RTC_ITConfig(RTC_IT_SEC,ENABLE);
  117.                 RTC_WaitForLastTask();
  118.         }
  119.                 RCC_ClearFlag();
  120.                 Time_Show();       
  121. }
  122. //RTC初始化(配置函数,Set引参,Get获得时间)

  123. //设置时间函数
  124. void Time_Adjust(void){
  125.    //等待RTC最后一次操作完成
  126.     RTC_WaitForLastTask();
  127.                  //将秒数存取寄存器
  128.           RTC_SetCounter(rtc_timeSet(2023,9,22,14,30,0));
  129.           //等待RTC最后一次操作完成
  130.     RTC_WaitForLastTask();
  131. }
  132. //用设置的时间去获得秒,我们使用秒中断       
  133. uint32_t rtc_timeSet(uint16_t syear,uint8_t smonth,uint8_t sdays,uint8_t shour,uint8_t sminute,uint8_t ssecond){
  134.                          
  135.     uint16_t old_year=1970;
  136.          //uint32_t all_second=0;
  137.           uint16_t days=0;
  138.           uint8_t month=0;
  139.           uint32_t second=0;
  140.         //时间大于一年的计算
  141.         while(old_year<syear){
  142.           if(IS_temp_year(old_year)){
  143.             days +=        366;                       
  144.           }else{
  145.             days +=365;
  146.           }       
  147.                 old_year++;
  148.         }
  149.         //时间不足一年的计算
  150.   for(;month<smonth;month++){
  151.                 if(!IS_temp_year(syear)){
  152.                    days += month_table[month];
  153.                 }else{
  154.                    if(month==1){
  155.                             days = days + month_table[month]+1;
  156.                          }else{
  157.                             days += month_table[month];
  158.                          }
  159.                 }   
  160.         }
  161.         days += sdays;
  162.         //得到年月日的秒数,一天有86400秒
  163.         second = days * 86400;
  164.         //不足一天的秒数--时
  165.         second +=shour * 3600;
  166.   //不足一天的秒数--分
  167.         second += sminute * 60;
  168.         //不足一天的秒数--秒
  169.         second += ssecond;
  170.   return second;
  171.        
  172. }
  173. //用得到的秒数去计算现在的日期
  174. uint8_t rtc_timeGet(){
  175.   uint32_t getsecond = RTC_GetCounter();
  176.         uint16_t gyear = 1970;
  177.         uint16_t gdays = 0;
  178.         uint8_t gmonth = 0;
  179.         uint8_t ghour = 0;
  180.         uint8_t gminute = 0;
  181.         uint16_t gsecond = 0;
  182.        
  183.         gdays = getsecond / 86400;
  184.         while(gdays < 365){
  185.            if(IS_temp_year(gyear)){
  186.                     gdays -= 366;
  187.                  }else{
  188.                     gdays -= 365;
  189.                  }
  190.                  gyear++ ;
  191.         }
  192.        
  193.         while(gdays >= 28){
  194.                         if(IS_temp_year(gyear)){
  195.                            gdays = gdays - month_table[gmonth]-1;
  196.                         }else{
  197.                            gdays -= month_table[gmonth];
  198.                         }
  199.             gmonth++ ;
  200.          }
  201.         calendar.year = gyear;
  202.         calendar.month = gmonth;
  203.         calendar.day = (uint8_t)gdays;
  204.         //不足一天的秒数
  205.         gsecond = getsecond % 86400 ;
  206.         ghour = gsecond / 3600;
  207.         gminute = (gsecond % 3600) / 60;
  208.         gsecond = (gsecond % 3600) %60 ;
  209.   calendar.hour = ghour;
  210.         calendar.minute = gminute;
  211.         calendar.second = (uint8_t)gsecond;
  212.         return 0;

  213. }
  214. //判断现在的年份是不是闰年
  215. int IS_temp_year(uint16_t year){
  216.    if(year%4==0){
  217.             if(year%100!=0){
  218.                             return 1;
  219.                         }else{
  220.                             return 0;
  221.                         }
  222.          
  223.          }else{
  224.            if(year%400==0){
  225.                     return 1;
  226.                  }else{
  227.                     return 0;
  228.                  }
  229.          }
  230. }
  231. void Time_Show(void){
  232.         printf("\n\r");
  233.    while(1){
  234.                  //秒标志位
  235.            if(TimeDisplay == 1){
  236.                          //Time_Display(RTC_GetCounter());
  237.                          Time_Display2();
  238.                          TimeDisplay = 0;
  239.                  }
  240.          
  241.          }

  242. }

  243. void Time_Display(uint32_t time){
  244.     uint32_t hh=0,mm=0,ss=0;
  245.         /*当时间走到23:59:59,RTC复位,计数值清零*/
  246.         if(RTC_GetCounter() == 0x0001517f){  //(23*3600=82800)+(59*60=3540)+(59)=86399变十六进制是0x0001517f
  247.            RTC_SetCounter(0x0);
  248.                 RTC_WaitForLastTask();
  249.         }
  250.         hh=time/3600;
  251.         mm=(time%3600)/60;
  252.         ss=(time%3600)%60;
  253. }
  254. void RTC_IRQHandler(void){
  255.         //秒中断是否开启
  256.    if(RTC_GetITStatus(RTC_IT_SEC)==SET){
  257.                  /*清除秒中断标识位*/
  258.                  RTC_ClearITPendingBit(RTC_IT_SEC);
  259.                  /*置1s标志位*/
  260.                  TimeDisplay=1;
  261.                  RTC_WaitForLastTask();
  262. //                 //显示时间
  263. //                 Time_Display2();
  264.                  
  265.          }
  266.          RTC_WaitForLastTask();

  267. }
  268. void Time_Display2(void){
  269.    rtc_timeGet();
  270.    printf("Now time is: %d-%d-%d %d:%d:%d\r\n", calendar.year, calendar.month, calendar.day, calendar.hour, calendar.minute, calendar.second);
  271. }
 楼主| g36xcv 发表于 2023-11-24 00:20 | 显示全部楼层
3、usart.h
  1. #ifndef _USART_H
  2. #define _USART_H

  3. #include <stm32f10x.h>
  4. #include <stdio.h>

  5. void usart_init(uint32_t bound);
  6. void USART_SendString(uint8_t *ch);
  7. void usart_byte(uint8_t ch);
  8. void usart_buf(uint8_t *buf,uint8_t len);
  9. #endif
 楼主| g36xcv 发表于 2023-11-24 00:20 | 显示全部楼层
3、usart.h
  1. #ifndef _USART_H
  2. #define _USART_H

  3. #include <stm32f10x.h>
  4. #include <stdio.h>

  5. void usart_init(uint32_t bound);
  6. void USART_SendString(uint8_t *ch);
  7. void usart_byte(uint8_t ch);
  8. void usart_buf(uint8_t *buf,uint8_t len);
  9. #endif
 楼主| g36xcv 发表于 2023-11-24 00:20 | 显示全部楼层
4、usart.c
  1. #include <usart.h>

  2. //FILE _stdout;
  3. //_sys_exit(int x)
  4. //{
  5. //  x=x;

  6. //}
  7. //int fputc(int ch,FILE *f)
  8. //{
  9. //   while((USART1->SR&0x40)==0);
  10. //        USART1->DR=(u8) ch;
  11. //        return ch;
  12. //}
  13. //int fputc(int ch, FILE *f)
  14. //{
  15. //        while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);  //通过串口把ch给发送出去
  16. //        USART1_SendData(USART1,ch);
  17. //        return ch;
  18. //}



  19. void usart_init(uint32_t bound)
  20. {
  21.    GPIO_InitTypeDef GPIO_InitStructure;
  22.          USART_InitTypeDef USART_InitStructure;
  23.    NVIC_InitTypeDef NVIC_InitStructure;
  24.        
  25.          RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1|RCC_APB2Periph_AFIO,ENABLE);
  26.    
  27.          GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;
  28.          GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
  29.          GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;
  30.          GPIO_Init(GPIOA,&GPIO_InitStructure);
  31.        
  32.          GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;
  33.          GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;;
  34.          GPIO_Init(GPIOA,&GPIO_InitStructure);
  35.        
  36.          USART_InitStructure.USART_BaudRate=bound;
  37.          USART_InitStructure.USART_WordLength=USART_WordLength_8b;
  38.          USART_InitStructure.USART_StopBits=USART_StopBits_1;
  39.          USART_InitStructure.USART_Parity=USART_Parity_No;
  40.          USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
  41.          USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
  42.          USART_Init(USART1,&USART_InitStructure);
  43.          USART_Cmd(USART1,ENABLE);
  44.          USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
  45.          USART_ClearFlag(USART1,USART_FLAG_TC);
  46.          
  47.          NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
  48.          NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn ;
  49.          NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
  50.          NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
  51.          NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
  52.          NVIC_Init(&NVIC_InitStructure);
  53.          
  54. }
  55. void usart_byte(uint8_t ch){
  56.    USART_SendData(USART1,ch);
  57.         while(USART_GetFlagStatus(USART1,USART_FLAG_TXE)==RESET);
  58. }
  59. //void USART_SendString(uint8_t *ch){
  60. //  uint16_t k=0;
  61. //        while(*(ch+k) !='\0'){
  62. //                k++;
  63. //                usart_byte(*(ch+k));
  64. //        }
  65. //}
  66. void USART_SendString(uint8_t *ch){
  67.     while((*ch)!='\0')
  68.                 {
  69.                    usart_byte(*ch++);
  70.                 }
  71. }
  72. void usart_buf(uint8_t *buf,uint8_t len){
  73.    uint16_t i;
  74.         for(i=0;i<len;i++){
  75.             usart_byte(buf[i]);
  76.         }
  77. }
  78. uint16_t usart_rx_buf[8]={0};
  79. uint8_t USART_RX_CNT=0;
  80. /*
  81. void USART1_IRQHandler(void)
  82. {
  83.   if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)//接收中断(接收到的数据必须是0x0d)
  84.         {
  85.                 USART_ClearITPendingBit(USART1,USART_IT_RXNE);
  86.           usart_rx_buf[USART_RX_CNT]=USART_ReceiveData(USART1);//读取接收到的
  87.                 USART_RX_CNT++;         
  88.                    if((usart_rx_buf[USART_RX_CNT-1]=='\r')||(usart_rx_buf[USART_RX_CNT-1]=='\n'))
  89.                                  {
  90.                                           USART_SendString((uint8_t *)usart_rx_buf);
  91.                                           //遇到\r或\n就保存一次数据到队列中
  92.                                           USART_RX_CNT=0;//重新开始接收数据       
  93.                                  }
  94.                                                                    
  95.         }               
  96. }*/

  97. void USART1_IRQHandler(void)
  98. {
  99.         uint16_t  temp;
  100.   if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)//接收中断(接收到的数据必须是0x0d)
  101.         {
  102.           temp = USART_ReceiveData(USART1);//读取接收到的
  103.           usart_byte((uint8_t)temp);       
  104.         }       
  105.         USART_ClearITPendingBit(USART1,USART_IT_RXNE);

  106. }
  107. /*
  108. void USART1_IRQHandler(void)
  109. {
  110.   if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET)//接收中断(接收到的数据必须是0x0d)
  111.         {
  112.                 USART_ClearITPendingBit(USART1,USART_IT_RXNE);
  113.           usart_rx_buf[USART_RX_CNT]=USART_ReceiveData(USART1);//读取接收到的
  114.                 USART_RX_CNT++;
  115.                    if(usart_rx_buf[USART_RX_CNT] == '\0'&&  (USART_RX_CNT >= 7)){
  116.                                    usart_buf((uint8_t *)usart_rx_buf,8);       
  117.                                          //遇到\r或\n就保存一次数据到队列中
  118.                                          USART_RX_CNT=0;//重新开始接收数据
  119.                           }
  120.   }                                
  121. }*///(usart_rx_buf[usart_rx_len-1]=='\r')||(usart_rx_buf[usart_rx_len-1]=='\n')
 楼主| g36xcv 发表于 2023-11-24 00:20 | 显示全部楼层
5、main.c
  1. #include "led.h"
  2. #include "delay.h"
  3. #include "rtc.h"
  4. #include <stm32f10x.h>
  5. #include "usart.h"
  6. #include <stdio.h>

  7. int main(void){
  8.         usart_init(115200);
  9.         printf("串口配置.\r\n");
  10.         led_init();
  11.         printf("led灯配置\r\n");
  12.         USART_SendString("你好\r\n");
  13.         clockinit_RTC();
  14.         printf("This is a RTC test.\r\n");

  15.         while(1){
  16.      Time_Show();
  17.         }
  18. }

 楼主| g36xcv 发表于 2023-11-24 00:20 | 显示全部楼层
9、本实验卡在了等待时钟死循环,也验证不出其他的问题,暂时终止
您需要登录后才可以回帖 登录 | 注册

本版积分规则

38

主题

412

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部