MODUŁ PROGRAMATORA |
Rys1.1.
Schemat modułu programatora
Rozpocznijmy omawianie układu od serca, czyli mikrokontrolera AT89C51 (U1) on bowiem nadzoruje pracę całego urządzenia. W wewnętrznej pamięci FLASH procesora znajduje się program zarządzający klawiaturą, wyświetlaczami i zewnętrzną szeregową pamięcią EEPROM. Komunikacja z użytkownikiem odbywa się głównie za pomocą klawiatury i wyświetlaczy. Kod źródłowy znajduje się tutaj. Wszelkie opisy programu mają postać komentarzy i zawarte są w pliku źródłowym. W dodatku C znajduje się pełna dokumentacja mikrokontrolera. Bezpośrednio do portu P0 i bitów P2.6 i P2.7 podłączona jest magistrala danych urządzenia - przez nią wymieniane są dane między modułami programatora i wykonawczym. Magistralę fizycznie stanowi plastykowa tasiemka (FC-16) dostarczająca jednocześnie stabilizowane napięcie 5V dla programatora. Układ wyposażony jest w 16 przyciskową klawiaturę przeglądaną sekwencyjnie. Rozwiązanie to zostało wybrane ze względu na ograniczoną ilość portów zastosowanego mikrokontrolera, oraz łatwość obsługi. Sekwencyjne działanie klawiatury najlepiej będzie przedstawić na rysunku. ![]() Rys.1.2.
Klawiatura przeglądana sekwencyjnie
Jak widać, w każdym rzędzie i w każdej kolumnie znajdują się po 4 przyciski, a więc łączna ich ilość daje liczbę 16 (4*4). Jest to rozwiązanie bardzo ergonomiczne, ponieważ zaoszczędzamy aż 12 linii portów I/O, w przypadku gdybyśmy chcieli podłączyć każdy guzik pojedynczo. W razie potrzeby zastosowania klawiatury 20-klawiszowej, wystarczyłoby dodać jeden rząd (lub kolumnę) przycisków... Załóżmy, że na bit 0 portu 1 (P1.0) wystawiamy wartość logiczną 0. Odczytując stan bitu P1.4 możemy sprawdzić czy guzik SW4 jest wciśnięty - jeśli jest wciśnięty stan 0 z bitu P1.0 zostanie "przeniesiony" na bit P1.4 poprzez zwarcie przyciskiem. Jeśli natomiast SW4 nie będzie wciśnięty, to na P1.4 będzie stan wysoki - wymuszony rezystorem R15. Program obsługi klawiatury wykonuje odpowiednią pętlę, która najpierw zeruje bit P1.0, po czym sprawdza stan linii P1.4, P1.5, P1.6, P1.7 - jeśli na żadnej z nich nie będzie niskiego poziomu, ustawia bit P1.0 a zeruje P1.1 i znów sprawdza P1.4, .., P1.7, czynność powtarza. Jeśli któryś z guzików zostanie naciśnięty, procedura wpisze jego numer do odpowiedniej komórki pamięci. Jeśli procedura wyzeruje P1.3 lecz na liniach P1.4, .., P1.7 nie będzie stanu niskiego, znaczy to tyle, że żaden guzik nie został naciśnięty - wówczas ustawia P1.3 w stan wysoki i w zależności od potrzeby albo rozpoczyna swe działanie od początku, albo w odpowiedniej komórce umieszcza jakąś umowną wartość (na przykład 0). Nasz program zawiera dwie procedury obsługi klawiatury. Pierwsza sprawdza stan klawiatury i umieszcza numer wciśniętego guzika w odpowiedniej komórce pamięci. Jeśli żaden przycisk nie jest wciśnięty funkcja zwraca wartość zero. Takie rozwiązanie jest bardzo przydatne, gdy chcemy tylko sprawdzić, który / czy guzik jest wciśnięty. KEY_X1
EQU P1.0
KEY_X2 EQU P1.1 KEY_X3 EQU P1.2 KEY_X4 EQU P1.3 KEY_Y1 EQU P1.4 KEY_Y2 EQU P1.5 KEY_Y3 EQU P1.6 KEY_Y4 EQU P1.7 KEY_NUMBER EQU 30H GET_KEY: PUSH ACC MOV A,#1 MOV P1,#11111111B CLR KEY_X1 LCALL GET_KEY_GET SETB KEY_X1 CLR KEY_X2 LCALL GET_KEY_GET SETB KEY_X2 CLR KEY_X3 LCALL GET_KEY_GET SETB KEY_X3 CLR KEY_X4 LCALL GET_KEY_GET SETB KEY_X4 GET_KEY_CHECK: MOV A,KEY_NUMBER CJNE A,#17,GET_KEY_END MOV KEY_NUMBER,#0 GET_KEY_END: POP ACC RET GET_KEY_GET: JNB KEY_Y1,GET_KEY_GET_END_KEY INC A JNB KEY_Y2,GET_KEY_GET_END_KEY INC A JNB KEY_Y3,GET_KEY_GET_END_KEY INC A JNB KEY_Y4,GET_KEY_GET_END_KEY INC A RET GET_KEY_GET_END_KEY: MOV KEY_NUMBER,ACC RET Druga funkcja, zbudowana przy użyciu pierwszej, czeka na naciśnięcie guzika i dopiero wtedy powraca z wywołania. WAIT_FOR_KEY:
PUSH ACC WAIT_FOR_KEY_LOOP: LCALL GET_KEY MOV A,KEY_NUMBER CJNE A,#0,WAIT_FOR_KEY_END LJMP WAIT_FOR_KEY_LOOP WAIT_FOR_KEY_END: POP ACC RET ![]() Rys.1.3.
Wyświetlacz multipleksowany
Detonator wyposażony jest w czterocyfrowy cyfrowy wyświetlacz numeryczny LED. Składa się on z czterech pojedyńczych wyświetlaczy siedmiosegmentowych (W1..W4) ze wspólną anodą. Jako dekoder BCD na 7 segmentów użyty został układ scalony 7447 (U3). Ponieważ dekoder ten potrafi obsłużyć tylko jeden wyświetlacz, konieczne było zastosowanie 4 tranzystorów i trybu multipleksowania. Wyświetlacz multipleksowany może składać się z wielu pojedyńczych wyświetlaczy. Jeśli stosujemy wyświetlacze 7. segmentowe, to wszystkie mają równolegle podłączone segmenty a...g i dp (kropka). Takie rozwiązanie powoduje, że zapalenie segmentu a na pierwszym spowoduje zapalnie tegoż segmentu na wszystkich pozostałych. Osobno jednak sterowane są anody poszczególnych "cyfr" - co daje możliwość wyboru / uaktywnienia tylko wybranych wyświetlaczy. Cała sekwencyjność polega na tym, że najpierw ustala się które segmenty mają świecić, później włącza się odpowiedni wyświetlacz... najczęściej jest to robione po kolei / sekwencyjnie dla każdego wyświetlacza, i powtarzane bez przerwy - stąd nazwa. Kolejne włączanie i wyłączanie poszczególnych "cyfr" potocznie nazywane jest przemiataniem czy też odświeżaniem. Jeśli odstęp czasu pomiędzy zgaszeniem jednego wyświetlacza a włączeniem następnego jest wystarczająco mały (odświeżanie jest szybkie / duże), wówczas bezwładność oka ludzkiego sprawi, że obraz wszystkich cyfr złoży się w jeden. Procedura obsługi wyświetlacza wysyła do układu 7447 (U) informacje, jaki znak ma być wyświetlony, po czym włącza pierwszą cyfrę wyświetlacza. Po odczekaniu określonego czasu "pozycja" pierwsza jest gaszona, a do układu 7447 trafia informacja o znaku dla drugiej "pozycji", po czym włączana jest cyfra druga wyświetlacza itd... Po zgaszeniu "pozycji" czwartej wyświetlana jest od nowa "pozycja" pierwsza. W detonatorze wyświetlanie odbywa się w przerwaniu timera T0. Na początku ustawiamy odpowienie parametry timera i systemu przerwań. LED_W1
EQU P3.7
LED_W2 EQU P3.6 LED_W3 EQU P3.5 LED_W4 EQU P3.4 LED_DIGIT1 EQU 38H LED_DIGIT2 EQU 39H LED_DIGIT3 EQU 3AH LED_DIGIT4 EQU 3BH TMOD_SET EQU 00000001B MOV TMOD,#TMOD_SET ; tryb 1 T0 - licznik impulsów MOV TL0,#0 ; wartości początkowe MOV TH0,#0 ; rejstrów licznika SETB EA ; ogólne zezwolenie na przerwania SETB ET0 ; zezwolenie na przerwanie T0 Obsługa przerwania T0 odbywa się pod adresem 0BH, tam następuje skok do odpowiedniej procedury:
ORG 0BH
LJMP WRITE_LED WRITE_LED: PUSH ACC CLR TR0 MOV ACC,#11110000B WRITE_LED_1: CJNE R7,#1,WRITE_LED_2 ORL LED_DIGIT1,A MOV P3,LED_DIGIT1 CLR LED_W1 LJMP WRITE_LED_END WRITE_LED_2: CJNE R7,#2,WRITE_LED_3 ORL LED_DIGIT2,A MOV P3,LED_DIGIT2 CLR LED_W2 LJMP WRITE_LED_END WRITE_LED_3: CJNE R7,#3,WRITE_LED_4 ORL LED_DIGIT3,A MOV P3,LED_DIGIT3 CLR LED_W3 LJMP WRITE_LED_END WRITE_LED_4: CJNE R7,#4,WRITE_LED_SET0 ORL LED_DIGIT4,A MOV P3,LED_DIGIT4 CLR LED_W4 LJMP WRITE_LED_END WRITE_LED_SET0: MOV R7,#0 WRITE_LED_END: INC R7 POP ACC MOV TL0,#100 MOV TH0,#225 SETB TR0 RETI Jak widać, procedura za każdym razem wyświetla kolejną cyfrę - najpierw pierwszą, później drugą, trzecią, czwartą i od nowa. Wartości wyświetlane przechowywane są w komórkach wewnętrznej pamięci RAM, dla ułatwienia nazwanych LED_DIGIT1..LED_DIGIT4. Na LED wyświetlane są zawsze dwie liczby dwucyfrowe - krok i opóźnienie. Procedura rozbija te liczby na cyfry i ładuje je do komórek LED_DIGIT1..LED_DIGIT4: LED_PRINT_STEP_AND_DELAY:
PUSH ACC MOV A,CURRENT_STEP MOV B,#10 DIV AB MOV LED_DIGIT4,A MOV LED_DIGIT3,B MOV A,CURRENT_DELAY MOV B,#10 DIV AB MOV LED_DIGIT2,A MOV LED_DIGIT1,B POP ACC RET Włączenie wyświetlania odbywa się przez włączenie timera T0: SETB
TR0
Wyłączenie wyświetlania odbywa się po zatrzymaniu timera T0:CLR
TR0
Szeregowa pamięć EEPROM serii 24Cxx (U2), w jaką zostało wyposażone urządzenie, pozwala na zapisanie stukrokowej sekwencji wyjściowej. Oczywiście typ zastosowanej pamięci zwalnia użytkownika z obowiązku bateryjnego podtrzymania jej zawartości. Pamięć ta podzielona jest przez producenta na "strony". Program urządzenia wykorzystuje ten podział przechowując w pierwszej (strona 0) czas opóźnienia do następnego kroku, zaś w drugiej (strona 1) stan zacisków wyjściowych. Przechowywana w pamięci wartość opóźnienia podczas odtwarzania sekwencji jest mnożona przez 100msek, zatem użytkownik ustawia opóźnienie w setnych częściach sekundy. Zarówno zastosowana pamięć, jak i mikrokontroler są ośmiobitowe, dlatego też strona 1 przechowuje każdą sekwencję wyjściową w dwóch bajtach (dwa bajty po 8 bitów każdy). Widać zatem przyczynę podziału logicznego wyjścia na dwie sekcje. Wydawać by się mogło, że jest to wada. Tak jednak nie jest - gdybyśmy chcieli w przyszłości rozbudować urządzenie o dodatkowe wyjścia, wystarczy dodać sekcje reprezentowane przez jedną linię I/O mikrokontrolera każda, nie zaś całe 8 bitów, jak by to było w przypadku pojedynczych wyjść... Bez modyfikacji oprogramowania jako zamiennik można zastosować pamięć 24C04, 24C08 czy 24C16, nie mniejsze, ponieważ tylko te pamięci posiadają odpowiedni podział na strony (mają ich dwie lub więcej). Kompletna dokumentacja układów znajduje się z dodatku D. Program urządzenia zwiera kilka procedur obsługujących szeregową pamięć EEPROM: ;
deklaracja stałych i zmiennych
I2C_MEMORY_SDA EQU P2.4 I2C_MEMORY_SCL EQU P2.3 I2C_MEMORY_ADDR EQU 31H I2C_MEMORY_PAGE EQU 32H I2C_READ EQU 33H I2C_FAIL EQU 34H I2C_FAIL_COUNT EQU 50 I2C_BYTE_COUNT EQU 35H I2C_MEMORY_CHIP_ADDR EQU 0H I2C_MEMORY_DATA EQU 36H I2C_MEMORY_DATA_ADDR EQU 37H Odczytuje bajt z aktualnego adresu w pamięci I2C_MEMORY_READ_BYTE
zwraca wartość w: I2C_MEMORY_DATAOdczytuje bajt spod wskazanego adresu w pamięci: I2C_MEMORY_ADDRESS_READ_BYTE
należy podać adres w:
I2C_MEMORY_DATA_ADDRnależy podać stronę w: I2C_MEMORY_PAGE zwraca wartość w: I2C_MEMORY_DATA Zapisuje bajt pod wskazany adres: I2C_MEMORY_WRITE_BYTE
należy podać adres w:
I2C_MEMORY_DATA_ADDRnależy podać stronę w: I2C_MEMORY_PAGE należy podać daną w: I2C_MEMORY_DATA Zapisuje stronę danych: I2C_MEMORY_PAGE_WRITE_FIRST
należy podać adres w:
I2C_MEMORY_DATA_ADDRnależy podać stronę w: I2C_MEMORY_PAGE należy podać pierwszą daną w: I2C_MEMORY_DATA zaraz po czym należy wywoływać funkcję: I2C_MEMORY_PAGE_WRITE_NEXT
należy podać następne dane w: I2C_MEMORY_DATAkoniec zapisu do pamięci należy zakończyć funkcją: I2C_MEMORY_PAGE_WRITE_END
Diody LED w znacznym stopniu ułatwiają programowanie urządzenia odzwierciedlając stan zacisków wyjściowych. Świecenie jednej z ośmiu diód ("1"-"8") oznacza aktywność odpowiedniego wyjścia sekcji wskazanej przez diody "A" lub "B". Wyjście jest aktywne, gdy na zapalnik przekazane jest napięcie zdolne odpalić ładunek. UWAGA!
Oczywiście podczas programowania sygnały z "diód"
nie są przekazywane do modułu wykonawczego - są jedynie pomocą przy
wizualizacji sekwencji wyjściowej. Faktem jest jednak, że diody te
bezpośrednio odzwierciedlają stan portu P0, a zatem i magistralę między
programatorem a modułem wykonawczym. Przypadkowy impuls ujemny na linii
zegarowej jednego z zatrzasków mógłby uaktywnić wyjścia. Dlatego też
układ powinien być wyłączony do momenty, gdy w pobliżu ładunków nie
będzie znajdować się żadna osoba.Ostatnim elementem informacyjnym modułu programatora jest buzzer piszczyk. Służy on do akustycznej komunikacji z użytkownikiem oraz sygnalizacji stanu pracy urządzenia. |
Wskazówki dotyczące materiałów pirotechnicznych |
Urządzenie na zaciskach wyjściowych w momencie aktywacji wystawia napięcie 12V. Pozwala to na zastosowanie zwykłej żarówki jako zapalnika. Najlepsze do tego celu są miniaturowe żaróweczki do podświetlania paneli w radiach samochodowych (zwykle na napięcia 3..12V). Aby spreparować zapalnik należy delikatnie stłuc bańkę żarówki nie naruszając żarnika. ![]() Taki zapalnik jest od razu gotowy do użycia - należy wcisnąć go do ładunku wybuchowego (oczywiście bardzo delikatnie, aby nie naruszyć żarnika). Jeśli stosujemy petardy zakupione w sklepie, zapalnik umieszczamy w miejscu pozostałym po "pierwotnym elemencie zapłonowym" (najczęściej uprzednio usuniętym loncie czy drasce). Zwrócić uwagę należy na budowę "standardowych" petard, które to składają się z ładunku inicjującego (najczęściej prochu) oraz właściwego ładunku wybychowego. Taka konstrucja wprowadza nieprzewidywalne opóźnienie detonacji w granicach ok 2..5 sekund. Fakt ten należy wziąć pod uwagę opracowując sekwencje wybuchów. ![]() Jeśli używamy ładunków własnej konstrukcji pamiętać należy, że im bardziej wytrzymała i szczelna obudowa, tym lepszy efekt pirotechniczny. Najlepiej gdy używamy ładunków złożonych z jednej substancji, o niskiej temperaturze zapłonu (wystarczająco niskiej na odpalenie żażącym włóknem żarówki, lecz nie nazbyt niskiej ze względów bezpieczeństwa). Jeśli potrzbujemy odpalić ładunek posiadający lont, możemy to zrobić w następujący sposób: ![]() |