Kiedy kompiluję ten szkic dla Yúna:
int led = 7;
void setup() {
pinMode(led, OUTPUT);
}
void loop() {
digitalWrite(led, HIGH);
}
Dostaję:
Szkic wykorzystuje 5 098 bajtów (17%) miejsca do przechowywania programu.
Maksymalnie wynosi 28 672 bajtów. Zmienne globalne używają 153 bajtów (5%) pamięci dynamicznej, pozostawiając 2 407 bajtów dla zmiennych lokalnych. Maksymalnie wynosi 2560 bajtów.
Nawet kiedy skompiluję szkic BareMinimum:
void setup() {
// setup
}
void loop() {
// loop
}
Dostaję:
Sketch wykorzystuje 4548 bajtów (15%) miejsca do przechowywania programu.
Maksymalnie wynosi 28 672 bajtów. Zmienne globalne używają 151 bajtów (5%) pamięci dynamicznej, pozostawiając 2 409 bajtów dla zmiennych lokalnych. Maksymalnie wynosi 2560 bajtów.
Dlaczego szkic minimalny zajmuje 15% przydzielonej przestrzeni dyskowej programu? I dlaczego bardzo prosty szkic zajmuje 17% miejsca w pamięci programu? Według strony internetowej Arduino :
Łatwo jest to wszystko wykorzystać, mając wiele ciągów w swoim programie. Na przykład deklaracja typu:
char message[] = "I support the Cape Wind project.";
wstawia 33 bajty do pamięci SRAM (każdy znak zajmuje bajt plus terminator „\ 0”).
Jednak w żadnym z tych szkiców nie ma zadeklarowanych ciągów.
Wygląda na to, że mogą importować lub używać innych bibliotek / klas, których nie określam. Może importuje domyślną bibliotekę systemową? A może to coś innego?
źródło
Masz już kilka doskonale dobrych odpowiedzi. Publikuję to tylko po to, by podzielić się statystykami, które zrobiłem pewnego dnia zadałem sobie te same pytania: co zajmuje tyle miejsca na minimalnym szkicu? Jakie jest minimum potrzebne do osiągnięcia tej samej funkcjonalności?
Poniżej znajdują się trzy wersje minimalnie mrugającego programu, który przełącza diodę LED na pinie 13 co sekundę. Wszystkie trzy wersje zostały skompilowane dla Uno (bez udziału USB) przy użyciu avr-gcc 4.8.2, avr-libc 1.8.0 i arduino-core 1.0.5 (nie używam Arduino IDE).
Po pierwsze, standardowy sposób Arduino:
To kompiluje się do 1018 bajtów. Używając obu
avr-nm
i demontażu , podzieliłem ten rozmiar na poszczególne funkcje. Od największego do najmniejszego:Na powyższej liście pierwsza kolumna ma rozmiar w bajtach, a druga kolumna informuje, czy kod pochodzi z biblioteki podstawowej Arduino (A, łącznie 822 bajtów), środowiska wykonawczego C (C, 148 bajtów) czy użytkownika (U , 48 bajtów).
Jak można zobaczyć na tej liście, największą funkcją jest procedura obsługująca przerwanie przepełnienia timera 0. Procedura ta jest odpowiedzialna za śledzenie czasu, a jest potrzebny
millis()
,micros()
idelay()
. Druga co do wielkości funkcjainit()
, która ustawia timery sprzętowe dla PWM, włącza przerwanie TIMER0_OVF i rozłącza USART (który był używany przez bootloader). Zarówno ta, jak i poprzednia funkcja są zdefiniowane w<Arduino directory>/hardware/arduino/cores/arduino/wiring.c
.Dalej jest wersja C + avr-libc:
Podział poszczególnych rozmiarów:
Jest to 132 bajty dla środowiska wykonawczego C i 26 bajtów kodu użytkownika, w tym funkcji wbudowanej
_delay_ms()
.Można zauważyć, że ponieważ ten program nie używa przerwań, tablica wektorów przerwań nie jest potrzebna, a zwykły kod użytkownika może zostać wstawiony na jej miejsce. Następująca wersja zestawu robi dokładnie to:
Jest to złożone (z
avr-gcc -nostdlib
) w zaledwie 14 bajtów, z których większość jest wykorzystywana do opóźniania przełączania, aby widoczne było mrugnięcie. Po usunięciu tej pętli opóźnienia powstaje 6-bajtowy program, który miga zbyt szybko, aby można go było zobaczyć (przy 2 MHz):źródło
Napisałem post na temat: Dlaczego mrugnięcie jednej diody LED zajmuje 1000 bajtów? .
Krótka odpowiedź brzmi: „Miganie dwóch diod LED nie zajmuje 2000 bajtów !”
Dłuższą odpowiedzią jest to, że standardowe biblioteki Arduino (z których nie musisz korzystać, jeśli nie chcesz) mają fajną funkcjonalność, która uprości twoje życie. Na przykład, możesz adresować piny według numeru w czasie wykonywania, gdzie biblioteka konwertuje (powiedzmy) pin 8 na właściwy port i prawidłowy numer bitu. Jeśli masz sztywny kod dostępu do portu, możesz zaoszczędzić ten narzut.
Nawet jeśli ich nie używasz, standardowe biblioteki zawierają kod zliczający „tiki”, dzięki czemu możesz dowiedzieć się o bieżącym „czasie” (dzwoniąc
millis()
). W tym celu należy dodać narzut niektórych procedur obsługi przerwań.Po uproszczeniu (w Arduino Uno) do tego szkicu zużycie pamięci programu spadnie do 178 bajtów (w IDE 1.0.6):
OK, 178 bajtów to niewiele, a pierwsze 104 bajty to wektory przerwań sprzętowych (po 4 bajty na 26 wektorów).
Prawdopodobnie więc wystarczy 74 bajty, aby mrugnąć diodą LED. A z tych 74 bajtów większość to tak naprawdę kod generowany przez kompilator w celu zainicjowania pamięci globalnej. Jeśli dodasz wystarczającą ilość kodu, aby mrugnąć dwie diody LED:
Następnie rozmiar kodu wzrasta do 186 bajtów. Dlatego można argumentować, że
186 - 178 = 8
miganie diody LED zajmuje tylko bajty.8 bajtów migania diody LED. Brzmi dla mnie dość wydajnie.
Jeśli masz ochotę spróbować tego w domu, powinienem zauważyć, że chociaż powyższy kod miga dwie diody LED, robi to naprawdę bardzo szybko. W rzeczywistości migają przy 2 MHz - patrz zrzut ekranu. Kanał 1 (żółty) to styk 12, kanał 2 (cyjan) to styk 13.
Jak widać, piny wyjściowe mają prostokątną falę o częstotliwości 2 MHz. Pin 13 zmienia stan 62,5 ns (jeden cykl zegara) przed pinem 12, ze względu na kolejność przełączania pinów w kodzie.
Więc jeśli nie masz znacznie lepszych oczu niż moje, nie zobaczysz żadnego efektu mrugania.
Jako zabawny dodatek, możesz faktycznie przełączać dwa piny w tej samej przestrzeni programu, co przełączanie jednego pinu.
To kompiluje się w 178 bajtów.
To daje wyższą częstotliwość:
Teraz jesteśmy do 2,66 MHz.
źródło
init()
(jak normalnymain()
robi), a następnie wiring.c plik (który mainit
w nim) nie był związany w. W rezultacie przetwarzanie dla przerwań ładowarki (domillis()
,micros()
itd.) Został pominięty. Prawdopodobnie nie jest szczególnie praktyczne pominięcie go, chyba że nigdy nie musisz mierzyć czasu, ale faktem jest, że szkic powiększa się w zależności od tego, co w nim umieścisz. Na przykład, jeśli używasz portu szeregowego, pamięć programu i pamięć RAM są trafione.