怎么咨询网络服务商,深圳网站建设制作优化,开发公司对施工单位管理措施,县级网站建设一、RTC振荡器
PY32F003F18实时时钟的振荡器是内部RC振荡器#xff0c;频率为32.768KHz。它也可以使用HSE时钟#xff0c;不建议使用。HAL库提到LSE振荡器#xff0c;但PY32F003F18实际上没有这个振荡器。
缺点#xff1a;CPU掉电后#xff0c;需要重新配置RTC#xff…一、RTC振荡器
PY32F003F18实时时钟的振荡器是内部RC振荡器频率为32.768KHz。它也可以使用HSE时钟不建议使用。HAL库提到LSE振荡器但PY32F003F18实际上没有这个振荡器。
缺点CPU掉电后需要重新配置RTC这个确实不太友好有点像是鸡肋在要求不严格的场合凑合使用吧。
RTC时钟框图如下 二、RTC的HAL库有一个不是很严重的bug PY32F003F18的HAL库润年函数中有一个BUG不是很严重因为2400年是一个闰年它把年定义为字节型变量是没有办法分辨出是不是闰年。
闰年的计算方法年数能被4整除但不能被100年整除为闰年若年数能400年整除也为闰年。
HAL库确实不大好它喜欢用全局变量来实现其功能让人受不了。我改了让它适合自己需要的。HAL处的好处就是我们可以从中抠出自己需要的部分修修改改就可以了比HAL库的灵活多了。时刻不忘黑它一把因为人云亦云的人太多了。
三、非完全HAL库测试程序
如果你觉得HAL库就用HAL中的程序也是可以的。
#include RTC.h
#include LED.h
#include stdio.h //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()uint8_t Century;//世纪,21世纪用20表示
RTC_DateTypeDef RTC_DateStructureure;//用来保存读到的年月日
RTC_TimeTypeDef RTC_TimeStructureure;//用来保存读到的时分秒
RTC_AlarmTypeDef RTC_AlarmStructureure;void RTC_Init(void);
void RTC_Display(void);//函数功能:读RTC计数寄存器
uint32_t Read_RTC_Time_Counter(void)
{uint16_t high1 0U, high2 0U, low 0U;uint32_t timecounter 0U;high1 READ_REG(RTC-CNTH RTC_CNTH_RTC_CNT);//读RTC计数寄存器高位RTC_CNTHlow READ_REG(RTC-CNTL RTC_CNTL_RTC_CNT);//读RTC计数寄存器低位RTC_CNTLhigh2 READ_REG(RTC-CNTH RTC_CNTH_RTC_CNT);//读RTC计数寄存器高位RTC_CNTHif (high1 ! high2){//读RTC计数寄存器低位RTC_CNTL时,发现RTC计数寄存器高位RTC_CNTH中的数据发生改变了//In this case the counter roll over during reading of CNTL and CNTH registers,//read again CNTL register then return the counter valuetimecounter (((uint32_t) high2 16U) | READ_REG(RTC-CNTL RTC_CNTL_RTC_CNT));}else{//No counter roll over during reading of CNTL and CNTH registers, //counter value is equal to first value of CNTL and CNTHtimecounter (((uint32_t) high1 16U) | low);}return timecounter;
}//函数功能:
//等待RTC写操作结束
//返回0,表示退出RTC配置模式,开始更新RTC寄存器
HAL_StatusTypeDef Enter_RTC_Init_Mode(void)
{uint32_t tickstart 0U;tickstart HAL_GetTick();/* Wait till RTC is in INIT state and if Time out is reached exit */while ( (RTC-CRL RTC_CRL_RTOFF) (uint32_t)RESET ){//读RTC控制寄存器RTC_CRL中的RTOFF,若RTOFF0,则上一次对RTC寄存器的写操作仍在进行if ((HAL_GetTick() - tickstart) RTC_TIMEOUT_VALUE){//RTC_TIMEOUT_VALUE2000,最大等待时间为2000msreturn HAL_TIMEOUT;}}_HAL_RTC_WRITEPROTECTION_DISABLE(RTC);//将RTC控制寄存器RTC_CRL中的CNF0,退出配置模式,开始更新RTC寄存器//Disable the write protection for RTC registersreturn HAL_OK;
}//函数功能:
//等待RTC写操作结束
//返回0,表示RTC写操作结束
HAL_StatusTypeDef Exit_RTC_Init_Mode(void)
{uint32_t tickstart 0U;_HAL_RTC_WRITEPROTECTION_ENABLE(RTC);//将RTC控制寄存器RTC_CRL中的CNF1,进入RTC配置模式tickstart HAL_GetTick();while ((RTC-CRL RTC_CRL_RTOFF) RTC_CRL_RTOFF){//读RTC控制寄存器RTC_CRL中的RTOFF,若RTOFF1,则上一次对RTC寄存器的写操作已经完成if ((HAL_GetTick() - tickstart) RTC_RTOFF_RESET_TIMEOUT_VALUE){//RTC_RTOFF_RESET_TIMEOUT_VALUE4,最大等待时间为4msbreak;}}tickstart HAL_GetTick();while ((RTC-CRL RTC_CRL_RTOFF) (uint32_t)RESET){//读RTC控制寄存器RTC_CRL中的RTOFF,若RTOFF0,则上一次对RTC寄存器的写操作仍在进行if ((HAL_GetTick() - tickstart) RTC_TIMEOUT_VALUE){//RTC_TIMEOUT_VALUE2000,最大等待时间为2000msreturn HAL_TIMEOUT;}}return HAL_OK;
}//函数功能:将TimeCounter写入RTC计数寄存器
HAL_StatusTypeDef Write_RTC_Time_Counter( uint32_t TimeCounter )
{HAL_StatusTypeDef status HAL_OK;if (Enter_RTC_Init_Mode() ! HAL_OK){//等待RTC写操作结束//返回0,表示退出RTC配置模式,开始更新RTC寄存器status HAL_ERROR;}else{WRITE_REG(RTC-CNTH, (TimeCounter 16U));//写RTC计数寄存器高位RTC_CNTH//Set RTC COUNTER MSB wordWRITE_REG(RTC-CNTL, (TimeCounter RTC_CNTL_RTC_CNT));//写RTC计数寄存器低位RTC_CNTL//Set RTC COUNTER LSB wordif (Exit_RTC_Init_Mode() ! HAL_OK){//等待RTC写操作结束status HAL_ERROR;}}return status;
}//函数功能:读RTC闹钟寄存器
uint32_t Read_RTC_Alarm_Counter(void)
{uint16_t high1 0U, low 0U;high1 READ_REG(RTC-ALRH RTC_CNTH_RTC_CNT);//读RTC闹钟寄存器高位RTC_ALRHlow READ_REG(RTC-ALRL RTC_CNTL_RTC_CNT);//读RTC闹钟寄存器低位RTC_ALRLreturn (((uint32_t) high1 16U) | low);
}//函数功能:将AlarmCounter写入RTC闹钟寄存器
HAL_StatusTypeDef Write_RTC_Alarm_Counter( uint32_t AlarmCounter)
{HAL_StatusTypeDef status HAL_OK;/* Set Initialization mode */if (Enter_RTC_Init_Mode() ! HAL_OK){//等待RTC写操作结束//返回0,表示退出RTC配置模式,开始更新RTC寄存器status HAL_ERROR;}else{WRITE_REG(RTC-ALRH, (AlarmCounter 16U));//写RTC闹钟寄存器高位RTC_ALRH,Set RTC COUNTER MSB wordWRITE_REG(RTC-ALRL, (AlarmCounter RTC_ALRL_RTC_ALR));//写RTC闹钟寄存器低位RTC_ALRL,Set RTC COUNTER LSB word/* Wait for synchro */if (Exit_RTC_Init_Mode() ! HAL_OK){//等待RTC写操作结束status HAL_ERROR;}}return status;
}//函数功能:返回0表示闰年
uint8_t Is_LeapYear(uint16_t nYear)
{uint16_t y;yCentury;//2023年9月26日yy*100;//2023年9月26日nYearynYear;//2023年9月26日if ((nYear % 4U) ! 0U){return 0U;}if ((nYear % 100U) ! 0U){return 1U;}if ((nYear % 400U) 0U){return 1U;}else{return 0U;}
}//函数功能;读取星期几的值
uint8_t Read_RTC_WeekDay(uint32_t nYear, uint8_t nMonth, uint8_t nDay)
{uint32_t year 0U, weekday 0U;year 2000U nYear;if (nMonth 3U){/*D { [(23 x month)/9] day 4 year [(year-1)/4] - [(year-1)/100] [(year-1)/400] } mod 7*/weekday (((23U * nMonth) / 9U) nDay 4U year ((year - 1U) / 4U) - ((year - 1U) / 100U) ((year - 1U) / 400U)) % 7U;}else{/*D { [(23 x month)/9] day 4 year [year/4] - [year/100] [year/400] - 2 } mod 7*/weekday (((23U * nMonth) / 9U) nDay 4U year (year / 4U) - (year / 100U) (year / 400U) - 2U) % 7U;}return (uint8_t)weekday;
}void Update_RTC_Date(RTC_DateTypeDef *update_RTCDate, uint32_t DayElapsed)
{uint32_t year 0U, month 0U, day 0U;uint32_t loop 0U;/* Get the current year*/year update_RTCDate-Year;/* Get the current month and day */month update_RTCDate-Month;day update_RTCDate-Date;for (loop 0U; loop DayElapsed; loop){if ((month 1U) || (month 3U) || (month 5U) || (month 7U) || \(month 8U) || (month 10U) || (month 12U)){if (day 31U){day;}/* Date structure member: day 31 */else{if (month ! 12U){month;day 1U;}/* Date structure member: day 31 month 12 */else{month 1U;day 1U;year;}}}else if ((month 4U) || (month 6U) || (month 9U) || (month 11U)){if (day 30U){day;}/* Date structure member: day 30 */else{month;day 1U;}}else if (month 2U){if (day 28U){day;}else if (day 28U){if (Is_LeapYear(year))//不闰年{//返回0表示闰年day;}else //闰年{month;day 1U;}}else if (day 29U){month;day 1U;}}}if(year100)//2023年9月26日{Century;yearyear-100;}/* Update year */update_RTCDate-Year year;/* Update day and month */update_RTCDate-Month month;update_RTCDate-Date day;/* Update day of the week */update_RTCDate-WeekDay Read_RTC_WeekDay(year, month, day);//读取星期几的值
}HAL_StatusTypeDef Read_RTC_Time(RTC_DateTypeDef *update_RTCDate, RTC_TimeTypeDef *sTime)
{uint32_t counter_time 0U, counter_alarm 0U, days_elapsed 0U, hours 0U;counter_time Read_RTC_Time_Counter();//读RTC计数寄存器,总秒数hours counter_time / 3600U;//计算有多少小时sTime-Minutes (uint8_t)((counter_time % 3600U) / 60U);//计算分钟数值sTime-Seconds (uint8_t)((counter_time % 3600U) % 60U);//计算秒数值if (hours 24U){days_elapsed (hours / 24U);//计算天sTime-Hours (hours % 24U);//计算今天的小时时间counter_alarm Read_RTC_Alarm_Counter();//读RTC闹钟寄存器//Read Alarm counter in RTC registers/* Calculate remaining time to reach alarm (only if set and not yet expired)*/if ((counter_alarm ! 0xFFFFFFFF) (counter_alarm counter_time)){//RTC_ALARM_RESETVALUE0xFFFFFFFFUcounter_alarm - counter_time;//计算距离报警时间的差值}else{/* In case of counter_alarm counter_time *//* Alarm expiration already occurred but alarm not deactivated */counter_alarm 0xFFFFFFFF;//RTC_ALARM_RESETVALUE0xFFFFFFFFU}/* Set updated time in decreasing counter by number of days elapsed */counter_time - (days_elapsed * 24U * 3600U);//计算今天的总秒数/* Write time counter in RTC registers */if (Write_RTC_Time_Counter(counter_time) ! HAL_OK){//将今天的总秒数counter_time写入RTC计数寄存器return HAL_ERROR;}/* Set updated alarm to be set */if (counter_alarm ! 0xFFFFFFFF){//RTC_ALARM_RESETVALUE0xFFFFFFFFUcounter_alarm counter_time;//报警时间 距离报警时间的差值 今天的总秒数if (Write_RTC_Alarm_Counter(counter_alarm) ! HAL_OK){//将AlarmCounter写入RTC闹钟寄存器return HAL_ERROR;}}else{/* Alarm already occurred. Set it to reset values to avoid unexpected expiration */if (Write_RTC_Alarm_Counter(counter_alarm) ! HAL_OK){//将AlarmCounter写入RTC闹钟寄存器return HAL_ERROR;}}/* Update date */Update_RTC_Date(update_RTCDate, days_elapsed);}else{sTime-Hours hours;}return HAL_OK;
}HAL_StatusTypeDef Read_RTC_Date(RTC_DateTypeDef *update_RTCDate,RTC_DateTypeDef *sDate)
{RTC_TimeTypeDef stime {0U};/* Call HAL_RTC_GetTime function to update date if counter higher than 24 hours */if (Read_RTC_Time(update_RTCDate, stime) ! HAL_OK){return HAL_ERROR;}/* Fill the structure fields with the read parameters */sDate-WeekDay update_RTCDate-WeekDay;sDate-Year update_RTCDate-Year;sDate-Month update_RTCDate-Month;sDate-Date update_RTCDate-Date;return HAL_OK;
}void RTC_Init(void)
{RTC_HandleTypeDef RTC_HandleStructureure;RCC_OscInitTypeDef RCC_OscInit_Structureure;RCC_PeriphCLKInitTypeDef PeriphClkInit_Structureure;Century20;//世纪,21世纪用20表示RTC_HandleStructureure.Instance RTC; //选择RTCRTC_HandleStructureure.Init.AsynchPrediv RTC_AUTO_1_SECOND; //RTC一秒时基自动计算//HAL_RTC_MspInit函数开始//RCC_OscInit_Structureure.OscillatorType RCC_OSCILLATORTYPE_LSI;RCC_OscInit_Structureure.LSIState RCC_LSI_ON;HAL_RCC_OscConfig(RCC_OscInit_Structureure);PeriphClkInit_Structureure.PeriphClockSelection RCC_PERIPHCLK_RTC;PeriphClkInit_Structureure.RTCClockSelection RCC_RTCCLKSOURCE_LSI;HAL_RCCEx_PeriphCLKConfig(PeriphClkInit_Structureure);__HAL_RCC_RTCAPB_CLK_ENABLE();//使能RTC APB外部设备时钟,Enable RTC peripheral Clocks__HAL_RCC_RTC_ENABLE();//使能RTC时钟,Enable RTC ClockHAL_NVIC_SetPriority(RTC_IRQn, 0x01, 0);//设置RTC中断优先级为0x01,0无意义NVIC_EnableIRQ(RTC_IRQn);//使能RTC中断__HAL_RTC_OVERFLOW_ENABLE_IT(RTC_HandleStructureure, RTC_IT_OW);//使能溢出中断,Overflow interrupt__HAL_RTC_ALARM_ENABLE_IT(RTC_HandleStructureure, RTC_IT_ALRA);//使能报警中断,Alarm interrupt__HAL_RTC_SECOND_ENABLE_IT(RTC_HandleStructureure, RTC_IT_SEC);//使能秒中断,Second interrupt
//HAL_RTC_MspInit函数结束//HAL_RTC_Init(RTC_HandleStructureure);//RTC初始化/设置日期: 2023/9/27 星期三/RTC_DateStructureure.Year 23;RTC_DateStructureure.Month 9;RTC_DateStructureure.Date 27;RTC_DateStructureure.WeekDay RTC_WEEKDAY_WEDNESDAY;HAL_RTC_SetDate(RTC_HandleStructureure, RTC_DateStructureure, RTC_FORMAT_BIN);//设置RTC日期/设置时间: 09:00:00/RTC_TimeStructureure.Hours 9;RTC_TimeStructureure.Minutes 00;RTC_TimeStructureure.Seconds 00;HAL_RTC_SetTime(RTC_HandleStructureure, RTC_TimeStructureure, RTC_FORMAT_BIN);//设置RTC时间/设置RTC闹钟时间到09:01:00产生中断/RTC_AlarmStructureure.AlarmTime.Hours 9;RTC_AlarmStructureure.AlarmTime.Minutes 1;RTC_AlarmStructureure.AlarmTime.Seconds 00;HAL_RTC_SetAlarm_IT(RTC_HandleStructureure, RTC_AlarmStructureure, RTC_FORMAT_BIN);
}void RTC_Display(void)
{Read_RTC_Time(RTC_DateStructureure,RTC_TimeStructureure);
// Read_RTC_Date(RTC_DateStructureure,RTC_DateStructureure);// RTC_HandleTypeDef RTC_HandleStructureure;// RTC_HandleStructureure.Instance RTC;//选择RTC
// printf(RTC_IT_SEC\r\n);
// HAL_RTC_GetTime(RTC_HandleStructureure, RTC_TimeStructureure, RTC_FORMAT_BIN);//读取RTC时间
// HAL_RTC_GetDate(RTC_HandleStructureure, RTC_DateStructureure, RTC_FORMAT_BIN);//读取RTC日期printf(%02d%02d-%02d-%02d %02d:%02d:%02d\r\n, Century,RTC_DateStructureure.Year,RTC_DateStructureure.Month,RTC_DateStructureure.Date,RTC_TimeStructureure.Hours, RTC_TimeStructureure.Minutes, RTC_TimeStructureure.Seconds);//显示时间格式为 : YY-MM-DD hh:mm:ssif(RTC_DateStructureure.WeekDayRTC_WEEKDAY_SUNDAY) printf(Sunday\r\n);if(RTC_DateStructureure.WeekDayRTC_WEEKDAY_MONDAY) printf(Monday\r\n);if(RTC_DateStructureure.WeekDayRTC_WEEKDAY_TUESDAY) printf(Tuesday\r\n);if(RTC_DateStructureure.WeekDayRTC_WEEKDAY_WEDNESDAY) printf(Wednesday\r\n);if(RTC_DateStructureure.WeekDayRTC_WEEKDAY_THURSDAY) printf(Thursday\r\n);if(RTC_DateStructureure.WeekDayRTC_WEEKDAY_FRIDAY) printf(Friday\r\n);if(RTC_DateStructureure.WeekDayRTC_WEEKDAY_SATURDAY) printf(Saturday\r\n);
}//函数功能;RTC中断服务函数
void RTC_IRQHandler(void)
{if (_HAL_RTC_SECOND_GET_FLAG(RTC,RTC_FLAG_SEC)){if (_HAL_RTC_SECOND_GET_FLAG(RTC, RTC_FLAG_OW)){//RTC计数器溢出中断
/HAL_RTCEx_RTCEventCallback函数开始/printf(%s,\r\nRTC Overflow!!!\r\n);
/HAL_RTCEx_RTCEventCallback函数结束/_HAL_RTC_OVERFLOW_CLEAR_FLAG(RTC, RTC_FLAG_OW);//清除溢出中断}else{//RTC产生秒中断
/HAL_RTCEx_RTCEventCallback函数开始/MCU_LED_Toggle();
/HAL_RTCEx_RTCEventCallback函数结束/}_HAL_RTC_SECOND_CLEAR_FLAG(RTC, RTC_FLAG_SEC);}if (_HAL_RTC_ALARM_GET_FLAG(RTC, RTC_FLAG_ALRAF) ! (uint32_t)RESET){//RTC产生报警中断
/HAL_RTC_AlarmAEventCallback函数开始/printf(%s,\r\nRTC Alarm!!!\r\n);
/HAL_RTC_AlarmAEventCallback函数结束/_HAL_RTC_ALARM_CLEAR_FLAG(RTC, RTC_FLAG_ALRAF);//Clear the Alarm interrupt pending bit}
}
#ifndef __RTC_H
#define __RTC_H#include py32f0xx_hal.h#define _HAL_RTC_SECOND_GET_FLAG(__INSTANCE__, __FLAG__) (((((__INSTANCE__)-CRL) (__FLAG__)) ! RESET)? SET : RESET)
#define _HAL_RTC_OVERFLOW_CLEAR_FLAG(__INSTANCE__, __FLAG__) ((__INSTANCE__)-CRL) ~(__FLAG__)
#define _HAL_RTC_SECOND_CLEAR_FLAG(__INSTANCE__, __FLAG__) ((__INSTANCE__)-CRL) ~(__FLAG__)
#define _HAL_RTC_ALARM_GET_FLAG(__INSTANCE__, __FLAG__) (((((__INSTANCE__)-CRL) (__FLAG__)) ! RESET)? SET : RESET)
#define _HAL_RTC_ALARM_CLEAR_FLAG(__INSTANCE__, __FLAG__) ((__INSTANCE__)-CRL) ~(__FLAG__)
//#define _HAL_RTC_ALARM_ENABLE_IT(__INSTANCE__, __INTERRUPT__) SET_BIT((__INSTANCE__)-CRH, (__INTERRUPT__))#define _HAL_RTC_WRITEPROTECTION_ENABLE(__INSTANCE__) CLEAR_BIT((__INSTANCE__)-CRL, RTC_CRL_CNF)
//将RTC控制寄存器RTC_CRL中的CNF1,进入RTC配置模式#define _HAL_RTC_WRITEPROTECTION_DISABLE(__INSTANCE__) SET_BIT((__INSTANCE__)-CRL, RTC_CRL_CNF)
//将RTC控制寄存器RTC_CRL中的CNF0,退出配置模式,开始更新RTC寄存器
extern void RTC_Init(void);
extern void RTC_Display(void);#endif /* __RTC_H */
#include py32f0xx_hal.h
#include SystemClock.h
#include delay.h
#include LED.h
#include SystemClock.h
#include USART2.h
#include stdio.h //getchar(),putchar(),scanf(),printf(),puts(),gets(),sprintf()
#include string.h //使能strcpy(),strlen(),memset()
#include RTC.hconst char CPU_Reset_REG[]\r\nCPU reset!\r\n;
int main(void)
{HSE_Config();
// HAL_Init();//systick初始化delay_init();HAL_Delay(1000);USART2_Init(115200);
//PA0是为USART2_TX,PA1是USART2_RX
//中断优先级为0x01
//波特率为115200,数字为8位,停止位为1位,无奇偶校验,允许发送和接收数据,只允许接收中断,并使能串口printf(%s,CPU_Reset_REG);MCU_LED_Init();RTC_Init();while (1){delay_ms(1000);RTC_Display();}
}
四、误差分析 误差 每10分钟误差6秒。1%的误差还行。