0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

单片机变量不被初始化的实现方法

strongerHuang 来源:strongerHuang 作者:strongerHuang 2023-05-11 09:29 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

最近有读者问了一个这样的问题:看门狗复位之后,能不能保持复位之前的状态?

这种问题,或者类似的问题,相信很多小伙伴都经历过,特别是有多年单片机开发经验的小伙伴,而且现实中的很多项目确实有这样的需求。

实现的方法有很多种,这里给大家讲讲在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上电将引发备份区域复位。

修饰符

实现处理器复位而变量不被初始化方法之前,让我们先了解一下修饰符的知识。

修饰符是用于限定类型以及类型成员申明的一种符号。如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_init

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


3f6b8b62-ef92-11ed-90ce-dac502259ad0.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 = 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
如果不被修饰:
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”一直不变。

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 单片机
    +关注

    关注

    6074

    文章

    45340

    浏览量

    663424
  • mcu
    mcu
    +关注

    关注

    147

    文章

    18604

    浏览量

    386848
  • 看门狗
    +关注

    关注

    10

    文章

    607

    浏览量

    72578
  • IAR
    IAR
    +关注

    关注

    5

    文章

    400

    浏览量

    38334
  • 初始化
    +关注

    关注

    0

    文章

    51

    浏览量

    12297

原文标题:单片机变量不被初始化的实现方法

文章出处:【微信号:strongerHuang,微信公众号:strongerHuang】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    SD卡初始化原理讲解与实现

    初始化过程: 在对 SD 卡初始化之前,我们需要对其上电后复位。复位的方法为: 1 拉高 CS,发送至少 74 个时钟周期来使 SD 卡达到正常工作电压和进行同步 2 选低 CS,发送 CMD0,需要
    发表于 10-29 06:33

    串口通信基石:Air8000下Modbus RTU串口初始化详解!

    串口初始化是Modbus RTU通信稳定可靠的关键起点。本篇深入剖析Air8000开发板串口参数配置、初始化代码实现及调试要点,结合master_rtu示例,分享实际操作中的经验与避坑指南,让您
    的头像 发表于 10-28 16:33 1440次阅读
    串口通信基石:Air8000下Modbus RTU串口<b class='flag-5'>初始化</b>详解!

    NVMe高速传输之摆脱XDMA设计33:初始化功能验证与分析

    本文主要交流NVMe设计思路,在本博客已给出相关博文五十多篇,希望对初学者有一定作用 初始化功能主要实现 PCIe 链路设备的初始化配置和 NVMe 初始化配置。 复杂的PCIe 事务
    发表于 10-08 08:02

    GraniStudio:IO初始化以及IO资源配置例程

    IO资源配置.gsp文件,点击打开,完成导入。 2.功能说明 实现连接格拉尼控制器IO块以及配置输入输出IO点。 2.1通过初始化IO算子连接格拉尼控制器IO块,导入工程自动进行连接。 2.2 通过IO配置算子输出配置的IO表。 第一次使用GS软件时操作步骤如下: (1)
    的头像 发表于 08-22 17:34 745次阅读
    GraniStudio:IO<b class='flag-5'>初始化</b>以及IO资源配置例程

    GraniStudio:初始化例程

    1.文件运行 导入工程 双击运行桌面GraniStudio.exe。 通过引导界面导入初始化例程,点击导入按钮。 打开初始化例程所在路径,选中初始化.gsp文件,点击打开,完成导入。 2.功能
    的头像 发表于 08-22 16:45 700次阅读
    GraniStudio:<b class='flag-5'>初始化</b>例程

    定义IO初始化结构体

    由上述IOPORT相关功能的枚举类型我们可以知道,在对IOPORT模块进行初始化时需要根据情况配置它们。因此我们定义一个IOPORT初始化的结构体类型IOPORT_Init_t,它的成员包括了由上述所有枚举类型所声明的变量,因此
    的头像 发表于 07-16 16:26 1105次阅读

    NVMe高速传输之摆脱XDMA设计之七:系统初始化

    直接采用PCIe实现NVMe功能,它的系统初始化流程主要分为链路训练、PCIe 初始化和 NVMe 初始化, 分别实现 PCIe链路连接、
    发表于 07-04 09:14

    IM 系列设备过载保护机制下界面初始化中断的底层逻辑与解决方案

    一、过载保护机制与界面初始化的关联基础 IM 系列设备的过载保护机制是保障设备安全运行的核心功能,其通过传感器实时采集设备运行参数,如电流、电压、温度、系统资源占用率等。一旦这些参数超出预设阈值
    的头像 发表于 06-27 09:58 358次阅读

    使用jlink连接mcu查看日志,偶发重新初始化,部分线程未退出,变量错位怎么解决?

    使用jlink连接mcu查看日志,偶发重新初始化,部分线程未退出,变量错位。 串口1的线程是在main最后面。 未见初始化打印,就已经发送数据了。并且发送的数据不对。感觉是重新初始化
    发表于 03-07 07:19

    STM32CubeMX用于STM32配置和初始化C代码生成

    电子发烧友网站提供《STM32CubeMX用于STM32配置和初始化C代码生成.pdf》资料免费下载
    发表于 02-26 17:32 678次下载

    EE-359:ADSP-CM40x启动时间优化和器件初始化

    电子发烧友网站提供《EE-359:ADSP-CM40x启动时间优化和器件初始化.pdf》资料免费下载
    发表于 01-13 16:33 0次下载
    EE-359:ADSP-CM40x启动时间优化和器件<b class='flag-5'>初始化</b>

    EE-88:使用21xx编译器在C中初始化变量

    电子发烧友网站提供《EE-88:使用21xx编译器在C中初始化变量.pdf》资料免费下载
    发表于 01-13 15:54 0次下载
    EE-88:使用21xx编译器在C中<b class='flag-5'>初始化</b><b class='flag-5'>变量</b>

    OMAP5912多媒体处理器初始化参考指南

    电子发烧友网站提供《OMAP5912多媒体处理器初始化参考指南.pdf》资料免费下载
    发表于 12-17 16:20 0次下载
    OMAP5912多媒体处理器<b class='flag-5'>初始化</b>参考指南

    STM32F407 MCU使用SD NAND 不断电初始化失效解决方案

    STM32F407微控制器单元(MCU)与SD NAND的结合提供了强大的存储解决方案。然而,不断电初始化失效问题可能会导致系统稳定性和数据完整性受损。我们将STM32F407与SD NAND集成时可能遇到的初始化问题,并提供专业的解决方案。
    的头像 发表于 12-11 10:51 1476次阅读
    STM32F407 MCU使用SD NAND 不断电<b class='flag-5'>初始化</b>失效解决方案

    segger编译器初始化问题

    的图; 2.第二张图是该变量在文件中的所有操作,第一行是初始化,该行代码在初始化部分最后一个,执行完就是主循环了; 3.第2,3行也是对变量的赋值,在主循环中; 4.第4行已注释; 5
    发表于 12-09 18:06