一种可行的STM32F103外设RTC使用方法

2019-07-19来源: eefocus关键字:STM32F103  外设RTC  使用方法

前言

最近做的项目需要用RTC功能,记录掉上电时间。然后就开始琢磨STM32的RTC,在使用的过程中出现各种问题。搞的很是头痛。几经折腾,终于弄出一种稳定的使用方法。刚开始最大的问题就是掉电后时钟不走,代码改来该去,最后发现不管是第一次初始化还是每次上电运行,都需要打开PWR和BKP时钟。下面就把我的代码全贴出来,可以直接调用。


代码

#ifndef BSP_RTC_H

#define BSP_RTC_H


#include "stm32f10x.h"

#include

//BCD码表示时间

typedef struct systemtime_tag

{

    unsigned char year;

    unsigned char month;

    unsigned char day;

    unsigned char hour;

    unsigned char minute;

    unsigned char second;

}SystemTime_Type;



void bsp_RTC_Init(void);//RTC初始化


void Time_SetUnixTime(time_t t);//将给定的unix时间戳写入RTC


u32 Time_GetUnixTime(void);//从RTC取当前unix 时间格式值


struct tm Time_ConvUnixToCalendar(time_t t);//转换unix时间戳为日历时间


u32 Time_ConvCalendarToUnix(struct tm t);//将给定的公元格式时间转换为unix时间戳


void Time_SetCalendarTime(struct tm t);//设置当前日历时间


void SetSysTime(SystemTime_Type time);//设置系统时间


void GetSysTime(SystemTime_Type* sys_time);//获取系统时间


uint8_t RTC_ByteToBcd2(uint8_t Value);//1字节转BCD码


uint8_t RTC_Bcd2ToByte(uint8_t Value);//BCD码转字节

#endif

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

RTC初始化时要写一个备份寄存器的标志位,以便容易识别是否是第一次初始化。rtc只需要初始化一次就可以了。当然也可以写一个标志在FLASH中,同样的作为初始化标志。该时间换算,使用的是unix系统时间戳。具体的介绍可以百度一下。该换算的时间没有星期几表示。因为我不需要这个显示,也就没有定义它。


#include "bsp_rtc.h"



void bsp_RTC_Init(void)

{

  SystemTime_Type time={0x17,0x06,0x22,0x15,0x10,0x00};


    if(BKP_ReadBackupRegister(BKP_DR1)!=0xAA55)

    {

        RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP| RCC_APB1Periph_PWR,ENABLE);


        PWR_BackupAccessCmd(ENABLE);//使能RTC和后备寄存器访问


        BKP_DeInit();//

        RCC_LSEConfig(RCC_LSE_ON);//启动外部低速晶振

        while(RCC_GetFlagStatus(RCC_FLAG_LSERDY)==RESET);//等待外部低速晶振重启

        RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);

        RCC_RTCCLKCmd(ENABLE); //使能RTC时钟

        RTC_WaitForSynchro(); //等待RTC寄存器同步完成

        RTC_WaitForLastTask(); //等待最后一次对RTC的寄存器写操作完成

        RTC_ITConfig(RTC_IT_SEC,ENABLE); //使能秒中断

        RTC_WaitForLastTask();

        RTC_SetPrescaler(32767);//设置RTC时钟分频值

        RTC_WaitForLastTask();      


        SetSysTime(time);//初始化系统时钟


        BKP_WriteBackupRegister(BKP_DR1, 0xAA55);//目的是标识是否是第一次配置

    }

    else

    {


        RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP| RCC_APB1Periph_PWR,ENABLE);


        /* Wait for RTC registers synchronization */

        RTC_WaitForSynchro();


        /* Enable the RTC Second */

        RTC_ITConfig(RTC_IT_SEC, ENABLE);

        /* Wait until last write operation on RTC registers has finished */

        RTC_WaitForLastTask();      

    }   


  PWR_BackupAccessCmd(ENABLE);//

  /* Clear reset flags */

  RCC_ClearFlag();

}


