关闭

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

标签: stm32rtc
602人阅读 评论(0) 收藏 举报
分类:

前言

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

代码

#ifndef BSP_RTC_H
#define BSP_RTC_H

#include "stm32f10x.h"
#include <time.h>
//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

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);
      }
}
0
0
查看评论
发表评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场

STM32外设使用要点

1、时钟安全系统(CSS)     时钟安全系统被激活后,时钟监控器将实时监控外部高速振荡器;如果HSE时钟发生故障,外部振荡器自动被关闭,产生时钟安全中断,该中断被连接到Cortex-M3的NMI...
  • lookedsky
  • lookedsky
  • 2015-09-19 17:39
  • 1332

stm32f103 RTC周期性待机唤醒(一)

转载于http://blog.csdn.net/u011732167/article/details/50958520 今天终于发现问题出在哪里了,对待机唤醒的问题做一个总结(只针对我遇到的问题...
  • android_lover2014
  • android_lover2014
  • 2016-04-05 19:51
  • 718

STM32F103系列RTC晶振问题解决记录

我从2014年开始使用STM32内部RTC用于产品,之前出现过很多问题,也换过很多晶振,比如按照ST推荐的6pF晶振,也出现很多问题,贴片的很贵的那种也用过几种,都不行,查询了一些晶振启振的资料,最后...
  • cp1300
  • cp1300
  • 2017-07-14 10:01
  • 1170

STM32 RTC实时时钟

今天是周天,哈尔滨阴天转阵雨。。博主原本准备今天去逛街的。原因你懂的→_→ 接下来进入今天的正题(博主用的是战舰STM32库函数版):博主今天将会和大家讨论两个知识点:       一、RTC时钟框图...
  • HouQi02
  • HouQi02
  • 2016-05-15 13:35
  • 9528

stm32f103 RTC周期性待机唤醒(一)

做一个低功耗的东西,搞了好几天,程序一直卡在一个地方(见下图),今天终于发现问题出在哪里了,对待机唤醒的问题做一个总结(只针对我遇到的问题,其他部分网上都有,基于stm32f103) 1、解决我遇...
  • u011732167
  • u011732167
  • 2016-03-22 22:16
  • 7563

stm32 RTC时钟配置

stm32——RTC实时时钟 一、关于时间   2038年问题   在计算机应用上,2038年问题可能会导致某些软件在2038年无法正常工作。所有使用UNIX时间表示时间的程序都将将...
  • HardessGod
  • HardessGod
  • 2017-03-15 16:03
  • 1243

关于STM32使用RTC唤醒停止模式的设置

工程中用到低功耗的控制,本来想使用待机模式,后来发现待机后所有IO口为高阻态,这样对于一些IO口控制的外设有些不妥,想过外部上拉一个电阻可是功耗不好控制放弃该方案选用停止模式。停止模式后IO口保持停止...
  • louyangyang91
  • louyangyang91
  • 2016-03-07 19:06
  • 8795

STM32 RTC掉电不走时

今天调试RTC使用LSI调试,后来改外部晶振不起振。可是使用内部晶振使用后备电池又不走时。网上找到答案 http://blog.chinaunix.net/uid-27106528-id-42885...
  • diyer_zhou
  • diyer_zhou
  • 2015-03-06 22:35
  • 3656

使用STM32 HAL库读取RTC时间芯片SD3088

美信的RTC芯片看起来不错,但是贵。 威帆的这个不错,而且还可以给电池充电,便宜很多,淘宝上价格6元一片。我这项目对时间要求严格,就不使用1元多的芯片了。 网传STM32F1的I2C有Bug,模拟...
  • fengyu09
  • fengyu09
  • 2015-12-02 10:45
  • 3464

zynq-7000系列基于7015的linux下IIC->RTC的扩展使用(DS3232)

zynq-7000系列基于7015的linux下IIC->RTC的扩展使用(DS3232)                            ...
  • luhao806
  • luhao806
  • 2017-03-06 08:43
  • 620
    个人资料
    • 访问:14052次
    • 积分:224
    • 等级:
    • 排名:千里之外
    • 原创:8篇
    • 转载:0篇
    • 译文:0篇
    • 评论:9条
    文章分类
    最新评论