Fråga:
Hur kan jag minska storleken på min skiss?
Shpigford
2016-04-01 00:59:39 UTC
view on stackexchange narkive permalink

Det verkar som om jag överskrider lagringen av min Adafruit Trinket:

  Sketch använder 5600 byte (105%) av programlagringsutrymmet. Maximalt är 5 310 byte. Globala variabler använder 109 byte dynamiskt minne.  

Några tips för att minska fotavtrycket för min kod?

  # inkluderar <Adafruit_NeoPixel.h> # inkluderar <Wire.h> # inkluderar <RTClib.h> # definiera LEDPIN 1 # definiera TONE 4 # definiera BTNPIN 3RTC_DS; Ad. * 10000L; // X minutesint colorStops = 256; int delaySpeed ​​= fadeTime / colorStops; int notes [] = {262,294,330,349}; int timeHour = 14; int timeMinute = 43; uint32_t alarmLength = 5 * 60000L; // 5 minuter avbryt installation () {rtc.begin (); om (! rtc.isrunning ()) {rtc.adjust (DateTime (__ DATE__, __TIME__)); } pinMode (TONE, OUTPUT); pinMode (BTNPIN, INPUT); digitalWrite (BTNPIN, HIGH); strip.begin (); strip.show ();} void loop () {DateTime now = rtc.now (); if (now.hour () == timeHour && now.minute () == timeMinute && now.second () == 0) {// Fade in light for (int i = 1; i<colorStops; i ++) () == true) {break; } för (int np = 0; np<strip.numPixels (); np ++) {strip.setPixelColor (np, strip.Color (i, i, 0)); } strip.show (); delay (delaySpeed); } // Spela ton efter ljus helt ljusstarkt för (uint32_t tStart = millis (); (millis () - tStart) < alarmLength;) {if (kill () == true) {break; } för (int np = 0; np<strip.numPixels (); np ++) {strip.setPixelColor (np, strip.Color (random (100,255), random (100,255), random (100,255))); } strip.show (); pip (TON, anteckningar [slumpmässig (0,3)], 50); fördröjning (100); } för (int np = 0; np<strip.numPixels (); np ++) {strip.setPixelColor (np, strip.Color (0,0,0)); } strip.show (); }}
