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;
else
RTC_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 UP
RTC_WakeUpCmd(DISABLE);
//唤醒时钟选择RTC配置好的时钟
RTC_WakeUpClockConfig(RTC_WakeUpClock_CK_SPRE_16bits);
//设置WAKE UP自动重装载寄存器,写入零值默认是0+1=1
RTC_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
// }
//}