Hai già delle risposte perfettamente valide. Sto pubblicando questo solo per condividere alcune statistiche che ho fatto un giorno mi sono posto lo stesso tipo di domande: cosa sta prendendo così tanto spazio su uno schizzo minimo? Qual è il minimo necessario per ottenere la stessa funzionalità?
Di seguito sono riportate tre versioni di un programma lampeggiante minimo che attiva / disattiva il LED sul pin 13 ogni secondo. Tutte e tre le versioni sono state compilate per Uno (nessuna USB coinvolta) usando avr-gcc 4.8.2, avr-libc 1.8.0 e arduino-core 1.0.5 (non uso l'IDE Arduino).
Innanzitutto, il modo standard di Arduino:
const uint8_t ledPin = 13;
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
digitalWrite(ledPin, HIGH);
delay(1000);
digitalWrite(ledPin, LOW);
delay(1000);
}
Questo si compila a 1018 byte. Usando entrambi avr-nm
e disassemblando , ho suddiviso quella dimensione in singole funzioni. Dal più grande al più piccolo:
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
Nell'elenco sopra, la prima colonna è la dimensione in byte e la seconda colonna indica se il codice proviene dalla libreria principale di Arduino (A, 822 byte totali), dal runtime C (C, 148 byte) o dall'utente (U , 48 byte).
Come si può vedere in questo elenco, la funzione più grande è la manutenzione ordinaria dell'interrupt di overflow del timer 0. Questa routine è responsabile di tempo di monitoraggio, ed è necessario per millis()
, micros()
e delay()
. La seconda funzione più grande è init()
, che imposta i timer hardware per PWM, abilita l'interruzione TIMER0_OVF e disconnette USART (utilizzato dal bootloader). Sia questa che la precedente funzione sono definite in
<Arduino directory>/hardware/arduino/cores/arduino/wiring.c
.
La prossima è la versione C + avr-libc:
#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);
}
}
La suddivisione delle singole dimensioni:
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
Sono 132 byte per il runtime C e 26 byte di codice utente, inclusa la funzione incorporata _delay_ms()
.
Si potrebbe notare che, poiché questo programma non utilizza gli interrupt, la tabella dei vettori di interrupt non è necessaria e al suo posto potrebbe essere inserito un normale codice utente. La seguente versione dell'assembly fa esattamente questo:
#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
Questo è assemblato (con avr-gcc -nostdlib
) in soli 14 byte, la maggior parte dei quali vengono utilizzati per ritardare le levette in modo che il battito di ciglia sia visibile. Se rimuovi quel loop di ritardo, finisci con un programma a 6 byte che lampeggia troppo velocemente per essere visto (a 2 MHz):
sbi io(DDRB), 5 ; set PB5 as output
loop:
sbi io(PINB), 5 ; toggle PB5
rjmp loop