Ya tienes algunas respuestas perfectamente buenas. Estoy publicando esto solo para compartir algunas estadísticas que hice un día. Me hice el mismo tipo de preguntas: ¿Qué está tomando tanto espacio en un boceto mínimo? ¿Cuál es el mínimo necesario para lograr la misma funcionalidad?
A continuación se presentan tres versiones de un programa mínimo de parpadeo que alterna el LED en el pin 13 cada segundo. Las tres versiones se han compilado para Uno (sin USB) usando avr-gcc 4.8.2, avr-libc 1.8.0 y arduino-core 1.0.5 (no uso el IDE de Arduino).
Primero, la forma estándar de Arduino:
const uint8_t ledPin = 13;
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
digitalWrite(ledPin, HIGH);
delay(1000);
digitalWrite(ledPin, LOW);
delay(1000);
}
Esto compila a 1018 bytes. Utilizando ambos avr-nm
y el desmontaje , dividí ese tamaño en funciones individuales. De mayor a menor:
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
En la lista anterior, la primera columna es el tamaño en bytes, y la segunda columna indica si el código proviene de la biblioteca principal de Arduino (A, 822 bytes en total), el tiempo de ejecución C (C, 148 bytes) o el usuario (U , 48 bytes).
Como se puede ver en esta lista, la función más grande es la rutina que da servicio a la interrupción por desbordamiento del temporizador 0. Esta rutina es responsable del seguimiento del tiempo, y es necesaria por millis()
, micros()
y delay()
. La segunda función más grande es init()
, que establece los temporizadores de hardware para PWM, habilita la interrupción TIMER0_OVF y desconecta el USART (que fue usado por el gestor de arranque). Tanto esta como la función anterior se definen en
<Arduino directory>/hardware/arduino/cores/arduino/wiring.c
.
La siguiente es la versión 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);
}
}
El desglose de los tamaños individuales:
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
Esto es 132 bytes para el tiempo de ejecución C y 26 bytes de código de usuario, incluida la función en línea _delay_ms()
.
Cabe señalar que, dado que este programa no utiliza interrupciones, la tabla de vectores de interrupción no es necesaria y se puede colocar el código de usuario normal en su lugar. La siguiente versión de ensamblaje hace exactamente eso:
#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
Esto se ensambla (con avr-gcc -nostdlib
) en solo 14 bytes, la mayoría de los cuales se utilizan para retrasar los conmutadores para que el parpadeo sea visible. Si elimina ese ciclo de retraso, termina con un programa de 6 bytes que parpadea demasiado rápido para ser visto (a 2 MHz):
sbi io(DDRB), 5 ; set PB5 as output
loop:
sbi io(PINB), 5 ; toggle PB5
rjmp loop