Fråga:
Varför tar skisser så mycket utrymme och minne?
hichris123
2014-02-22 03:29:25 UTC
view on stackexchange narkive permalink

När jag sammanställer denna skiss för Yún:

  int led = 7; void setup () {pinMode (led, OUTPUT); } void loop () {digitalWrite (led, HIGH);}  

Jag får:

Sketch använder 5098 byte (17%) av programlagringsutrymmet .

Maximalt är 28 672 byte. Globala variabler använder 153 byte (5%) av det dynamiska minnet, vilket lämnar 2 407 byte för lokala variabler. Maximalt är 2560 byte.

Även när jag kompilerar BareMinimum-skissen:

  tomrumsinställning () {// inställning} tomrumsslinga () {// loop}  

Jag får:

Skiss använder 4548 byte (15%) av programlagringsutrymmet.

Maximalt är 28 672 byte . Globala variabler använder 151 byte (5%) av det dynamiska minnet, vilket lämnar 2 409 byte för lokala variabler. Maximalt är 2.560 byte.

Varför tar en minsta skiss upp till 15% av det tilldelade programlagringsutrymmet? Och varför tar en mycket enkel skiss upp 17% av programmets lagringsutrymme? Enligt Arduino-webbplatsen:

Det är enkelt att använda allt genom att ha massor av strängar i ditt program. Till exempel en deklaration som: char message [] = "Jag stöder Cape Wind-projektet."; sätter 33 byte i SRAM (varje tecken tar en byte, plus '\ 0' terminatorn).

Det finns dock inga strängar deklarerade i någon av dessa skisser.

Det verkar som om de kan importera eller använda andra bibliotek / klasser som jag inte ' t specificera. Kanske importerar det ett systemets standardbibliotek? Eller är det något annat?

Fyra svar:
jippie
2014-02-22 03:36:27 UTC
view on stackexchange narkive permalink

Arduino sammanställer i många standardbibliotek, avbrott etc. ... Till exempel använder pinMode- och digitalWrite-funktionerna en uppslagstabell för att ta reda på vid körning vilken GPIO registrerar för att skriva data till. Ett annat exempel är att Arduino håller reda på tiden, det definierar vissa avbrott som standard och all denna funktionalitet kräver lite utrymme. Du kommer att märka att om du förlänger programmet kommer fotavtrycket bara att förändras något.

Jag gillar personligen att programmera styrenheter med ett minimum, utan "uppblåsthet", men du kommer snabbt in i världen av EE.SE och SO eftersom flera lättanvända funktioner inte längre fungerar ur lådan. Det finns några alternativa bibliotek för pinMode och digitalWrite som sammanställs till ett mindre fotavtryck, men har andra nackdelar som till exempel statiska kompilerade stift (där ledd inte kan vara en variabel utan är en konstant). p>

Så i princip sammanställs det i alla möjliga standardbibliotek utan att du frågar? Propert.
Ja, jag brukar kalla det "uppblåst", men det är verkligen en användbarhet. Arduino är en låg ingångsmiljö som bara fungerar utan för mycket tanke. Om du behöver mer tillåter Arduino dig att använda alternativa bibliotek eller så kan du kompilera mot bar metall. Det sista är förmodligen utom räckhåll för Arduino.SE
Se mitt @mpflaga-svar. Det är inte lika mycket uppblåsthet. Eller åtminstone i kärnbiblioteket för minimal funktionalitet. Det finns inte riktigt mycket av några standardbibliotek inkluderade, såvida det inte kallas skissen. Snarare beror 15% på USB-stödet för 32u4.
mpflaga
2014-02-22 11:58:43 UTC
view on stackexchange narkive permalink

YUN är en kombination. Del Arduino och del OpenWRT (Linux). Din fråga hänvisar till Arduino. Där detta faktiskt är en ATmega32u4 som liknar en Leonardo och inte en UNO (ATmega328p). 32u4 (Leo) kommunicerar via virtuella seriella portar via USB (kort svar: detta måste stödjas) där UNO har en riktig seriell port (aka UART). Nedan finns statistik för olika korttyper för AVR-processorerna.

Observera att det finns ett externt chip på UNO som konverterar USB till seriell portens DTR-stift som växlar mellan ATmega328: s återställningsstift när den är ansluten och orsakar en omstart till startladdaren. Däremot är Leo / Yuns USB to Serial implementerad i firmware på 32u4. För att fjärrstarta Leo eller YUN: s 32u4-chip måste den laddade firmware alltid stödja drivrutinen för USB-klientsidan. Vilket förbrukar ungefär 4K.

Om USB INTE behövdes och inga andra biblioteksresurser anropades som i fallet BareMinimum.ino på en UNO, behövs bara cirka 466 byte för Arduino-kärnbiblioteket.

sammanställa statistik för BareMinimum.ino på en UNO (ATmega328p)

  Sketch använder 466 byte (1%) av programlagringsutrymmet. Maximalt är 32 256 byte. Globala variabler använder 9 byte (0%) av det dynamiska minnet, vilket lämnar 2039 byte för lokala variabler. Maximalt är 2048 byte.  

sammanställ statistik för BareMinimum.ino på en Leonardo (ATmega32u4)

  Skiss använder 4554 byte (15%) av programlagringsutrymmet . Maximalt är 28 672 byte. Globala variabler använder 151 byte (5%) av det dynamiska minnet, vilket lämnar 2 409 byte för lokala variabler. Maximalt är 2560 byte.  

sammanställ statistik för BareMinimum.ino på en Yun (ATmega32u4)

  Skiss använder 4548 byte (15%) av programlagringsutrymmet . Maximalt är 28 672 byte. Globala variabler använder 151 byte (5%) av det dynamiska minnet, vilket lämnar 2 409 byte för lokala variabler. Maximalt är 2560 byte.  
Edgar Bonet
2015-07-07 13:12:17 UTC
view on stackexchange narkive permalink

Du har redan några helt bra svar. Jag lägger upp det här bara för att dela statistik som jag gjorde en dag och jag frågade mig samma slags frågor: Vad tar så mycket utrymme på en minimal skiss? Vad behövs minst för att uppnå samma funktionalitet?

Nedan följer tre versioner av ett minimalt blinkande program som växlar mellan LED på stift 13 varje sekund. Alla tre versionerna har sammanställts för anUno (ingen USB inblandad) med avr-gcc 4.8.2, avr-libc 1.8.0 andarduino-core 1.0.5 (jag använder inte Arduino IDE).

Först, det vanliga Arduino-sättet:

  const uint8_t ledPin = 13; void setup () {pinMode (ledPin, OUTPUT);} void loop () {digitalWrite (ledPin, HIGH); fördröjning (1000); digitalWrite (ledPin, LOW); delay (1000);}  

Detta sammanställs till 1018 byte. Med både avr-nm och demontering delade jag upp den storleken i enskilda funktioner. Från största till minsta:

  148 A ISR (TIMER0_OVF_vect) 118 A init 114 A pinMode 108 A digitalWrite 104 C vektortabell 82 A turnOffPWM 76 A fördröjning 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) ------------------------ 1018 TOTALT  

