软件STM32cubeIDE下STM32F1xx和STM32F4xx使用:备份寄存器+复位标志位-基础样例

34 篇文章 2 订阅

1、前言

最近在项目上使用备份寄存器和复位标志,于是学习了一下,并使用。
用STM32也好几年了,很多像pwm和串口,也调试过很多了,但仍然认为很多东西,依旧要当自己为新手。像这次调试的这两个,之前没有调试过,也没有想到过会要用上这两个。

2 、 实验环境

  • 软件环境:STM32cubeIDE 1.8.0
  • 硬件芯片:STM32F103VET6(野火:指南者)
  • 硬件芯片:STM32F407ZET6(正点原子:探索者)
  • 其它硬件:串口转换器,下载器,有电的纽扣电池等。

3、自我总结

(1)对于备份寄存器(BKP):

你可以理解在STM32芯片中,有个地方(备份寄存器BKP)或者一块区域(备份SRAM)帮忙保存数据,当然这是有条件的:
第一个是,不能完全断电,物理意义上的不能完全断电。
第二个是,写入时是有限制的,写入时,要开使能,才允许写入,这么做是为保护,不让随意写入。

他们三个:RTC时钟、备份寄存器和备份SRAM,是有关系的,都在备份区域,所以在查BKP备份寄存器时,总能看到RTC时钟相关的内容。

(2)对于复位标志位(RCC_CSR):

复位标志位,你可以理解是软件自己检测的一种工具,打个比方,当代码出现异常,不再喂狗的时候,看门狗就会使得整个系统复位,起来后,你去读取复位标志,复位标志位,就会告诉软件,上次是因为什么而复位的。

一些复位信号的产生,会引起整个系统的产生,然后有个地方会存下是什么复位了,记录这个复位,让你好读取。软件做的只有读取和将那个地方清空一下,方便下次起来,好判定。如果不清空,那么因为本次已经置位了,下次,你可能不知道是什么复位了。

(3)实验阶段和实际应用有区别

自己使用过程中,其实分为实验验证阶段和实际应用阶段的,这点还是要注意的,我们试验阶段是要证明它可以使用,并且熟悉相应的特性,了解其原理。

而实际情况可能跟测试时会有不同:
第一个是:本次使用备份寄存器就是这样,在测试时,发现完全断电,备份寄存器确实也被复位为0了,但是实际融合项目上,发现因为整个设备比较复杂,虽然设备关机了,但是因为有其他部分存在,给备份寄存器供电了,没有电池,但相当一个电池了。而且还时灵时不灵,只有将外围设备拔除完全,才会被复位为0。

4、先行了解

对于更专业的解释,可以直接找手册,发现网上大部分知识点,在参考手册里都有,或者说,都是从手册里扒的,手册直接在网上找就可以了。
参考手册F1:STM32F10x中文参考手册.pdf
参考手册F4:STM32F4xx中文参考手册.pdf

这里放一些自己认为重要的吧。
(1)如下链接,全面简绍了一下,可以收获的两个点是:
第一个:备份寄存器等,需要很低的电,就可以将数据保存下来。
第二个:BKP和RTC之间是有关系的。
博文链接:https://blog.csdn.net/ZCShouCSDN/article/details/82896924

(2)看过一些博文后,回来看参考手册,发手册里面有些可以更好帮我们理解,这里建议多看手册吧。
在这里插入图片描述
这里告诉我们两个点是:
第一个:备份区域也是可以复位的,一种方式是通过软件的方式复位。
第二个:第二个复位方式是,完全断电,同时我们也可以理解,为啥纽扣电池要接V-BAT引脚,因为V-BAT专门连接备份区域,以保证数据存在。
在这里插入图片描述
(3)对于复位标志位,我截图以下几张,也自己认为比较重要的图,它告诉你复位标志位有哪些,分别都是什么复位。
在这里插入图片描述
(4)需要了解的库函数,实际使用过程中,要使能的定时器和一些函数这里先列举。在看资料过程中,一些博文都会提到要使能一些定时器开关的,这里因为咱们使用了IDE软件,自动生成,反而不需要关心,但是要知道有这些东西存在,移植的时候要带上。

在这里插入代码片

/* 以下都是在需要自己编写的代码 */
/* 获取某个复位标志位函数 */
  if (__HAL_RCC_GET_FLAG(RCC_FLAG_LSIRDY) != RESET)
  {
  }
/* 复位  复位标志位,就是清空标志位,让其为0 */  
__HAL_RCC_CLEAR_RESET_FLAGS();
/* 读取某个备份寄存器函数 */  
  g_nBackup_reg_value=HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1) ;
