[012] Automatyczne formatowanie, stałe i zmienne

[012] Automatyczne formatowanie, stałe i zmienne

O optymalizacji pisałem już nieco, czas dowiedzieć się kilku kolejnych rzeczy. Wrócimy na chwilę do osławionego WC komputera, lecz nie będziemy już się zagłębiać w ideę programu, a skupimy się na kilku szczegółach. Po pierwsze, wielu pewno znalazło funkcję formatującą kod, która znajduje się pod skrótem klawiszowym Ctrl-T albo w menu: Narzędzia/Automatyczne formatowanie. Po jej użyciu program jest układany w charakterystyczny sposób, z wcięciami i mnóstwem spacji. Twórcy Arduino uznali, że tak jest czytelniej. Nie mogę się z tym do końca zgodzić, ale mój punkt widzenia jest subiektywny i pochodzi jeszcze z czasów asemblerowych, gdy zwykle pisało się gęsto i zwięźle. Faktem jest, że użycie tej funkcji sprawi, iż ktokolwiek nie pisałby szkicu, otrzyma standardowy jego wygląd, zgodny z pewnym wzorcem, może nieco zbyt rozwlekłym, co jednak w sumie ma więcej zalet niż wad. Oto przykład kodu zagęszczonego:


void loop() {

if(digitalRead(pstryczekPierwszy)==LOW){wyzeruj();lcd.print("    Zajete!     ");} // Sprawdzamy czy wciśnięto pstryczek pierwszy.
while(digitalRead(pstryczekPierwszy)==LOW){sekundnik();} // Czekamy, dopóki przycisk nie zostanie puszczony.

if(digitalRead(pstryczekDrugi)==LOW){wyzeruj();lcd.print(" Jeszcze moment ");} // To samo robimy z pstryczkiem drugim...
while (digitalRead(pstryczekDrugi)==LOW){sekundnik();}

if(digitalRead(pstryczekTrzeci)==LOW){wyzeruj();lcd.print("Ciezka sprawa...");} // Oraz z trzecim.
while(digitalRead(pstryczekTrzeci)==LOW){sekundnik();}

wyzeruj();lcd.print("    Wolne :)    ");
while(digitalRead(pstryczekPierwszy)==HIGH&&digitalRead(pstryczekDrugi)==HIGH&&digitalRead(pstryczekTrzeci)==HIGH){sekundnik();}
}
void sekundnik() // To jest podprogram rysujący sekundnik.
{lcd.setCursor(0,1);lcd.print(" Juz ");lcd.print(now());lcd.print(" sekund   ");}

void wyzeruj() // A to jest podprogram, który ustawia kursor i zeruje zegar.
{lcd.home();setTime(0);}

I ten sam kod sformatowany w standardzie promowanym przez Arduino IDE:

void loop() {

  if (digitalRead(pstryczekPierwszy) == LOW) {  // Sprawdzamy czy wciśnięto pstryczek pierwszy.
    wyzeruj();
    lcd.print("    Zajete!     ");
  }
  while (digitalRead(pstryczekPierwszy) == LOW) {  // Czekamy, dopóki przycisk nie zostanie puszczony.
    sekundnik();
  }

  if (digitalRead(pstryczekDrugi) == LOW) {  // To samo robimy z pstryczkiem drugim...
    wyzeruj();
    lcd.print(" Jeszcze moment ");
  }
  while (digitalRead(pstryczekDrugi) == LOW) {
    sekundnik();
  }

  if (digitalRead(pstryczekTrzeci) == LOW) {  // Oraz z trzecim.
    wyzeruj();
    lcd.print("Ciezka sprawa...");
  }
  while (digitalRead(pstryczekTrzeci) == LOW) {
    sekundnik();
  }

  wyzeruj();
  lcd.print("    Wolne :)    ");
  while (digitalRead(pstryczekPierwszy) == HIGH && digitalRead(pstryczekDrugi) == HIGH && digitalRead(pstryczekTrzeci) == HIGH) {
    sekundnik();
  }
}

void sekundnik()  // To jest podprogram rysujący sekundnik.
{
  lcd.setCursor(0, 1);
  lcd.print(" Juz ");
  lcd.print(now());
  lcd.print(" sekund   ");
}

void wyzeruj()  // A to jest podprogram, który ustawia kursor i zeruje zegar.
{
  lcd.home();
  setTime(0);
}

Druga postać jest bardziej czytelna, ale trudniej objąć całość wzrokiem. Myślę jednak, że dobrze trzymać się standardów, zatem polecam raz na jakiś czas wcisnąć Ctrl-T, a jeśli nawet na początku nie spodoba się to nam, po jakimś czasie przyzwyczaimy się do tego, dość charakterystycznego stylu. Trzeba też pamiętać, że sposób formatowania kodu nie ma zupełnie znaczenia dla jego treści i różnie sformatowane szkice będą pracować dokładnie tak samo.

Czas na optymalizację, która czasem pozwala zaoszczędzić nieco pamięci, gdyż tej nigdy za wiele. Kompilator jest już dojrzały i nasze bezrefleksyjne szastanie danymi potrafi świetnie zoptymalizować, więc większość z wymienionych za chwilę działań może nic nie wnieść, ale uczy dobrych nawyków. Zauważmy, że po kompilacji na dole podawane są zasoby. W naszym przypadku zużycie obu pamięci wynosi kilka procent i w zasadzie można się nie przejmować zupełnie optymalizacją mającą na celu ich oszczędzanie.

Czasem jednak, przy dużych projektach, może tych dóbr zabraknąć. Spójrzmy tutaj.