I listan ovan är den första kolumnen storleken i byte , och den andra kolumnen berättar om koden kommer från Arduino-kärnbiblioteket (A, totalt 822 byte), C-körningstiden (C, 148 byte) eller användaren (U, 48byte).

Som kan vara sett i den här listan är den största funktionen rutinservicering av timern 0 överflödsavbrott. Denna rutin ansvarar för spårningstiden och behövs av millis () , micros () och delay () . Den näst största funktionen är init () , som ställer in hårdvarutimrarna för PWM, möjliggör avbrott i TIMER0_OVF och kopplar bort USART (som användes av startladdaren). Både denna och den tidigare funktionen definieras i <Arduino-katalog> / hardware / arduino / cores / arduino / wiring.c .

Nästa är C + avr-libc-versionen:

  #include <avr / io.h> # include <util / delay.h>int main (void) {DDRB | = _BV (PB5); / * ställa in stift PB5 som utgång * / för (;;) {PINB = _BV (PB5); / * växla PB5 * / _fördröjning_ms (1000); }}  

Fördelningen av de enskilda storlekarna:

  104 C vektortabell 26 U main 12 C __init 8 C .init9 (call main, jmp exit) 4 C __bad_interrupt 4 C _exit ---------------------------------- 158 TOTALT  

Detta är 132 byte för C-körning och 26 byte användarkod, inklusive den inline-funktionen _fördröjning_ms().

Det kan noteras att eftersom detta programmet använder inte avbrott, avbrottsvektortabellen behövs inte och vanlig användarkod kan placeras på sin plats. Följande monteringsversion gör exakt det:

  #include <avr / io.h> # define io (reg) _SFR_IO_ADDR (reg) sbi io (DDRB), 5; ställa in PB5 som utgångsslinga: sbi io (PINB), 5; växla PB5 ldi r26, 49; fördröjning för 49 * 2 ^ 16 * 5 cyklerfördröjning: sbiw r24, 1 sbci r26, 0 brne fördröjning rjmp-slinga  