/* 写入某个备份寄存器函数,要开使能 */ 
  HAL_PWR_EnableBkUpAccess();
  HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, 0x02);// Writes a data in a RTC Backup data Register 1
 HAL_PWR_DisableBkUpAccess();


/* 以下都是在生成好的代码中,之间复制过来的,知道有这些函数就可以了,软件会自动生成 */
    __HAL_RCC_AFIO_CLK_ENABLE();
    __HAL_RCC_PWR_CLK_ENABLE();  //RCC电源时钟使能
    __HAL_AFIO_REMAP_SWJ_NOJTAG();
    HAL_PWR_EnableBkUpAccess();
    __HAL_RCC_BKP_CLK_ENABLE(); /* Enable BKP CLK enable for backup registers */
    __HAL_RCC_RTC_ENABLE();  /* Peripheral clock enable */
    HAL_NVIC_SetPriority(RTC_IRQn, 0, 0);/* RTC interrupt Init */
    HAL_NVIC_EnableIRQ(RTC_IRQn);

5、在STM32F1和STM32F4上进行实验

实验说明

(1)因为要进行复位,我们之前进行过看门狗实验,正好可以让它进行复位,看看复位标志位能不能记录。
看门狗相关文章:# 软件stm32cubeIDE下配置STM32F103的独立看门狗iwdg-学习笔记-基础样例

(2)而备份寄存器,我们需要需要完全断电和使用开发板上纽扣电池,看看断到外部电源后,会有什么情况。

(3)因为配置工程过程差不多,所以合并在一起说明了,如果对代码有疑问,可以去看代码。

1)新建工程配置

(1)基本配置:外部RCC和下载
在这里插入图片描述
在这里插入图片描述

2)串口打印uart1

配置串口,就是为显示用的,没啥特殊要求,就直接默认了。
在这里插入图片描述

3)看门狗配置,用来造成复位

如果下图,是看门狗配置,具体为啥是8秒左右,看之前文章吧,有详细说明。
在这里插入图片描述
如下图,是计算的方式
在这里插入图片描述

4)配置备份寄存器和标志位

复位标志位其实是不用配置什么的,而备份寄存器需要配置下,通过配置RTC,配置使能,没什么特别要求,默认既可以了。
在这里插入图片描述

5)配置系统时钟

STM32F1基本是72Mhz,而STM32F4基本是168M,这块配置下就行,自己使用的时候忘记配置系统时钟了,不过也不影响。
在这里插入图片描述

6)生成代码后,加入的代码段

这里主要分为三个部分的代码段,一段是读取复位标志的,一段是备份寄存器读写的,一段是看门狗的,他们都在main.c函数里。这里为了方便,我也不分开了,直接将主要的部分放在下面。


/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
//第二�??
#include "string.h"
#include "stdint.h"

uint8_t u_buf[64];

#define printf(...)  HAL_UART_Transmit((UART_HandleTypeDef * )&huart1, (uint8_t *)u_buf,\
											sprintf((char *)u_buf,__VA_ARGS__),0x200);

/
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/


/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
IWDG_HandleTypeDef hiwdg;

RTC_HandleTypeDef hrtc;

UART_HandleTypeDef huart1;

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_IWDG_Init(void);
static void MX_RTC_Init(void);
static void MX_USART1_UART_Init(void);
/* USER CODE BEGIN PFP */
//第三步加喂狗函数
void iwdg_feeddog(void)
{
    HAL_IWDG_Refresh(&hiwdg); // feed dog
}


