查看原文
其他

有一种修饰符能使变量在处理器复位而不被初始化

strongerHuang strongerHuang 2021-01-31


先了解一下修饰符知识


修饰符是用于限定类型以及类型成员申明的一种符号。如C语言中常见的修饰符:

1.static静态修饰符:修饰变量,函数。作用域:变量仅仅在本文件可见,函数在本文件可以被调用;

2.extern声明修饰符:修饰变量,函数。修饰变量时候,变量的声明在外面;

3.const常量修饰符:修饰变量,函数。修饰变量时候,不能被重复赋值,只能放在只读段中;

4.volatile不稳定变量修饰符:这个变量不好翻译,在c中的作用大概有两点意思:A.表示变量是易失的,易变的; B.强制访存操作,防止编译器去优化,告诉编译器每次必须去内存中取值,而不是从寄存器或者缓存。


在C++  JAVA中还有更多:

public公共访问修饰符、private私有访问修饰符、protected保护访问修饰符、friendly、abstract等。

了解了修饰符之后,看见本文标题就知道本文提供的那个修饰符对于变量来说是比较重要的。



之前写过一篇文章【CM3(STM32)内核复位与系统复位区别及应用】,讲述了系统和内核复位之后存在差异,其实主要就是说内核复位之后,芯片外设资源没有进行复位的操作


而本文说的修饰符,修饰的变量位于RAM中,在默认情况下,编译器会将其变量存放在主RAM中,并在启动时对其进行初始化。而本文说的__no_init类型修饰符使编译器把变量放在非易失RAM区中,在启动时也不对它们进行初始化,也就是说__no_init在系统启动时不初始化变量。


什么情况下使用这修饰符使系统禁止变量的初始化?

看门狗复位的现场恢复,如果初始化了就完全不可恢复了。


在Keil和IAR集成开发环境下,这个修饰符有所不同;Keil中不集成这个修饰符,需要配置; 而IAR中集成这个修饰符,可直接使用。


Keil中__no_init的配置和使用

在Keil中,__no_init不是集成在开发环境中,故需要配置,配置之后就可以使用了。


1.宏定义__no_init

#define __no_init __attribute__((zero_init))


2.在工程选项中配置__no_init

Project -> Options for Targets -> Target,里面右下有个NoInit,这个就是需要我们配置的区域(可设定某一区域);


3.使用方法

__no_init uint16_t Cnt_NoInit;

提示:不能初始化这个变量。


IAR中的__no_init

IAR中的“__no_init”是一个关键字,你会发现在使用这个修饰符之后,字体都是关键字颜色。


__no_init uint16_t Cnt_NoInit;


例程源代码下载与说明

代码下载地址:

http://pan.baidu.com/s/1hskScba


两个工程名称:

1.STM32F103ZE(Keil)_复位不初始化变量NoInit

2.STM32F103ZE(IAR)_复位不初始化变量NoInit


本文提供的例程是一个Demo比较简单,但具有实际意义。Keil和IAR工程实现的功能一样。


源代码

__no_init uint16_t Cnt_NoInit;

uint16_t Cnt_Init = 100;


int main(void)

{

  System_Initializes();

  printf("Start...\n");  //复位打印


  while(1)

  {

    printf("Cnt_NoInit = %d\n", Cnt_NoInit);   //打印变量

    Cnt_NoInit++;

    if(Cnt_NoInit > 1000)

    {

      Cnt_NoInit = 0;

    }


    printf("Cnt_Init = %d\n", Cnt_Init);

    Cnt_Init++;

    if(Cnt_Init > 1000)

    {

      Cnt_Init = 0;

    }


    LED_ON;  

    TIMDelay_Nms(500);

    LED_OFF;

    TIMDelay_Nms(500);


    NVIC_SystemReset(); //系统复位

  }

}


不初始化变量,则会打印如下消息:

Start...

Cnt_NoInit = 0

Cnt_Init = 100


Start...

Cnt_NoInit = 1

Cnt_Init = 100


Start...

Cnt_NoInit = 2

Cnt_Init = 100


Start...

Cnt_NoInit = 3

Cnt_Init = 100



如果Cnt_NoInit不被修饰成不初始化

uint16_t Cnt_NoInit;

uint16_t Cnt_Init = 100;


则会打印出如下信息

Start...

Cnt_NoInit = 0

Cnt_Init = 100


Start...

Cnt_NoInit = 0

Cnt_Init = 100


Start...

Cnt_NoInit = 0

Cnt_Init = 100


Start...

Cnt_NoInit = 0

Cnt_Init = 100


相信聪明的你,看了上面例子会明白为什么没有初始化的变量“Cnt_NoInit”在变化,而初始化了的“Cnt_Init”一直不变。


最后

微信搜索“EmbeddDeveloper” 或者扫描下面二维码、关注,在我的底部菜单查看更多精彩内容!

长按识别二维码 关注



不求赞赏  只求点赞、点广告给与支持!

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存