RTC实时时钟
主要特性:
由于RTC实时时钟提供了三种时钟源可供选择(LSI,LSE,HSE) ,一般我们选择低速外部时钟源(32.768KHZ)来作为RTC的时钟源
另外,RTC实时时钟可以由系统主电源供电,但是也可以由备份电源供电(系统主电源不工作时),所以想要使用,就必须打开电源控制器的外设时钟,PWR外设挂载在APB1总线下。
RTC具有闹钟中断以及唤醒中断功能 可以利用RTC的唤醒中断功能用来周期性的产生中断并且获取时间和日期 ,优点是获取的时间精准 精度高
RTC中断
#include "rtc.h"
#include "usart.h"static RTC_TimeTypeDef RTC_TimeStructure;
static RTC_InitTypeDef RTC_InitStructure;
static RTC_AlarmTypeDef RTC_AlarmStructure;
static NVIC_InitTypeDef NVIC_InitStructure;
static EXTI_InitTypeDef EXTI_InitStructure;
static RTC_DateTypeDef RTC_DateStructure;/*RTC APB1初始化配置
*/void rtc_Config(void)
{/* Enable the PWR clock */RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);/* Allow access to RTC */PWR_BackupAccessCmd(ENABLE);/* Enable the LSE OSC */RCC_LSEConfig(RCC_LSE_ON);//等待外部低速振荡器稳定while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);/* Select the RTC Clock Source */RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);/* Enable the RTC Clock */RCC_RTCCLKCmd(ENABLE);/* Wait for RTC APB registers synchronisation */RTC_WaitForSynchro();/* Configure the RTC data register and RTC prescaler */RTC_InitStructure.RTC_AsynchPrediv = 0x7F;RTC_InitStructure.RTC_SynchPrediv = 0xFF;RTC_InitStructure.RTC_HourFormat = RTC_HourFormat_24;RTC_Init(&RTC_InitStructure);/* Set Time hh:mm:ss */RTC_TimeStructure.RTC_H12 = RTC_H12_AM;RTC_TimeStructure.RTC_Hours = 0x14; RTC_TimeStructure.RTC_Minutes = 0x38;RTC_TimeStructure.RTC_Seconds = 0x00;RTC_SetTime(RTC_Format_BCD, &RTC_TimeStructure);/* Set Date Week/Date/Month/Year */RTC_DateStructure.RTC_WeekDay = RTC_Weekday_Thursday;RTC_DateStructure.RTC_Date = 0x26;RTC_DateStructure.RTC_Month = RTC_Month_September;RTC_DateStructure.RTC_Year = 0x12;RTC_SetDate(RTC_Format_BCD, &RTC_DateStructure);/* Write BkUp DR0 */RTC_WriteBackupRegister(RTC_BKP_DR0, 0x32F2);
}/*
函数名:Set_Alarm
功能:RTC 闹钟设置
参数:hou 时 min分 sec秒 date/week日期/星期
描述:包括中断配置闹钟使能*/void Set_Alarm(uint32_t hou,uint32_t min,uint32_t sec,uint32_t date_week)
{/* Enable RTC Alarm A Interrupt *///设置闹钟必须先关闭闹钟RTC_ITConfig(RTC_IT_ALRA, DISABLE);/* Enable the alarm */RTC_AlarmCmd(RTC_Alarm_A, DISABLE);/* Set the alarm 05h:20min:30s */if(hou<0x12)RTC_AlarmStructure.RTC_AlarmTime.RTC_H12 = RTC_H12_AM;elseRTC_AlarmStructure.RTC_AlarmTime.RTC_H12 = RTC_H12_PM;RTC_AlarmStructure.RTC_AlarmTime.RTC_Hours = hou;RTC_AlarmStructure.RTC_AlarmTime.RTC_Minutes = min;RTC_AlarmStructure.RTC_AlarmTime.RTC_Seconds = sec;RTC_AlarmStructure.RTC_AlarmDateWeekDay = date_week;//日期或者星期几闹RTC_AlarmStructure.RTC_AlarmDateWeekDaySel = RTC_AlarmDateWeekDaySel_Date;//按天开始闹钟RTC_AlarmStructure.RTC_AlarmMask = RTC_AlarmMask_DateWeekDay;//屏蔽日期和星期/* Configure the RTC Alarm A register */RTC_SetAlarm(RTC_Format_BCD, RTC_Alarm_A, &RTC_AlarmStructure);/* Enable RTC Alarm A Interrupt */RTC_ITConfig(RTC_IT_ALRA, ENABLE);/* Enable the alarm */RTC_AlarmCmd(RTC_Alarm_A, ENABLE);
}/*闹钟初始化闹钟中断使能*/
void rtc_AlarmConfig(void)
{/* Enable RTC Alarm A Interrupt */RTC_ITConfig(RTC_IT_ALRA, ENABLE);/* Enable the alarm */RTC_AlarmCmd(RTC_Alarm_A, ENABLE);/* Clear the RTC Alarm Flag */RTC_ClearFlag(RTC_FLAG_ALRAF);/* Clear the EXTI Line 17 Pending bit (Connected internally to RTC Alarm) */EXTI_ClearITPendingBit(EXTI_Line17);/* RTC Alarm A Interrupt Configuration *//* EXTI configuration *******************************************************/EXTI_ClearITPendingBit(EXTI_Line17);EXTI_InitStructure.EXTI_Line = EXTI_Line17;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);/* Enable the RTC Alarm Interrupt */NVIC_InitStructure.NVIC_IRQChannel = RTC_Alarm_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);
}/*函数:rtc_init(void)功能:RTC初始化
*/
void rtc_Init(void)
{//检测有没有配置时间if(RTC_ReadBackupRegister(RTC_BKP_DR0) != 0x32F2){rtc_Config();Set_Alarm(0x18,0x00,0x00,0x04);}else{/* Enable the PWR clock */RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);/* Allow access to RTC */PWR_BackupAccessCmd(ENABLE);/* Enable the LSE OSC */RCC_LSEConfig(RCC_LSE_ON);/* Wait till LSE is ready */ while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);/* Select the RTC Clock Source */RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);/* Enable the RTC Clock 使能*/RCC_RTCCLKCmd(ENABLE);/* Wait for RTC APB registers synchronisation 等待寄存器就绪*/RTC_WaitForSynchro();}//关闭WAKE UPRTC_WakeUpCmd(DISABLE); //唤醒时钟选择RTC配置好的时钟RTC_WakeUpClockConfig(RTC_WakeUpClock_CK_SPRE_16bits);//设置WAKE UP自动重装载寄存器,写入零值默认是0+1=1RTC_SetWakeUpCounter(0); //注意:必须添加清空RTC唤醒中断标志位,否则RTC不会触发RTC_ClearITPendingBit(RTC_IT_WUT);/* Enable RTC Wakeup Interrupt ,使能RTC唤醒中断*/RTC_ITConfig(RTC_IT_WUT, ENABLE);/* Enable the Wakeup ,开启RTCWakeup定时器*/RTC_WakeUpCmd(ENABLE);/* EXTI configuration *******************************************************/EXTI_ClearITPendingBit(EXTI_Line22);EXTI_InitStructure.EXTI_Line = EXTI_Line22;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);/* Enable the RTC Wakup Interrupt,使能RTC唤醒中断 */NVIC_InitStructure.NVIC_IRQChannel = RTC_WKUP_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);rtc_AlarmConfig();//初始化闹钟}void RTC_Date_TimeShow(void)
{char buf[128]={0};/* Get the current Time,获取时间 */RTC_GetTime(RTC_Format_BIN, &RTC_TimeStructure);/* Display time Format : 时:分:秒,格式化字符串 */sprintf((char*)buf,"time:%02d:%02d:%02d\r\n",RTC_TimeStructure.RTC_Hours, RTC_TimeStructure.RTC_Minutes, RTC_TimeStructure.RTC_Seconds);//串口发送//printf("%s",buf);//蓝牙发送//USARTx_SendString(USART_BLE, (uint8_t *)buf); RTC_GetDate(RTC_Format_BIN,&RTC_DateStructure);/* Display date Format 年/月/日 星期几,格式化字符串 */sprintf((char*)buf,"date:20%02d/%02d/%02d Week:%d\r\n",RTC_DateStructure.RTC_Year, RTC_DateStructure.RTC_Month, RTC_DateStructure.RTC_Date,RTC_DateStructure.RTC_WeekDay);//串口发送printf("%s",buf);//蓝牙发送//USARTx_SendString(USART_BLE, (uint8_t *)buf); }//RTC WAKE UP中断服务函数
void RTC_WKUP_IRQHandler(void)
{ if(RTC_GetFlagStatus(RTC_FLAG_WUTF)==SET) //WK_UP中断?{ RTC_ClearFlag(RTC_FLAG_WUTF); //清除中断标志} RTC_ClearITPendingBit(RTC_IT_WUT);EXTI_ClearITPendingBit(EXTI_Line22); //清除中断线22的中断标志
}//闹钟中断服务函数
void RTC_Alarm_IRQHandler(void)
{if(RTC_GetITStatus(RTC_IT_ALRA) != RESET){RTC_ClearITPendingBit(RTC_IT_ALRA);EXTI_ClearITPendingBit(EXTI_Line17);}
}/*****************实时时钟任务控制块*************************/
OS_TCB RTC_Task_TCB;CPU_STK RTC_Task_stk[128]; //实时时钟任务的任务堆栈,大小为128字,也就是512字节
void RTC_Task(void *parg);
void RTC_Task(void *parg)
{//CPU_SR_ALLOC(); //申请保护CPU的状态OS_ERR err;OSTimeDlyHMSM(0,0,2,0,OS_OPT_TIME_HMSM_STRICT,&err);while(1){//进入临界区,保护以下的代码//OS_CRITICAL_ENTER();OSSemPend(&SYNC_SEM,0,OS_OPT_PEND_BLOCKING,0,&err); //请求信号量//退出临界区//OS_CRITICAL_EXIT();RTC_Date_TimeShow();OSSemPost(&SYNC_SEM,OS_OPT_POST_1,&err); //发送信号量OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&err); //让出CPU,延时100ms}}
#ifndef __RTC_H
#define __RTC_H
#include "stm32f4xx.h"
#include "includes.h"
extern OS_SEM SYNC_SEM;/*****************实时时钟任务控制块*************************/
extern OS_TCB RTC_Task_TCB;extern void RTC_Task(void *parg);extern CPU_STK RTC_Task_stk[128]; //实时时钟任务的任务堆栈,大小为128字,也就是512字节extern void rtc_Init(void);extern void Set_Alarm(uint32_t hou,uint32_t min,uint32_t sec,uint32_t date_week);
void rtc_Config(void);
void rTC_Date_TimeShow(void);
void rtc_AlarmConfig(void);#endif
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "includes.h"
#include "rtc.h"任务1控制块
//OS_TCB Task1_TCB;//void task1(void *parg);//CPU_STK task1_stk[128]; //任务1的任务堆栈,大小为128字,也就是512字节OS_SEM SYNC_SEM; //定义一个信号量,用于任务同步
//主函数
int main(void)
{//定义一个错误处理对象OS_ERR err;//RTC实时时钟初始化rtc_Init();delay_init(168); //时钟初始化 利用嘀嗒定时器来为操作系统产生周期性的节拍//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断分组配置 uart_init(115200); //串口初始化//OS初始化,它是第一个运行的函数,初始化各种的全局变量,例如中断嵌套计数器、优先级、存储器OSInit(&err); //初始化UCOSIII//创建开始任务//创建任务1,着重填写前8个参数//创建实时时钟任务OSTaskCreate( (OS_TCB *)&RTC_Task_TCB, //任务控制块(CPU_CHAR *)"RTC_Task", //任务的名字(OS_TASK_PTR)RTC_Task, //任务函数(void *)0, //传递参数(OS_PRIO)2, //任务的优先级 (CPU_STK *)RTC_Task_stk, //任务堆栈基地址(CPU_STK_SIZE)128/10, //任务堆栈深度限位,用到这个位置,任务不能再继续使用(CPU_STK_SIZE)128, //任务堆栈大小 (OS_MSG_QTY)0, //禁止任务消息队列(OS_TICK)0, //默认时间片长度 (void *)0, //不需要补充用户存储区(OS_OPT)OS_OPT_TASK_NONE, //没有任何选项&err //返回的错误码);//创建一个信号量,且信号量初值为1,若为0,一开始调用等待信号量就会永远等待下去,不会执行程序。OSSemCreate ((OS_SEM* )&SYNC_SEM,(CPU_CHAR* )"SYNC_SEM",(OS_SEM_CTR)1, (OS_ERR* )&err); OSStart(&err); //启动OS,进行任务调度
}任务1 优先级1
//void task1(void *parg)
//{
// OS_ERR err;
// printf("task1 is create ok\r\n");// while(1)
// {
// printf("task1 is running ...\r\n");
//
// OSTimeDlyHMSM(0,0,1,0,OS_OPT_TIME_HMSM_STRICT,&err); //让出CPU,延时1s
// }
//}