单片机异常复位后如何保存变量数据

简介: 单片机异常复位后如何保存变量数据

目录

1、理论


2、实践


1、理论

众所周知,单片机复位后变量数值会自动初始化,以华大半导体HC32L136为例,具有 7 个复位信号来源,每个复位信号都可以让 CPU 重新运行,绝大多数寄存器会被复位到复位值,程序会从复位向量处开始执行。


数字区域上电掉电复位 POR

外部 Reset PAD,低电平为复位信号

WDT 复位

PCA 复位

LVD 低电压复位

Cortex-M0+ SYSRESETREQ 软件复位

Cortex-M0+ LOCKUP 硬件复位

每个复位源由相应的复位标志进行指示,复位标志均由硬件置位,需要用户软件清零。


华大半导体各区域的复位来源如下图所示:


image.png


本篇博客主要讲授华大半导(STM32、C51等单片机均可适用)复位(以看门狗复位为例)后变量数据保存的方法。


这里将用到__not_init属性,其用于变量声明,可禁止系统启动时变量的初始化,有了__not_init属性,编译器只给指定变量分配空间,不会再初始化。


image.png


__not_init的两种定义方式如下所示:


方式1:不指定存储位置,由编译器分配
    __no_init 类型 变量名;        ///< 例如:__no_init uint8_t cou_num;
    方式2:指定存储位置
    __no_init 类型 变量名 @地址;  ///< 例如:__no_init uint8_t cou_num @0x20000000;

2、实践

实践描述:使用__no_init属性创建一个变量cou_num,其将数据存储在SRAM中,每隔300毫秒自加1并通过串口打印输出数值,当检测到上电复位和按键复位后,变量cou_num数值置为0,在看门狗复位下变量cou_num数值不变。


第1步:配置串口引脚、串口使能和串口中断,代码如下所示:


///< 串口引脚配置
static void App_PortInit(void)
{
    stc_gpio_cfg_t stcGpioCfg;
    DDL_ZERO_STRUCT(stcGpioCfg);
    ///< 使能GPIO模块时钟
    Sysctrl_SetPeripheralGate(SysctrlPeripheralGpio,TRUE); 
    ///< 配置PA02端口为URART1_TX
    stcGpioCfg.enDir = GpioDirOut;
    Gpio_Init(GpioPortA, GpioPin2, &stcGpioCfg);
    Gpio_SetAfMode(GpioPortA, GpioPin2, GpioAf1);            
}
///< 串口配置
static void App_UartCfg(void)
{
    stc_uart_cfg_t    stcCfg;
    DDL_ZERO_STRUCT(stcCfg);
    ///< 开启UART1外设时钟
    Sysctrl_SetPeripheralGate(SysctrlPeripheralUart1,TRUE);
    ///< UART1初始化
    stcCfg.enRunMode        = UartMskMode3;           ///< 模式3
    stcCfg.enStopBit        = UartMsk1bit;            ///< 1bit停止位
    stcCfg.enMmdorCk        = UartMskEven;            ///< 偶检验
    stcCfg.stcBaud.u32Baud  = 9600;                   ///< 波特率9600  注意误差
    stcCfg.stcBaud.enClkDiv = UartMsk8Or16Div;        ///< 通道采样分频配置
    stcCfg.stcBaud.u32Pclk  = Sysctrl_GetPClkFreq();  ///< 获得外设时钟(PCLK)频率值
    Uart_Init(M0P_UART1, &stcCfg);                    ///< 串口初始化
    ///< UART1中断使能
    Uart_ClrStatus(M0P_UART1,UartTC);                 ///< 清发送请求
    Uart_EnableIrq(M0P_UART1,UartTxIrq);              ///< 使能串口发送中断
    EnableNvic(UART1_IRQn, IrqLevel3, TRUE);          ///< 系统中断使能
}
///< UART1中断函数
void Uart1_IRQHandler(void)
{
    ///< UART1数据发送
    if(Uart_GetStatus(M0P_UART1, UartTC))         
    {
        ///< 清中断状态位
        Uart_ClrStatus(M0P_UART1, UartTC);  
    }
}