int main(void)
{
  /* USER CODE BEGIN 1 */
int sum=0;
uint32_t g_nBackup_reg_value=0;
  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_IWDG_Init();
  MX_RTC_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  复位标志/
//  //printf("RCC_FLAG_LSIRDY:%d \n\t",__HAL_RCC_GET_FLAG(RCC_FLAG_LSIRDY));HAL_Delay(100);
//  printf("RCC_FLAG_PINRST:%d \n\t",__HAL_RCC_GET_FLAG(RCC_FLAG_PINRST));HAL_Delay(100);
//  printf("RCC_FLAG_PORRST:%d \n\t",__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST));HAL_Delay(100);
//  printf("RCC_FLAG_SFTRST:%d \n\t",__HAL_RCC_GET_FLAG(RCC_FLAG_SFTRST));HAL_Delay(100);
//  printf("RCC_FLAG_IWDGRST:%d \n\t",__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST));HAL_Delay(100);
//  printf("RCC_FLAG_WWDGRST:%d \n\t",__HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST));HAL_Delay(100);
//  printf("RCC_FLAG_LPWRRST:%d \n\t",__HAL_RCC_GET_FLAG(RCC_FLAG_LPWRRST));HAL_Delay(100);
//
//
//  __HAL_RCC_CLEAR_RESET_FLAGS();
//  printf("=========================================================");
//  printf("RCC_FLAG_PINRST:%d \n\t",__HAL_RCC_GET_FLAG(RCC_FLAG_PINRST));HAL_Delay(100);
//  printf("RCC_FLAG_PORRST:%d \n\t",__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST));HAL_Delay(100);
//  printf("RCC_FLAG_SFTRST:%d \n\t",__HAL_RCC_GET_FLAG(RCC_FLAG_SFTRST));HAL_Delay(100);
//  printf("RCC_FLAG_IWDGRST:%d \n\t",__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST));HAL_Delay(100);
//  printf("RCC_FLAG_WWDGRST:%d \n\t",__HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST));HAL_Delay(100);
//  printf("RCC_FLAG_LPWRRST:%d \n\t",__HAL_RCC_GET_FLAG(RCC_FLAG_LPWRRST));HAL_Delay(100);

/* 按位与在一个里
#define RCC_FLAG_LSIRDY    6
#define RCC_FLAG_PINRST    5
#define RCC_FLAG_PORRST    4
#define RCC_FLAG_SFTRST    3
#define RCC_FLAG_IWDGRST   2
#define RCC_FLAG_WWDGRST   1
#define RCC_FLAG_LPWRRST   0
  */

  //LSIRDY:内部低速振荡器就绪 (Internal low-speed oscillator ready)
  if (__HAL_RCC_GET_FLAG(RCC_FLAG_LSIRDY) != RESET)
  {
  	printf(" RCC_FLAG_LSIRDY_flag=1 ");

  }
  else
  {
	  printf(" RCC_FLAG_LSIRDY_flag=0 ");

  }
  HAL_Delay(100);
  //PINRSTF:NRST引脚复位标志 (PIN reset flag)
   if (__HAL_RCC_GET_FLAG(RCC_FLAG_PINRST) != RESET)
  {
  	printf(" RCC_FLAG_PINRST=1  ");

  }
   else
   {
 	  printf(" RCC_FLAG_PINRST=0 ");

   }
   HAL_Delay(100);
   //PORRSTF:POR/PDR 复位标志 (POR/PDR reset flag)
   if (__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST) != RESET)
  {
  	printf(" RCC_FLAG_PORRST=1 ");

  }
   else
  {
	printf(" RCC_FLAG_PORRST=0 ");

  }
  HAL_Delay(100);

   //SFTRSTF:软件复位标�? (Software reset flag)
   if (__HAL_RCC_GET_FLAG(RCC_FLAG_SFTRST) != RESET)
  {
  	printf(" RCC_FLAG_SFTRST=1 ");

  }
   else
  {
	printf(" RCC_FLAG_SFTRST=0 ");

  }
  HAL_Delay(100);

  //IWDGRSTF:独立看门狗复位标志 (Independent watchdog reset flag)
   if (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST) != RESET) //看门狗复�?
  {
  	printf(" RCC_FLAG_IWDGRST=1 ");

  }
   else
  {
	printf(" RCC_FLAG_IWDGRST=0 ");

  }
  HAL_Delay(100);
  //WWDGRSTF:窗口看门狗复位标志 (Window watchdog reset flag)
   if (__HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST) != RESET) //看门狗复�?
  {
  	printf(" RCC_FLAG_WWDGRST=1 ");

  }
   else
  {
	printf(" RCC_FLAG_WWDGRST=0 ");

  }
  HAL_Delay(100);
   // LPWRRSTF:低功�?�复位标�? (Low-power reset flag)
   if (__HAL_RCC_GET_FLAG(RCC_FLAG_LPWRRST) != RESET) //看门狗复�?
  {
  	printf(" RCC_FLAG_LPWRRST=1 ");

  }
   else
  {
	printf(" RCC_FLAG_LPWRRST=0 ");

  }
  HAL_Delay(500);
