stm32 BKP寄存器操作[操作寄存器+库函数]

BKP是“BACKUP”的缩写,stm32f103RCTE的内部配备了10个16位宽度的BKP寄存器。在主电源切断或系统产生复位时间时,BKP寄存器仍然可以在备用电源的支持下保持其内容。 
BKP在实际应用中可以存入重要数据,防止被恶意查看,或用于断电回复等。
本例实现对BKP寄存器的读写操作,和入侵检测和处理。主程序中写入寄存器后,依次打印出10个BKP寄存器数据,然后触发GPIOC13的入侵中断(输入低电平),在中断中打印出入侵事件发生后的寄存器内容(复位为0 )。
直接操作寄存器
用到的寄存器描述如下:
备份数据寄存器x(BKP_DRx) (x = 1 … 10):低16位[15:0]有效,用来写入或读出备份数据。
备份控制寄存器(BKP_CR):
低两位有效。
TPAL[1]:侵入检测TAMPER引脚有效电平(TAMPER pin active level)
  •          0:侵入检测TAMPER引脚上的高电平会清除所有数据备份寄存器(如果TPE位为1)
  •          1:侵入检测TAMPER引脚上的低电平会清除所有数据备份寄存器(如果TPE位为1)

    TPE[0]:启动侵入检测TAMPER引脚(TAMPER pin enable)

  • 0:侵入检测TAMPER引脚作为通用IO口使用

  • 1:开启侵入检测引脚作为侵入检测使用
    备份控制/状态寄存器(BKP_CSR):
    BKP_CSR.png

TIF[9]:侵入中断标志(Tamper interrupt flag)      0:无侵入中断     1:产生侵入中断
当检测到有侵入事件且TPIE位为1时,此位由硬件置1。
通过向CTI位写1来清除此标志位(同时也清除了中断)。如果TPIE位被清除,则此位也会被清除。 
TEF[8]:侵入事件标志(Tamper event flag)         0:无侵入事件       1:检测到侵入事件 
当检测到侵入事件时此位由硬件置1。通过向CTE位写1可清除此标志位 
TPIE[2]:允许侵入TAMPER引脚中断(TAMPER pin interrupt enable)
0:禁止侵入检测中断 1:允许侵入检测中断(BKP_CR寄存器的TPE位也必须被置1)
注1:侵入中断无法将系统内核从低功耗模式唤醒。 注2:仅当系统复位或由待机模式唤醒后才复位该位。
CTI[1]:清除侵入检测中断(Clear tamper interrupt)  
0:无效 1:清除侵入检测中断和TIF侵入检测中断标志
CTE[0]:清除侵入检测事件(Clear tamper event)
 0:无效 1:清除TEF侵入检测事件标志(并复位侵入检测器)。