第2步:配置看门狗复位,每隔820毫秒若没有喂狗,则复位,代码如下所示:


///< WDT初始化配置
static void App_WdtInit(void)
{
    ///< 开启WDT外设时钟
    Sysctrl_SetPeripheralGate(SysctrlPeripheralWdt,TRUE);
    ///< WDT 初始化,喂狗时间:820ms
    Wdt_Init(WdtResetEn, WdtT820ms);
}

第3步:使用__no_init属性定义cou_num变量,将数组存储在SRAM寄存器0x20001000中,代码如下所示:


__no_init uint8_t cou_num @ 0x20001000;

第4步:添加上电复位源和RESET脚复位源检测,当检测到其中之一个复位的时候,cou_num置为0,代码如下所示:


int32_t main(void)
{
    char * data_buf = (char *)malloc(sizeof(char) * 19);
    ///< 串口引脚配置
    App_PortInit();
    ///< 串口配置
    App_UartCfg();
    ///< WDT初始化
    App_WdtInit();
    ///< 启动 WDT
    Wdt_Start();
    ///< 当上电复位或者RESET脚复位后cou_num为0,看门狗复位数值不变
    if((Reset_GetFlag(ResetFlagMskPor5V) == 1) || (Reset_GetFlag(ResetFlagMskRstb) == 1))
    {
      cou_num = 0;
      Reset_ClearFlag(ResetFlagMskPor5V);
      Reset_ClearFlag(ResetFlagMskRstb);
    }
    while (1)
    {
        cou_num = cou_num + 1;
        delay1ms(300);
        ///< 开启喂狗后,将不会产生复位
        //Wdt_Feed(); 
        sprintf(data_buf,"numerical value:%d\n",cou_num);
        for(int8_t i = 0;i < 19;i++)
        {
          Uart_SendDataIt(M0P_UART1,data_buf[i]); 
          delay1ms(5);
        }
    }
}

运行效果如下所示:



image.png

可见虽然看门狗每隔820毫秒复位一次,但是cou_num数值不收影响,但是也可以看出cou_num数值中间存在丢失,例如没有打印输出数值3,主要原因是运行到此数时,恰巧看门狗复位,所以串口未来得及打印,但是不影响cou_num计数。


相关文章
|
6月前
|
存储 移动开发
80C51单片机----数据传送类指令
80C51单片机----数据传送类指令
182 2
【单片机期中测试】13.串口通信的应用(2)—— 超声波通过串口返回数据
【单片机期中测试】13.串口通信的应用(2)—— 超声波通过串口返回数据
102 0
|
安全 网络协议 API
利用单片机实现天气服务器获取指定位置天气数据
大家好,今天主要和大家聊一聊,如何利用单片机从心知天气服务器上获取到指定位置的天气数据,咱们先来了解一下心知天气吧!​
261 0
利用单片机实现天气服务器获取指定位置天气数据
|
存储 芯片
复习单片机:8*8点阵---->点亮数字0(内含:1.设计思路+2.数字0的编程数据+3.原始代码+4.实验现象)(注:获得编程数据工具的下载和使用放在下一篇文章)
复习单片机:8*8点阵---->点亮数字0(内含:1.设计思路+2.数字0的编程数据+3.原始代码+4.实验现象)(注:获得编程数据工具的下载和使用放在下一篇文章)
451 0
复习单片机:8*8点阵---->点亮数字0(内含:1.设计思路+2.数字0的编程数据+3.原始代码+4.实验现象)(注:获得编程数据工具的下载和使用放在下一篇文章)
第二章(2) 单片机内并行口P2,P3 位结构,输入,复位特性,功能第二章
第二章(2) 单片机内并行口P2,P3 位结构,输入,复位特性,功能
第二章(2) 单片机内并行口P2,P3 位结构,输入,复位特性,功能第二章
|
存储 算法 编译器
单片机如何从上电复位执行到main函数?
单片机如何从上电复位执行到main函数?
单片机如何从上电复位执行到main函数?