/*******************************************************************************

 ******************************************************************************/

void Time_SetUnixTime(time_t t)

{   

  RTC_WaitForLastTask();

  RTC_EnterConfigMode();

    RTC_SetCounter((u32)t);

    RTC_WaitForLastTask();

    return ;

}

/*******************************************************************************

 ******************************************************************************/

u32 Time_GetUnixTime(void)

{

    return (u32)RTC_GetCounter();

}

/*******************************************************************************

 ******************************************************************************/

struct tm Time_ConvUnixToCalendar(time_t t)

{

    struct tm* t_tm;

    t_tm=localtime(&t);

    t_tm->tm_year +=1900;

    return *t_tm;

}

/*******************************************************************************

 ******************************************************************************/

u32 Time_ConvCalendarToUnix(struct tm t)

{

    t.tm_year -= 1900;

    return mktime(&t);

}

/*******************************************************************************

 ******************************************************************************/

void Time_SetCalendarTime(struct tm t)

{

    u32 tm;

    tm=Time_ConvCalendarToUnix(t);

    Time_SetUnixTime(tm);

}


void SetSysTime(SystemTime_Type time)

{

    struct tm unix_time={0};


    unix_time.tm_year=RTC_Bcd2ToByte(time.year)+2000;//转换unix时间

    unix_time.tm_mon =RTC_Bcd2ToByte(time.month)-1;//time.h中定义的month是以0开始计算

    unix_time.tm_mday=RTC_Bcd2ToByte(time.day);

    unix_time.tm_hour=RTC_Bcd2ToByte(time.hour);

    unix_time.tm_min =RTC_Bcd2ToByte(time.minute);

    unix_time.tm_sec =RTC_Bcd2ToByte(time.second);


    Time_SetCalendarTime(unix_time);

}


void GetSysTime(SystemTime_Type* sys_time)

{

    u32 CurrenTime=0;

    struct tm time_now={0};


    CurrenTime=Time_GetUnixTime();

    time_now=Time_ConvUnixToCalendar(CurrenTime);


    sys_time->year  =RTC_ByteToBcd2(time_now.tm_year%2000);//转换unix时间

    sys_time->month =RTC_ByteToBcd2((uint8_t)time_now.tm_mon+1);//time.h中定义的month是以0开始计算

    sys_time->day   =RTC_ByteToBcd2((uint8_t)time_now.tm_mday);

    sys_time->hour  =RTC_ByteToBcd2((uint8_t)time_now.tm_hour);

    sys_time->minute=RTC_ByteToBcd2((uint8_t)time_now.tm_min);

    sys_time->second=RTC_ByteToBcd2((uint8_t)time_now.tm_sec);

}


/**

  * @brief  Converts a 2 digit decimal to BCD format.

  * @param  Value: Byte to be converted.

  * @retval Converted byte

  */

uint8_t RTC_ByteToBcd2(uint8_t Value)

{

  uint8_t bcdhigh = 0;


  while (Value >= 10)

  {

    bcdhigh++;

    Value -= 10;

  }


  return  ((uint8_t)(bcdhigh << 4) | Value);

}


/**

  * @brief  Convert from 2 digit BCD to Binary.

  * @param  Value: BCD value to be converted.

  * @retval Converted word

  */

uint8_t RTC_Bcd2ToByte(uint8_t Value)

{

  uint8_t tmp = 0;

  tmp = ((uint8_t)(Value & (uint8_t)0xF0) >> (uint8_t)0x4) * 10;

  return (tmp + (Value & (uint8_t)0x0F));

}



秒中断时,要更新时间结构体。device.SysTime改成你自己的变量名。系统时间就保存在这里


void RTC_IRQHandler(void) 

{

     if(RTC_GetITStatus(RTC_IT_SEC)!=RESET)//秒中断

     {

        RTC_ClearITPendingBit(RTC_IT_SEC);

        RTC_WaitForLastTask();

        GetSysTime(&device.SysTime);

    }

      if(RTC_GetITStatus(RTC_IT_ALR)!=RESET)//闹钟中断

      {

        RTC_ClearITPendingBit(RTC_IT_ALR);

      }

}