const int pstryczekPierwszy = 8;  // Używamy trzech pstryczków do wywoływania komunikatów.
int pstryczekDrugi = 9;
int pstryczekTrzeci = 10;

int lcdRS = 2;  // "lcd" to oczywiście wyświetlacz, którego wyprowadzenia ponazywaliśmy tutaj.
int lcdEN = 3;
int lcdD4 = 4;
int lcdD5 = 5;
int lcdD6 = 6;
int lcdD7 = 7;

int lcdKolumny = 16;  // "Kolumny" to ilość kolumn na naszym wyświetlaczu,
int lcdWiersze = 2;   // a "Wiersze" to ilość wierszy.

Zadeklarowaliśmy sobie kilka zmiennych, a przecież tak naprawdę są to stałe. Adresy linii wyświetlacza czy pstryczków deklaruje się raz na zawsze i nic się tam nie zmienia. Jeśli przed int napiszemy const, kompilator będzie traktować takie zmienne jako stałe, a więc nie będzie ich osadzał w pamięci RAM, której jest dużo mniej od pamięci programu.

const int pstryczekPierwszy = 8;  // Używamy trzech pstryczków do wywoływania komunikatów.
const int pstryczekDrugi = 9;
const int pstryczekTrzeci = 10;

const int lcdRS = 2;  // "lcd" to oczywiście wyświetlacz, którego wyprowadzenia ponazywaliśmy tutaj.
const int lcdEN = 3;
const int lcdD4 = 4;
const int lcdD5 = 5;
const int lcdD6 = 6;
const int lcdD7 = 7;

const int lcdKolumny = 16;  // "Kolumny" to ilość kolumn na naszym wyświetlaczu,
const int lcdWiersze = 2;   // a "Wiersze" to ilość wierszy.

Lecz, jak mówiłem, i bez naszych zmian kompilator, analizując resztę kodu, tak zadecydował. Ale nie do końca. Zyskaliśmy dwa bajty. Niby nic, lecz w przypadku dużych programów zysk może być większy. Co ciekawe, kompilator nie poradził sobie z linią, w której deklarujemy ilość kolumn. Po usunięciu const zasoby zmaleją o wymienione dwa bajty. Podsumowując, wszędzie gdzie deklarujemy coś, co podczas działania programu nigdy się nie zmienia, wpisujemy const i już.

Teraz jednak pokażę prawdziwą optymalizację. Otóż wszystkie napisy, które mają się pojawić na wyświetlaczu, a ogólniej – łańcuchy znaków, domyślnie przechowywane są w pamięci RAM. Jeśli taki łańcuch złapiemy w nawias zaczynający się literą F, kompilator przeniesie go do pamięci programu.

lcd.print(F("  WC komputer   "));
lcd.print(F("    Zajete!     "));
lcd.print(F(" Jeszcze moment "));
lcd.print(F("Ciezka sprawa..."));
lcd.print(F("    Wolne :)    "));
lcd.print(F(" Juz "));
lcd.print(F(" sekund   "));

Tym razem zysk jest ogromy, zużywaliśmy siedem procent RAM-u, teraz zużywamy tylko dwa procenty. Napisy trafiły do pamięci programu, lecz tej jest piętnaście razy więcej, zatem zużycie wzrosło niezauważalnie.

Ostatnią dziś metodą optymalizacji, choć nie wnoszącą wiele albo i nic – za sprawą świetnego kompilatora – jest deklarowanie takich typów zmiennych, jakie są naprawdę potrzebne. Powróćmy do int, czyli deklaracji zmiennych, czy też już teraz – stałych. Jak mówi nam dokumentacja, int określa liczbę całkowitą z zakresu – 32768 do +32767. Ale przecież największa liczba, jaka tam jest zadeklarowana, to 16. Może da się coś ugrać? Oczywiście! Jest inny typ zmiennych, który ogranicza wartości do zakresu liczb naturalnych od zera do 255. O ile w przypadku int potrzeba dwóch bajtów pamięci, gdy zakres ograniczymy do 256 wartości, wystarczy jeden bajt. I tak właśnie wygląda ta deklaracja: to byte.

const byte pstryczekPierwszy = 8;  // Używamy trzech pstryczków do wywoływania komunikatów.
const byte pstryczekDrugi = 9;
const byte pstryczekTrzeci = 10;

const byte lcdRS = 2;  // "lcd" to oczywiście wyświetlacz, którego wyprowadzenia ponazywaliśmy tutaj.
const byte lcdEN = 3;
const byte lcdD4 = 4;
const byte lcdD5 = 5;
const byte lcdD6 = 6;
const byte lcdD7 = 7;

const byte lcdKolumny = 16;  // "Kolumny" to ilość kolumn na naszym wyświetlaczu,
const byte lcdWiersze = 2;   // a "Wiersze" to ilość wierszy.

Niestety w tym prostym programie niczego nie odzyskaliśmy, ale to dlatego, że kompilator naprawił za nas użycie zbyt bogatej deklaracji. Jednak jeśli nauczymy się gospodarować zasobami bez oglądania się każdorazowo na zysk, nasze programy będą oszczędne z założenia i bardziej czytelne. No i będą działać szybciej. Czasem niezauważalnie, a czasem istotnie.

Powiązane tematy

Płytka edukacyjna TME-EDU-ARD-2Płytka edukacyjna TME-EDU-ARD-2Sprawdź tutaj

Przeczytaj również

Nasi partnerzy

TMETech Master EventTME EducationPoweredby
Copyright © 2024 arduino.pl