单片机
单片机内存的合理使用对于一名嵌入式软件工程师来说是至关重要的,这深深关系到项目代码的稳定性。对于c语言程序的bug,最为致命、最难发觉的也是内存的使用不当造成的,这种奇葩现象。之前对这一块有过了解,可惜没有真正的领会其中的要害和内涵。大抵是平时写写代码玩的时候单片机资源足够多,也从来不会去理会内存够不够的问题。最近受领导一番话点醒了我,也逐渐明白了它的重要性。
背景大概是这样的:某个项目写到一个数据处理函数,这里需要进行大量数据处理和拼接长字符串,需要大量的中间变量作为转存(超过1k长度的大数组),我左思右想到底是用全局变量?还是局部变量?抑或是利用malloc申请一段内存来使用,年少无知的我想来想去果断使用了定义在函数内的局部变量,理由是局部变量所占用的内存在该函数运行完之后即会自动释放,这样只会在短时间内占用cpu的ram,至于不使用malloc的理由是怕堆生长太大覆盖了栈区的内存。然而....领导看了这段代码惊呼卧槽,他告诉我如果在函数内使用大数组的局部变量有可能会造成全局变量区的内存被这货覆盖,我接着问难不成我使用全局?这样不会占用太多的RAM嘛?他说宁可牺牲掉RAM的部分资源作为固定的内存,也不要这种随时可能爆炸的定时炸弹(大数组局部变量),因为它可能在某个时间节点内突然申请一块巨大的内存,到时候内存覆盖刷掉了全局变量的地址就真的GG了。我仔细一想局部变量大数组还真的是一枚定时炸弹,心里默默地记下他的一番话,开始重新去审视和理解关于单片机内存相关的知识。
说了一大段废话....
以下是我对该内容的一个整理:
单片机内存被分为flash和sram(ram),在查看任何一款单片机的时候都会有它们的介绍,可以看看最近使用的合泰单片机HT32F2253的介绍
我们看到它的flash是128KB、SRAM是16KB。(其实它的内存还算挺大的........)
以下是我按照自己的理解画的的一个内存结构图:
初始化前:
初始化后:
嗯...可以看到,初始化时RW-data从flash拷贝到RAM,所以在程序跑起来了Rw-data是在RAM里面的。
其中:Code为程序代码部分
RO-data 表示 程序定义的常量const temp;
RW-data 表示 已初始化的全局变量
ZI-data 表示 未初始化的全局变量
(以上这一段是copy的,原地址在:http://anlx27.iteye.com/blog/1575848)
而栈区(stack)、堆区(heap)、全局区(静态区)(static)、文字常量区和程序代码区和上面所介绍的code、RO-data等的关系。
1、栈区(stack):由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。 这些值是可读写的,那么stack应该被包含在RW-data(读写数据存储区),也就是单片机的sram中。
2、堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。可以理解,这些也是被包含在单片机的sram中的。
3、全局区(静态区)(static):全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域,程序结束后由系统释放。这些数据也是可读可写的,和stack、heap一样,被包含在sram中。
4、文字常量区:常量字符串就是放在这里的。这些数据是只读的,分配在RO-data(只读数据存储区),则被包含在flash中。
5、程序代码区:存放函数体的二进制代码,可以想象也是被包含在flash,因为对于MCU来说,当其重新上电,代码还会继续运行,并不会消失,所以存储在flash中。
(然而上这一段还是copy的,原地址在:http://www.51hei.com/mcu/4293.html)
下面是网上找的例子:
int a = 0; // RW-data 全局初始化区
char *p1; // ZI-data 全局未初始化区
const int b = 0; // RO-data 只读变量区
main(void)
{
int b; // RW-data 栈区
char s[] = "abc"; // RW-data 栈区
char *p2; // RW-data 栈区
char *p3 = "123456"; // "123456/0" 在Ro-data 常量区,p3在RW-data 栈区
static int c =0; // 全局(静态)初始化区 rw-data -> static区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20); // 分配得来的10和20字节的区域就在Rw-data 堆区
strcpy(p1, "123456"); // "123456/0" 放在常量区,编译器可能会将它
// 与p3所指向的"123456"优化成一个地方
}
所以,重点来了,在实际编程中,应当实时关注.map的内容来判断单片机内存的使用情况。
在keil中,右击工程就会出现opne map flie的选项,打开它,浏览到最后一段
可以看到该工程占用单片机ram12.43kb,flash13.91kb。
来源:CSDN ,作者:sinat_dtj
原文:https://blog.csdn.net/sinat_30146065/article/details/82221179
版权声明:本文为博主原创文章,转载请附上博文链接!
在我们刚一开始接触到51单片机的时候对P0口必须加上上拉电阻,否则P0就是高阻态。
对这个问题可能感到疑惑,为什么是高阻态?加上拉电阻?今天针对这一概念进行简单讲解。
高阻态
高阻态这是一个数字电路里常见的术语,指的是电路的一种输出状态,既不是高电平也不是低电平。
如果高阻态再输入下一级电路的话,对下级电路无任何影响,和没接一样,如果用万用表测的话有可能是高电平也有可能是低电平,随它后面接的东西定。
高阻态的实质
电路分析时高阻态可做开路理解,你可以把它看作输出(输入)电阻非常大。
它的极限可以认为悬空,也就是说理论上高阻态不是悬空,它是对地或对电源电阻极大的状态。而实际应用上与引脚的悬空几乎是一样的。
高阻态的意义
当门电路的输出上拉管导通而下拉管截止时,输出为高电平,反之就是低电平。
如果当上拉管和下拉管都截止时,输出端就相当于浮空(没有电流流动),其电平随外部电平高低而定,即该门电路放弃对输出端电路的控制 。
典型应用
在总线连接的结构上。总线上挂有多个设备,设备于总线以高阻的形式连接。这样在设备不占用总线时自动释放总线,以方便其他设备获得总线的使用权。
大部分单片机I/O使用时都可以设置为高阻输入。高阻输入可以认为输入电阻是无穷大的,认为I/O对前级影响极小,而且不产生电流(不衰减),而且在一定程度上也增加了芯片的抗电压冲击能力。
高阻态常用表示方法:高阻态常用字母 Z 表示。
在一个系统中或在一个整体中,我们往往定义了一些参考点,就像我们常常说的海平面,在单片中也是如此,我们无论说是高电平还是低电平都是相对来说的。明确了这一点对这一问题可能容易理解。
单片机中的高阻态
在51单片机,没有连接上拉电阻的P0口相比有上拉电阻的P1口在I/O口引脚和电源之间相连是通过一对推挽状态的FET来实现的,51具体结构如下图。
组成推挽结构,从理论上讲是可以通过调配管子的参数轻松实现输出大电流,提高带载能力,两个管子根据通断状态有四种不同的组合,上下管导通相当于把电源短路了,这种情况下在实际电路中绝对不能出现。
从逻辑电路上来讲,上管开-下管关开时IO与VCC直接相连,IO输出低电平0,这种结构下如果没有外接上拉电阻,输出0就是开漏状态(低阻态),因为I/O引脚是通过一个管子接地的,并不是使用导线直接连接,而一般的MOS在导通状态也会有mΩ极的导通电阻。
到这里就很清楚了,无论是低阻态还是高阻态都是相对来说的,把下管子置于截止状态就可以把GND和I/O口隔离达到开路的状态,这时候推挽一对管子是截止状态,忽略读取逻辑的话I/O口引脚相当于与单片机内部电路开路,考虑到实际MOS截止时会有少许漏电流,就称作“高阻态”。
由于管子PN节带来的结电容的影响,有的资料也会称作“浮空”,通过I/O口给电容充电需要一定的时间,那么IO引脚处的对地的真实电压和水面浮标随波飘动类似了,电压的大小不仅与外界输入有关还和时间有关,在高频情况下这种现象是不能忽略的。
总之一句话高阻态是一个相对概念。在使用的时候我们只要按照要求去做,让我们加上拉我们就加上,都是有一定道理的。
来源:电子产品世界
单片机要这么学?八条谨记!
demi 在 提交