stm32的RTC操作

发布者:平安宁静最新更新时间:2016-10-05 来源: eefocus关键字:stm32  RTC操作 手机看文章 扫描二维码
随时随地手机看文章
分为两个文件:
rtc.c


/*******************************************************************************
* 文件名 :rtc.c
* 描述 :wit_yuan
* 论坛 :
**********************************************************************************/
#include "rtc.h"
#include "stdio.h"
#include "misc.h"
uint8_t const *WEEK_STR[] = {"日", "一", "二", "三", "四", "五", "六"};
uint8_t const *zodiac_sign[] = {"猪", "鼠", "牛", "虎", "兔", "龙", "蛇", "马", "羊", "猴", "鸡", "狗"};

/* 秒中断标志,进入秒中断时置1,当时间被刷新之后清0 */
__IO uint32_t TimeDisplay;
extern struct rtc_time systemtime;
/*
* 函数名:NVIC_Configuration
* 描述 :配置RTC秒中断的主中断优先级为1,次优先级为0
* 输入 :无
* 输出 :无
* 调用 :外部调用
*/
void RTC_NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;

/* Configure one bit for preemption priority */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);

/* Enable the RTC Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = RTC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}

/*
* 函数名:RTC_Configuration
* 描述 :配置RTC
* 输入 :无
* 输出 :无
* 调用 :外部调用
*/
void RTC_Configuration(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
PWR_BackupAccessCmd(ENABLE);
BKP_DeInit();
RCC_LSEConfig(RCC_LSE_ON);
while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
{}
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
RCC_RTCCLKCmd(ENABLE);
RTC_WaitForSynchro();
RTC_WaitForLastTask();
RTC_ITConfig(RTC_IT_SEC, ENABLE);
RTC_WaitForLastTask();
RTC_SetPrescaler(32767);
RTC_WaitForLastTask();
}

/*
* 函数名 :Time_Regulate
* 描述 :返回用户在超级终端中输入的时间值,并将值储存在
* RTC 计数寄存器中。
* 输出 :用户在超级终端中输入的时间值,单位为 s
* 调用 :内部调用
* editted : 2014-07-05
* author : wit_yuan
*/
extern struct rtc_time systemtime;

uint32_t Time_Regulate(struct rtc_time *tm)
{
tm->tm_year = systemtime.tm_year + 2000;
tm->tm_mon = systemtime.tm_mon;
tm->tm_mday = systemtime.tm_mday;
tm->tm_hour = systemtime.tm_hour;
tm->tm_min = systemtime.tm_min;
tm->tm_sec = systemtime.tm_sec;
/* Return the value to store in RTC counter register */
return(((systemtime.tm_hour) * 3600 + (systemtime.tm_min) * 60 + systemtime.tm_sec));
}


/*
* 函数名:Time_Adjust
* 描述 :时间调节
* 输入 :无
* 输出 :无
* 调用 :外部调用
*/
void Time_Adjust(struct rtc_time *tm)
{
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
/* Get time entred by the user on the hyperterminal */
Time_Regulate(tm);

/* Get wday */
GregorianDay(tm);
/* Change the current time */
RTC_SetCounter(mktimev(tm));
/* Wait until last write operation on RTC registers has finished */
RTC_WaitForLastTask();
}


/*
* 函数名:Time_Display
* 描述 :显示当前时间值
* 输入 :-TimeVar RTC计数值,单位为 s
* 输出 :无
* 调用 :内部调用
*/
void Time_Display(uint32_t TimeVar,struct rtc_time *tm)
{
volatile uint32_t THH = 0, TMM = 0, TSS = 0;
uint32_t BJ_TimeVar;
/*把标准时间转换为北京时间*/
BJ_TimeVar =TimeVar + 8*60*60;

to_tm(BJ_TimeVar, tm);/*把定时器的值转换为北京时间*/
}
/*
* 函数名:Time_Show
* 描述 :在超级终端中显示当前时间值
* 输入 :无
* 输出 :无
* 调用 :外部调用
*/
void Time_Show(void)
{

}


uint8_t USART_Scanf(uint32_t value)
{
uint32_t index = 0;
uint32_t tmp[2] = {0, 0};

while (index < 2)
{
while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET)
{}
tmp[index++] = (USART_ReceiveData(USART1));
if ((tmp[index - 1] < 0x30) || (tmp[index - 1] > 0x39))
{
index--;
}
}
index = (tmp[1] - 0x30) + ((tmp[0] - 0x30) * 10);
if (index > value)
{
return 0xFF;
}
return index;
}

