STM32系列为处理器都有备份寄存器,他它们处于备份区域里,当VDD电源被切断,它们仍然由VBAT维持供电,当系统在待机模式下被唤醒,或者系统复位或电源复位是,它们都不会被复位。以实时时钟RTC为例,在上一篇文章中讲过,RTC处理依赖系统电源(VDD供电)外,还依赖者备份电源(VBAT供电),即使系统电源被切断,只要备份电源还在,RTC就能继续工作。备份寄存器也是依赖者备份电源的。STM32都有备份寄存器,但是备份寄存器的数量却不一定相同!对于大容量的微处理器系列来说,它有着42个16位的寄存器,而中小容量的微处理器却只有10个16为的寄存器。我使用的微处理器是STM32F103ZET6,属于大容量系列,所以它他有着42个备份寄存器。下面就是基于大容量的。
下面就来讲讲备份寄存器(BKP)的操作,还是基于我自己的规范工程。
1、工程的修改
1)首先当然要添加stm32f10x_bkp.c文件到STM32F10x_StdPeriph_Driver工程组中。除此之外,要想访问备份寄存器,还要讲stm32f10x_pwr.c文件再添加进去。
2)打开stm32f10x_conf.c文件,将其中原先屏蔽着的:#include "stm32f10x_bkp.h" 与 #include "stm32f10x_pwr.h"这两句话的屏蔽去掉。
3)新建Backup.c与Backup.h两个文件,分别保存在BSP文件下的src与inc中,并将Backup.c文件添加到BSP工作组中。
2、Backup.c与Backup.h两个文件的代码编写
首先要初始化下备份寄存器,代码如下:
/*************************************************************
Function : Backup_Init
Description: 备份寄存器初始化
Input : none
return :
*************************************************************/
void Backup_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP, ENABLE);//初始化电源控制时钟与备份寄存器时钟
PWR_BackupAccessCmd(ENABLE); //允许访问备份寄存器
BKP_ClearFlag();//清除入侵引脚事件标志位
if(RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET)//上电复位
{
RCC_ClearFlag();//清除复位标志位
if(Backup_CheckData(0x0001) != 0)//备份寄存器数据错误或,没有数据 {
Backup_WriteData(0x0001);//写入数据
}
}
}
要初始化备份寄存器,当然要线初始化PWR与BKP的时钟了,接着设置允许访问,然后清除入侵事件标志位。什么是入侵事件?STM32对应有一个入侵引脚,STM32F103ZET6对应的入侵引脚是PC13,当它的电平从0变成1或者从1变成0时,就会产生一个入侵检测事件,然后会把所有的数据备份寄存器的内容清除张佑赫就是为什叫做"入侵"这个名字的原因了。所以这里初始化的时候,要将它的标志位清除。接下去再判断上电复位标志位,如果检测到上电复位,那么先清除下标志位,再调用自己写的Backup_CheckData()函数来读取备份寄存器的数据进而判断之前备份寄存器的数据是否有数据或者说正确的指定数据,如果没有,则想他写入数据,这里调用自己编写的Backup_WriteData()函数向备份急寄存器写入数据,下面马上讲到。
下面先来讲讲Backup_WriteData()函数如何向备份寄存器写数据,代码如下:
uint16_t BKPDataReg[42] ={//对大容量微处理器来说,它有42个备份寄存器,地址偏移为:0x04~0x48,0x40~0xBC
BKP_DR1, BKP_DR2, BKP_DR3, BKP_DR4, BKP_DR5, BKP_DR6, BKP_DR7, BKP_DR8,
BKP_DR9, BKP_DR10, BKP_DR11, BKP_DR12, BKP_DR13, BKP_DR14, BKP_DR15, BKP_DR16,
BKP_DR17, BKP_DR18, BKP_DR19, BKP_DR20, BKP_DR21, BKP_DR22, BKP_DR23, BKP_DR24,
BKP_DR25, BKP_DR26, BKP_DR27, BKP_DR28, BKP_DR29, BKP_DR30, BKP_DR31, BKP_DR32,
BKP_DR33, BKP_DR34, BKP_DR35, BKP_DR36, BKP_DR37, BKP_DR38, BKP_DR39, BKP_DR40,
BKP_DR41, BKP_DR42
};
/*************************************************************
Function : Backup_WriteData
Description: 向备份寄存器写的数据
Input : firstBackupData - 数据的首数据
return : none
*************************************************************/
static void Backup_WriteData(u32 firstBackupData)
{
u32 index;
PRINTF("Begin to wite data to backup registers\r\n");
for(index = 0; index < 42; index++)
{ /向备份寄存器写数据
BKP_WriteBackupRegister(BKPDataReg[index], firstBackupData + index);/
PRINTF("BKP_DR%d: %d\r\n", index + 1, firstBackupData + index);
}
}
代码很简单,不过在这个函数之前要线定义一个数组BKPDataReg[],它的元素就是42个备份寄存器的地址。在Backup_WriteData()函数中,通过一个循环函数,使用库函数BKP_WriteBackupRegister()分别向备份寄存器中写入firstBackupData + index,也就是1~42了。
再来讲讲Backup_CheckData()函数,代码如下:
/*************************************************************
Function : Backup_CheckData
Description: 检查备份寄存器的数据是否正确
Input : firstBackupData-第一个备份寄存器数据
return : 0-正确 其他-错误
*************************************************************/
static u8 Backup_CheckData(u32 firstBackupData)
{
u32 index;
PRINTF("Begin to check backup registers\r\n");
for(index = 0; index < 42; index++)
{ //检查备份寄存器的数据是否正确
if(BKP_ReadBackupRegister(BKPDataReg[index]) != (firstBackupData + index))
{
PRINTF("BKP_DR%d data check impare!\r\n", index + 1);
return (index + 1);
}
else
{
PRINTF("BKP_DR%d data check OK!\r\n", index + 1);
}
}
return 0;
}
这个函数其实也是很简单,循环42次读出42个备份寄存器的数据,在与之前写入的数据进行比较,如果相等则放回0,否者返回最先不同的备份寄存器索引。这里调用库函数BKP_ReadBackupRegister()来读取备份寄存器的值。
这样Backup.c的代码就结束了,下面贴下Backup.h的代码,如下:
#ifndef __BACKUP_H__
#define __BACKUP_H__
#include "stm32f10x.h"
void Backup_Init(void);
#endif
3、main函数的编写
main函数很简单,只是调用下备份寄存器的初始化函数就可以了,代码如下:
/*************************************************************
Function : main
Description: main入口
Input : none
return : none
*************************************************************/
int main(void)
{
BSP_Init();
PRINTF("\nmain() is running!\r\n");
Backup_Init();
while(1)
{
LED1_Toggle();
Delay_ms(1000);
}
}
4、测试
下载好程序后,用串口线将开发板与电脑连接,打开串口调试软件,查看信息。给开发板上电,就会看到下图的现象:
图中可以看到,第一次上电的时候,向备份寄存器写入1~42。接下去,再复位下开发板,就i可以看到下图现象:
复位后,因为备份寄存器已经被设置了初值,所以先会读取备份寄存器的值,图中可以看到备份寄存器的值与设置的值相同,所以不会在一次对备份寄存器写数据了!