关于RTC的初步认识总结

由于最近项目需要,研究了一下STM32L系列的RTC的基本用法,本人还是小白,还请各位大佬多多指点。

1.首先我们项目的思路是利用RTC的秒中断模式来形成一个S计数器,每秒进一次中断进行标志位判断,在SRAM中进行标志位的判断。如果到达了传感器采集时间。就将标志位置一,执行压力采集。
在SRAM中,累加判断RTC->ISR寄存器是否到达1S,如果是则进行数据清零,从0s开始计时,之后判断任务标志位
注意一点:在SRAM调用的函数必须操作寄存器,只能调用在SRAM中的函数,不能调用Flash中的函数。
if(RTC->ISR & 0x00000100)
{
RTC->ISR &= RTC->ISR & 0xFFFFFEFF;
task_1sec_handler(); //任务标志位判断
}

2.配置S中断执行函数,
注:必须清除EXTI_17和RTC_IT_ALRA ,否则会出现异常
两个函数总都会进行任务标志位的判断(为了更稳定吧~~)
void RTC_Alarm_IRQHandler(void)
{
if(RTC_GetITStatus(RTC_IT_ALRA) != RESET)
{
RTC_ClearITPendingBit(RTC_IT_ALRA);
EXTI_ClearITPendingBit(EXTI_Line17);
task_1sec_handler();
}
}
3.下面就应该说一下任务处理函数了,在任务处理函数中,定义一个变量累加,每进一次任务处理函数,变量加1,当加到规定的数值时,标志位置一,执行任务。
task_struct task_flag;
rt_uint32_t task_sec_cnt = 0;

void task_init(void)
{
task_flag.get = 0;
task_flag.save = 0;
task_flag.upload = 0;
}

void attribute((section(".data")))
task_1sec_handler(void)
{
task_sec_cnt++;
//压力采集标志置位
if(task_sec_cnt % 60 == 0)
// if(cnt % g_gprs_para_conf.ZQ_cgq == 0)
{
task_flag.get = 1;
}
//存储历史数据标志置位
if(task_sec_cnt % 60 == 0)
// if(cnt % g_gprs_para_conf.ZQ_Save == 0)
{
task_flag.save = 1;
}
//周期上传历史数据
if(task_sec_cnt % 600 == 0)
// if(cnt % g_gprs_para_conf.ZO_upload == 0)
{
task_flag.upload = 1;
}
}

uint8_t attribute((section(".data"))) task_has_exec(void)
{
if(task_flag.get)
return 1;
if(task_flag.save)
return 1;
if(task_flag.upload)
return 1;
return 0;
}
当程序累加到60S则会将 task_flag.get = 1; 在下面的函数中在进行判断,如果为真,则返回1.执行函数。

4.RTC的使用的基本流程就是这样,下面说一下RTC初始化的相关配置。
参考ST官方的Demo 的RTC_Timer 模式(秒表)程序
void RTC_Config(void)
{

RTC_InitTypeDef RTC_InitStructure;
RTC_TimeTypeDef RTC_TimeStruct;
RTC_DateTypeDef RTC_DataStruct;
/* Enable the PWR clock */
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);

/* 允许访问 RTC */
PWR_RTCAccessCmd(ENABLE);

/* 使能外部晶振32.768 LSE */
RCC_LSEConfig(RCC_LSE_ON);

/* 使能内部晶振 LSI 40kHZ*/
RCC_LSEConfig(RCC_LSE_ON); //使用内部低速时钟会导致计数不准确,建议使用外部LSE时钟作为时钟源*/

/* Wait till LSE is ready等待LSE准备完成 */
while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)
{
}

/选择RTC的时钟源/
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
或者
RCC_RTCCLKConfig(RCC_RTCCLKSource_LSI);

/*
配置RTC数据寄存器和RTC预分频器*/
RTC_InitStructure.RTC_AsynchPrediv = 128-1;
RTC_InitStructure.RTC_SynchPrediv = 37000/128-1;
RTC_InitStructure.RTC_HourFormat = RTC_HourFormat_24;
RTC_Init(&RTC_InitStructure);
在这里插入图片描述
由参考手册的知,内部的LSI时钟源为3.7Khz