void Time_Config(struct rtc_time *tm)
{
if (BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)
{
RTC_Configuration();
Time_Adjust(tm);
BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);
}
else
{
if (RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET)
{
}
else if (RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET)
{
}
RTC_WaitForSynchro();

RTC_ITConfig(RTC_IT_SEC, ENABLE);

RTC_WaitForLastTask();
}
#ifdef RTCClockOutput_Enable
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);
PWR_BackupAccessCmd(ENABLE);
BKP_TamperPinCmd(DISABLE);
BKP_RTCOutputConfig(BKP_RTCOutputSource_CalibClock);
#endif
RCC_ClearFlag();
//Time_Show();
}

/*********************************************************
* funciton : drv_set_time
* description : set the rtc time
* time : 2015-08-22 pm
* author : wit_yuan
***********************************************************/
void drv_set_time(struct rtc_time *tm)
{
RTC_Configuration();
Time_Adjust(tm);
BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);
RCC_ClearFlag();
}

/*********************************************************
* funciton : wit_get_time
* description : get the rtc time
* time : 2015-07-07 am
* author : wit_yuan
***********************************************************/

void drv_get_time(struct rtc_time *tm)
{
uint32_t TimeVar;
//struct rtc_time tm;
uint32_t BJ_TimeVar;
TimeVar = RTC_GetCounter();
*tm = systemtime;
BJ_TimeVar =TimeVar + 8 * 60 * 60;
to_tm(BJ_TimeVar, tm);/*把定时器的值转换为北京时间*/
// printf("%d年%d月%d日 %d时%d分%d秒 \n",tm.tm_year,tm.tm_mon,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec);
// return tm;
}



void RTC_IRQHandler(void)
{
if (RTC_GetITStatus(RTC_IT_SEC) != RESET)
{
RTC_ClearITPendingBit(RTC_IT_SEC);
TimeDisplay = 1;
if (TimeDisplay == 1)
{
TimeDisplay = 0;
}
RTC_WaitForLastTask();
}
}


void init_rtc(void )
{
RTC_NVIC_Configuration();
Time_Config(&systemtime);
}


/*****************************END OF FILE****2015-08-23 guide by wit_yuan**************************/

 
2、date.c

#include "date.h"

#define FEBRUARY 2
#define STARTOFTIME 1970
#define SECDAY 86400L
#define SECYR (SECDAY * 365)
#define leapyear(year) ((year) % 4 == 0)
#define days_in_year(a) (leapyear(a) ? 366 : 365)
#define days_in_month(a) (month_days[(a) - 1])

static int month_days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

/*
* This only works for the Gregorian calendar - i.e. after 1752 (in the UK)
*/
/*计算公历*/
void GregorianDay(struct rtc_time * tm)
{
int leapsToDate;
int lastYear;
int day;
int MonthOffset[] = { 0,31,59,90,120,151,181,212,243,273,304,334 };

lastYear=tm->tm_year-1;

/*计算从公元元年到计数的前一年之中一共经历了多少个闰年*/
leapsToDate = lastYear/4 - lastYear/100 + lastYear/400;
/*如若计数的这一年为闰年,且计数的月份在2月之后,则日数加1,否则不加1*/
if((tm->tm_year%4==0) &&
((tm->tm_year%100!=0) || (tm->tm_year%400==0)) &&
(tm->tm_mon>2)) {
/*
* We are past Feb. 29 in a leap year
*/
day=1;
} else {
day=0;
}
day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + tm->tm_mday ; /*计算从公元元年元旦到计数日期一共有多少天*/

tm->tm_wday=day%7;
}

/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
* Assumes input in normal date format, i.e. 1980-12-31 23:59:59
* => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
*
* [For the Julian calendar (which was used in Russia before 1917,
* Britain & colonies before 1752, anywhere else before 1582,
* and is still in use by some communities) leave out the
* -year/100+year/400 terms, and add 10.]
*
* This algorithm was first published by Gauss (I think).
*
* WARNING: this function will overflow on 2106-02-07 06:28:16 on
* machines were long is 32-bit! (However, as time_t is signed, we
* will already get problems at other places on 2038-01-19 03:14:08)

