前天,有个朋友问:如果电脑突然掉电导致一些重要数据丢失怎么办?我觉得对于STM32而言无需外挂E2PROM,凭借自身资源就可以解决:1,大容量STM32一般有512k的flash,可以在程序运行当中实时将重要数据更新到片内flash中;具体如何操作可以参考IAP例程,这个例程很好,不光可以学习IAP(在应用编程功能),还可以学到CM3内核的一些结构知识和对片内flash的操作;2,STM32的备份域(BKP)有42个u16类型数据寄存器,只要按流程操作这42个16位的备份域数据寄存器就可以当E2PROM用,当然必须配有电池。通过对备份域的操作还可以做一个闹钟。
STM32的资源很丰富对应每个功能,STM32的软件工程师为其搭配了相应的库函数。有了这个固件库使得我们对STM32的应用程序开发更加简单,节省开发时间。但是我感觉要熟练运用库函数也不是一件容易的事,必须经常练习。
下面是RTC实时时钟固件库版驱动函数(原子例程):
- //实时时钟配置
- //初始化RTC时钟,同时检测时钟是否工作正常
- //BKP->DR1用于保存是否第一次配置的设置
- //返回0:正常
- //其他:错误代码
- u8 RTC_Init(void)
- {
- //检查是不是第一次配置时钟
- u8 temp=0;
-
- if (BKP_ReadBackupRegister(BKP_DR1) != 0x5050)//从指定的后备寄存器中读出数据:读出了与写入的指定数据不相乎
- {
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);//使能PWR和BKP外设时钟
- PWR_BackupAccessCmd(ENABLE);//使能后备寄存器访问
- BKP_DeInit();//复位备份区域
- RCC_LSEConfig(RCC_LSE_ON);//设置外部低速晶振(LSE),使用外设低速晶振
- while (RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET)//检查指定的RCC标志位设置与否,等待低速晶振就绪
- {
- temp++;
- delay_ms(10);
- }
- if(temp>=250)return 1;//初始化时钟失败,晶振有问题
- RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);//设置RTC时钟(RTCCLK),选择LSE作为RTC时钟
- RCC_RTCCLKCmd(ENABLE);//使能RTC时钟
- RTC_WaitForLastTask();//等待最近一次对RTC寄存器的写操作完成
- RTC_WaitForSynchro();//等待RTC寄存器同步
- RTC_ITConfig(RTC_IT_SEC, ENABLE);//使能RTC秒中断
- RTC_WaitForLastTask();//等待最近一次对RTC寄存器的写操作完成
- RTC_EnterConfigMode();/// 允许配置
- RTC_SetPrescaler(32767); //设置RTC预分频的值
- RTC_WaitForLastTask();//等待最近一次对RTC寄存器的写操作完成
- RTC_Set(2009,12,2,10,0,55); //设置时间
- RTC_ExitConfigMode(); //退出配置模式
- BKP_WriteBackupRegister(BKP_DR1, 0X5050);//向指定的后备寄存器中写入用户程序数据
- }
- else//系统继续计时
- {
- RTC_WaitForSynchro();//等待最近一次对RTC寄存器的写操作完成
- RTC_ITConfig(RTC_IT_SEC, ENABLE);//使能RTC秒中断
- RTC_WaitForLastTask();//等待最近一次对RTC寄存器的写操作完成
- }
- RTC_NVIC_Config();//RCT中断分组设置
- RTC_Get();//更新时间
- return 0; //ok
- }
复制代码
该函数用的就是固件库中关于RTC部分的函数,整个操作都是按数据手册的操作流程来执行;其中用到了c语言编程技巧,临时变量temp防止程序死机。中断如何配置?一般都有固定格式。
下面是RTC实时时钟寄存器版驱动函数(原子例程):
- //实时时钟配置
- //初始化RTC时钟,同时检测时钟是否工作正常
- //BKP->DR1用于保存是否第一次配置的设置
- //返回0:正常
- //其他:错误代码
- u8 RTC_Init(void)
- {
- //检查是不是第一次配置时钟
- u8 temp=0;
- if(BKP->DR1!=0X5050)//第一次配置
- {
- RCC->APB1ENR|=1<<28; //使能电源时钟
- RCC->APB1ENR|=1<<27; //使能备份时钟
- PWR->CR|=1<<8; //取消备份区写保护
- RCC->BDCR|=1<<16; //备份区域软复位
- RCC->BDCR&=~(1<<16); //备份区域软复位结束
- RCC->BDCR|=1<<0; //开启外部低速振荡器
- while((!(RCC->BDCR&0X02))&&temp<250)//等待外部时钟就绪
- {
- temp++;
- delay_ms(10);
- };
- if(temp>=250)return 1;//初始化时钟失败,晶振有问题
- RCC->BDCR|=1<<8; //LSI作为RTC时钟
- RCC->BDCR|=1<<15;//RTC时钟使能
- while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成
- while(!(RTC->CRL&(1<<3)));//等待RTC寄存器同步
- RTC->CRH|=0X01; //允许秒中断
- while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成
- RTC->CRL|=1<<4; //允许配置
-
- RTC->PRLH=0X0000;
- RTC->PRLL=32767; //时钟周期设置(有待观察,看是否跑慢了?)理论值:32767
-
- RTC_Set(2012,9,7,13,16,55); //设置时间
- RTC->CRL&=~(1<<4); //配置更新
- while(!(RTC->CRL&(1<<5))); //等待RTC寄存器操作完成
- BKP->DR1=0X5050;
- printf("FIRST TIME\n");
- }else//系统继续计时
- {
- while(!(RTC->CRL&(1<<3)));//等待RTC寄存器同步
- RTC->CRH|=0X01; //允许秒中断
- while(!(RTC->CRL&(1<<5)));//等待RTC寄存器操作完成
- printf("OK\n");
- }
- MY_NVIC_Init(0,0,RTC_IRQChannel,2);//优先级设置
- RTC_Get();//更新时间
- return 0; //ok
- }
复制代码
就个人而言偏爱寄存器版本函数,思路清晰;同时可以学习如何操作寄存器。
|