Lekcja 3, programujemy linijke LED
Linijka LED, kolejny program
Dzisiaj zajmiemy się programem, którego celem będzie wyświetlanie linijki LED na wyjściach PORTA. Wiesz chyba co to jest linijka LED? Chodzi o to, że co pewien okres czasu zapala się kolejna dioda podłączona do wyjścia PORTA, a gaśnie poprzednia. Cykl powtarza się, aż do dojścia do ostatniej diody i rozpoczyna powrót dokładnie w ten sam sposób.
Wstępne założenia
Ze względów omówionych później do linijki nie wykorzystałem w swoim programie wyjścia PORT,4, dlatego moja linijka skład się jedynie z czterech diod o kolorze żółtym. Program jest napisany tak by 1 na wyjściu włączała diodę. Oznacza to, że dla uzyskania tego samego efektu dioda powinna być włączona z wyjścia portu do masy. Schemat znajdziesz na końcu artykułu. Oczywiście nic nie stoi na przeszkodzie, aby umieścić diody drugą stroną. To znaczy od plusa do wejścia portu. W takim przypadku diody zapalałyby się, kiedy na wyjściu byłoby zero logiczne, a rotacja 1 z opisywanego programu wyglądałaby tak, że poruszałaby się jak gdyby jedna zgaszona dioda zamiast jednej zapalonej jak w przypadku opisywanej linijki.
Zmiany
Oczywiście Ty jeżeli masz trochę chęci możesz zmienić podany program i podłączyć diody LED pod wyjście PORTB. Będziesz miał wtedy aż 8 diod do testów. Pamiętaj tylko, że linia programatora RB7 nie może być włączona podczas działania programu. Jeżeli pozostawisz ją włączoną nic się nie stanie programatorowi, ani procesorowi. Nie będzie po prostu się zapalać ostatnia dioda z linijki. Pisałem już o tym w jednej z poprzednich części.
Nowe komendy
Poznaliśmy już ostatnimi czasy kilka pożytecznych komend teraz czas na kolejne. Przy realizacji programu przyda nam się komenda, która przesuwa bity rejestru w określona stronę. W asemblerze pod PICa mamy dwie takie komendy. Mianowicie
RRF rejestr,d
Gdzie rejestr to nazwa rejestru, którego bit chcemy przesuwać, a d to miejsce do którego ma zostać przeniesiona liczba powstała po przesunięciu. Dla przykładu w rejestrze PORTA mamy liczbę 00100 i chcemy ta jedynkę przesunąć o jedno miejsce. Możemy oczywiście w najnormalniejszy sposób wpisać do Porta liczbę 00010, ale my tego nie robimy, ponieważ chcemy poznać działanie nowej komendy.
RRF PORTA,f
Po wykonaniu tego działania liczba zapisana w PORTA będzie miała postać 00010, czyli taką jaką oczekiwaliśmy. To f na końcu oznacza, że przesuniętą wartość wpisujemy do PORTA. Gdyby komenda miała postać:
RRF PORTA,w
Liczba, czy mówiąc ściślej wynik nie zostałby zapisany do PORTA tylko do rejestru w. Nasz PORTA miałby wtedy wygląd taki jak na początku czyli 00100.
Najpierw wpisujemy jedynkę
Hasło z tytułu jest chyba najważniejszą rzeczą w tym projekcie. To jest chyba jedyne miejsce, w którym można i popełnia się błąd. Próba przesunięcie zawartości rejestru, w którym znajduję się liczba 00000 spełźnie na niczym. Zapamiętaj, żeby przesunąć jakakolwiek jedynkę w lewo, czy w prawo najpierw musimy ta jedynkę tam wpisać, chyba że już tam jest 😉 . W każdym bądź razie rejestr, na którym chcemy dokonać przesunięcia musi zawierać choćby jedną jedynkę.
Program
Po kilku wstępnych uwagach bierzemy się za program. Oczywiście na samym początku ustawiamy fusebity, deklarujemy procesor itp. Kolejny krok to ustawienie portów. Ja w swoim programie jako port wyjściowy dla LED przyjąłem PORTA, ale równie dobrze mógłby to być PORTB. Nawet byłoby lepiej, ponieważ do niego możemy podłączyć większą ilość LED-ów.
Procedury, rotacja w lewo
Kolejną czynnością do wykonania dla programisty, czyli w tym przypadku Ciebie, jest wpisanie tej jedynki do aktualnie czystego, wyzerowanego rejestru. Jak już wspominałem musimy mieć co przesuwać. Osobiście na wszelki wypadek, gdyby coś w rejestrze przez przypadek znalazło się po zaprogramowaniu, zeruje cały rejestr przed głównym programem komendą:
CLRF PORTA
Wpisanie wspomnianej jedynki może wyglądać tak:
movlw 01h ;wpisanie pierwszej jedynki
movwf PORTA ;wpisanie do PORTA 1 do najmłodszego bitu
Teraz wystarczy już wpisać komendę RLF i wszystko będzie działać. STOP. Zapomnielibyśmy o przymusie dodania opóźnienia pomiędzy włączanie i wyłączanie kolejnych LED-ów.
Opóźnienie
Podprogram opóźnienia był już ostatnio opisany, więc nie ma co marnować na to objętości kolejnego. Tym razem dla uzyskania odpowiednio długiego opóźnienia użyłem aż trzech zmiennych. Ich inicjalizacja wygląda u mnie tak:
;***ZMIENNE***
cblock 0x0c ;blok zmiennych
liczba1 ;zmienna do opóźnienia
liczba2 ;zmienna do opóźnienia
liczba3 ;zmienna do opóźnienia
endc ;koniec bloku zmiennych
Natomiast sam podprogram opóźnienia tak:
opoznienie ;podprogram opóźnienia (długie)
movlw .4 ;czterokrotne powtórzenie najdłuższej pętli petla1
movwf liczba3
petla1
movlw .200 ;200 razy powtarza petla2
movwf liczba2
petla2
movlw .200 ;200 razy powtarza petle3
movwf liczba1
petla3
decfsz liczba1
goto petla3
decfsz liczba2
goto petla2
decfsz liczba3
goto petla1
return ;powrót do programu
Rotacja w lewo
Po wpisaniu podprogramu opóźnienia możemy już dokonać przesunięcia. Piszemy więc w ciele głównym programu np.
Program
Call opóźnienie
Rlf PORTA,f
Goto program
Kompilujemy odpalamy. Okazuje się, że program działa zgodnie z zamierzeniami. Przemiata jedynką po kolei po wszystkich wyjściach aż do samego końca. My jednak chcemy, żeby po osiągnięciu ostatniego wyjścia program zaczął wracać kolejno do poprzedniego i tak aż do pierwszego, a następnie znowu do drugiego aż do końca i tak dalej.
Sprawdzanie czy liczba osiągnęła pożądany stan
Naszym zadaniem jest teraz wyłapać moment, w którym włączone jest ostatnie wyjście i wymusić rotację w drugą stronę. W moim przypadku dla ostatniego wyświetlanego położenia jedynki w PORTA znajduję się liczba 01000 (PORTA.4 nie biorę pod uwagę ze względu na występowanie tam taimera). Jak widac musimy znaleźć moment, w którym bit PORTA,3 jest ustawiony. Dokonujemy tego znaną już procedurą :
Btfss PORTA,3
Jeżeli PORTA,3 będzie ustawiony to program przeskoczy o dwa miejsca na przykład do goto prawo, a jeżeli będzie wyzerowany powróci do programu przesuwania w lewo.
Btfss PORTA,3
Goto lewo
Goto prawo
Nasz program powinien składać się z dwóch części. Pierwsza to podprogram prawo, a druga to podprogram lewo. W podprogramie prawo odczekujemy opóźnienie, przesuwamy w prawo, sprawdzamy czy osiągnęliśmy stan końcowy. Jeżeli osiągnęliśmy to idziemy do podprogramu prawo, a jeżeli nie wykonujemy kolejne kroki w podprogramie lewo. Podprogram prawo wygląda identycznie tyle, że przesuwamy w prawo, sprawdzenia dokonujemy dla ustawienie PORTA,0, a jeżeli będzie on ustawiony to idziemy do podprogramu lewo.
PS. W tym przypadku nie chodzi mi o podprogramy wywoływane komendą CALL, tylko zwykłe etykiety prawo, lewo, do których dostajemy się przez komendę GOTO.
Miejsce opóźnienia
Ważne jest, żeby procedura opóźnienia była na samym początku podprogramu. Mam nadzieję, że powód wydaję Ci się oczywisty. Po prostu dzięki niej możemy zobaczyć jak gdyby liczbę wpisaną do PORTA. Jako, że chcemy oglądać kolejne stany 00001, 00010, 00100, 01000, 00100 itd. Opóźnienie musi wystąpić już na samym początku gdy mamy wpisaną do rejestru PORTA jedynkę do najmłodszego bitu. Jeżeli najpierw dokonalibyśmy przesunięcia, a następnie dodali opóźnienie ta jedynka na najmłodszym bicie trwałaby tak krótko, że zamiast niej zobaczylibyśmy od razu stan 00010. Tak samo, gdy wykryjemy stan skrajny. W moim przypadku jest to PORTA,3 = 1 lub PORTA,0 = 1, musimy poczekać na wyświetlenie. Z tego względu opóźnienie umieszczamy przed, a nie po rotacji. Pewnie było to dla Ciebie oczywiste, ale zawsze warto się upewniać 😉 .
Zakończenie i przykładowy program
Dobrze by było gdybyś sam powalczył z napisaniem programu linijki LED. Najważniejsze fragment masz tutaj wklejone, ale wcale nie musisz z nich korzystać. W razie problemów dodaje program, który wykonałem. Następna lekcja to będzie omówienie przycisków. Zajmiemy się eliminacją drgań styków i dostosowaniem microswitchy do swoich potrzeb. Możliwe, że zdążymy również wzbogacić zaprogramowaną linijkę LED o obsługę przycisków. Do zobaczenia. Pamiętaj o komentarzu 😉 .