*ADD by fire:本函数在工程中的输入参数为北京时间,
所以在转换成时间戳时最后要从北京时间转换为标准时间的时间戳
*/
u32 mktimev(struct rtc_time *tm)
{
if (0 >= (int) (tm->tm_mon -= 2)) { /* 1..12 -> 11,12,1..10 */
tm->tm_mon += 12; /* Puts Feb last since it has leap day */
tm->tm_year -= 1;
}

return (((
(u32) (tm->tm_year/4 - tm->tm_year/100 + tm->tm_year/400 + 367*tm->tm_mon/12 + tm->tm_mday) +
tm->tm_year*365 - 719499
)*24 + tm->tm_hour /* now have hours */
)*60 + tm->tm_min /* now have minutes */
)*60 + tm->tm_sec-8*60*60; /* finally seconds */
/*Add by fire: -8*60*60 把输入的北京时间转换为标准时间,
再写入计时器中,确保计时器的数据为标准的UNIX时间戳*/
}

void to_tm(u32 tim, struct rtc_time * tm)
{
register u32 i;
register long hms, day;

day = tim / SECDAY;
hms = tim % SECDAY;
/* Hours, minutes, seconds are easy */
tm->tm_hour = hms / 3600;
tm->tm_min = (hms % 3600) / 60;
tm->tm_sec = (hms % 3600) % 60;
/* Number of years in days */ /*算出当前年份,起始的计数年份为1970年*/
for (i = STARTOFTIME; day >= days_in_year(i); i++) {
day -= days_in_year(i);
}
tm->tm_year = i;
/* Number of months in days left */ /*计算当前的月份*/
if (leapyear(tm->tm_year)) {
days_in_month(FEBRUARY) = 29;
}
for (i = 1; day >= days_in_month(i); i++) { //程序编写时间是2013年8月
day -= days_in_month(i);
}
days_in_month(FEBRUARY) = 28;
tm->tm_mon = i;
/* Days are what is left over (+1) from all that. *//*计算当前日期*/
tm->tm_mday = day + 1;//+ 1; //2013年8月3日修改,实现功能
/*
* Determine the day of week
*/
GregorianDay(tm);

}
 

对外接口:
函数:init_rtc(),drv_set_time(),drv_get_time().
变量:extern struct rtc_time systemtime;
关键字:stm32  RTC操作 引用地址:stm32的RTC操作

上一篇:stm32中AT发送可变短信
下一篇:stm32的DMA空闲中断数据配置

推荐阅读最新更新时间:2024-03-16 15:13