ogiltigt pip (osignerad rödhögtalarePin, int frekvensInHertz, lång tidInMillisekunder) {// http://web.media.mit.edu/~leah/LilyPad/07_sound_code.html int x; lång fördröjningAmount = (lång) (1000000 / frekvensInHertz); lång loopTime = (lång) ((timeInMilliseconds * 1000) / (delayAmount * 2)); för (x = 0; x<loopTime; x ++) {digitalWrite (speakerPin, HIGH); delayMicroseconds (delayAmount); digitalWrite (speakerPin, LOW); delayMicroseconds (delayAmount); }} bool kill () {if (! digitalRead (BTNPIN)) {for (int np = 0; np<strip.numPixels (); np ++) {strip.setPixelColor (np, strip.Color (0,0,0)); } strip.show (); återvänd sant; } annat {returnera falskt; }}  
Ett förslag skulle vara att ändra alla int-variabler som du vet inte kommer att ligga utanför intervallet [-127, 127] till en bytevariabel. byte-datatyp är av storlek 1 byte, int är 4 byte. Detta liknande koncept kan också användas för andra variabler.
Har du provat olika kompilatoroptimeringsnivåer?
@JonathanSmit: Området för en `byte 'är [0, 255], inte [-127, 127], eftersom det skrivs som en' uint8_t '. Och `int 'är 2 byte, inte 4.
Ops, ledsen för det, tänkte mig helt. Jag glömde byte är osignerad. Är inte heller 4 byte på de flesta 32-bitars och 64-bitars kompilatorer? http://stackoverflow.com/questions/11438794/is-the-size-of-c-int-2-bytes-or-4-bytes
@JonathanSmit: “_ ​​Är det inte heller 4 byte på de flesta 32-bitars och 64-bitars kompilatorer? _” Ja, det är det, men ATtiny85 inuti Trinket är ett 8-bitars chip.
Jag tycker att bli av med arduino digitalRead / Write () och pinMode kan spara utrymme. Som ett snabbtest sparar jag 6% utrymme på ett program genom att ta bort en digitalRead och pinMode. Ger dig en idé.
Jag undrar om det finns ett mer kompakt sätt att utföra avsikten bakom "pip" -funktionen. I slutändan försöker vi bara få piezo att generera en uppsättning snabba pipande ljud (den här saken är för ett larm).
"Jag undrar om det finns ett mer kompakt sätt att utföra avsikten bakom pipfunktionen" - Jag skrev ett litet bibliotek för att göra det, dock för Atmega328. Du borde kunna anpassa det.
Tre svar:
AMADANON Inc.
2016-04-01 01:26:45 UTC
view on stackexchange narkive permalink

AdaFruit Trinket har bara inte mycket minne - 8 kb, varav 3 kb används av startladdaren.

Den ordning jag letar efter saker för att minska fotavtrycket för ett Arduino-program är:

  • data (t.ex. stora strängar)
  • bibliotek
  • din kod (speciellt gör samma saker flera gånger, som kan kombineras till loopar eller funktioner ).

I det här fallet har du inte mycket data. Det mesta av din resulterande programstorlek finns i de bibliotek du använder.

Det verkar som att du bara använder klockan för att upptäcka året - det verkar som en hel del omkostnader bara för att ta reda på vilket år det är. Det gör då ingenting för efterföljande år (eller tidigare år) om jag läser din kod korrekt. Du kanske skulle överväga att släppa den här koden? Sedan kan du hoppa över hela RTC-biblioteket. Försök åtminstone att se hur mycket du sparar. Jag misstänker att RTC-biblioteket kommer att använda ett annat bibliotek för att göra det underliggande arbetet.

Du använder biblioteket men hänvisar inte till det i din kod. Det bör optimeras (om det inte används någon annanstans), men det finns ingen anledning att ha det där.

Du kan också spara lite utrymme genom att ersätta initialiserade variabler som inte ändras till konstanter. Att lagra 25 i en variabel tar 1 byte plus 2 byte varje gång du refererar till den. 25 i en konstant blir optimerad bort och tar upp 1 byte varje gång du refererar till den.

Som nämnts i kommentarerna kan du också spara några byte genom att ange storleken på dina int, särskilt initialiserade.

Ett annat alternativ skulle vara att använda ett större chip - AtMega328p som används i (till exempel) Arduino har 32 kb flash - 6 gånger den (tillgängliga) storleken.

Du kan också spara vissa byte genom att ta bort klausulen if (! rtc.isrunning ()) {, när du har ställt in den en gång.

Ytterligare: Jag har lyckats med att minska fotavtryck genom att implementera en delmängd av ett bibliotek igen. Vanligtvis är bibliotek mycket väl implementerade, men om dina behov är väsentligt annorlunda / enklare än vad biblioteket var designat för, eller om du är villig att avstå från delar av det (t.ex. felkontroll), då kan det ibland hjälpa till. VARNING! Det finns ett HÖGT pris att betala (kodning, felsökning, förlust av felkontroll, oupptäckta buggar etc), och det kan spara dig vad som helst i slutändan.

Du kan också (ibland) flytta data (t.ex. stora strängar) till eeprom. Trinket har 512 byte eeprom. Du kan behöva en skiss för att ladda in data i eeprom, för att köra innan du laddar din huvudskiss. eeprom har sin egen overhead, så det kanske inte lönar sig för 512 byte, det är långsammare (vilket förmodligen inte spelar någon roll för detta), och du har ett begränsat antal skrivningar.

Ytterligare några byte kan vara sparas genom att göra all matematik för tonfrekvensen / tiden i förväg och offra något. Till exempel piper du i 50 ms. Om istället för att passera frekvensen (mellan 262 och 349 hertz) och istället förberäkna fördröjningsbeloppet (för 262 hz skulle detta vara 1 000 000/262 = 3817 ms); din looptime för detta är ((timeInMilliseconds * 1000) / (delayAmount * 2)) = (50 * 1000) / (3817 * 2) = 6,55 cykler. 7 cykler är förmodligen "tillräckligt nära" för alla toner du vill producera. Så du kan hårdkoda 7 cykler (med konstanten 7 för looptime) och bli av med den formeln för att beräkna looptime.

På ett liknande sätt, om du inte bryr dig för mycket om den exakta frekvensen (som varierar mellan 3817ms och 2865ms beroende på ditt slumpmässiga nummer), du kan ange fördröjningsbeloppet som 2865 + slumpmässigt (0,3) * 238 (se till att du lagrar åtminstone slumpmässigt tal, du vill inte att det ska ändras under loop!).

Du har nu:

  #define random_beep_length 7void random_beep (unsigned char speakerPin) {// http://web.media.mit.edu /~leah/LilyPad/07_sound_code.html // Tungt modifierad! int x;
osignerad rödhöjd = 2865 + slumpmässig (0,3) * 238; för (x = 0; x<random_beep_length; x ++) {digitalWrite (speakerPin, HIGH); delayMicroseconds (delayAmount); digitalWrite (speakerPin, LOW); delayMicroseconds (delayAmount); }}  
Tack för tipsen! Jag glömde att uppdatera min kod från när jag gjorde felsökning. Jag behöver faktiskt RTC för att upptäcka aktuell timme och minut (vilket nu återspeglas i mitt inlägg).
Jag tycker att det är en bra idé att ställa in klockan en gång - i en separat skiss - och sedan utelämna den del som kontrollerar om klockan går. Om det inte hjälper kan du ändra klockbiblioteket (eller göra en kopia) för att utelämna de delar som ställer in tiden.
“_Du kan ange fördröjningsbeloppet som 2865 + slumpmässigt (0,3) * 238_”. Eller, ännu bättre, `2945 + slumpmässig (0,4) * 256`. Detta sparar 8 byte på bekostnad av en liten felaktighet i frekvenserna. Eller en motsvarande men mindre läsbar form: '2945+ (slumpmässig () & 3) * 256' (sparar 18 byte).
@EdgarBonet, varför inte `(11 + slumpmässig () & 3) * 256`, vilket sparar ytterligare en byte? :)
Summan av dessa tips gjorde tricket. Jag är på 97% nu. :)
Du menar förmodligen `pip ((11+ (slumpmässig () & 3)) * 256);`. När jag kompilerar det tar det 28 byte flash, v.s. 20 byte för `pip (2945+ (slumpmässig () & 3) * 256);`. Av någon anledning beräknar gcc -Os din summa som ett 32-bitarsnummer. Detta kan fixas med `pip ((11 + ((uint8_t) slumpmässig () & 3)) * 256);`, som ser ful ut men kompilerar till endast 16 byte! :-)
Edgar Bonet
2016-04-01 15:08:05 UTC
view on stackexchange narkive permalink

