while( ){
//wlacz diodę LED PORTD|= x01 ;
} Listing 5
//ustaw port DDRC&= //wejście
PORTC|= ;//pull-up
//naciśnięto przycisk ? if(PINC& 1){ value =100 ;
} Listing 6
Niestety narzędzia debugujące są niekiedy bardzo drogie. Wspomniany PICkit 2 kosztuje w granicach 140 zł, co może przekraczać możliwości początkującego, młodego konstruktora. Za taką cenę można opracować co najmniej dwa interesujące urządzenia. Co zatem zrobić? Otóż wykorzystać wspomniane wcześniej narzędzia: diody, wyświetlacze, przyciski, port szeregowy, etc.
Pułapkę w programie można zastawić bardzo łatwo - listing 5. Jest to możliwe w zasadzie w każdym urządzeniu wyposażonym choćby w diodę LED. Program po napotkaniu takiej pułapki zaświeci diodę i zatrzyma się. Warto pamiętać o wyłączeniu przerwania globalnego, gdyż w niektórych przypadkach może ono prowadzić do mylnych wniosków, np. w sytuacji, gdy wewnątrz tego przerwania gaszona jest ta dioda LED. Krótkie mignięcie może nie zostać zauważone. Kilka diod LED umożliwia zastawienie pułapek w kilku miejscach programu. Należy jednak pamiętać, aby sprawdzić, czy taka pułapka działa prawidłowo (czy np. nie został pomylony port I/O). Zamiast diod LED można również wykorzystać port szeregowy, przez który zostanie wysłany krótki komunikat, numer pułapki lub jakaś wartość.
Dysponując przyciskiem, można również wymusić zmianę wartości wybranej zmiennej wykorzystując bardzo prosty kod - listing 6. Po naciśnięciu przycisku nastąpi zmiana wartości zmiennej. W przypadku obecności na płytce kilku przycisków można podstawić w ten sposób kilka różnych wartości. Nic nie stoi na przeszkodzie, aby taką wartość zapisać w zmiennej na stałe, skompilować program i go uruchomić - np. podmieniając linię z listingu 2: char value = 0 ; na:
char value = 0x12 ;
Będzie to jednoznaczne z operacją przeprowadzoną na rysunku 13.
Do przesyłania nowych wartości można także wykorzystać port szeregowy.
Pierwszym krokiem podczas pracy z kodem powinno być upewnienie się, czy program
się nie zawiesza. Jest to często spotykana sytuacja, gdy np. jakaś funkcja oczekuje na dane bądź działania użytkownika i ich nie otrzymuje. Podobnie dzieje się, gdy jest źle skonfigurowany układ przerwań, przerwania przychodzą zbyt często lub następuje przepełnienie stosu. Warto więc umieszczać w pętli głównej instrukcje sprawiające, że dioda LED będzie migotać lub co jakiś czas zostanie wysłana informacja na LCD lub do portu szeregowego. Jest to bardzo cenna informacja, gdyż pozwala stwierdzić, że program ogólnie się wykonuje. Dzięki tej technice udało mi się np. zdiagnozować błędy ze stosem w układzie LPC2142. W programie było używane przerwanie, które sprawiało, że program okresowo przestawał działać. Wiedząc o tym, mogłem skupić się na wyszukiwaniu przyczyny. Przy braku tej informacji szukałbym błędu logicznego, który powodował, że na wyjściu nie pojawiały się dane zgodne z założeniami. Nie mogły się ona tam
oczywiście pojawić, ponieważ procesor nic pracował normalnie i trzeba było usunąć ten problem (stanowił go zbyt mały stos).
Wiedząc, że któryś z fragmentów oprogramowania powoduje zawieszanie się mikrokontrolera, można stosować technikę polegającą na wyłączaniu bloków kodu poprzez objęcie ich znakami komentarza. Sukcesywnie tak postępując, można dotrzeć do fragmentu oprogramowania, które powoduje problem. Wiedząc, z grubsza, w którym miejscu on występuje, można zmniejszać liczbę instrukcji objętych komentarzem, aby bardziej zawęzić obszar poszukiwań. Czasami już same instrukcje wewnątrz bloku objętego komentarzem sugerują, co stanowi problem. Przykładem takiej sytuacji może być licznik wykorzystany do odmierzania czasu w pętli. Czasami zdarza się, że w pośpiechu zapomina się ten licznik uruchomić i pętla taka wykonuje się w nieskończoność. Inną przyczyną może być użycie tego samego licznika w innym miejscu programu lub przypadkowe zatrzymanie jego pracy. Wiedząc, że właśnie ta pętla się nie wykonuje, warto wstawić funkcję, która prześle do portu szeregowego albo na wyświetlacz wartość licznika w każdej iteracji. Od razu będzie widać, czy jego wartość ulega zmianie czy nic.
Podobny przypadek wystąpił podczas pracy z pakietem WinARM i mikrokontrolerami z serii LPC21xx. Z bliżej nieznanych mi powodów wartości zmiennych nie ulegały zmianie i program zawieszał się na pierwszej pętli. Właśnie ta technika pozwoliła ustalić przyczynę, wskazując na wadliwe działanie pętli, a następnie na fakt, że wartości zmiennych nic ulegają zmianie. Dojście do takiego wniosku wymagało jedynie wyświetlenia zmiennej przy każdej iteracji pętli.
Warto odpowiedzieć sobie na pytanie, czy czas wystąpienia błędu jest regularny (np. co 30 sekund albo zawsze w określonej sytuacji, np. po odebraniu 10B z portu szeregowego), czy raczej losowy. W pierwszym przypadku najprawdopodobniej winne jest oprogramowanie urządzenia, które w określonych sytuacjach przestaje normalnie funkcjonować. Winę mogą ponosić zbyt małe tablice niezdolne pomieścić danych doprowadzanych do mikrokontrolera, wyczerpanie wolnej pamięci RAM lub uruchamianie podprogramów zawierających określone błędy. Trudniej jest ustalić przyczynę błędów pojawiających się w losowych odstępach czasu. Winę może pono-
64 Marzec 2010 Elektronika dla Wszystkich