电子产业一站式赋能平台

PCB联盟网

搜索
查看: 726|回复: 0
收起左侧

怎么让单片机变量不被初始化?

[复制链接]

418

主题

418

帖子

4293

积分

四级会员

Rank: 4

积分
4293
发表于 2024-9-27 11:45:00 | 显示全部楼层 |阅读模式
关注+星标公众,不错过精彩内容

my0ltj552jh64017188158.jpg

my0ltj552jh64017188158.jpg

作者 | strongerHuang
微信公众号 | strongerHuang
用过看门狗做项目的小伙伴应该会遇到,或想到这么一个情况:看门狗复位之后,保持复位之前的状态!
举一个栗子:某设备正在执行xx任务,亮了一个【状态灯】,但中途看门狗复位了,此时,我们需要继续执行之前的xx任务,也要保持之前的【状态灯】。
遇到类似需求的情况,就需要复位保持变量不变。其实,实现的方法有很多种,这里给大家讲讲在Keil、 IAR编译环境下,单片机变量不被初始化的实现方法。
处理器复位
处理器复位的方式有很多种,这里结合STM来讲述MCU复位的来源:
STM32的复位为三类:系统复位、电源复位和后备域复位
系统复位:1. NRST引脚上的低电平(外部复位)2. 窗口看门狗计数终止(WWDG复位)3. 独立看门狗计数终止(IWDG复位)4. 软件复位(SW复位)5. 低功耗管理复位
电源复位:1. 上电/掉电复位(POR/PDR复位)2. 从待机模式中返回
备份区域复位:1. 软件复位,备份区域复位可由设置备份域控制寄存器(RCC_BDCR)中的BDRST位产生。2. 在VDD和VBAT两者掉电的前提下, VDD或VBAT上电将引发备份区域复位。
请参考《STM32复位来源,Cotrex-M系统与内核复位区别》。
修饰符
实现处理器复位而变量不被初始化方法之前,让我们先了解一下修饰符的知识。
修饰符是用于限定类型以及类型成员申明的一种符号。如C语言中常见的修饰符:
1.static静态修饰符:修饰变量,函数。作用域:变量仅仅在本文件可见,函数在本文件可以被调用;
2.extern声明修饰符:修饰变量,函数。修饰变量时候,变量的声明在外面;
3.const常量修饰符:修饰变量,函数。修饰变量时候,不能被重复赋值,只能放在只读段中;
4.volatile不稳定变量修饰符:这个变量不好翻译,在c中的作用大概有两点意思:A.表示变量是易失的,易变的; B.强制访存操作,防止编译器去优化,告诉编译器每次必须去内存中取值,而不是从寄存器或者缓存。
其实,在C++  JAVA中还有更多:public公共访问修饰符、private私有访问修饰符、protected保护访问修饰符、friendly、abstract等。
而本文会使用到一个修饰符:
  • __no_init
    虽然这个修饰符不是C语言标准的修饰符,但在Keil、IAR这种集成开发环境中,他们支持这种修饰符。
    而本文说的修饰符,修饰的变量位于RAM中:在默认情况下,编译器会将其变量存放在主RAM中,并在启动时对其进行初始化。而__no_init类型修饰符使编译器把变量放在非易失RAM区中,在启动时也不对它们进行初始化,也就是说__no_init在系统启动时不初始化变量。
    Keil中__no_init的配置和使用
    在Keil中,__no_init不是标准的修饰符,需要进行配置,配置之后就可以使用了。
    1.宏定义__no_init
  • #define __no_init __attribute__((zero_init))
    2.在工程选项中配置__no_initProject -> Options for Targets -> Target,里面右下有个NoInit,这个就是需要我们配置的区域(可设定某一区域);

    fydsxnlecpu64017188258.png

    fydsxnlecpu64017188258.png


    3.使用方法比如定义变量:Cnt_NoInit
  • __no_init uint16_t Cnt_NoInit;
    提示:不能初始化这个变量(也就是定义时不要赋值)。
    IAR中中使用__no_init
    在IAR中“__no_init”属于是一个关键字,你会发现在使用这个修饰符之后,字体都是关键字颜色。
    直接使用即可,类似上面定义一个不被初始化的变量:
  • __no_init uint16_t Cnt_NoInit;
    参考源码
    这里给大家分享两个简单的Demo(源码),Keil和IAR工程实现的功能一样。
    源代码:
  • __no_inituint16_t Cnt_NoInit;uint16_t Cnt_Init = 100;
    int main(void){  System_Initializes();  printf("Start...
    ");  //复位打印
      while(1)  {    printf("Cnt_NoInit = %d
    ", Cnt_NoInit);   //打印变量    Cnt_NoInit++;
        if(Cnt_NoInit > 1000)    {      Cnt_NoInit = 0;    }
        printf("Cnt_Init = %d
    ", Cnt_Init);    Cnt_Init++;    if(Cnt_Init > 1000)    {      Cnt_Init = 0;    }
        LED_ON;      TIMDelay_Nms(500);    LED_OFF;    TIMDelay_Nms(500);    NVIC_SystemReset(); //系统复位  }}
    被Cnt_NoInit修饰,则会打印如下消息:
  • Start...Cnt_NoInit = 0Cnt_Init = 100
    Start...Cnt_NoInit = 1Cnt_Init = 100
    Start...Cnt_NoInit = 2Cnt_Init = 100
    Start...Cnt_NoInit = 3Cnt_Init = 100
    如果不被修饰:
  • uint16_t Cnt_NoInit;uint16_t Cnt_Init = 100;如果不被修饰:则会打印如下消息:
  • Start...Cnt_NoInit = 0Cnt_Init = 100
    Start...Cnt_NoInit = 0Cnt_Init = 100
    Start...Cnt_NoInit = 0Cnt_Init = 100
    Start...Cnt_NoInit = 0Cnt_Init = 100
    相信聪明的你,看了上面例子会明白为什么没有初始化的变量“Cnt_NoInit”在变化,而初始化了的“Cnt_Init”一直不变。
    ------------ END ------------

    dvg5fkifoqd64017188358.gif

    dvg5fkifoqd64017188358.gif


    ●专栏《嵌入式工具
    ●专栏《嵌入式开发》
    ●专栏《Keil教程》
    ●嵌入式专栏精选教程

    关注公众号回复“加群”按规则加入技术交流群,回复“1024”查看更多内容。

    gouuhxcgwok64017188458.jpg

    gouuhxcgwok64017188458.jpg


    e43mp1kbr2464017188558.png

    e43mp1kbr2464017188558.png


    点击“阅读原文”查看更多分享。
  • 回复

    使用道具 举报

    发表回复

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则


    联系客服 关注微信 下载APP 返回顶部 返回列表