S. Jemioło B. Jakubiec
G. Kulig Ł. Król
D. Gorący K. Kubik P. Kurek
Klasa VgT
Ćwiczenie nr 14
TEMAT: Programowa realizacja transmisji.
Cel ćwiczenia:
Celem ćwiczenie jest transmisja portem szeregowym wykorzystując do sterownia portem program (a nie sterownik).
Wiadomości wstępne:
W poprzedniej lekcji przedstawiona była transmisja szeregowa z wykorzystaniem wbudowanego w mikrokontroler 8051 sterownika transmisji szeregowej. Po odpowiednim ustawieniu sterownika, transmisja sprowadzała się w praktyce do zapisu bądź odczytu bajtu z rejestru SBUF. Jednak nie zawsze programista zastaje tak komfortowe warunki. Czasami trzeba zorganizować dwa oddzielne łącza szeregowe, a większość mikrokontrolerów posiada tylko l sterownik transmisji szeregowej. Niektóre małe mikrokontrolery w ogóle nie posiadają, sterownika transmisji szeregowej. W takich przypadkach pozostają dwa wyjścia:
• dołączyć zewnętrzny sterownik transmisji szeregowej
• zorganizować programowe sterowanie transmisji.
Pierwsze rozwiązanie prowadzi do podniesienia kosztów systemu, poboru prądu, wielkości płytki drukowanej itp. Jeśli nie ma innych przeciwwskazań, to raczej należy wykorzystać drugie rozwiązanie. W systemie DSM-51 wbudowano dwa kanały transmisji szeregowej:
COM1 - obsługiwany przez sterownik transmisji szeregowej mikrokontrolera 8051, COM2 - obsługiwany programowo przez mikrokontroler.
W niniejszej lekcji omówiona jest programowa obsługa transmisji szeregowej prowadzonej przez kanał COM2.
Dane wyjściowe są wysyłane z mikrokontrolera poprzez linię P l.0 - stan na złączu jest bezpośrednim odwzorowaniem stanu tej linii. Linia ta nie jest podłączona bezpośrednio do złącza COM2, gdyż pomiędzy mikrokontrolerem a złączem musi istnieć układ dopasowania napięć. Mikrokontroler może wystawiać napięcia OV (stan 0) i 5V (stan l), natomiast transmisja szeregowa odbywa się na poziomie napięć +12V (stan 0) i -12V (stan l). Zadanie to wykonywane jest przez układ typu MAX 232.
Wysłanie bajtu polega na ustawianiu linii P l.0 zgodnie z kolejnymi bitami. Każdy bit powinien być wystawiony na linię Pl.0 na jednakowy czas, zgodny z przyjętą prędkością transmisji. Należy jeszcze pamiętać o wysłaniu na początku bitu startu, a na koniec bitów stopu.
PRZYKŁAD 14.1
NADAWANIE
T0_G EQU 0 ;GATE
T0_C EQU 0 ;COUNTER/-TIMER
T0_M EQU 2 ;MODE (0..3)
TIM0 EQU T0_M+T0_C*4+T0_G*8
T1_G EQU 0 ;GATE
T1_C EQU 0 ;COUNTER/-TIMER
T1_M EQU 0 ;MODE (0..3)
TIM1 EQU T1_M+T1_C*4+T1_G*8
TMOD_SET EQU TIM0+TIM1*16
BIT_TIME EQU 11059200/12/4800
T0_SET EQU 256-BIT_TIME
OUT EQU P1.0
LJMP START
ORG 0BH
PUSH PSW
PUSH ACC
DJNZ R2,NEXT ;koniec transmisji bajtu
SETB OUT ;bit stopu
CLR TR0 ;stop Timer 0
POP ACC
POP PSW
RETI
NEXT: ;kolejny bit transmisji
MOV A,R7
RRC A
MOV OUT,C ;bit na port
MOV R7,A
RETI
ORG 100H
START:
MOV TMOD,#TMOD_SET ;Timer 0 dla
MOV TH0,#T0_SET ;transmisji
MOV TL0,#T0_SET
SETB EA ;włącz przerwanie
SETB ET0 ;od Timera 0
LCALL LCD_CLR
LOOP:
LCALL WAIT_KEY
ADD A,#30H
MOV R7,A ;znak do nadania
MOV R2,#9 ;licznik bitów
CLR OUT ;bit startu
SETB TR0 ;start Timera 0
LCALL WRITE_DATA ;wyświetl na LCD
SJMP LOOP
Powyższy przykład przedstawia prosty sposób realizacji nadawania przez kanał szeregowy.
Podstawową sprawą, przy programowej realizacji transmisji szeregowej jest dokładne odliczanie czasu. Najwygodniej jest to zrealizować wykorzystując do tego celu timery. Ponieważ wszystkie kolejne odcinki czasu muszą być jednakowe, wykorzystano więc Timer 0 pracujący w trybie 2, czyli z automatycznym przeładowywaniem. Dzięki temu, kolejne przerwania od timera taktujące transmisję szeregową, przychodzą w równych odcinkach czasu, ustawianych w rejestrze TH0. Zatem właśnie od wartości wpisanej do tego rejestru zależy prędkość transmisji. Ponieważ timer liczy impulsy zegarowe mikrokontrolera podzielone przez 12, prędkość transmisji wyraża się wzorem:
V = (f„sc /12 ) / okres Timera O
Ponieważ w trybie 2 timer pracuje jako 8-bitowy, minimalna prędkość transmisji przy tych ustawieniach wynosi:
V = (11.059.200 /12 )/256 = 3600
Jeżeli potrzebna jest prędkość niższa, to należy wykorzystać 16-bitowy tryb timera, ale wtedy trzeba przy każdym przerwaniu pamiętać o ładowaniu wartości początkowych do timera.
Należy oczywiście wybierać jedną ze standardowych prędkości transmisji. W przykładzie przyjęto wartość 4800 bodów. Dla tej prędkości timer musi odliczyć: N = (l 1.059.200 /12 ) / 4800 = 192 okresy zegara
Ponieważ timer liczy w górę, więc do rejestru THO należy wpisać wartość: 256 - 192 = 64.
Transmisja bajtu rozpoczyna się od wysłania bitu startu. W tym celu należy ustawić P l.0 na 0 i włączyć timer, który odliczy długość tego bitu (właściwa wartość timera powinna być wpisana wcześniej).
Przy kolejnych przerwaniach od timera wysyłany bajt obracany jest o jeden bit w prawo, poprzez wskaźnik przeniesienia (rozkaz RRC A). Zgodnie z bitem we wskaźniku przeniesienia ustawiany jest stan linii Pl.0. W ten sposób kolejne bity sterują linią P l. O przez czas określony timerem.
Podobnie jak nadawanie, można zorganizować odbiór transmisji szeregowej. Dane wejściowe trafiają do systemu mikroprocesorowego (również poprzez układ MAX 232) jako sygnał IRS. Sygnał ten podłączony jest do sterownika przerwań. Jednak przy standardowej konfiguracji sterownika przerwań, jest on faktycznie bezpośrednio podłączony do wejścia INTO mikrokontrolera. Dzięki temu, dane przychodzące poprzez łącze szeregowe mogą zarówno generować przerwanie, jak i być bezpośrednio czytane przez mikrokontroler. W poniższym przykładzie przedstawiono sposób odbioru z kanału szeregowego.
PRZYKŁAD 14.2
ODBIÓR
T0_G EQU 0 ;GATE
T0_C EQU 0 ;COUNTER/-TIMER
T0_M EQU 2 ;MODE (0..3)
TIM0 EQU T0_M+T0_C*4+T0_G*8
T1_G EQU 0 ;GATE
T1_C EQU 0 ;COUNTER/-TIMER
T1_M EQU 0 ;MODE (0..3)
TIM1 EQU T1_M+T1_C*4+T1_G*8
TMOD_SET EQU TIM0+TIM1*16
BIT_TIME EQU 11059200/12/4800
T0_SET EQU 256-BIT_TIME
T0_STRT EQU 256-BIT_TIME/2
IN EQU INT0
LJMP START
SETB TR0 ;włącz Timer 0
CLR EX0 ;blokuj przerwanie INT0
RETI
PUSH PSW
PUSH ACC
DJNZ R2,NEXT ;odebrano cały bajt aktualnie trwa bit stopu
CLR TR0 ;wyłącz Timer 0
MOV TL0,#T0_STRT ;ustawienia dla kolejnej
MOV R2,#10 ;transmisji
MOV A,R7 ;odebrany bajt na LCD
LCALL WRITE_DATA
POP ACC
POP PSW
RETI
NEXT: ;kolejny bit transmisji
MOV C,IN ;pobierz bit
RRC A ;dopisz do poprzednich
RETI
ORG 100H
START:
LCALL LCD_CLR
MOV TMOD,#TMOD_SET ;Timer 0 dla
MOV TH0,#T0_SET ;transmisji
MOV TL0,#T0_STRT ;1/2 bitu startu
MOV R2,#10 ;licznik bitów
SETB EA ;włącz przerwania
SETB ET0 ;od Timera 0
SETB EX0 ;i z wejścia INT0
SJMP $
Odbiór z kanału szeregowego jest inicjowany przychodzącym bitem startu. Początek tego bitu powoduje wygenerowanie przerwania z wejścia INTO. Od tego momentu mikrokontroler powinien odczytywać stan tej linii w równych odstępach czasu. Nie potrzeba, aby zmiany na tym wejściu powodowały przerwanie. Tak więc przerwania z wejścia INTO są blokowane, natomiast uruchamiany jest timer.
Timer, tak jak w poprzednim przykładzie, pracuje w trybie 2. Przy kolejnych przerwaniach od timera, stan linii jest odczytywany do bitu C, a następnie poprzez obrót wpisywany jest do rejestru, w którym gromadzony jest odbierany bajt. W ten sposób po 8 kolejnych przerwaniach w rejestrze zgromadzony jest cały bajt. Następne przerwanie od timera powinno trafić już w bit stopu. Stan na linii powinien być już ustawiony na „l" i nie może się zmienić, aż do transmisji kolejnego bajtu. Można więc zatrzymać timer i odblokować przerwanie z wejścia INTO. Dzięki temu, bit startu kolejnego bajtu ponownie zainicjuje odbiór.
Prędkość transmisji nigdy nie jest idealnie ustawiona ani w nadajniku, ani w odbiorniku. Powstałe błędy mogą się kumulować przy odczycie kolejnych bitów. Dlatego też najbezpieczniej odczytywać wartość danego bitu w środku czasu jego trwania. Zatem pierwszy odliczany czas powinien odpowiadać długości nie jednego a półtora bitu (od początku bitu startu do połowy pierwszego bitu).
W przykładzie przy prędkości 4800 bodów należało odliczyć 192 x 1.5 = 288 impulsy zegarowe. Liczba ta jest większa od 256, więc należałoby zmienić tryb pracy time-ra. Aby tego uniknąć, zastosowano inne rozwiązanie. Najpierw odliczany jest czas równy połowie jednego bitu, czyli 192 x 0.5 = 96 impulsów zegarowych. Następnie, już w odstępach l bitu, odczytywanych jest kolejno 9 bitów. Pierwszy z nich jest bitem startu. Jednak przy zastosowanej metodzie składania bąjtu, bit startu zostaje wysunięty z rejestru docelowego przy odczycie ósmego bitu przesyłanego bąjtu. W ten sposób po zakończeniu odbioru w rejestrze jest złożony przesłany bajt.
Przy prędkości transmisji 4800, gdy jeden bit trwa 192 cykle maszynowe, można było to wszystko pominąć. Ale chcąc osiągnąć wyższe prędkości, należy te wszystkie dodatkowe czasy uwzględniać. Należy na przykład odpowiednio skorygować czas od początku bitu startu do momentu odczytu pierwszego bitu.
Aby osiągnąć bardzo wysokie prędkości transmisji, trzeba wybrać inną metodę. Odliczanie prędkości na timerze trzeba zastąpić odpowiednią liczbą wykonywanych rozkazów. Kolejny przykład ilustruje nadawanie szeregowe z prędkością 115200.
PRZYKŁAD 14.3
NADAWANIE
;Cykle/Bit = Fosc[Hz] /12 /V[bod] = 11059200 /12 /115200 = 8
OUT EQU P1.0
LJMP START
ORG 100H
START:
LCALL LCD_CLR
LOOP:
LCALL WAIT_KEY
CLR OUT ;początek bitu startu
ADD A,#30H ;1c znak do nadania
MOV R2,#9 ;1c licznik bitów
SETB C ;1c C=1 -> bit stopu
NEXT:
NOP ;1c
NOP ;1c
RRC A ;1c
MOV OUT,C ;2c kolejne bity
NOP ;1c
DJNZ R2,NEXT ;2c
LCALL WRITE_DATA ;wyświetl na LCD
SJMP LOOP
Jak można łatwo policzyć, przy prędkości 115200 na jeden bit transmisji przypada: N = ( 11.059.200 /12 ) /115200 = 8 cykli maszynowych.
Tak więc, co 8 cykli linia wyjściowa musi być ustawiona zgodnie z kolejnym bitem. Nie jest to dużo, ale w mikrokontrolerze 8051 można to bez kłopotu wykonać - trzeba jeszcze dokładać rozkazy NOP. Jeżeli jednak w programie wykorzystywane są przerwania, to na czas transmisji trzeba je bezwzględnie wyłączyć. Nawet najkrótsze przerwanie skutecznie zakłóci nadawanie. Analogicznie do nadawania można również odbierać z taką. samą prędkością.
PRZYKŁAD 14.4
ODBIÓR
;Cykle/Bit = Fosc[Hz] /12 /V[bod] = 11059200 /12 /115200 = 8
IN EQU INT0
LJMP START
ORG 03H
MOV R2,#8 ;1c
NOP ;1c
NOP ;1c
NOP ;1c
NEXT:
NOP ;1c
NOP ;1c
NOP ;1c
NOP ;1c
MOV C,IN ;1c kolejny bit
RRC A ;1c
DJNZ R2,NEXT ;2c
LCALL WRITE_DATA ;znak na LCD
RETI
ORG 100H
START:
LCALL LCD_CLR
SETB EA ;włącz przerwanie
SETB EX0 ;z wejścia INT0
SJMP $
Odbiór całego bajtu odbywa się wewnątrz przerwania. Ponieważ w programie głównym stale wykonywany jest rozkaz SJMP, wejście w program obsługi przerwania będzie trwało od 3 do 5 cykli maszynowych. Do obliczeń w programie przyjęto wartość średnią, czyli 4. Odczytanie pierwszego bitu powinno nastąpić po 12 cyklach od wystąpienia sygnału przerwania, czyli po ośmiu cyklach wewnątrz przerwania. Odczytanie kolejnych bitów wykonywane jest co osiem cykli maszynowych.
Tak jak przy nadawaniu, odbiór bajtu nie może być niczym przerwany. Jeżeli więc w programie wykorzystywane są inne przerwania, to przerwanie z wejścia INTO musi mieć najwyższy priorytet.
Przy tym sposobie transmisji nadawanie i odbiór nie mogą odbywać się jednocześnie. Jednak przy prawidłowo zorganizowanym protokole transmisji, sposób ten może być z powodzeniem wykorzystywany. Należy zauważyć, że osiągnięta prędkość 115200 jest wyższa niż prędkość osiągana przez sterownik transmisji szeregowej mikrokontrolera 8051, który pracuje w trybie l lub 3.
Wnioski:
Lekcja ta nauczyła jak sobie radzić gdy w programowanym przez nas mikrokontrolerze nie ma wbudowanego sterownika transmisji szeregowej. Najprościej poprzez napisanie odpowiedniego programu.