如何真正缩小草图


9

为了测试,我想制作一个尽可能小的草图。问题是,当我编译BareMinimum草图(具有空的设置和循环)时,Uno会得到466个字节,Leonardo会得到4,242个字节。有什么办法可以编写自己的没有额外功能的代码(即millis()和的Timer0 delay())。我还希望能够禁用Leonardo的键盘/鼠标功能。


4
难道这不应该被标记为莱昂纳多吗?这些是单独的问题。
asheeshr 2014年

我只是指出,空白的草图对于许多电路板来说都是很大的,尤其是基于本地USB的电路板
TheDoctor 2014年

我还希望能够禁用Leonardo的键盘/鼠标功能。是第二个问题。
asheeshr 2014年

Answers:


3

您应该能够按照https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification使用自定义的board.txt文件创建自己的电路板定义。如我所见,莱昂纳多的定义中有几个USB功能。我希望4K的编译包含基于这些标志而不是处理器类型。

boards.txt将使用上载的地方,Leonardo的引导程序部分以及uno的构建部分。

所有这些都假设核心库构建不使用处理器特定的标志来包含USB功能。

如果得到这样的工作。回发,我相信其他人也会对此感兴趣。


我最近在一个库演示中遇到了这种4K使用限制,该限制实际上使UNO达到极限,必须放入一个

#if !defined(__AVR_ATmega32U4__)
...

草图中的大量额外功能,以适合Leonardo。

我以为(错误的)认为这是4K的原因,是因为当我通过Leo上的USB CDC时,我仍然包含Serial.print。但是我看到一个空草图的内存转储之后它们仍然在那里。

C:\Users\mflaga\AppData\Local\Temp\build8958339595868119500.tmp>avr-objdump -d sketch_feb13a.cpp.elf > sketch_feb13a.cpp.elf.lst

有道理。由于Leonardo仍然需要USB-CDC客户端(4K)来检测来自AVR-DUDE的1200波特连接,以触发远程重启。


因此,在构建中没有USB的情况下制作自定义board.txt时,也需要

leonardo.upload.use_1200bps_touch=true

删除。

一旦加载到目标上,这将要求上载与目标的手动重置同步。由于失去了远程重启的能力。


更新了为何仍编译4K的原因,即使省略了Serial.print。
mpflaga 2014年

3

我最近想做到这一点。由于没有很好的方法,所以我结束了为Stino崇高文本arduino插件编写补丁的工作。随后它被接受,因此应该在任何最新的Stino安装中使用。

这为Stino添加了一个新选项:

在此处输入图片说明

使用此模式会产生如下的编译结果:

对于Uno:

二进制草图大小:172字节(最大32256字节,百分之0.53)。
估计的内存使用量:0字节(最大1024字节,0.00%)。

为了莱昂纳多

二进制草图大小:240个字节(最大28672个字节,为0.84%)。
估计的内存使用量:0字节(最大2560字节,0.00%)。

实际上,使用上面的编译输出对leonardo进行编程可能不是一个好主意,因为它可能会破坏自动重置功能,但是如果需要,可以这样做。向mpflaga致谢,因为他在回答中指出了这一点。

请注意,内存报告实际上是不正确的,但这是一个单独的问题

用于上面的代码是:

int main()
{
    while (1)
    {

    }
}

一些注意事项:

  • 你是不是写一个“素描”了,而不是你曾经确实写一个草图。您编写程序。期。我不在乎Arduino wackos想要说什么,他们不需要重新定义术语。
  • 所有中断管理都是手动的。这意味着没有milis()或类似。
  • 如果需要,您仍然可以使用arduino串行库等。你一定要#include <Arduino.h>
  • 您定义main。您永远不会从返回main。如果您需要安装程序,它会放在之前while (1)

@jfpoilpret您称其为IDE?更像是带宏的记事本...
2014年

@ Ron-E 不称其为IDE,Arduino IDE是其名称,所以我只是使用了它的名称,即使它不值这个名称。
jfpoilpret 2014年

2
@FakeName Stack Exchange网站上不允许使用错误语言(请参阅:stackoverflow.com/help/behavior)。在这种情况下,我已对其进行了修改,但请避免以后再在此网站上使用专有名词。谢谢。
彼得·布卢姆菲尔德