Detta är monterat (med avr-gcc -nostdlib kod >) i endast 14 byte, varav de flesta används för att fördröja växlarna så att blinkningen är synlig. Om du tar bort fördröjningsslingan slutar du med ett 6-byte-program som blinkar för snabbt för att ses (vid 2 MHz):

  sbi io (DDRB), 5; ställa in PB5 som utgångsslinga: sbi io (PINB), 5; växla PB5 rjmp-slinga  
Nick Gammon
2015-07-07 07:17:10 UTC
view on stackexchange narkive permalink

Jag skrev ett inlägg om Varför krävs 1000 byte för att blinka en lysdiod?.

Det korta svaret är: "Det tar inte 2000 byte att blinka två lysdioder! "

Det längre svaret är att standard Arduino-bibliotek (som du inte behöver använda om du inte vill) har en fin funktion för att förenkla din liv. Du kan till exempel adressera stift efter nummer vid körning, där biblioteket omvandlar (säg) stift 8 till rätt port och rätt bitnummer. Om du har hårdkodsportåtkomst kan du spara den där utgiften.

Även om du inte använder dem innehåller standardbiblioteken kod för att räkna "fästingar" så att du kan ta reda på den aktuella "tiden" genom att ringa millis () ). För att göra detta måste du lägga till omkostnaderna för vissa avbrottsrutiner.

Om du förenklar ner (på Arduino Uno) till denna skiss får du programminnesanvändningen ner till 178 byte (på IDE 1.0. 6):

  int main () {DDRB = bit (5); medan (true) PINB = bit (5); }  

OK, 178 byte är inte så mycket, och därav är de första 104 byte hårdvaruavbrottsvektorerna (4 byte vardera, för 26 vektorer).

Så utan tvekan krävs det bara 74 byte för att blinka en lysdiod. Och av de 74 byte är de flesta verkligen koden som genereras av kompilatorn för att initiera globalt minne. Om du lägger till tillräckligt med kod för att blinka två lysdioder:

  int main () {DDRB = bit (5); // stift 13 DDRB | = bit (4); // stift 12 medan (true) {PINB = bit (5); // stift 13 PINB = bit (4); // pin 12}}  

Då ökar kodstorleken till 186 byte. Så därför kan du argumentera för att det bara tar 186 - 178 = 8 byte för att blinka en lysdiod.

Så, 8 byte för att blinka en LED. Låter ganska effektivt för mig.


Om du är frestad att prova det här hemma bör jag påpeka att även om den upplagda koden ovan blinkar två lysdioder så gör den det väldigt snabbt. Faktum är att de blinkar vid 2 MHz - se skärmdump. Kanal 1 (gul) är stift 12, kanal 2 (cyan) är stift 13.

Rapid blinking of pins 12 and 13

Som du kan se har utgångarna en fyrkantig våg med en frekvens på 2 MHz. Stift 13 ändrar tillstånd 62,5 ns (en klockcykel) före stift 12 på grund av ordningen på stiftens växling i koden.

Så om du inte har mycket bättre ögon än min, kommer du inte faktiskt ser någon blinkande effekt.


Som en underhållande extra kan du faktiskt växla mellan två stift i samma mängd programutrymme som att växla en stift.

  int main () {DDRB = bit (4) | bit (5); // ställ in stiften 12 och 13 så att de matas ut medan (true) PINB = bit (4) | bit (5); // växla stift 12 och 13} // slutet av huvud  

Som sammanställs till 178 byte.

Detta ger dig en högre frekvens:

Very rapid blinking of pins 12 and 13

Nu är vi upp till 2,66 MHz.

Det här är massor av mening. Så ingår standardbiblioteken bara rubriker automatiskt vid byggtiden? Och hur kunde du * inte * inkludera dem?
Länkaren tar aggressivt bort kod som inte används. Genom att inte anropa `init ()` (som den normala `main ()` gör) kopplades inte filledningen.c (som har `init` i sig). Som ett resultat bearbetades avbrotthanterarna ( för `millis ()`, `micros ()` etc.) utelämnades. Det är förmodligen inte särskilt praktiskt att utelämna det, såvida du aldrig behöver ta tid på saker, men faktum är att skissen växer i storlek beroende på vad du lägger i den. Om du till exempel använder Serial, slår både programminne och RAM en träff.


Denna fråga och svar översattes automatiskt från det engelska språket.Det ursprungliga innehållet finns tillgängligt på stackexchange, vilket vi tackar för cc by-sa 3.0-licensen som det distribueras under.
Loading...