sobota, 2 kwietnia 2011

Błędy kompilacji programu


Autor: Dondu

Kompilacja to proces zamiany programu pisanego na wynikowy kod maszynowy mikrokontrrolera, który będzie przez niego wykonywany. Dla początkującego właściwie nie ma znaczenia jak ten proces przebiega, choć niektóre jego elementy będziesz wykorzystywał na etapie zaawansowanym.




1. Błędy i ostrzeżenia

W czasie procesu kompilacji, kompilator wykrywa błędy w kodzie oraz potencjalne jego fragmenty, które mogą być nieprawidłowe. Jeżeli takowe znajdzie generuje błąd lub ostrzeżenie. Początkujących tak to denerwuje, że miewają takie pomysły:

Dr.Kuj
Czy można zrobić coś żeby ... Warningi (ostrzeżenia) w ogóle nie były wyświetlane?


Błędy (ang. Errors)
Z punktu widzenia programisty błędy nie pozwalają dokończyć procesu kompilacji, więc nie masz wyjścia i musisz je poprawić.

Ostrzeżenia (ang. Warnings)
Tutaj jest pułapka ... ostrzeżenia nie przerywają procesu kompilacji, więc kod wynikowy powstaje i możesz nim zaprogramować swój mikrokontroler. Ale niestety nie masz gwarancji, że program będzie działał prawidłowo.

Rys. Przykład kompilacji z jednym ostrzeżeniem


Doświadczony programista jest w stanie określić, czy dane ostrzeżenie może zignorować, czy nie. Początkujący może nie mieć wystarczającej wiedzy w tym zakresie, dlatego:


Początkującego bezwzględnie obowiązują 2 zasady:

1. OSTRZEŻENIE TRAKTUJ JAK BŁĄD!
2. PO KOMPILACJI ZERO OSTRZEŻEŃ!


Jako początkujący przestrzegaj tych zasad bezwzględnie, bo to zaoszczędzi Ci czas i nerwy, gdy układ nie będzie działał tak jak się spodziewałeś. Innymi słowy po zakończeniu kompilacji licznik błędów i ostrzeżeń muszą być ustawione na zero lub zakończone przykładowym komunikatem:


Rys. Przykład prawidłowej kompilacji


Nasz kolega to zrozumiał, ale czasu sporo stracił:

Dr.Kuj
Miałeś racje TMF - to było ważne ostrzeżenie.


Przykład dla AVR Studio 4
Chcę by mój program był na 100% poprawny!
Jeżeli chcesz by kompilator strzegł poprawności Twojego programu zawsze w 100%, możesz skorzystać z możliwości automatycznej zmiany ostrzeżeń na błędy. Wystarczy dodać parametr kompilacji:
-Werror 
w opcjach projektu. Dla AVR Studio 4 robi się to tak:
Menu > Project > Configuration Options > Custom Options

W ten sposób kompilator nie odpuści Ci nawet najmniejszej pomyłki :-)





2. Optymalizacja kodu

Każdy program można napisać na wiele sposobów. Kompilator przekształcając program na kod maszynowy, musi wiedzieć, czy zależy Ci na przykład na prędkości jego wykonywania, czy na objętości zajmowanej pamięci programu, itp.

Najbardziej prostą formą wyboru Twoich preferencji dot. tworzenia kodu wynikowego, jest wybranie jednej z dostępnych wersji optymalizacji kodu wynikowego. Niestety to może być dla Ciebie trudne i wymagać poznania dokumentacji kompilatora.

Którą optymalizację wybrać?
Tworząc nowy projekt z reguły optymalizacja ustawiana jest na najbardziej optymalną, więc nie musisz nic zmieniać. Jednakże może się okazać, że jest ona wyłączona. Wtedy niestety powinieneś szukać w opcjach projektu lub przeczytać dokumentację tego kompilatora.

Na przykład dla kompilatora GCC języka C dla mikrokontrolerów Atmel AVR, najlepszą dla Ciebie będzie: -Os

Przykład dla AVR Studio 4
Ustawień optymalizacji szukaj z reguły w opcjach projektu, ale może być to różnie rozwiązane w różnych środowiskach programistycznych.

Ten temat jest znacznie szerszy, ale to już wiedza dla zaawansowanych mikrokontrolerowych szamanów :-)









