最近有读者问了一个这样的问题:看门狗复位之后,能不能保持复位之前的状态?
这种问题,或者类似的问题,相信很多小伙伴都经历过,特别是有多年单片机开发经验的小伙伴,而且现实中的很多项目确实有这样的需求。
实现的方法有很多种,这里给大家讲讲在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这种集成开发环境中,他们支持这种修饰符。
Keil中__no_init的配置和使用
在Keil中,__no_init不是标准的修饰符,需要进行配置,配置之后就可以使用了。
1.宏定义__no_init
#define __no_init __attribute__((zero_init))
__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”一直不变。
审核编辑:汤梓红
全部0条评论
快来发表一下你的评论吧 !