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):
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的时钟和输入输出模式。
User/main.c
01 | #include <stm32f10x_lib.h> |
02 | #include "system.h" |
03 | #include "usart.h" |
04 | #include "bkp.h" |
05 |
06 | #define LED1 PAout(4) |
07 | #define LED2 PAout(5) |
08 |
09 | void Gpio_Init( void ); |
10 |
11 | int main( void ) |
12 | { |
13 | u16 data,i=10; |
14 |
15 | Rcc_Init(9); //系统时钟设置 |
16 |
17 | Usart1_Init(72,9600); |
18 |
19 | Bkp_Init(); |
20 |
21 | Tamper_Init(); |
22 |
23 | Nvic_Init(0,0,TAMPER_IRQChannel,0); //设置中断 |
24 | |
25 | Gpio_Init(); |
26 |
27 | while (i){ |
28 |
29 | Write_Bkp(i,i); |
30 |
31 | data = Read_Bkp(i); |
32 | |
33 | printf ( "\n DR%u = 0x%04X\n" ,i,data); |
34 |
35 | delay(30000); //延时30ms |
36 |
37 | i--; |
38 | |
39 | } |
40 | |
41 | while (1); |
42 | } |
43 |
44 |
45 | void Gpio_Init( void ) |
46 | { |
47 | RCC->APB2ENR|=1<<2; //使能PORTA时钟 |
48 |
49 | GPIOA->CRL&=0x0000FFFF; // PA0~3设置为浮空输入,PA4~7设置为推挽输出 |
50 | GPIOA->CRL|=0x33334444; |
51 |
52 | |
53 | //USART1 串口I/O设置 |
54 |
55 | GPIOA -> CRH&=0xFFFFF00F; //设置USART1 的Tx(PA.9)为第二功能推挽,50MHz;Rx(PA.10)为浮空输入 |
56 | GPIOA -> CRH|=0x000008B0; |
57 | } |
User/stm32f103x_it.c
01 | #include "stm32f10x_it.h" |
02 | #include "system.h" |
03 | #include "stdio.h" |
04 |
05 | #define LED1 PAout(4) |
06 | #define LED2 PAout(5) |
07 | #define LED3 PAout(6) |
08 | #define LED4 PAout(7) |
09 |
10 | extern u16 Read_Bkp(u8 reg); |
11 |
12 | void TAMPER_IRQHandler( void ) |
13 | { |
14 | u16 i=10,data; |
15 |
16 | LED4 =1 ; |
17 |
18 | printf ( "\r\n A Tamper is coming .\r\n" ); |
19 |
20 | while (i){ |
21 |
22 | data = Read_Bkp(i); |
23 | |
24 | printf ( "\n DR%u = 0x%04X\n" ,i,data); |
25 |
26 | delay(30000); //延时30ms |
27 |
28 | i--; |
29 | |
30 | } |
31 |
32 | BKP->CSR |= 3<<0; //清除事件中断标志位 |
33 |
34 | } |
Library/src/bkp.c
001 | #include <stm32f10x_lib.h> |
002 | #include "bkp.h" |
003 |
004 | void Bkp_Init( void ) |
005 | { |
006 | RCC->APB1RSTR |= 1<<27; //复位BKP寄存器 |
007 | RCC->APB1RSTR &= ~(1<<27); |
008 |
009 | RCC->APB1ENR|=1<<28; //使能电源时钟 |
010 | RCC->APB1ENR|=1<<27; //使能BKP时钟 |
011 | } |
012 |
013 |
014 | /** |
015 | * |
016 | *后备寄存器写入操作 |
017 | *reg:寄存器编号 |
018 | *data:要写入的数值 |
019 | * |
020 | **/ |
021 | void Write_Bkp(u8 reg,u16 data) |
022 | { |
023 |
024 | PWR->CR|=1<<8; //取消备份区写保护 |
025 |
026 | switch (reg) |
027 | { |
028 | case 1: |
029 | BKP->DR1=data; |
030 | break ; |
031 | case 2: |
032 | BKP->DR2=data; |
033 | break ; |
034 | case 3: |
035 | BKP->DR3=data; |
036 | break ; |
037 | case 4: |
038 | BKP->DR4=data; |
039 | break ; |
040 | case 5: |
041 | BKP->DR5=data; |
042 | break ; |
043 | case 6: |
044 | BKP->DR6=data; |
045 | break ; |
046 | case 7: |
047 | BKP->DR7=data; |
048 | break ; |
049 | case 8: |
050 | BKP->DR8=data; |
051 | break ; |
052 | case 9: |
053 | BKP->DR9=data; |
054 | break ; |
055 | case 10: |
056 | BKP->DR10=data; |
057 | break ; |
058 | } |
059 | } |
060 |
061 |
062 | u16 Read_Bkp(u8 reg) |
063 | { |
064 | u16 data; |
065 |
066 | switch (reg) |
067 | { |
068 | case 1: |
069 | data = BKP->DR1; |
070 | break ; |
071 | case 2: |
072 | data = BKP->DR2; |
073 | break ; |
074 | case 3: |
075 | data = BKP->DR3; |
076 | break ; |
077 | case 4: |
078 | data = BKP->DR4; |
079 | break ; |
080 | case 5: |
081 | data = BKP->DR5; |
082 | break ; |
083 | case 6: |
084 | data = BKP->DR6; |
085 | break ; |
086 | case 7: |
087 | data = BKP->DR7; |
088 | break ; |
089 | case 8: |
090 | data = BKP->DR8; |
091 | break ; |
092 | case 9: |
093 | data = BKP->DR9; |
094 | break ; |
095 | case 10: |
096 | data = BKP->DR10; |
097 | break ; |
098 | } |
099 |
100 | return data; |
101 | } |
102 |
103 | //开启入侵检测,检测引脚为GPIOC13 但是不用打开其时钟和设置引脚模式 |
104 | void Tamper_Init() |
105 | { |
106 |
107 | BKP->CSR |= 3<<0; //清除事件中断标志位 |
108 |
109 | BKP->CR |= 1<<1; //设定为入侵电平为低电平 |
110 | BKP->CSR |= 1<<2; //允许入侵中断 |
111 |
112 | BKP->CR |= 1<<0; //开启入侵检测 |
113 |
114 |
115 | } |
Library/inc/bkp.h
1 | #include <stm32f10x_lib.h> |
2 |
3 | void Bkp_Init( void ); |
4 |
5 | void Write_Bkp(u8 reg,u16 data); |
6 |
7 | u16 Read_Bkp(u8 reg); |
8 |
9 | void Tamper_Init( void ); |
库函数操作
main.c
001 | #include "stm32f10x.h" |
002 | #include "stdio.h" |
003 |
004 |
005 | #define PRINTF_ON 1 |
006 | #define CHECK_CODE 0xAE86 |
007 |
008 |
009 | void RCC_Configuration( void ); |
010 | void GPIO_Configuration( void ); |
011 | void NVIC_Configuration( void ); |
012 | void USART_Configuration( void ); |
013 | void BKP_Configuration( void ); |
014 |
015 | void PrintBKP( void ); |
016 | void WriteBKP(u16 Data,u8 DRNumber); |
017 | u8 CheckBKP( void ); |
018 |
019 | int main( void ) |
020 | { |
021 | RCC_Configuration(); |
022 | GPIO_Configuration(); |
023 | NVIC_Configuration(); |
024 | USART_Configuration(); |
025 | BKP_Configuration(); |
026 | |
027 |
028 |
029 | if (CheckBKP()) |
030 | { |
031 | printf ( "\r\n The datas are as their initial status. \r\n" ); |
032 | WriteBKP(0xA522,2); |
033 | PrintBKP(); |
034 | } else { |
035 | printf ( "\r\n The datas have been changed . \r\n" ); |
036 | WriteBKP(0xA53C,1); |
037 | PrintBKP(); |
038 | } |
039 | while (1); |
040 | } |
041 |
042 |
043 |
044 |
045 | |
046 | void GPIO_Configuration( void ) |
047 | { |
048 | GPIO_InitTypeDef GPIO_InitStructure; |
049 | |
050 | GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; |
051 | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; |
052 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; |
053 | GPIO_Init(GPIOA , &GPIO_InitStructure); |
054 |
055 | GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; |
056 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; |
057 | GPIO_Init(GPIOA , &GPIO_InitStructure); |
058 | } |
059 |
060 | void BKP_Configuration( void ) |
061 | { |
062 | PWR_BackupAccessCmd(ENABLE); |
063 | BKP_ClearFlag(); |
064 | BKP_TamperPinLevelConfig(BKP_TamperPinLevel_Low); |
065 | BKP_ITConfig(ENABLE); |
066 | BKP_TamperPinCmd(ENABLE); |
067 | } |
068 |
069 |
070 | void RCC_Configuration( void ) |
071 | { |
072 | /* 定义枚举类型变量 HSEStartUpStatus */ |
073 | ErrorStatus HSEStartUpStatus; |
074 |
075 | /* 复位系统时钟设置*/ |
076 | RCC_DeInit(); |
077 | /* 开启HSE*/ |
078 | RCC_HSEConfig(RCC_HSE_ON); |
079 | /* 等待HSE起振并稳定*/ |
080 | HSEStartUpStatus = RCC_WaitForHSEStartUp(); |
081 | /* 判断HSE起是否振成功,是则进入if()内部 */ |
082 | if (HSEStartUpStatus == SUCCESS) |
083 | { |
084 | /* 选择HCLK(AHB)时钟源为SYSCLK 1分频 */ |
085 | RCC_HCLKConfig(RCC_SYSCLK_Div1); |
086 | /* 选择PCLK2时钟源为 HCLK(AHB) 1分频 */ |
087 | RCC_PCLK2Config(RCC_HCLK_Div1); |
088 | /* 选择PCLK1时钟源为 HCLK(AHB) 2分频 */ |
089 | RCC_PCLK1Config(RCC_HCLK_Div2); |
090 | /* 设置FLASH延时周期数为2 */ |
091 | FLASH_SetLatency(FLASH_Latency_2); |
092 | /* 使能FLASH预取缓存 */ |
093 | FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); |
094 | /* 选择锁相环(PLL)时钟源为HSE 1分频,倍频数为9,则PLL输出频率为 8MHz * 9 = 72MHz */ |
095 | RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); |
096 | /* 使能PLL */ |
097 | RCC_PLLCmd(ENABLE); |
098 | /* 等待PLL输出稳定 */ |
099 | while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); |
100 | /* 选择SYSCLK时钟源为PLL */ |
101 | RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); |
102 | /* 等待PLL成为SYSCLK时钟源 */ |
103 | while (RCC_GetSYSCLKSource() != 0x08); |
104 | } |
105 | /* 打开APB2总线上的GPIOA时钟*/ |
106 | RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1, ENABLE); |
107 |
108 | RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR|RCC_APB1Periph_BKP, ENABLE); |
109 | |
110 | } |
111 |
112 | |
113 | void USART_Configuration( void ) |
114 | { |
115 | USART_InitTypeDef USART_InitStructure; |
116 | USART_ClockInitTypeDef USART_ClockInitStructure; |
117 |
118 | USART_ClockInitStructure.USART_Clock = USART_Clock_Disable; |
119 | USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low; |
120 | USART_ClockInitStructure.USART_CPHA = USART_CPHA_2Edge; |
121 | USART_ClockInitStructure.USART_LastBit = USART_LastBit_Disable; |
122 | USART_ClockInit(USART1 , &USART_ClockInitStructure); |
123 |
124 | USART_InitStructure.USART_BaudRate = 9600; |
125 | USART_InitStructure.USART_WordLength = USART_WordLength_8b; |
126 | USART_InitStructure.USART_StopBits = USART_StopBits_1; |
127 | USART_InitStructure.USART_Parity = USART_Parity_No; |
128 | USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; |
129 | USART_InitStructure.USART_Mode = USART_Mode_Rx|USART_Mode_Tx; |
130 | USART_Init(USART1,&USART_InitStructure); |
131 |
132 | USART_Cmd(USART1,ENABLE); |
133 | } |
134 |
135 |
136 | void NVIC_Configuration( void ) |
137 | { |
138 | NVIC_InitTypeDef NVIC_InitStructure; |
139 |
140 | NVIC_InitStructure.NVIC_IRQChannel = TAMPER_IRQn; |
141 | NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; |
142 | NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; |
143 | NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; |
144 | NVIC_Init(&NVIC_InitStructure); |
145 |
146 | } |
147 |
148 | void WriteBKP(u16 Data,u8 DRNumber) // 还可加入一些加密算法;DRNumber (1-9) |
149 | { |
150 | switch (DRNumber) |
151 | { |
152 | case 0x01: BKP_WriteBackupRegister(BKP_DR1,Data); break ; |
153 | case 0x02: BKP_WriteBackupRegister(BKP_DR2,Data); break ; |
154 | case 0x03: BKP_WriteBackupRegister(BKP_DR3,Data); break ; |
155 | case 0x04: BKP_WriteBackupRegister(BKP_DR4,Data); break ; |
156 | case 0x05: BKP_WriteBackupRegister(BKP_DR5,Data); break ; |
157 | case 0x06: BKP_WriteBackupRegister(BKP_DR6,Data); break ; |
158 | case 0x07: BKP_WriteBackupRegister(BKP_DR7,Data); break ; |
159 | case 0x08: BKP_WriteBackupRegister(BKP_DR8,Data); break ; |
160 | case 0x09: BKP_WriteBackupRegister(BKP_DR9,Data); break ; |
161 | default : BKP_WriteBackupRegister(BKP_DR1,Data); |
162 | } |
163 | BKP_WriteBackupRegister(BKP_DR10,CHECK_CODE); |
164 | } |
165 |
166 | u8 CheckBKP( void ) |
167 | { |
168 | if ( BKP_ReadBackupRegister(BKP_DR10) == 0xAE86 ) // 如果此位数据丢失,则BPK数据丢失 |
169 | return 1; |
170 | else |
171 | return 0; |
172 | } |
173 |
174 | void PrintBKP( void ) |
175 | { |
176 | printf ( "DR1 = 0x%04X\t" ,BKP_ReadBackupRegister(BKP_DR1)); |
177 | printf ( "DR2 = 0x%04X\t" ,BKP_ReadBackupRegister(BKP_DR2)); |
178 | printf ( "DR3 = 0x%04X\t" ,BKP_ReadBackupRegister(BKP_DR3)); |
179 | printf ( "DR4 = 0x%04X\t" ,BKP_ReadBackupRegister(BKP_DR4)); |
180 | printf ( "DR5 = 0x%04X\t" ,BKP_ReadBackupRegister(BKP_DR5)); |
181 | printf ( "DR6 = 0x%04X\t" ,BKP_ReadBackupRegister(BKP_DR6)); |
182 | printf ( "DR7 = 0x%04X\t" ,BKP_ReadBackupRegister(BKP_DR7)); |
183 | printf ( "DR8 = 0x%04X\t" ,BKP_ReadBackupRegister(BKP_DR8)); |
184 | printf ( "DR9 = 0x%04X\t" ,BKP_ReadBackupRegister(BKP_DR9)); |
185 | printf ( "DR10 = 0x%04X\t" ,BKP_ReadBackupRegister(BKP_DR10)); |
186 |
187 | } |
188 |
189 |
190 | #if PRINTF_ON |
191 |
192 | int fputc ( int ch, FILE *f) |
193 | { |
194 | USART_SendData(USART1,(u8) ch); |
195 | while (USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET); |
196 | return ch; |
197 | } |
198 |
199 | #endif |
stm12f10x_it.c
01 | #include "stm32f10x_it.h" |
02 |
03 | #include "stdio.h" |
04 |
05 | extern void PrintBKP( void ); |
06 |
07 | void TAMPER_IRQHandler( void ) |
08 | { |
09 | printf ( "\r\n A Tamper is coming .\r\n" ); |
10 | PrintBKP(); |
11 | BKP_ClearITPendingBit(); |
12 | BKP_ClearFlag(); |
13 |
14 | } |