Som redan nämnts av AMADANON Inc. i sitt svar, bör du kvalificera dig som const alla de konstanta variablerna i början av programmet. Detta är förmodligen den största platsbespararen.

Du kan få ungefär 100 byte genom att använda direktportaccess istället för pinMode / digitalRead / digitalWrite. När det gäller ATtiny85 har du bara port B, och Arduino-stiftnumren är desamma som Atmel-bitnumren. Så du skulle till exempel använda PINB & _BV (BTNPIN) istället för digitalRead (BTNPIN) .

Det finns några optimeringsmöjligheter i pip () :

  • skickar endast en parameter, som speakerPin och timeInMilliseconds som konstanter i ditt program
  • har den här parametern delayAmount istället för frequencyInHertz och lagrar dessa förseningar istället för frekvenser i -anteckningarna [] konstant array
  • beräkna inte antalet iterationer (den felaktiga namnet loopTime ) i förväg, istället beräkna den förflutna tiden och loop tills du når önskad tid

Här är min version av beep () med dessa optimeringar:

  void beep (int delayAmount) {for (uint16_t t = 0; t < BEEP_TIME * 1000/2; t + = delayAmount) {PORTB | = _BV (TONE); // digitalWrite (TONE, HIGH); delayMicroseconds (delayAmount); PORTB & = ~ _BV (TONE); // digitalWrite (TONE, LOW); delayMicroseconds (delayAmount); }}  

Observera att loopvariabeln faktiskt är halv den förflutna tiden. Sparar några byte. Att göra antalet iterationer konstant, som föreslagits av AMADANON Inc., sparar också några byte (6 byte i mitt test).

Du bör också ta bort alla samtal till -remsan. Färg () : byt ut alla instanser av strip.setPixelColor (np, strip.Color (r, g, b)) med strip.setPixelColor (np, r, g, b) .

Med alla dessa optimeringar tillsammans är jag ganska säker på att du kommer att få mer än de 290 byte du behöver för att passa ditt program i Trinket.

"konstanta variabler"? LOL! Jag vet vad du menar :)
Majenko
2016-04-01 02:19:32 UTC
view on stackexchange narkive permalink

Ett alternativ som inte redan nämnts, men det kan vara värt att nämna, är att ta bort startladdaren och programmera chipet direkt med en hårdvaruprogrammerare (eller en annan Arduino). Det ökar det tillgängliga skissminnet från 5kiB till hela 8kiB på chipet.

Det här är en bra idé, men kom ihåg att du måste sätta startladdaren tillbaka om du någonsin vill använda den som den ursprungligen designades.
Finns det någon form av hur man gör någonstans om att göra detta? Jag har en Uno jag antar att jag skulle kunna göra det med.


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...