3. Błędne definiowanie częstotliwości zegara

Zanim opiszę błędy, trochę niezbędnej wiedzy.

Dla różnych kompilatorów różne są zasady informowania kompilatora, o częstotliwości zegara taktującego Twój mikrokontroler. Kompilator musi wiedzieć dla jakiej częstotliwości zegara ma tworzyć kod chociażby dlatego, że często początkujący stosują funkcje opóźnień delay(), itp., a opóźnienia przez nie generowane są obliczane przez kompilator na podstawie podanej częstotliwości zegara taktującego.


Jak więc informować kompilator o częstotliwości zegara?

Są dwie metody i obie są poprawne, ale każda ma swoich zatwardziałych zwolenników i przeciwników :-)

Pierwszą metodą jest zamieszczanie definicji F_CPU w pierwszej linii kodu przed linkowanymi bibliotekami i programem:
#define F_CPU 12000000UL
#include <io.h>
#include <util/delay.h>
... itd.

Aby kompilator nie miał wątpliwości co do liczby powinieneś zadeklarować jej typ dopisując na końcu literki UL, które oznaczają:
U - Unsigned
L - Long


Przykład dla AVR Studio 4
Drugą metodą (polecaną) jest zdefiniowanie zegara w opcjach projektu.

Uwaga praktyczna dla tej metody: 
Ewentualne archiwizowanie, publikowanie kodu musi zawierać w sobie informację, dla jakiego zegara kod jest przygotowany. Ma to istotne znaczenie, gdy archiwizujesz tylko pliki z kodem, a nie wszystkie pliki projektu lub gdy publikujesz kod w internecie w postaci listingu.

Warto wtedy, w komentarzu na początku kodu dopisać wartość F_CPU po to, by nie zatracić tej bardzo istotnej informacji:
/*** Kod dla zegara 12MHz ***/
#include <io.h>
#include <util/delay.h>
... itd.

Więcej na ten temat: F_CPU – gdzie definiować?


Mikrokontroler ze zmiennym zegarem
Sprawa nieco się komplikuje, gdy korzystasz z mikrokontrolerów, które mogą za pomocą programu zmieniać częstotliwość zegara ich taktującego. Wtedy możesz napotkać na problem, iż funkcje opóźnienia nie mogą być prawidłowo policzone przez kompilator, ponieważ nie jest on świadomy, że częstotliwość zegara taktującego, zostanie zmieniona i w którym momencie. Na szczęście takie przypadki to wyższa szkoła jazdy, więc raczej Tobie nie grożą :-)

Jednakże gdybyś chciał poznać głębiej ten temat przeczytaj:


Błędy związane z definicją zegara w kodzie
Najczęściej występuje problem zamieszczenia definicji F_CPU w kodzie po linkowaniu bibliotek, którym ta informacja jest potrzebna:

#include <io.h>
#include <util/delay.h>   //ta biblioteka potrzebuje informacji o F_CPU
#define F_CPU 12000000UL   // BŁĄD! informacja o zegarze za późno!
... itd.

Prawidłowo powinno być tak:
#define F_CPU 12000000UL  //najlepiej gdy w pierwszej linii kodu
#include <io.h>
#include <util/delay.h>
... itd.

Książki dla Ciebie

4 komentarze:

  1. Optymalizacja faktycznie dużo daje. Kod który zajmował 6000 bajtów po zmianie optymalizacji zajmuje 610 bajtów! nie spodziewałem się aż takiego efektu

    OdpowiedzUsuń
  2. Czy jest coś takiego jak optymalizacja w AtmelStudio6? Oraz jeżeli tak, to gdzie znajdę jej ustawienia i konfigurację?

    OdpowiedzUsuń
    Odpowiedzi
    1. Oczywiście:
      http://mikrokontrolery.blogspot.com/2011/04/atmel-studio-pelne-ide-avr-arm-cz1.html
      Podpunkt optymalizacja.

      Usuń
  3. Artykuł bardzo pomocny, jednak "z reguły optymalizacja ustawiana jest na najbardziej optymalną". Optymalny - najlepszy wg zadanych kryteriów więc nie powinno być tu stopniowania.

    OdpowiedzUsuń