//  __HAL_RCC_CLEAR_RESET_FLAGS();
//  printf(" =========__HAL_RCC_CLEAR_RESET_FLAGS()====== ");

  备份寄存�?/

  g_nBackup_reg_value=HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1) ;

  printf("(1)g_nBackup_reg_value:%d  ",g_nBackup_reg_value);

  HAL_PWR_EnableBkUpAccess();
 	       // Writes a data in a RTC Backup data Register 1
  HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, 0x02);
 HAL_PWR_DisableBkUpAccess();


 g_nBackup_reg_value=HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1) ;

  printf("(2)g_nBackup_reg_value:%d  ",g_nBackup_reg_value);

  printf("main start!! \t");
  HAL_Delay(1000);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {

//	    if (HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1) != 0xBEBE)
//	    {
//	       // Write Back Up Register 1 Data
//	       HAL_PWR_EnableBkUpAccess();
//	       // Writes a data in a RTC Backup data Register 1
//	       HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, 0xBEBE);
//	       HAL_PWR_DisableBkUpAccess();
//
//
//	    }
//	    else
//	    {
//	       // data register already written so turn LED3
//
//
//	    }

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	    sum++;
	 // printf("123456");
	  printf("sum_value:%d",sum);
	  if(sum>=3)
	  {

	  }else
	  {
		  iwdg_feeddog();
	  }


	  HAL_Delay(1000);

  }
  /* USER CODE END 3 */
}



6、实验结果展示与结论

1)结果情况1:

STM32F1和STM32F4,表现基本一致,有供电情况下,备份寄存器内写入值,可以被保存起来,完全断电后,会置为为0。如下图所示
在这里插入图片描述

2)结果情况2:

复位标志位,默认上电后,每一个复位标志位,都有自己的值,不一定一定是0,需要根据情况分析,但是F1和F4两块开发板,复位情况保持一致,如下图所示。
在这里插入图片描述
我们可以看到第一次默认上电,标志位 RCC_FLAG_PINRST 和 RCC_FLAG_PORRST 都是1
,通过手册我们可以知道,一个是复位引脚的,一个是上下电的。
在这里插入图片描述

3)结果情况3:

STM32F1和STM32F4,通过相同函数__HAL_RCC_GET_FLAG(RCC_FLAG_LSIRDY)读取复位标志位的值是不一样的,所以采用两种形式进行打印输出。
在这里插入图片描述
如下图所示,F1中读取反馈的值是非常大的一个数,所以使用和RESET进行比较的形式输出,只要比较是不是0,我们看REST的值,发现就是判定是0和非0.
在这里插入图片描述

而在STM32F4,这个值读回来就是1或者0,就直接打印就好。

7、实际应用遇到问题-实际应用

(1)没有纽扣电池情况下,备份寄存器的值被保存下来

这块之前也说些了,实际应用过程中,因为外部连了很多设备,虽然他们都没有电池,也不给目标芯片供电,但在整个系统加持下,形成了一个类似电池的设备,让值被保持下来,而这个电池还有时灵,有时不灵,干扰测试结果。

(2)写入备份寄存器会引发其它异常

在实际使用过程中,因为带有boot,发现写入备份寄存器,导致boot跳转满,还无法升级,这块实际使用时,多测试和注意吧。

(3)带有boot的可能会清掉复位标志位

在实际使用过程中,也用了boot,所以boot在跳转前,会清除所有标志位,包括复位标志,所以实际使用时,主要不要清除复位标志位。

8、代码链接

(1)STM32F1样例代码
代码链接:https://download.csdn.net/download/qq_22146161/87744129

(1)STM32F4样例代码
代码链接:https://download.csdn.net/download/qq_22146161/87744131

9、细节部分

(1)通过hal库来看都有什么复位标志位

我们在hal库中通过一个复位标志,就能找到其它复位标志,这样也可以知道有多少个复位标志,再去查手册,知道了每个复位都会什么情况下复位。

在这里插入图片描述

(2)通过hal库来看有多少个备份寄存器可以使用

同样道理,我们可以通过一个备份寄存器,知道本系列芯片下,可以使用多少个备份寄存器,因为不同系列这个可以的数量可能是不一样的。
在这里插入图片描述

(3)要保证外部供电完全断电

如下图,所示,在调试过程中,发现备份寄存器值被保存下拉,一查才发现,j-link插着呢,电池电源和j-link都要关闭。
在这里插入图片描述
在这里插入图片描述

(4)了解原理图也是不可少的

我们可以通过原理图,来查看,硬件有没有接电池,也就是VBAT引脚外部硬件连接情况,有没有电池给其供电。
在这里插入图片描述

10、总结

一个再小的东西,也要保持自己谦虚,谨慎对待,小心实验。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

好奇龙猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值