Cuando compilo este boceto para el Yún:
int led = 7;
void setup() {
pinMode(led, OUTPUT);
}
void loop() {
digitalWrite(led, HIGH);
}
Yo obtengo:
Sketch utiliza 5.098 bytes (17%) del espacio de almacenamiento del programa.
El máximo es de 28,672 bytes. Las variables globales usan 153 bytes (5%) de memoria dinámica, dejando 2,407 bytes para las variables locales. El máximo es de 2.560 bytes.
Incluso cuando compilo el boceto BareMinimum:
void setup() {
// setup
}
void loop() {
// loop
}
Yo obtengo:
Sketch utiliza 4.548 bytes (15%) del espacio de almacenamiento del programa.
El máximo es de 28,672 bytes. Las variables globales usan 151 bytes (5%) de memoria dinámica, dejando 2,409 bytes para las variables locales. El máximo es de 2.560 bytes.
¿Por qué un simple boceto mínimo ocupa el 15% del espacio de almacenamiento del programa asignado? ¿Y por qué un boceto muy simple ocupa el 17% del espacio de almacenamiento del programa? Según el sitio web de Arduino :
Es fácil usarlo todo teniendo muchas cadenas en su programa. Por ejemplo, una declaración como:
char message[] = "I support the Cape Wind project.";
pone 33 bytes en SRAM (cada carácter toma un byte, más el terminador '\ 0').
Sin embargo, no hay cadenas declaradas en ninguno de estos bocetos.
Parece que podrían importar o usar otras bibliotecas / clases que no especifico. ¿Tal vez importa una biblioteca predeterminada del sistema? ¿O es otra cosa?
fuente
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:
Esto compila a 1018 bytes. Utilizando ambos
avr-nm
y el desmontaje , dividí ese tamaño en funciones individuales. De mayor a menor: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()
ydelay()
. La segunda función más grande esinit()
, 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:
El desglose de los tamaños individuales:
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:
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):fuente
Escribí una publicación sobre ¿Por qué se necesitan 1000 bytes para parpadear un LED? .
La breve respuesta es: "¡No se necesitan 2000 bytes para parpadear dos LED!"
La respuesta más larga es que las bibliotecas Arduino estándar (que no tienes que usar si no quieres) tienen una buena funcionalidad para simplificar tu vida. Por ejemplo, puede direccionar los pines por número en tiempo de ejecución, donde la biblioteca convierte (digamos) el pin 8 en el puerto correcto y el número de bit correcto. Si codifica el acceso al puerto, puede guardar esa sobrecarga.
Incluso si no los usa, las bibliotecas estándar incluyen código para contar "ticks" para que pueda averiguar el "tiempo" actual (llamando
millis()
). Para hacer esto, debe agregar la sobrecarga de algunas rutinas de servicio de interrupción.Si simplifica (en el Arduino Uno) a este boceto, el uso de la memoria del programa se reduce a 178 bytes (en IDE 1.0.6):
OK, 178 bytes no es mucho, y de eso los primeros 104 bytes son los vectores de interrupción de hardware (4 bytes cada uno, para 26 vectores).
Podría decirse que solo se requieren 74 bytes para parpadear un LED. Y de esos 74 bytes, la mayoría son realmente el código generado por el compilador para inicializar la memoria global. Si agrega suficiente código para parpadear dos LED:
Luego, el tamaño del código aumenta a 186 bytes. Por lo tanto, podría argumentar que solo se necesitan
186 - 178 = 8
bytes para parpadear un LED.Entonces, 8 bytes para parpadear un LED. Suena bastante eficiente para mí.
En caso de que sienta la tentación de probar esto en casa, debo señalar que si bien el código publicado arriba parpadea dos LED, lo hace muy rápidamente. De hecho, parpadean a 2 MHz, mira la captura de pantalla. El canal 1 (amarillo) es el pin 12, el canal 2 (cian) es el pin 13.
Como puede ver, los pines de salida tienen una onda cuadrada con una frecuencia de 2 MHz. El pin 13 cambia el estado 62.5 ns (un ciclo de reloj) antes del pin 12, debido al orden de alternar los pines en el código.
Entonces, a menos que tenga ojos mucho mejores que los míos, en realidad no verá ningún efecto de parpadeo.
Como un extra divertido, puede alternar dos pines en la misma cantidad de espacio de programa que alternar un pin.
Eso se compila en 178 bytes.
Esto te da una frecuencia más alta:
Ahora estamos hasta 2.66 MHz.
fuente
init()
(como lomain()
hace normalmente ), entonces el archivo alambrado.c (que contieneinit
) no se vinculó. Como resultado, se omitió el procesamiento de los manejadores de interrupciones (paramillis()
,micros()
etc.). Probablemente no sea particularmente práctico omitirlo, a menos que nunca necesite cronometrar las cosas, pero el hecho es que el boceto crece en tamaño dependiendo de lo que ponga en él. Por ejemplo, si usa Serial, tanto la memoria del programa como la RAM reciben un golpe.