UwagaZamiast odtwarzać obrazki które znikły, stworzyłem animacje węża
http://jaktodziala.eu/To bardziej przemawia do intuicji. Polecam. Prawie nie wymaga objaśnień
Rozdział 5.8.2 o buforze cyklicznym w niebieskiej książce należy do trudniejszych. Bo czego tu nie ma? Przerwania, bufory cykliczne, bufory UDR... Mirek nieprzypadkowo bardzo poważnie podszedł do tematu. Prawie każda instrukcja została tu bardzo dokładnie opisana. Naprawdę opłaca się to dokładnie przetrawić. Jak wąż zresztą.
Do wyobrażenia sobie tych pełzających gadów pomogły mi odręczne rysunki. Może komuś się przydadzą? Przy okazji przypomniałem sobie Cada i nauczyłem się wklejać rysunki przy pomocy imageshock'a. Długo do niego się przymierzałem, ale nie żałuję. Polecam.
Zobaczymy narodziny węża, jego życie i śmierć. Wąż rośnie w prawą stronę o jeden znak, gdy bufor jest pośrednio "napełniany" przez urządzenie zewnętrzne. Wąż skraca się , gdy program główny czyta kolejne znaki z ogona ("najstarsze"). Opis dotyczy tylko bufora cyklicznego odbiorczego tj. str. 268...272. Jak będzie zainteresowanie to napiszę coś podobnego o buforze cyklicznym nadawczym str. 272...275?
Uwaga. Jestem początkujący. Mogą być babole!Tak czy owak, czytasz na własną odpowiedzialność.
Bufor cykliczny odbiorczy w stanie początkowym Są to 32 kolejne bajty w pamięci RAM. Uwaga!
Bajty, nie bity jak sugeruje rysunek. Choć niektórzy mówią, że wąż składa się tylko z ogona, to ma także głowę. Na rysunku nie ma jeszcze węża . Ściślej jest to wąż wirtualny o długości zero, w którym głowa jest jednocześnie ogonem. W tym miejscu narodzi się wąż. Czyli coś o życiu prenatalnym.
volatile char UART_RxBuf - Bufor cykliczny odbiorczy zawierający kolejne bajty 0...31
volatile uint8_t UART_RxHead - "głowa węża" - zmienna wskazująca na ostatni wpisany znak
volatile uint8_t UART_RxTail - "ogon węża" - zmienna wskazująca na "najwcześniejszy, czyli najstarszy" wpisany znak. Ściślej-na bajt przed tym najstarszym.
Co z tego wynika? - Po starcie programu bufor jest wypełniony zerami - bo zmienna jest typu volatile
- Ogon i głowa po starcie są bajcie nr 0 - bo UART_RxHead i UART_RxTail też są typu volatile
- Nic się nie dzieje dopóki nie przyjdzie przerwanie ISR(USART_RXC_vect)
- Na pierwszy rzut oka wygląda to na rejestr przesuwny cykliczny. Nie jest on jednak przesuwny. Tzn. jeżeli w bajcie nr 23 był znak 'G' to on tam będzie do końca życia węża. To jego "pełzanie" wynika z tego, że nowy znak wpisywany jest przed poprzednim, a stary znak w ogonie może być jest kasowany.
- Z czego wynika "cykliczność"? Gdy ogon lub głowa mają wartość 31 to po dodaniu 1 następną wartością będzie 0. Zapewnia to maska opisana w p (6) na str. 270. A gdyby nie było maski? Też byłby cykliczny, ale o długości 256 bajtów. Ciut za dużo.
A teraz proszę Państwa przychodzi przerwanie ISR(USART_RXC_vect) Co było przyczyną pojawienia się znaku 'R'?
Np. jakiś inny ATMEL 644p w sąsiednim pokoju poprzez swoje wyjście Tx wysłał znak 'R' co spowoduje:
- Po 2 kabelkach poleci 8 bitów kodu znaku 'R', chyba "01010010" + opakowanie czyli bity sterujące. Szczegóły tego przesyłu patrz -->Forum/Poradniki/Podstawy RS232C.
- Bity te wpadają do wejścia Rx UARTU naszego ATMELA.
- Gdy wszystkie bity "wpadną" to zostaną zapisane w rejestrze odbiorczym UDR należącego do UART-u. Jak to się dzieje, to sprawa konstruktorów ATMEL-a. Biorą tam udział jakieś rejestry przesuwne i inne wichajstery. Nazywa się to mądrze "zamiana kodu szeregowego na równoległy". Jest to robota czystego hardaware'u. Czyli jest zupełnie
- Pojawienie się znaku 'R' w UDR spowoduje przerwanie ISR(USART_RXC_vect) i wpisanie 'R' do bajtu nr 1 naszego buforu cyklicznego.
A teraz najważniejsze! Proszę zauważyć, że od początku przesyłu, aż do pojawienia 'R' w UDR nasz procek wykonuje jakiś program, zupełnie niezwiązany z transmisją RS232C! Mało tego. On nawet nie wie, że jest jakaś transmisja! . Przy prędkości 9600 baudów przesył trwa ok 1 ms W tym czasie program procesora wykonuje np. 1000 instrukcji (Co prawda assemblerowych , instrukcji C będzie mniej, może być 100...200 . Nie wchodźmy w szczegóły).
Przychodzi następne przerwanie i w buforze cyklicznym pojawi się znak'O'W końcu ostatnie przerwanie i w buforze cyklicznym pojawi się znak 'K'I co my widziem proszę wycieczki?
- To co wysłał procek w sąsiednim pokoju pojawiło się w UART_RxBuf - buforze cykliczny odbiorczym
- Chociaż sam przesył tekstu "ROK" trwał nie mniej niż 3 ms (czyli baaardzo dłuuugo) to w minimalnym stopniu wpłynęło na program główny.
Teraz nasz program będzie czytał bufor cykliczny odbiorczy przy pomocy funkcji uart_getc()? Zauważ, że nic nie musi wiedzieć o transmisji, bitach... Dla niego jest to łatwizna jak czytanie zwykłej zmiennej. Dla uproszczenia zakładam, że z "sąsiedniego pokoju" nie przychodzą do UART-u nowe znaki. Czyli nie ma przerwań ISR(...)
Przed pierwszą funkcją uart_getc() w buforze jest oczywiście "ROK" (tak jak na poprzednim rysynku)
Bufor po wykonaniu pierwszej funkcji uart_getc()Bufor po wykonaniu drugiej funkcji uart_getc()Bufor po wykonaniu trzeciej funkcji uart_getc()Widzimy że ogon=głowa czyli bufor jest pusty. Nastąpiła śmierć węża. Ale nie martwmy się. Następne przerwania urodzą tu nowego węża!
WNIOSKI1. Nowy wąż rodzi się w miejscu śmierci starego.
2. Przerwanie, czyli odbiór nowego znaku powoduje przyrost węża w prawo.
3. Odczyt przez program powoduje skracanie węża z lewej strony.
4. Śmierć węża następuje wtedy gdy ogon = głowa (wszystkie znaki w buforze są odebrane przy pomocy uart_getc()-->bufor pusty)
5. Nowy wąż może pojawić się w dowolnym miejscu bufora.
6. Gdybyśmy próbowali wczytać 32 znaki, to "ogon = głowa". To oznacza, że bufor jest pusty, co jest nieprawdą. Stąd maksymalna liczba znaków to 31. Nie mówiąc o tym że 33 i więcej znaków skasuje starą zawartość.
7. Nie poruszałem tego, ale wpisywanie nowego znaku przez przerwanie ISR(...) i odczyt przez uart_getc() mogą się przeplatać. Analizę pozostawiam czytelnikowi.