2

尽管它取决于您的草图,但是您可以通过使用方法重用代码来减小大小

采取以下代码:

int led = 13;
int val;

void setup() {                
  pinMode(led, OUTPUT);     
}

void loop() {
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second

  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second

  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second

  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second

  val = digitalRead(10);
}

Arduino Uno上的1,322字节 现在让我们缩小一点:

int led = 13;
int val;

void setup() {                
  pinMode(led, OUTPUT);     
}

void loop() {
  for(uint8_t i = 0; i < 8; i++) {
    blink(HIGH);
    blink(LOW);
  }    
  val = digitalRead(10);
}

void blink(uint8_t state) {
  digitalWrite(led, state);   // turn the LED to the right state
  delay(1000);                // wait for a second
}

1,194字节。大约减少了10%!

无论如何,尽管它不会大大缩小草图,但是当您超出限制两个字节时,或者只是想制作一个更紧凑的草图而又不丧失任何功能时,它有时可能是最简单的路线。并非适用于所有情况,但有时会有用。


通常,如果将代码提取到函数中,则编译器将进行艰苦的工作,并为您提供其余的信息。
Cyber​​gibbons 2014年

@Cyber​​gibbons您可以为[不熟悉的用户]定义吗?
匿名企鹅2014年

3
如果将代码分解为一个函数,但效率不高,通常编译器会为您内联代码。但是,编译器永远不会将代码分解为功能。因此,编写更多函数几乎总是更好。
Cyber​​gibbons 2014年

1
加上将代码放入函数中,使其更易于阅读和理解

使用直接端口访问,大小减小为646字节。仅使用avr-libc(无Arduino内核),它减少到220个字节。
Edgar Bonet 2015年

0

@annonomus企鹅,当然可以。尽管代码可以编译为1180字节的flash + 13字节的RAM,可以在我的计算机上使用uno,但我们可以对其进行改进:)因此,我们接受高尔夫挑战赛,并且这里还有一些有用的技巧,因为我们从事学习。

步骤1:降低可变需求。使用一个int作为led端口似乎有点过大,我们当然在arduino上没有65535个可寻址的IO端口:)因此,我们只是为了好玩而将其更改为一个字节。稍后,我们将其更改为#define,但以显示使用太大的变量类型的影响。

byte led = 13;
int val;

void setup() {                
  pinMode(led, OUTPUT);     
}

void loop() {
  blink();
  val = digitalRead(10);
}

void blink() {
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second
}

编译为1172字节+ 13字节RAM。由于该字节(而不是整数)所需的操作较少,因此可以节省8个字节的闪存。我希望有12个字节的ram,但是还可以。没那么多,但是保存的每个字节都是好的。

步骤2:何时将变量转换为定义。例如,不需要led字节,引脚不会自行解焊。

#define LED 13
int val;

void setup() {                
  pinMode(LED, OUTPUT);     
}

void loop() {
  blink();
  val = digitalRead(10);
}

void blink() {
  digitalWrite(LED, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);               // wait for a second
  digitalWrite(LED, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);               // wait for a second
}

编译为1142字节的Flash + 11字节的RAM。已保存38个字节。这是由于获取int值所需的寄存器操作较少。另外,我们从RAM中节省了2个字节。(仍然想知道为什么该字节没有被编译成ram少1个字节.....)

步骤3:优化代码。我看到2个延迟。我想知道是否将其更改为1延迟会节省空间,但是我必须弄清楚LED引脚的值并进行切换(反转)。我们可以使用digitalRead()做到这一点,但是会节省空间吗?

#define LED 13
int val;
void setup() {                
  pinMode(LED, OUTPUT);     
}
void loop() {
  blink();
  val = digitalRead(10);
}
void blink() {
  digitalWrite(LED, !digitalRead(LED));   // toggle the led based on read value
  delay(1000);               // wait for a second and spare yourself the other delay
}

编译为1134字节+ 11字节ram 好极了!另外8个字节。这样一来,总共有46个字节,少了2行代码。

关于减小代码大小的另一个通用技巧。不要使用String类。非常庞大,了解如何处理char数组,strcpy(),strcmp()。如果您所拥有的只是一些基本的字符串操作,那么String类的用法通常只是浪费闪存和RAM上的空间。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.