Arduino - 关于内存

来源:互联网 发布:英语语言变迁 知乎 编辑:程序博客网 时间:2022/07/04 23:54

转自:
http://www.geek-workshop.com/forum.php?mod=redirect&goto=findpost&ptid=10816&pid=113693

Arduino 328p 用的芯片 属于 哈弗结构,他把存储区分为 三个部分:1. FLASH 程序存储区, 2. RAM 动态 内存,3. ROM 区 。他不同于 诺依曼 结构的  程序存储区  和  RAM  内存是在一起的。由于 程序存储区  和  RAM  内存 是分开的,于是就有了  32K 的 FLASH 程序存储区 和  2K 的 RAM 动态内存,当然还有 ROM .32K 的 FLASH 程序存储区 是存放 你的 经过 编译的 程序本体。 2K 的 RAM 动态内存 是存放 程序运行时 需要的 临时 变量。由于 Arduino 本初的 想发是 给那些 非 计算机专业的 设计者们 使用的,所以他使用了人们习惯的思维方式来编程。于是他发明了很多自己专用的 指令(确切的说应该是 函数,或  宏替换 ),这样,就带来了 代码 不精练的 问题。当然 宏替换 没有问题。这不等于不 高效 和不 简练,因为 Arduino IDE  是 基于 C / C++ 的 编译器, C / C++ 在 编译时 还是做了很多 代码优化工作。我们看 几个 例子: Arduino IDE 版本 1.6.61.   编译一个  空 程序      void setup() {  // put your setup code here, to run once:}void loop() {  // put your main code here, to run repeatedly:}Arduino IDE  版本 1.6.6   显示的 编译结果:项目使用了 450 字节,占用了 (1%) 程序存储空间。最大为 30,720 字节。全局变量使用了9字节,(0%)的动态内存,余留2,039字节局部变量。最大为2,048字节。这个程序 什么也没有做,他也要占用 这么多 空间。 那是因为 他要 初始化 各个端口 和 很多 寄存器,还要 运行 上面那段 看起来像是 空代码 的代码。不信吗?看看     Arduino IDE    他 隐藏 包含的  main.cppint main(void)                        //  这是一段 c  程序{        init();        initVariant();#if defined(USBCON)        USBDevice.attach();#endif        setup();        for (;;) {                loop();                if (serialEventRun) serialEventRun();        }               return 0;}这就是 我们看得到   Arduino IDE  编程器的 初始 界面 ,别看他是 空的,但是 上面的代码是要 运行的。记住  这段 空代码 使用的 空间,我们再做 下面的 实验,给个 Arduino 自带的 经典代码,点亮 一颗 LED 灯。void setup() {  pinMode(13, OUTPUT);         //   将   D13   端口 设置为  输出, 因为 他上面 连着 一颗  LED 灯。}void loop() {  digitalWrite(13, HIGH);        //  将 D13 设为 高电平, 点亮 LED 灯。  delay(1000);                      //  延时 1秒  digitalWrite(13, LOW);       //   将 D13 设为 低电平, 关闭 LED 灯。  delay(1000);                     //   再 延时 1秒}编译他:项目使用了 1,030 字节,占用了 (3%) 程序存储空间。最大为 30,720 字节。全局变量使用了9字节,(0%)的动态内存,余留2,039字节局部变量。最大为2,048字节。这个程序 占用的空间是    1030 - 450 = 580 字节。   (本次编译 使用空间  1030 字节 -  空程序 使用空间 450 字节。)变量 占用的 RAM 空间 还是  9 字节,这是因为  上面的 4 个 看起来像变量数据 (13, OUTPUT ,HIGH,LOW )其实都是 宏 替换,占用的是  FLASH 程序存储区。为了叙述方便,我们只改动 一条 语句。void setup() {  //   pinMode(13, OUTPUT);         //   注释掉 这一句,不让他 参与 编译}void loop() {  digitalWrite(13, HIGH);        //  将 D13 设为 高电平, 点亮 LED 灯。  delay(1000);                      //  延时 1秒  digitalWrite(13, LOW);       //   将 D13 设为 低电平, 关闭 LED 灯。  delay(1000);                     //   再 延时 1秒}再次 编译 他,看看  FLASH 程序存储区 占用情况。项目使用了 900 字节,占用了 (2%) 程序存储空间。最大为 30,720 字节。全局变量使用了9字节,(0%)的动态内存,余留2,039字节局部变量。最大为2,048字节。他比 上次 编译 节省了   1030 - 900 = 130 字节,而且他是 能工作的 ,只是 LED 灯 很暗 ,在很暗的地方可以看清他。为什么 他还能亮呢? 因为 编译器在什么程序也不编译的时候,他还是要初始化 各个 端口的,这时 PB 端口 都被 初始化成 输入状态,AVR 的 芯片 在 端口为 输入状态时,给他写入 高电平,就启动了 上拉 电阻,电压从 正电源 通过 上拉电阻传递给了 LED ,尽管 电流非常小,但是他还是亮了。这也是 空程序 也要占用空间的原因。那么  pinMode(13, OUTPUT); 语句为什么要占用 130 字节的空间呢,因为 Arduino 指令 格式 是 16 比特,也就是 2 字节,参数 13 要用 2 字节,OUTPUT 要用 2 字节,调用   pinMode( ) 函数 要用 4 字节,剩下的 是 函数  pinMode( ) 本身 要占用的 空间,由于 IDE 版本 不一样, 函数 本身 要占用的 空间 也不一样,大家可以 试试。这个程序 不能正常 干活,我们换条指令 让他 正常 干活。看下面的程序:void setup() {  //   pinMode(13, OUTPUT);         //   注释掉 这一句,  改为 下面 一句    bitSet(DDRB,5);                       //   设置  PB 端口的    DDR   输出寄存器 第 5 位 为输出状态,(就是 D13 端口)}void loop() {  digitalWrite(13, HIGH);        //  将 D13 设为 高电平, 点亮 LED 灯。  delay(1000);                      //  延时 1秒  digitalWrite(13, LOW);       //   将 D13 设为 低电平, 关闭 LED 灯。  delay(1000);                     //   再 延时 1秒}编译一下,奇迹出现了,项目使用了 902 字节,占用了 (2%) 程序存储空间。最大为 30,720 字节。全局变量使用了9字节,(0%)的动态内存,余留2,039字节局部变量。最大为2,048字节。  bitSet(DDRB,5);     语句 只用了   2   字节 空间,而且和   pinMode(13, OUTPUT);   语句 干的事 同样的 活。这就是  Arduino ,他用 自己的 语言 方便了 我们,使我们能 很快 入门,但又使我们的程序 冗长,并且执行效率也不高。爱他,因为我们 很笨,恨他,因为我们嫌他 很笨。1. 代码的 种类 要尽可能的少,因为 每条 相同的函数 本身只占 一个空间,而每次 调用他 只占 很少的 空间,不信你可以多加几条    pinMode(  ,  ); 语句,看看他占用的空间是不是成倍增加。2. 最宝贵的是    RAM   空间,要尽量的 少用 全局 变量,因为 局部 变量 每次使用完后,他会释放 内存空间给其他变量使用。3. 相同功能,不同发布者,占用的空间不一样,比如:驱动  OLED 屏的库文件。 u8g  占用的空间最少, SSD1306  次之,Adafruit_SSD1306-master  占用空间最多。
0 0