STM32的CubeMX关于串口中断
1、关于串口的初始化函数: MX_USART2_UART_Init()---波特率、奇偶校验等配置 HAL_UART_Init()---会将 huart- RxState = HAL_UART_STATE_READY; HAL_UART_MspInit()---GPIO,中断优先级等配置 2、当需要使用中断接收时需要调用 HAL_UART_Receive_IT()---配置接收的缓冲区指针,数量,huart- RxState = HAL_UART_STATE_BUSY_RX;,最后使能相应中断 3、当中断发生时,执行 HAL_UART_IRQHandler()--判断中断的类
[单片机]
<font color='red'>STM32</font>的CubeMX关于串口中断
关于STM32中Bank、Sector、Page的理解
本文通过对比F1、F4、L4系列的手册数据,浅谈对Bank、Sector、Page相关概念的理解。 以我们常用的STM32F103C8T6为例: 它具有64K的闪存大小,属于中容量产品。 在STM32中文参考手册_V10中,是这样描述嵌入式闪存的: 中容量产品主存储块最大为16x64位,每个存储块划分为128个1K字节的页,对应的表3如下: 在手册随后的擦除和编程相关的描述中: 我们就知道了,STM32F1系列最小擦除粒度为页面(1K),最小写入粒度为半字(2byte)。 再以STM32F4系列为例,这里就不看芯片手册,直接看中文参考手册了: 最小擦除粒度为扇区(最小的16K),最小写入粒度为字节(1b
[单片机]
关于<font color='red'>STM32</font>中Bank、Sector、Page的理解
stm32 霍尔传感器接口
13.3.18 与霍尔传感器的接口 使用高级控制定时器(TIM1或TIM8)产生PWM信号驱动马达时,可以用另一个通用TIMx(TIM2、TIM3、TIM4或TIM5)定时器作为 接口定时器 来连接霍尔传感器,见图93,3个定时器输入脚(CC1、CC2、CC3)通过一个异或门连接到TI1输入通道(通过设置TIMx_CR2寄存器中的TI1S位来选择), 接口定时器 捕获这个信号。 从模式控制器被配置于复位模式,从输入是TI1F_ED。每当3个输入之一变化时,计数器从新从0开始计数。这样产生一个由霍尔输入端的任何变化而触发的时间基准。 接口定时器 上的捕获/比较通道1配置为捕获模式,捕获信号为TRC(见图76)。捕获值反映了两个输入变
[单片机]
<font color='red'>stm32</font> 霍尔传感器接口
STM32时钟RCC详解(二)
一、RCC寄存器介绍: typedef struct { __IO uint32_t CR; __IO uint32_t CFGR; __IO uint32_t CIR; __IO uint32_t APB2RSTR; __IO uint32_t APB1RSTR; __IO uint32_t AHBENR; __IO uint32_t APB2ENR; __IO uint32_t APB1ENR; __IO uint32_t BDCR; __IO uint32_t CSR; #ifdef STM32F10X_CL __IO uint32_t AHBRSTR; __IO uint32_t CFGR2; #
[单片机]
STM32窗口看门狗(警犬)
二、窗口看门狗 独立看门狗主要用来监测硬件,窗口看门狗主用来监测软件。 窗口看门狗通常被用来监测,由外部干扰或不可预见的逻辑条件(程序)造成的应用程序背离正常的运行序列而产生的软件故障。除非递减计数器的值在T6位变成0前被刷新,看门狗电路在达到预置的时间周期时,会产生一个MCU复位。如果在递减计数器达到窗口寄存器值之前刷新控制寄存器中的7位递减计数器值,也会产生MCU复位。这意味着必须在限定的时间窗口内刷新计数器(即喂狗)。 窗口看门狗 (WWDG) 时钟由 APB1 时钟经预分频后提供,通过可配置的时间窗口来检测应用程序非正常的过迟或过早的操作。 1、主要特性 窗口看门狗跟独立看门狗一样,也是一个递减计数器不断的往下
[单片机]
<font color='red'>STM32</font>窗口看门狗(警犬)
STM32之FLASH操作
说到STM32的FLSAH,我们的第一反应是用来装程序的,实际上,STM32的片内FLASH不仅用来装程序,还用来装 芯片 配置、 芯片 ID、自举程序等等。当然, FLASH还可以用来装数据。 自己收集了一些资料,现将这些资料总结了一下,不想看的可以直接调到后面看怎么操作就可以了。 FLASH分类 根据用途,STM32片内的FLASH分成两部分:主存储块、信息块。 主存储块用于存储程序,我们写的程序一般存储在这里。 信息块又分成两部分:系统存储器、选项字节。 系统存储器存储用于存放在系统存储器自举模式下的启动程序(BootLoader),当使用ISP方式加载程序时,就是由这个程序执行。这个区域由芯片厂写入BootLoa
[单片机]
STM32笔记(三)---寄存器映射--BSRR分析
GPIO与引脚区别? GPIO包含在引脚内(引脚内还有电源、晶振等特殊功能引脚),除GPIO拓展内容即为单片机最小系统 GPIO功能如何检索? 通过芯片datasheet中的pin definitions去检索GPIO功能 输出控制 推挽输出(ODR寄存器输出1时推出3.3V/25mA,输出0时拉入GND) 开漏输出(只能输出低电平,开漏时P-MOS不工作,N-MOS工作;开漏输出就是不输出电压,控制输出低电平时引脚接地,控制输出高电平时引脚既不输出高电平,也不输出低电平,为高阻态。如果外接上拉电阻,则在输出高电平时电压会拉到上拉电阻的电源电压。这种方式适合在连接的外设电压比单片机电压低的时候。) 补充说
[单片机]
<font color='red'>STM32</font>笔记(三)---寄存器映射--BSRR分析
ST吸引Linux用户使用STM32微控制器免费开发嵌入式应用
意法半导体(STMicroelectronics,简称ST)为包括工程师、学者和业余爱好者等在内的Linux 系统用户拓展了使用广受欢迎的意法半导体STM32微控制器免费开发应用的机会。 大多数Linux发行版都是免费使用的,开源应用软件让技术发烧友对Linux着迷。不过,此前市面上常见的嵌入式计算技术开发工具多数只支持Windows PC平台。 现在,STM32CubeMX配置器及初始化工具和System Workbench for STM32(由Ac6 Tools公司开发的集成开发环境(IDE),得到openSTM32.org社区的支持、可在www.st.com/sw4stm32上下载)已经上市并都能在Linux操
[嵌入式]
ST吸引Linux用户使用<font color='red'>STM32</font>微控制器免费开发嵌入式应用
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

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

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved