2026/4/6 9:32:04
网站建设
项目流程
json网站开发,房山网站建设怎么样,江苏建设人才网证书查询,子网站域名ip地址查询1. 什么是BKP• 备份寄存器(BKP)在大容量STM32芯片中通常是42个16位寄存器#xff08;共84字节#xff09;#xff0c;用于存储用户数据。它们位于备份域中#xff0c;当VDD电源切断时#xff0c;可由VBAT引脚连接的备用电池维持供电保证数据不丢失。当系统从待机模式唤醒…1. 什么是BKP•备份寄存器(BKP)在大容量STM32芯片中通常是42个16位寄存器共84字节用于存储用户数据。它们位于备份域中当VDD电源切断时可由VBAT引脚连接的备用电池维持供电保证数据不丢失。当系统从待机模式唤醒、或发生系统复位/电源复位时BKP数据不会被清除除非主动进行备份域复位或VBAT断电。• 注意:BKP特殊的一点就是他们是由两个电源控制的(VDD和VBAT)当VDD不工作了还有VBAT给BKP供电。但是BKP也不是掉电不丢失数据的。当两个电源都没了那数据可能也就没了。• 此外 BKP控制寄存器用来管理侵入检测(TAMPWE)和RTC校准功能。• 作用:•存储RTC的配置参数如校准值、时钟源选择。•保存关键数据如时间戳、闹钟设置避免复位或掉电后丢失。• 复位后对备份寄存器(BKP)和RTC的访问被禁止并且备份域被保护以防止可能存在的意外的写操作。执行以下操作可以使能对备份寄存器(BKP)和RTC的访问• 通过设置寄存器RCC_APB1ENR的PWREN和BKPEN位来打开电源和后备接口的时钟如图:• 电源控制寄存器(PWR_CR)的DBP位来使能对后备寄存器(BKP)和RTC的访问如图• 用户数据存储容量20字节中容量和小容量/ 84字节大容量和互联型)。2. BKP框图• 侵入检测的作用:防止别人恶意读取数据保护数据如果一旦发生别人读取数据数据自动销毁。3. 实操读写BKP3.1在rtc.c#include rtc.h RTC_HandleTypeDef rtc_handle {0}; void rtc_init(){ __HAL_RCC_PWR_CLK_ENABLE();//打开电源时钟 __HAL_RCC_BKP_CLK_ENABLE();//打开备份接口时钟 HAL_PWR_EnableBkUpAccess();//使能允许写入RTC和BKP rtc_handle.Instance RTC; rtc_handle.Init.AsynchPrediv 32767; rtc_handle.Init.OutPut RTC_OUTPUTSOURCE_NONE; HAL_RTC_Init(rtc_handle);//rtc和bkp是紧密的都在一个区域(后备域)并且还共用一个VBAT } uint16_t rtc_read_bkr(uint8_t bkrx){//读 uint32_t recv_data 0; recv_data HAL_RTCEx_BKUPRead(rtc_handle,bkrx); return (uint16_t) recv_data; } void rtc_write_bkr(uint8_t bkrx,uint16_t data){//写 HAL_RTCEx_BKUPWrite(rtc_handle,bkrx,data); }3.2在main.c#include sys.h #include uart1.h #include delay.h #include led.h #include rtc.h int main(void) { HAL_Init(); /* 初始化HAL库 */ stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */ led_init(); /* LED初始化 */ uart1_init(115200); rtc_init(); printf(hello world\r\n); rtc_write_bkr(1,0x11CD); printf(读到的数据是:%X\r\n,rtc_read_bkr(1)); while(1)//流水灯实验 { } }4. 什么是RTC•实时时钟是一个独立的定时器。RTC模块拥有一组连续计数的计数器(32位的可编程计数器)在相应软件配置下可提供时钟日历的功能(F1系列是没有的)。修改计数器的值可以重新设置系统当前的时间和日期。•RTC模块和时钟配置系统(RCC_BDCR寄存器)处于后备区域即在系统复位或从待机模式唤醒后 RTC的设置和时间维持不变。•复位后对备份寄存器和RTC的访问被禁止并且备份域被保护以防止可能存在的意外的写操作。执行以下操作可以使能对备份寄存器和RTC的访问•通过设置寄存器RCC_APB1ENR的PWREN和BKPEN位来打开电源和后备接口的时钟。•电源控制寄存器(PWR_CR)的DBP位来使能对后备寄存器和RTC的访问。•32位的可编程计数器(RTC):保存的是可对应的UNIX时间戳•20位的可编程预分频器可以适配不同速率的输入时钟•RTC的时钟源有三种:•HSE的时钟除以128(通常是8MHz/128)。•LSE振荡器时钟(通常是32.768KHz)(最常用的)可以配置为1hz(经过分频之后)•LSI振荡器时钟(40KHz)(这个是不精确的)•如图:5.RTC框图• 工作原理:(在RTC预分频器)•假设要生成1hz的时钟信号(TR_CLK),可以设置RTC_PRL(分频系数)为32768 - 1然后重装载给RTC_DIV(余数寄存器)RTC模块把把32.768khz的外部时钟分频32768次得到1hz然后再将1hz的信号存入RTC_CNT中。•RTC_DIV在每次计数时自减当计数到0时触发TR_CLK存入RTC_CNT中然后并重装载RTC_PRL的值继续分频。6.RTC驱动步骤•使能电源及后备域时钟•使能后背域访问•初始化RTC(设置分频及工作参数)•设置msp函数(使能RTC设置时钟源中断配置)•编写读写RTC时间函数•编写闹钟相关函数•注意事项:•必须设置RTC_CRL寄存器中的CNF位(配置位)使RTC进入配置模式后才能写入RTC_PRL、RTC_CNT、RTC_ALR寄存器。•对RTC任何寄存器的写操作都必须在前一次写操作结束后进行。可以通过查询RTC_CR寄存器中的RTOFF状态位判断RTC寄存器是否处于更新中。仅当RTOFF状态位是1时才可以写入RTC寄存器。7.实操读写RTC时间实验7.1 在rtc.c#include rtc.h #include stdio.h RTC_HandleTypeDef rtc_handle {0}; void rtc_init(){ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_RCC_BKP_CLK_ENABLE(); HAL_PWR_EnableBkUpAccess(); rtc_handle.Instance RTC; rtc_handle.Init.AsynchPrediv 32767; rtc_handle.Init.OutPut RTC_OUTPUTSOURCE_NONE;//RTC不会输出任何信号到侵入引脚 HAL_RTC_Init(rtc_handle);//rtc和bkp是紧密的都在一个区域(后备域)并且还共用一个VBAT //在HAL库中CNF位的写1操作被封装在RTC初始化、时间设置和预分频配置等函数中开发者无需直接操作寄存器。 //通过调用HAL_RTC_Init()、HAL_RTC_SetTime()等函数库函数会自动管理CNF位的状态确保寄存器的安全访问。 } void rtc_set_time(struct tm time_data){ RTC_DateTypeDef rtc_date {0}; RTC_TimeTypeDef rtc_time {0}; rtc_date.Year time_data.tm_year; rtc_date.Month time_data.tm_mon; rtc_date.Date time_data.tm_mday; HAL_RTC_SetDate(rtc_handle,rtc_date,RTC_FORMAT_BIN); rtc_time.Hours time_data.tm_hour; rtc_time.Minutes time_data.tm_min; rtc_time.Seconds time_data.tm_sec; HAL_RTC_SetTime(rtc_handle,rtc_time,RTC_FORMAT_BIN); /*两种格式区别 BIN格式需要将每个数值从二进制转换为十进制 例如将小时的二进制值1100转换为十进制的12。 BCD格式可以直接将每个4位二进制数组分解并解码为十进制数字 例如小时的BCD值0001 0010直接解码为12。 其中每个部分分别表示十进制数 1 和 2。 */ while(!__HAL_RTC_ALARM_GET_FLAG(rtc_handle,RTC_FLAG_RTOFF));//等待写入完成。 } void rtc_get_time(){ RTC_DateTypeDef rtc_date {0}; RTC_TimeTypeDef rtc_time {0}; HAL_RTC_GetDate(rtc_handle,rtc_date,RTC_FORMAT_BIN); HAL_RTC_GetTime(rtc_handle,rtc_time,RTC_FORMAT_BIN); printf(%d-%02d-%02d %02d:%02d:%02d\r\n,rtc_date.Year2000,rtc_date.Month,rtc_date.Date,rtc_time.Hours,rtc_time.Minutes,rtc_time.Seconds); } void HAL_RTC_MspInit(RTC_HandleTypeDef *hrtc){ //HAL_RCC_ClockConfig 是 STM32 微控制器中用于配置系统时钟、 //AHB高级高性能总线、APB1高级外设总线1和 APB2高级外设总线2总线时钟的函数 __HAL_RCC_RTC_ENABLE();//开启RTC RCC_OscInitTypeDef rcc_osc {0};//配置时钟振荡器的函数 RCC_PeriphCLKInitTypeDef rcc_ppc {0}; rcc_osc.OscillatorType RCC_OSCILLATORTYPE_LSE; rcc_osc.LSEState RCC_LSE_ON; rcc_osc.PLL.PLLState RCC_PLL_NONE;//没用到锁相环 //HAL_RCC_OscConfig 是 STM32 微控制器中用于配置时钟振荡器的函数。它属于 STM32 的硬件抽象层HAL库 HAL_RCC_OscConfig(rcc_osc); rcc_ppc.PeriphClockSelection RCC_PERIPHCLK_RTC; rcc_ppc.RTCClockSelection RCC_RTCCLKSOURCE_LSE; //HAL_RCCEx_PeriphCLKConfig 是 STM32 微控制器中用于配置外设时钟的函数 HAL_RCCEx_PeriphCLKConfig(rcc_ppc); } uint16_t rtc_read_bkr(uint8_t bkrx){ uint32_t recv_data 0; recv_data HAL_RTCEx_BKUPRead(rtc_handle,bkrx); return (uint16_t) recv_data; } void rtc_write_bkr(uint8_t bkrx,uint16_t data){ HAL_RTCEx_BKUPWrite(rtc_handle,bkrx,data); }7.2 在main.c#include sys.h #include uart1.h #include delay.h #include led.h #include rtc.h int main(void) { HAL_Init(); /* 初始化HAL库 */ stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */ led_init(); /* LED初始化 */ uart1_init(115200); rtc_init(); printf(hello world\r\n); if(rtc_read_bkr(1) ! 0x11CD){//防止复位干扰时间 rtc_write_bkr(1,0x11CD); printf(读到的数据是:%X\r\n,rtc_read_bkr(1)); struct tm time_data; time_data.tm_year 2025; time_data.tm_mon 3; time_data.tm_mday 12; time_data.tm_hour 15; time_data.tm_min 56; time_data.tm_sec 30; rtc_set_time(time_data); } while(1)//流水灯实验 { rtc_get_time(); delay_ms(1000); } }8. 实操 RTC闹钟实验8.1 在rtc.c#include rtc.h #include stdio.h RTC_HandleTypeDef rtc_handle {0}; void rtc_init(){ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_RCC_BKP_CLK_ENABLE(); HAL_PWR_EnableBkUpAccess(); rtc_handle.Instance RTC; rtc_handle.Init.AsynchPrediv 32767; rtc_handle.Init.OutPut RTC_OUTPUTSOURCE_NONE; HAL_RTC_Init(rtc_handle);//rtc和bkp是紧密的都在一个区域(后备域)并且还共用一个VBAT } void rtc_set_time(struct tm time_data){ RTC_DateTypeDef rtc_date {0}; RTC_TimeTypeDef rtc_time {0}; rtc_date.Year time_data.tm_year; rtc_date.Month time_data.tm_mon; rtc_date.Date time_data.tm_mday; HAL_RTC_SetDate(rtc_handle,rtc_date,RTC_FORMAT_BIN); rtc_time.Hours time_data.tm_hour; rtc_time.Minutes time_data.tm_min; rtc_time.Seconds time_data.tm_sec; HAL_RTC_SetTime(rtc_handle,rtc_time,RTC_FORMAT_BIN); while(!__HAL_RTC_ALARM_GET_FLAG(rtc_handle,RTC_FLAG_RTOFF)); } void rtc_get_time(){ RTC_DateTypeDef rtc_date {0}; RTC_TimeTypeDef rtc_time {0}; HAL_RTC_GetDate(rtc_handle,rtc_date,RTC_FORMAT_BIN); HAL_RTC_GetTime(rtc_handle,rtc_time,RTC_FORMAT_BIN); printf(%d-%02d-%02d %02d:%02d:%02d\r\n,rtc_date.Year2000,rtc_date.Month,rtc_date.Date,rtc_time.Hours,rtc_time.Minutes,rtc_time.Seconds); } void rtc_set_alarm(struct tm alarm_data){ RTC_AlarmTypeDef rtc_alarm {0}; rtc_alarm.AlarmTime.Hours alarm_data.tm_hour; rtc_alarm.AlarmTime.Minutes alarm_data.tm_min; rtc_alarm.AlarmTime.Seconds alarm_data.tm_sec; rtc_alarm.Alarm RTC_ALARM_A; HAL_RTC_SetAlarm_IT(rtc_handle,rtc_alarm,RTC_FORMAT_BIN);//启动闹钟中断。 while(!__HAL_RTC_ALARM_GET_FLAG(rtc_handle,RTC_FLAG_RTOFF)); } void HAL_RTC_MspInit(RTC_HandleTypeDef *hrtc){ __HAL_RCC_RTC_ENABLE(); RCC_OscInitTypeDef rcc_osc {0}; RCC_PeriphCLKInitTypeDef rcc_ppc {0}; rcc_osc.OscillatorType RCC_OSCILLATORTYPE_LSE; rcc_osc.LSEState RCC_LSE_ON; rcc_osc.PLL.PLLState RCC_PLL_NONE; HAL_RCC_OscConfig(rcc_osc); rcc_ppc.PeriphClockSelection RCC_PERIPHCLK_RTC; rcc_ppc.RTCClockSelection RCC_RTCCLKSOURCE_LSE; HAL_RCCEx_PeriphCLKConfig(rcc_ppc); HAL_NVIC_SetPriority(RTC_Alarm_IRQn,2,0); HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn); } void RTC_Alarm_IRQHandler(){ HAL_RTC_AlarmIRQHandler(rtc_handle); } void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc){ printf(ring ring ring\r\n); } uint16_t rtc_read_bkr(uint8_t bkrx){ uint32_t recv_data 0; recv_data HAL_RTCEx_BKUPRead(rtc_handle,bkrx); return (uint16_t) recv_data; } void rtc_write_bkr(uint8_t bkrx,uint16_t data){ HAL_RTCEx_BKUPWrite(rtc_handle,bkrx,data); }8.2 在main.c#include sys.h #include uart1.h #include delay.h #include led.h #include rtc.h int main(void) { HAL_Init(); /* 初始化HAL库 */ stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */ led_init(); /* LED初始化 */ uart1_init(115200); rtc_init(); printf(hello world\r\n); if(rtc_read_bkr(1) ! 0x11CD){ rtc_write_bkr(1,0x11CD); printf(读到的数据是:%X\r\n,rtc_read_bkr(1)); struct tm time_data; struct tm alarm_data; time_data.tm_year 2025; time_data.tm_mon 3; time_data.tm_mday 12; time_data.tm_hour 15; time_data.tm_min 56; time_data.tm_sec 30; rtc_set_time(time_data); alarm_data.tm_hour 15; alarm_data.tm_min 56; alarm_data.tm_sec 40; rtc_set_alarm(alarm_data); } while(1)//流水灯实验 { rtc_get_time(); delay_ms(1000); } }