Vous avez déjà de très bonnes réponses. Je poste ceci uniquement pour partager certaines statistiques que j'ai faites un jour, je me suis posé le même genre de questions: qu'est-ce qui prend autant de place sur un croquis minimal? Quel est le minimum requis pour obtenir la même fonctionnalité?
Vous trouverez ci-dessous trois versions d'un programme minimal clignotant qui fait basculer la LED sur la broche 13 chaque seconde. Les trois versions ont été compilées pour un Uno (pas d'USB impliqué) en utilisant avr-gcc 4.8.2, avr-libc 1.8.0 et arduino-core 1.0.5 (je n'utilise pas l'IDE Arduino).
Tout d'abord, la méthode Arduino standard:
const uint8_t ledPin = 13;
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
digitalWrite(ledPin, HIGH);
delay(1000);
digitalWrite(ledPin, LOW);
delay(1000);
}
Cela compile à 1018 octets. En utilisant les deux avr-nm
et le démontage , j'ai décomposé cette taille en fonctions individuelles. Du plus grand au plus petit:
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
Dans la liste ci-dessus, la première colonne est la taille en octets, et la deuxième colonne indique si le code provient de la bibliothèque principale Arduino (A, 822 octets au total), du runtime C (C, 148 octets) ou de l'utilisateur (U , 48 octets).
Comme on peut le voir dans cette liste, la fonction la plus importante est la routine d'entretien de l'interruption de débordement du temporisateur 0. Cette routine est responsable du suivi du temps, et il est nécessaire par millis()
, micros()
et delay()
. La deuxième plus grande fonction est init()
, qui définit les temporisations matérielles pour PWM, active l'interruption TIMER0_OVF et déconnecte l'USART (qui a été utilisé par le chargeur de démarrage). Cette fonction et la fonction précédente sont définies dans
<Arduino directory>/hardware/arduino/cores/arduino/wiring.c
.
Vient ensuite la version 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 répartition des tailles individuelles:
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
Cela représente 132 octets pour le runtime C et 26 octets de code utilisateur, y compris la fonction intégrée _delay_ms()
.
Il peut être noté que, puisque ce programme n'utilise pas d'interruptions, la table des vecteurs d'interruption n'est pas nécessaire, et un code utilisateur régulier pourrait être mis à sa place. La version d'assemblage suivante fait exactement cela:
#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
Celui-ci est assemblé (avec avr-gcc -nostdlib
) en seulement 14 octets, dont la plupart sont utilisés pour retarder les basculements afin que le clignotement soit visible. Si vous supprimez cette boucle de retard, vous vous retrouvez avec un programme de 6 octets qui clignote trop vite pour être vu (à 2 MHz):
sbi io(DDRB), 5 ; set PB5 as output
loop:
sbi io(PINB), 5 ; toggle PB5
rjmp loop