/设置秒表初始化时间为00:00:00/
/* Set the time to 00h 00mn 00s AM */
RTC_TimeStruct.RTC_H12 = RTC_H12_AM;
RTC_TimeStruct.RTC_Hours = 0x00;
RTC_TimeStruct.RTC_Minutes = 0x00;
RTC_TimeStruct.RTC_Seconds = 0x00;

	RTC_DataStruct.RTC_Year = 0;
	RTC_DataStruct.RTC_Month = 1;
	RTC_DataStruct.RTC_Date = 1;
	RTC_DataStruct.RTC_WeekDay = RTC_Weekday_Monday;

RTC_SetTime(RTC_Format_BIN, &RTC_TimeStruct);
RTC_SetTime(RTC_Format_BIN, &RTC_DataStruct);
/* Enable the RTC Clock */
RCC_RTCCLKCmd(ENABLE);

/* Wait for RTC APB registers synchronisation */
RTC_WaitForSynchro();
}

5.RTC中断的配置

void RTC_AlarmConfig(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
RTC_AlarmTypeDef RTC_AlarmStructure;
NVIC_InitTypeDef NVIC_InitStructure;

/* 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);

/* Set the alarmA Masks */
RTC_AlarmStructure.RTC_AlarmMask = RTC_AlarmMask_All;
RTC_SetAlarm(RTC_Format_BIN, RTC_Alarm_A, &RTC_AlarmStructure);

/* Set AlarmA subseconds and enable SubSec Alarm : generate 8 interripts per Second */
RTC_AlarmSubSecondConfig(RTC_Alarm_A, 0xFF, RTC_AlarmSubSecondMask_SS14_5);

/* Enable AlarmA interrupt */
RTC_ITConfig(RTC_IT_ALRA, ENABLE);

/* Enable the alarmA */
RTC_AlarmCmd(RTC_Alarm_A, DISABLE);

}
6.中断配置完之后,配合S中断就可以正常的跑RTC时间。

7.下面说一次设置时间的函数
写时间内和读时间
void rtc_get_time(Rtc_Struct *result)
{
RTC_TimeTypeDef time;
RTC_DateTypeDef date;

RTC_GetTime(RTC_Format_BIN, &time);
RTC_GetDate(RTC_Format_BIN, &date);

result->nHour = time.RTC_Hours;
result->nMin = time.RTC_Minutes;
result->nSec = time.RTC_Seconds;

result->nYear = date.RTC_Year;
result->nMonth = date.RTC_Month;
result->nDay = date.RTC_Date;

}
void rtc_set_time(Rtc_Struct *result)
{
RTC_TimeTypeDef time;
RTC_DateTypeDef date;

rtc_error = RTC_ERR_NONE;

time.RTC_H12 = RTC_H12_AM;
time.RTC_Hours = result->nHour;
time.RTC_Minutes = result->nMin;
time.RTC_Seconds = result->nSec;

date.RTC_Year = result->nYear;
date.RTC_Month = result->nMonth;
date.RTC_Date = result->nDay;
date.RTC_WeekDay = RTC_Weekday_Monday;

if(RTC_SetDate(RTC_Format_BIN,&date) == ERROR)
	rtc_error = RTC_ERR_SET_FAIL;
if(RTC_SetTime(RTC_Format_BIN,&time) == ERROR)
	rtc_error = RTC_ERR_SET_FAIL;

RTC_WriteBackupRegister(RTC_BKP_DR0, 0x32F2);
rtc_state = RTC_STA_NORM;

}
下面就是BCD码和16进制相互转换的函数

rt_uint8_t rtc_bcd2hex(rt_uint8_t bcd_data)
{
return ((bcd_data >> 4) * 10) + (bcd_data & 0x0f);
}

rt_uint8_t rtc_hex2bcd(rt_uint8_t hex_data)
{
return ((hex_data / 10) << 4) | (hex_data % 10);
}

以上基本上就是对RTC的相关总结,第一次写没什么经验,希望在以后的日子中能够多写多练。一步一个脚印,慢慢成长。

你可能感兴趣的:(关于RTC的初步认识总结)