stm32之备份寄存器(BKP)应用(侵入检测中断)
2019-08-20 来源:eefocus
前言:很多的嵌入式设备使用过程中,当系统掉电时,往往需要把一些用户设置的参数保存起来,或者是将掉电前的一些状态信息保存,或者是统计系统重启次数。保存这些动态信息其实有很多种方法,第一种:在系统掉电前保存到片内flash,但是对flash的读写是按页操作,对于保存一些少量的数据来说并不合算。第二种:在系统掉电前保存在片外的EEPROM,可以根据需要选用合适的EEPROM存储的大小,但这样需要增加额外电路,增加成本。第三种:利用片内的备份寄存器里的后备数据寄存器存储。对于一些中、小型容量产品来说,有10个16位的数据后备寄存器。与前两种不同,它需要将引脚接上电池,否则数据会丢失。下面对备份寄存器深入了解。
1.备份寄存器的特性
● 20字节数据后备寄存器(中容量和小容量产品),或84字节数据后备寄存器(大容量和互联型产品)
● 用来管理防侵入检测并具有中断功能的状态/控制寄存器
● 用来存储RTC校验值的校验寄存器。
● 在PC13引脚(当该引脚不用于侵入检测时)上输出RTC校准时钟,RTC闹钟脉冲或者秒脉冲
备份寄存器在后备供电区域里,当电源被切断,他们仍然由维持供电。当系统在待机模式下被唤醒,或系统复位或电源复位时,他们也不会被复位。下面主要介绍入侵检测和数据后备寄存器的应用,关于RTC部分单独一篇介绍。备份寄存器之所以与RTC有关,是因为RTC在电源切断后也是需要保持计数。
2.侵入检测功能
当TAMPER引脚(即PC.13)上的信号从0变成1或者从1变成0(取决于备份控制寄存器BKP_CR的TPAL位),会产生一个侵入检测事件(即使切断)。侵入检测事件将所有数据备份寄存器内容清除。
然而为了避免丢失侵入事件,侵入检测信号是边沿检测的信号与侵入检测允许位的逻辑与,从而在侵入检测引脚被允许前发生的侵入事件也可以被检测到。
● 当TPAL=0时(高电平有效):如果在启动侵入检测TAMPER引脚前(通过设置TPE位)该引脚已经为高电平,一旦启动侵入检测功能,则会产生一个额外的侵入事件(尽管在TPE位置’1’后并没有出现上升沿)。
● 当TPAL=1时(低电平有效):如果在启动侵入检测引脚TAMPER前(通过设置TPE位)该引脚已经为低电平,一旦启动侵入检测功能,则会产生一个额外的侵入事件(尽管在TPE位置’1’后并没有出现下降沿)。
注意:对TAMPER引脚的检测,可以是边沿触发(上升沿、下降沿),也可以是电平触发,后者需要启用中断配合,下面会讲解。产生侵入事件会将备份寄存器复位,产生事件的同时也可以通过软件使能中断,进入一个侵入检测中断TAMPER_IRQHandler。当然中断不使能,事件仍然会发生。
3.代码设计
涉及到的寄存器不逐一介绍,下面通过标准库里的函数进行开发。如果需要直接操作寄存器可以打开相应库函数的定义,函数里面也是执行寄存器的操作,将其内容复制出来即可。
#include 'stm32f10x.h'
#include 'stdio.h'
void TAMPER_ITConfig(void);
static void NVIC_Configuration(void);
static void USART1_Config(void);
int main(void)
{
unsigned short i;
char ch;
USART1_Config();//串口1输出调试信息
NVIC_Configuration();//配置串口接收中断的优先级
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR, ENABLE);//使能电源管理单元的时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP, ENABLE);
PWR_BackupAccessCmd(ENABLE);//使能后备寄存器访问
BKP_TamperPinCmd(DISABLE); //先关闭侵入检测引脚
BKP_ITConfig(DISABLE); //关闭侵入中断
BKP_TamperPinLevelConfig(BKP_TamperPinLevel_Low); //设置检测引脚低电平有效
BKP_ClearFlag(); //清除侵入检测事件
TAMPER_ITConfig();//配置中断优先级并打开侵入中断,不需要进入中断可以注释掉这句,并不影响侵入事件的发生
BKP_TamperPinCmd(ENABLE);//开启侵入检测引脚
#if 0 //调试方法一
printf('上电读取BKP数据:rn');
for(i=0x0004;i<=0x0028;i+=4){ // baseaddr:0x0004~0x0028 共10个16位的数据后备寄存器
printf('%c ',BKP_ReadBackupRegister(i));
}
printf('rn');
printf('往BKP写入数据:rn');
ch='a';
for(i=0x0004;i<=0x0028;i+=4){
BKP_WriteBackupRegister(i,ch++);
printf('%c ',BKP_ReadBackupRegister(i));
}
printf('rn');
#else //调试方法二
i=BKP_ReadBackupRegister(BKP_DR1);
printf('上电次数%d rn',i);
i++;
BKP_WriteBackupRegister(BKP_DR1,i);
#endif
while(1)
{
}
}
void TAMPER_ITConfig(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = TAMPER_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);//初始化侵入中断的优先级
BKP_ITConfig(ENABLE);//使能侵入中断
}
void USART1_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
//配置串口1(USART1)时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
//配置串口1(USART1 Tx (PA.09))
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//配置串口1 USART1 Rx (PA.10)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//串口1模式(USART1 mode)配置
USART_InitStructure.USART_BaudRate = 9600;//一般设置为9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No ;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断
USART_Cmd(USART1, ENABLE); //使能串口
USART_ClearFlag(USART1,USART_FLAG_TC);
}
int fputc(int ch, FILE *f)//重写标准库的fputc函数
{
//将Printf内容发往串口
USART_SendData(USART1, (unsigned char) ch);
while( USART_GetFlagStatus(USART1,USART_FLAG_TC)!= SET);
return (ch);
}
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_Init(&NVIC_InitStructure);
}
在stm32f10x_it.c文件加入:
void TAMPER_IRQHandler(void)
{
if(BKP_GetITStatus()!=RESET){
printf('触发侵入中断rn');
BKP_ClearITPendingBit();//清除侵入检测中断
BKP_ClearFlag();//清除侵入检测事件
//如果将下面两句执行,那么就变成电平触发,导致的现象:若PC.13引脚保持有效电平,则系统会反复进入中断
//BKP_TamperPinCmd(DISABLE);
//BKP_TamperPinCmd(ENABLE);
}
}
首先需要准备两个独立的电源,将板子的和PC.13(侵入检测引脚)接到一个电源(因为我的板子没有电池),将接到另一个电源,并且将两个电源共地。并串口1接到电脑,利用电脑上位机显示调试打印信息。
其次,编译下载程序,打开串口助手,按下板子的复位键(我这里按了四次),也可以切断再上电反复四次,如下图:

可看出,不管系统复位还是掉电,上电次数得到了记录。下面将PC.13引脚从高电平且换到低电平(产生一个侵入信号),再进行系统复位或重新上电(我这里按了两次复位):

可看出,侵入事件发生后,备份寄存器里的数据被复位。当掉电时,PC.13引脚仍然在检测,若出现下降沿,备份寄存器也会进行复位,这个可以自行验证。还有上面提到的电平触发,也可以自行验证。我自己验证过,这里不做赘述。
- 意法半导体中国本地造STM32微控制器启动规模量产
- 意法半导体全新STM32C5系列,重新定义入门级微控制器性能与价值,赋能万千智能设备
- 使用 Keil Studio for Visual Studio Code开发 STM32 设备
- 基于机智云与STM32的智能拐杖安全监测系统在养老物联网中的应用
- 内置全栈安全,一站式满足CRA法案与IEC 62443标准——米尔STM32MP257核心板
- 如何用 STM32 FLASH 实现等效 100 万次擦写的 EEPROM 功能?
- 实战解析:通过一个小项目掌握STM32所有外设
- STM32学了两年半,却还是不会做项目
- 意法半导体推出最新STM32MP21微处理器,兼具高性价比、低功耗、高灵活性
- 基于STM32的矿井作业环境监测系统设计与实现
- 六大全新产品系列推出,MCX A微控制器家族迎来创新
- 意法半导体全新STM32C5系列,重新定义入门级微控制器性能与价值,赋能万千智能设备
- 模组复用与整机重测在SRRC、CCC、CTA/NAL认证中的实践操作指南
- 从控制到系统:TI利用边缘AI重塑嵌入式MCU的边界
- 有源晶振与无源晶振的六大区别详解
- 英飞凌持续巩固全球微控制器市场领导地位
- 使用 Keil Studio for Visual Studio Code开发 STM32 设备
- 蓝牙信道探测技术原理与开发套件实践
- Microchip 推出生产就绪型全栈边缘 AI 解决方案,赋能MCU和MPU实现 智能实时决策
- LoRa、LoRaWAN、NB-IoT与4G DTU技术对比及工业无线方案选型分析