要写入BKP寄存器数据必须在 PWR->CR中取消备份区写保护,才可以写入BKP数据。stm32开启入侵检测也不需要设置GPIOC的时钟和输入输出模式。
代码如下:(system.h 和 stm32f10x_it.h 等相关代码参照 stm32 直接操作寄存器开发环境配置
User/main.c
#include <stm32f10x_lib.h>
#include “system.h”
#include “usart.h”
#include “bkp.h”

#define LED1 PAout(4)

#define LED2 PAout(5)

void Gpio_Init(void);

int main(void)
{
u16 data,i=10;

Rcc_Init(9);                            //系统时钟设置

Usart1_Init(72,9600);

Bkp_Init();

Tamper_Init();

Nvic_Init(0,0,TAMPER_IRQChannel,0);      //设置中断

Gpio_Init();

while(i){

    Write_Bkp(i,i);

    data = Read_Bkp(i);

    printf("\n DR%u = 0x%04X\n",i,data);

    delay(30000);   //延时30ms

    i--;

}

while(1);        

}

void Gpio_Init(void)
{
RCC->APB2ENR|=1<<2; //使能PORTA时钟

GPIOA-&gt;CRL&amp;=0x0000FFFF; // PA0~3设置为浮空输入,PA4~7设置为推挽输出
GPIOA-&gt;CRL|=0x33334444; 

//USART1 串口I/O设置

GPIOA -&gt; CRH&amp;=0xFFFFF00F;   //设置USART1 的Tx(PA.9)为第二功能推挽,50MHz;Rx(PA.10)为浮空输入
GPIOA -&gt; CRH|=0x000008B0;      

}

User/stm32f103x_it.c
#include “stm32f10x_it.h”

#include “system.h”

#include “stdio.h”

#define LED1 PAout(4)

#define LED2 PAout(5)

#define LED3 PAout(6)

#define LED4 PAout(7)

extern u16 Read_Bkp(u8 reg);

void TAMPER_IRQHandler(void)
{
u16 i=10,data;

LED4 =1 ;

printf("\r\n A Tamper is coming .\r\n");

while(i){

    data = Read_Bkp(i);

    printf("\n DR%u = 0x%04X\n",i,data);

    delay(30000);   //延时30ms

    i--;

}

BKP-&gt;CSR |= 3&lt;&lt;0;    //清除事件中断标志位

}

Library/src/bkp.c
#include <stm32f10x_lib.h>

#include “bkp.h”

void Bkp_Init(void)
{
RCC->APB1RSTR |= 1<<27; //复位BKP寄存器
RCC->APB1RSTR &= ~(1<<27);

RCC-&gt;APB1ENR|=1&lt;&lt;28;     //使能电源时钟        
RCC-&gt;APB1ENR|=1&lt;&lt;27;     //使能BKP时钟      

}

/**

  • 后备寄存器写入操作 reg:寄存器编号
    data:要写入的数值
    **/
    void Write_Bkp(u8 reg,u16 data)
    {

    PWR->CR|=1<<8; //取消备份区写保护

    switch(reg)
    {

    case 1:
        BKP-&gt;DR1=data;
        break;
    case 2:
        BKP-&gt;DR2=data;
        break;
    case 3:
        BKP-&gt;DR3=data;
        break; 
    case 4:
        BKP-&gt;DR4=data;
        break;
    case 5:
        BKP-&gt;DR5=data;
        break;
    case 6:
        BKP-&gt;DR6=data;
        break;
    case 7:
        BKP-&gt;DR7=data;
        break;
    case 8:
        BKP-&gt;DR8=data;
        break;
    case 9:
        BKP-&gt;DR9=data;
        break;
    case 10:
        BKP-&gt;DR10=data;
        break;
    

    }
    }

u16 Read_Bkp(u8 reg)
{
u16 data;

switch(reg)
{
    case 1:
        data = BKP-&gt;DR1;
        break;
    case 2:
        data = BKP-&gt;DR2;
        break;
    case 3:
        data = BKP-&gt;DR3;
        break; 
    case 4:
        data = BKP-&gt;DR4;
        break;
    case 5:
        data = BKP-&gt;DR5;
        break;
    case 6:
        data = BKP-&gt;DR6;
        break;
    case 7:
        data = BKP-&gt;DR7;
        break;
    case 8:
        data = BKP-&gt;DR8;
        break;
    case 9:
        data = BKP-&gt;DR9;
        break;
    case 10:
        data = BKP-&gt;DR10;
        break;
} 

return data;

}

//开启入侵检测,检测引脚为GPIOC13 但是不用打开其时钟和设置引脚模式
void Tamper_Init()
{

BKP-&gt;CSR |= 3&lt;&lt;0;            //清除事件中断标志位

BKP-&gt;CR  |= 1&lt;&lt;1;            //设定为入侵电平为低电平
BKP-&gt;CSR |= 1&lt;&lt;2;            //允许入侵中断

BKP-&gt;CR  |= 1&lt;&lt;0;            //开启入侵检测

}

Library/inc/bkp.h
#include <stm32f10x_lib.h>

void Bkp_Init(void);

void Write_Bkp(u8 reg,u16 data);

u16 Read_Bkp(u8 reg);

void Tamper_Init(void);

库函数操作
main.c
#include “stm32f10x.h”

#include “stdio.h”

#define PRINTF_ON 1

#define CHECK_CODE 0xAE86

void RCC_Configuration(void);
void GPIO_Configuration(void);
void NVIC_Configuration(void);
void USART_Configuration(void);
void BKP_Configuration(void);

void PrintBKP(void);
void WriteBKP(u16 Data,u8 DRNumber);
u8 CheckBKP(void);

int main(void)
{
RCC_Configuration();
GPIO_Configuration();
NVIC_Configuration();
USART_Configuration();
BKP_Configuration();

if(CheckBKP())
{
    printf("\r\n The datas are as their initial status. \r\n");
    WriteBKP(0xA522,2);
    PrintBKP();
}else{
    printf("\r\n The datas have been changed . \r\n");
    WriteBKP(0xA53C,1);
    PrintBKP();
}  
while(1);

}

void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;            
GPIO_Init(GPIOA , &amp;GPIO_InitStructure); 

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;            
GPIO_Init(GPIOA , &amp;GPIO_InitStructure); 

}

void BKP_Configuration(void)
{
PWR_BackupAccessCmd(ENABLE);
BKP_ClearFlag();
BKP_TamperPinLevelConfig(BKP_TamperPinLevel_Low);
BKP_ITConfig(ENABLE);
BKP_TamperPinCmd(ENABLE);
}

