У вас вже є кілька ідеально хороших відповідей. Я публікую це лише для того, щоб поділитися статистикою, яку я зробив одного разу, я задав собі такі ж запитання: Що займає стільки місця на мінімальному ескізі? Який мінімум необхідний для досягнення тієї ж функціональності?
Нижче наведено три версії мінімальної миготливої програми, яка щомісяця перемикає світлодіод на контакт 13. Всі три версії були складені для Uno (не задіяний USB) за допомогою avr-gcc 4.8.2, avr-libc 1.8.0 та arduino-core 1.0.5 (я не використовую ID Arduino IDE).
По-перше, стандартний спосіб Arduino:
const uint8_t ledPin = 13;
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
digitalWrite(ledPin, HIGH);
delay(1000);
digitalWrite(ledPin, LOW);
delay(1000);
}
Це складає 1018 байт. Використовуючи avr-nm
і розбирання , і я розбив цей розмір на окремі функції. Від найбільшого до найменшого:
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
У наведеному вище списку перший стовпець має розмір у байтах, а другий стовпець повідомляє, чи походить код з основної бібліотеки Arduino (A, 822 байти загалом), часу виконання C (C, 148 байт) або користувача (U , 48 байт).
Як видно з цього списку, найбільшою функцією є рутинне обслуговування переривання переповнення таймера 0. Ця процедура несе відповідальність за відстеження часу, і необхідна millis()
, micros()
і delay()
. Друга за величиною функція init()
, яка встановлює апаратні таймери для ШІМ, дозволяє TIMER0_OVF переривати і відключати USART (який використовувався завантажувачем). І ця, і попередня функції визначені в
<Arduino directory>/hardware/arduino/cores/arduino/wiring.c
.
Далі - версія 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);
}
}
Розбивка за окремими розмірами:
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
Це 132 байти за час виконання C і 26 байт коду користувача, включаючи вкладену функцію _delay_ms()
.
Можна зазначити, що оскільки ця програма не використовує переривань, таблиця векторів переривань не потрібна, і звичайний код користувача може бути поставлений на її місце. Наступна версія збірки робить саме це:
#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
Це зібрано (з avr-gcc -nostdlib
) лише в 14 байт, більшість з яких використовується для затримки перемикань, щоб миготіло було видно. Якщо ви вилучите цю петлю затримки, ви отримуєте 6-байтну програму, яка блимає занадто швидко, щоб її побачили (на 2 МГц):
sbi io(DDRB), 5 ; set PB5 as output
loop:
sbi io(PINB), 5 ; toggle PB5
rjmp loop