关键字:STM32F103  外设RTC  使用方法 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic468573.html 本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:RT-Thread的STM32系列外设驱动添加 ---- 以PWM外设为例
下一篇:STM32总结之开启外设时钟

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

stm32入门——跑马灯(基于stm32f103zet6)
的驱动都要使能相应的时钟,首先看stm32系统的时钟框图经查阅资料可知,GPIO的时钟在APB2的外设时钟使能寄存器上,相关函数的定义在stm32f10x_rcc.h中 void   RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)其源代码为:void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState){  /* Check the parameters */ //检查值的有效性&nbs
发表于 2019-10-21
stm32入门——跑马灯(基于stm32f103zet6)
stm32入门——跑马灯(基于stm32f103zet6)
的驱动都要使能相应的时钟,首先看stm32系统的时钟框图经查阅资料可知,GPIO的时钟在APB2的外设时钟使能寄存器上,相关函数的定义在stm32f10x_rcc.h中 void   RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)其源代码为:void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState){  /* Check the parameters */ //检查值的有效性&nbs
发表于 2019-10-21
stm32入门——跑马灯(基于stm32f103zet6)
STM32F103流水灯实验
#include "led.h"//初始化PB5和PE5为输出口.并使能这两个口的时钟     //LED IO初始化void LED_Init(void){  GPIO_InitTypeDef  GPIO_InitStructure;  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOD, ENABLE); //使能PB,PE端口时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8
发表于 2019-10-19
STM32F4 SPI2初始化及收发数据【使用库函数】
我的STM32F4 Discovery上边有一个加速度传感器LIS302DL。在演示工程中,ST的工程师使用这个传感器做了个很令人羡慕的东西:解算开发板的姿态。当开发板倾斜时候,处于最上边的LED点亮,其他LED不亮。同时,用MicroUSB数据线将开发板连接电脑时,开发板就会虚拟成一个鼠标。倾斜开发板时,鼠标指针会向倾斜的方向移动。归根结底,就是牛B的ST工程师用加速度传感器完成了姿态解算。在开发板上,加速度传感器使用了SPI方式用STM32F4芯片进行通信。STM32F4的SPI1 作为主机,与LIS302Dl进行通信,读取或者写入数据。由于我没有使用过STM32的SPI口,因此在板子的空余资源中找到了SPI2接口来做实验
发表于 2019-10-19
使用STM32CubeMX,生成STM32F103ZE SPI3 HAL 工程
1,选择芯片型号为STM32F103ZET6,开始工程,引脚配置如下:主要是RCC,SPI3,和SYS三个模块2,时钟配置,可按下图进行:3,SPI3配置,如下图,配完这一步其它可以不管,直接生成工程。4,生成工程,打开工程手动输入红框中内容。运行:成功输出波形。
发表于 2019-10-18
使用STM32CubeMX,生成STM32F103ZE SPI3 HAL 工程
STM32F103xC 之 SPI 引脚分解
芯片:STM32F103RCT6 (64pin ,256K ,LQFP ,-40~85)对象:spiSPI1连接在APB2总线上;SPI2/3连接在APB1总线上;串行外设接口(SPI)在全双工和单工通信模式下,多达三个SPI能够在从属模式和主模式下以高达18 Mbits / s的速度进行通信。 3位预分频器提供8个主模式频率,并且帧可配置为8位或16位。 硬件CRC生成/验证支持基本的SD卡/ MMC模式。所有SPI都可以由DMA控制器提供服务。内部集成I2S两个标准的I2S接口(与SPI2和SPI3复用)可用,可以在主模式或从模式下运行。 这些接口可以配置为以16/32位分辨率工作,作为输入或输出通道。 支持8 kHz至48
发表于 2019-10-18
小广播
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2019 EEWORLD.com.cn, Inc. All rights reserved