极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 53966|回复: 15

求助: 关于Arduino的内存!

[复制链接]
发表于 2014-8-25 21:28:33 | 显示全部楼层 |阅读模式
本帖最后由 zyzand 于 2018-5-6 17:44 编辑

已解决,感谢10楼老来疯大神

本人刚入门Arduino,在写了几个小程序后开始写一些稍大的工程。由于以前只在电脑编过程序,所以不大注意内存,今天在写了一大堆代码后出现了一些莫名其妙的错误,经过多次尝试后才发现是内存的原因。

在此想求助各位,Arduino UNO大约能写多少行代码?字符串能装下多少?

望各位能分享一下经验,不胜感谢!



最后补充一下:ESP8266了解一下,最高16MB内存。嗯,没错,是MB。可以用Arduino直接编程。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

发表于 2014-8-25 21:52:49 | 显示全部楼层
有个库可以帮你计算可用的 参考 http://www.geek-workshop.com/archiver/tid-9335.html 这个帖子吧

和代码行数没关系.......看行数估计不出来,是在不行你就换更高级一点的吧

否则要很折腾的
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-8-25 22:04:38 | 显示全部楼层
本帖最后由 zyzand 于 2014-8-25 22:07 编辑
zoologist 发表于 2014-8-25 21:52
有个库可以帮你计算可用的 参考 http://www.geek-workshop.com/archiver/tid-9335.html 这个帖子吧

和代 ...


原来Arduino还能查看剩余内存,可真是帮了我大忙,学习了。
不过下载是不是需要翻墙?
回复 支持 反对

使用道具 举报

发表于 2014-8-26 08:37:11 | 显示全部楼层
不知道唉  我没用过这个库~
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-8-26 08:52:11 | 显示全部楼层
zoologist 发表于 2014-8-26 08:37
不知道唉  我没用过这个库~

哈哈,我已经想办法弄下来了,感谢zoologist。
回复 支持 反对

使用道具 举报

发表于 2014-8-27 14:19:42 | 显示全部楼层
我用SublimeText2编译的时候直接就显示了flash和内存占用

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复 支持 反对

使用道具 举报

发表于 2014-8-28 11:47:13 | 显示全部楼层
编译完成的提示会有程序的大小
UNO或者所有328P核心的就是32K
2560MEGA就是 256K
一般只要你不写个几千航的代码都不是大问题

代码量和程序实际代码大小没有完全的必然关系
高级语言编程 编译的过程有3个阶段
先是编译 还要链接 最后汇编转换成二进制代码

还有就是你的标题不正确
内存是个大概念 普通电脑分为 RAM和ROM (不要说硬盘 U盘 软盘 光驱啥的 那些叫外部存储器)
单片机 的ROM还要分为程序和数据部分 高级语言编程不需要考虑  用单片机汇编需要考虑
单片机的RAM还涉及到大量的寄存器(PC的寄存器不多 AX BX之类的东西)不过高级语言也不用考虑了
编译的时候编译器自动搞定。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-8-28 15:01:26 | 显示全部楼层
本帖最后由 zyzand 于 2014-8-28 15:04 编辑
lexrajewcal 发表于 2014-8-27 14:19
我用SublimeText2编译的时候直接就显示了flash和内存占用


呃,据我观察这个用处不大,Arduino1.5以上的也有,而且更详细。还有就是我用MemoryFree这个库查看剩余内存时只剩100多字节的内存了(让7楼的一说也分不清这是什么了,只看懂了一部分,不过还是谢谢darkorigin)我写的程序用了许多String,挺复杂,结果是每个String只能容纳8个字符,多了就出乱码,再加了点东西后连8个都装不下了,悲催啊。{:soso_e109:}

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复 支持 反对

使用道具 举报

发表于 2015-12-8 08:57:18 | 显示全部楼层
zyzand 发表于 2014-8-28 15:01
呃,据我观察这个用处不大,Arduino1.5以上的也有,而且更详细。还有就是我用MemoryFree这个库查看剩余 ...

我和你碰到了相同的情况
回复 支持 反对

使用道具 举报

发表于 2015-12-9 03:40:14 | 显示全部楼层
我和你一样,新兵蛋子一个,不过最近我研究了一下这个问题。下面谈谈感想。

楼上的网友说的基本都对,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.6

1.   编译一个  空 程序      

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.cpp

int 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  占用空间最多。
回复 支持 反对

使用道具 举报

发表于 2015-12-22 13:56:31 | 显示全部楼层
受教了,谢谢啊啊啊啊
回复 支持 反对

使用道具 举报

发表于 2016-1-12 14:29:48 | 显示全部楼层
确实很吃内存。            
回复 支持 反对

使用道具 举报

发表于 2016-1-13 20:21:13 来自手机 | 显示全部楼层
如果是调试信息占用太多ram的话,可以把Serial.print("Hello world");的形式改写成Serial.print(F("Hello world"));
回复 支持 反对

使用道具 举报

发表于 2016-1-13 20:24:17 来自手机 | 显示全部楼层
这样的话可以把字符串常量储存到Flash里面而不是RAM
回复 支持 反对

使用道具 举报

发表于 2016-3-10 13:26:12 来自手机 | 显示全部楼层
谢谢,真的不错,解决了很多问题
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|联系我们|极客工坊

GMT+8, 2026-6-15 15:27 , Processed in 0.041504 second(s), 28 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表