void RCC_Configuration(void)
{
/ 定义枚举类型变量 HSEStartUpStatus /
ErrorStatus HSEStartUpStatus;

  /* 复位系统时钟设置*/
  RCC_DeInit();
  /* 开启HSE*/
  RCC_HSEConfig(RCC_HSE_ON);
  /* 等待HSE起振并稳定*/
  HSEStartUpStatus = RCC_WaitForHSEStartUp();
/* 判断HSE起是否振成功,是则进入if()内部 */
  if(HSEStartUpStatus == SUCCESS)
  {
    /* 选择HCLK(AHB)时钟源为SYSCLK 1分频 */
    RCC_HCLKConfig(RCC_SYSCLK_Div1); 
    /* 选择PCLK2时钟源为 HCLK(AHB) 1分频 */
    RCC_PCLK2Config(RCC_HCLK_Div1); 
    /* 选择PCLK1时钟源为 HCLK(AHB) 2分频 */
    RCC_PCLK1Config(RCC_HCLK_Div2);
    /* 设置FLASH延时周期数为2 */
    FLASH_SetLatency(FLASH_Latency_2);
    /* 使能FLASH预取缓存 */
    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
    /* 选择锁相环(PLL)时钟源为HSE 1分频,倍频数为9,则PLL输出频率为 8MHz * 9 = 72MHz */
    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
    /* 使能PLL */ 
    RCC_PLLCmd(ENABLE);
    /* 等待PLL输出稳定 */
    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
    /* 选择SYSCLK时钟源为PLL */
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    /* 等待PLL成为SYSCLK时钟源 */
    while(RCC_GetSYSCLKSource() != 0x08);
  } 
  /* 打开APB2总线上的GPIOA时钟*/
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1, ENABLE);

RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR|RCC_APB1Periph_BKP, ENABLE);

}

void USART_Configuration(void)
{
USART_InitTypeDef USART_InitStructure;
USART_ClockInitTypeDef USART_ClockInitStructure;

USART_ClockInitStructure.USART_Clock = USART_Clock_Disable;
USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low;
USART_ClockInitStructure.USART_CPHA = USART_CPHA_2Edge;                                                                                                                                                      
USART_ClockInitStructure.USART_LastBit = USART_LastBit_Disable;
USART_ClockInit(USART1 , &amp;USART_ClockInitStructure);

USART_InitStructure.USART_BaudRate = 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,&amp;USART_InitStructure);

 USART_Cmd(USART1,ENABLE);

}

void NVIC_Configuration(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(&amp;NVIC_InitStructure);

}

void WriteBKP(u16 Data,u8 DRNumber) // 还可加入一些加密算法;DRNumber (1-9)
{
switch(DRNumber)
{
case 0x01: BKP_WriteBackupRegister(BKP_DR1,Data); break;
case 0x02: BKP_WriteBackupRegister(BKP_DR2,Data); break;
case 0x03: BKP_WriteBackupRegister(BKP_DR3,Data); break;
case 0x04: BKP_WriteBackupRegister(BKP_DR4,Data); break;
case 0x05: BKP_WriteBackupRegister(BKP_DR5,Data); break;
case 0x06: BKP_WriteBackupRegister(BKP_DR6,Data); break;
case 0x07: BKP_WriteBackupRegister(BKP_DR7,Data); break;
case 0x08: BKP_WriteBackupRegister(BKP_DR8,Data); break;
case 0x09: BKP_WriteBackupRegister(BKP_DR9,Data); break;
default: BKP_WriteBackupRegister(BKP_DR1,Data);
}
BKP_WriteBackupRegister(BKP_DR10,CHECK_CODE);
}

u8 CheckBKP(void)
{
if( BKP_ReadBackupRegister(BKP_DR10) == 0xAE86 ) // 如果此位数据丢失,则BPK数据丢失
return 1;
else
return 0;
}

void PrintBKP(void)
{
printf(“DR1 = 0x%04X\t”,BKP_ReadBackupRegister(BKP_DR1));
printf(“DR2 = 0x%04X\t”,BKP_ReadBackupRegister(BKP_DR2));
printf(“DR3 = 0x%04X\t”,BKP_ReadBackupRegister(BKP_DR3));
printf(“DR4 = 0x%04X\t”,BKP_ReadBackupRegister(BKP_DR4));
printf(“DR5 = 0x%04X\t”,BKP_ReadBackupRegister(BKP_DR5));
printf(“DR6 = 0x%04X\t”,BKP_ReadBackupRegister(BKP_DR6));
printf(“DR7 = 0x%04X\t”,BKP_ReadBackupRegister(BKP_DR7));
printf(“DR8 = 0x%04X\t”,BKP_ReadBackupRegister(BKP_DR8));
printf(“DR9 = 0x%04X\t”,BKP_ReadBackupRegister(BKP_DR9));
printf(“DR10 = 0x%04X\t”,BKP_ReadBackupRegister(BKP_DR10));

}

#if PRINTF_ON

int fputc(int ch,FILE *f)
{
USART_SendData(USART1,(u8) ch);
while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET);
return ch;
}

#endif

stm12f10x_it.c
#include “stm32f10x_it.h”

#include “stdio.h”

extern void PrintBKP(void);

void TAMPER_IRQHandler(void)
{
printf(“\r\n A Tamper is coming .\r\n”);
PrintBKP();
BKP_ClearITPendingBit();
BKP_ClearFlag();

}