Sie haben bereits einige sehr gute Antworten. Ich poste dies nur, um einige Statistiken zu teilen, die ich eines Tages gemacht habe. Ich habe mir die gleichen Fragen gestellt: Was nimmt so viel Platz in einer minimalen Skizze ein? Was ist das Minimum, um die gleiche Funktionalität zu erreichen?
Im Folgenden finden Sie drei Versionen eines minimalen Blinkprogramms, mit dem die LED an Pin 13 jede Sekunde umgeschaltet wird. Alle drei Versionen wurden für ein Uno (ohne USB) mit avr-gcc 4.8.2, avr-libc 1.8.0 und arduino-core 1.0.5 kompiliert (ich verwende die Arduino-IDE nicht).
Erstens, der Standard-Arduino-Weg:
const uint8_t ledPin = 13;
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
digitalWrite(ledPin, HIGH);
delay(1000);
digitalWrite(ledPin, LOW);
delay(1000);
}
Dies kompiliert auf 1018 Bytes. Bei beiden avr-nm
und bei der Demontage habe ich diese Größe in einzelne Funktionen unterteilt. Vom größten zum kleinsten:
148 A ISR(TIMER0_OVF_vect)
118 A init
114 A pinMode
108 A digitalWrite
104 C vector table
82 A turnOffPWM
76 A delay
70 A micros
40 U loop
26 A main
20 A digital_pin_to_timer_PGM
20 A digital_pin_to_port_PGM
20 A digital_pin_to_bit_mask_PGM
16 C __do_clear_bss
12 C __init
10 A port_to_output_PGM
10 A port_to_mode_PGM
8 U setup
8 C .init9 (call main, jmp exit)
4 C __bad_interrupt
4 C _exit
-----------------------------------
1018 TOTAL
In der obigen Liste ist die erste Spalte die Größe in Bytes und die zweite Spalte gibt an, ob der Code aus der Arduino-Kernbibliothek (A, insgesamt 822 Bytes), der C-Laufzeit (C, 148 Bytes) oder dem Benutzer (U) stammt 48 Bytes).
Wie in dieser Liste zu sehen ist, ist die größte Funktion die Routine, die den Timer 0-Überlaufinterrupt bedient. Diese Routine ist verantwortlich Zeit der Verfolgung und benötigt wird , um durch millis()
, micros()
und delay()
. Die zweitgrößte Funktion ist init()
, die die Hardware-Timer für PWM einstellt, den TIMER0_OVF-Interrupt aktiviert und den USART (der vom Bootloader verwendet wurde) trennt. Sowohl diese als auch die vorherige Funktion sind in definiert
<Arduino directory>/hardware/arduino/cores/arduino/wiring.c
.
Als nächstes kommt die C + avr-libc-Version:
#include <avr/io.h>
#include <util/delay.h>
int main(void)
{
DDRB |= _BV(PB5); /* set pin PB5 as output */
for (;;) {
PINB = _BV(PB5); /* toggle PB5 */
_delay_ms(1000);
}
}
Die Aufteilung der einzelnen Größen:
104 C vector table
26 U main
12 C __init
8 C .init9 (call main, jmp exit)
4 C __bad_interrupt
4 C _exit
----------------------------------
158 TOTAL
Dies sind 132 Byte für die C-Laufzeit und 26 Byte für den Benutzercode, einschließlich der Inline-Funktion _delay_ms()
.
Es kann angemerkt werden, dass, da dieses Programm keine Interrupts verwendet, die Interruptvektortabelle nicht benötigt wird und regulärer Benutzercode an ihre Stelle gesetzt werden könnte. Die folgende Assembly-Version macht genau das:
#include <avr/io.h>
#define io(reg) _SFR_IO_ADDR(reg)
sbi io(DDRB), 5 ; set PB5 as output
loop:
sbi io(PINB), 5 ; toggle PB5
ldi r26, 49 ; delay for 49 * 2^16 * 5 cycles
delay:
sbiw r24, 1
sbci r26, 0
brne delay
rjmp loop
Dies ist (mit avr-gcc -nostdlib
) in nur 14 Bytes zusammengefasst, von denen die meisten verwendet werden, um die Umschaltvorgänge zu verzögern, so dass das Blinken sichtbar ist. Wenn Sie diese Verzögerungsschleife entfernen, erhalten Sie ein 6-Byte-Programm, das zu schnell blinkt, um gesehen zu werden (bei 2 MHz):
sbi io(DDRB), 5 ; set PB5 as output
loop:
sbi io(PINB), 5 ; toggle PB5
rjmp loop