Aplikacje zestawu Freescale KwikStik K40: obsługa UART
Chcąc otrzymać baudrate równy 9600 przy zegarze 25 MHz (taki jest domyślnie w MK40X256) musimy obliczyć (25000000/16)/9600, otrzymujemy 162,7604; czyli SBR=162 a najbliższa dostępna wartość BRFD to 0,75; czyli BRFA=11000=0x18.
Pozostała jeszcze konfiguracja ramki danych (8 bitów danych, brak bitu parzystości) oraz odblokowanie nadajnika i odbiornika UART, w tym celu w rejestrze UART5_C1 ustawiamy bity M=1 (8 bitów danych) i PE=0 (brak bitu parzystości) oraz w rejestrze UART5_C2 bity RIE=1 (odblokowanie przerwania odbiornika), TE=1 (odblokowanie nadajnika) i RE=1 (odblokowanie odbiornika).
Interfejs UART5 jest już gotowy do pracy, pozostaje jeszcze odblokowanie przerwania w kontrolerze przerwań NVIC (Nested Vectored Interrupt Controller). Żeby to zrobić musimy ustawić odpowiedni bit jednego z rejestrów ISER, w których każdy kolejny bit dotyczy jednego przerwania. W celu określenia numeru rejestru i bitu najlepiej jest sięgnąć do Reference Manuala, w tabeli 3-4 możemy odczytać numer przerwania (kolumna IRQ), dla naszego przerwania numer to 55. Ponieważ rejestry ISER są 32-bitowe i numerowane od 0 obliczenia wyglądają następująco
Numer rejestru ISER = 55 div 32 = 1
Numer bitu w rejestrze ISER = 55 mod 32 = 23
Czyli zapisujemy jedynkę w bicie 23 rejestru ISER1.
Nadawanie danych przez UART5 polega na zapisie bajtu do rejestru UART5->D, wcześniej jednak musimy poczekać aż ewentualna wcześniejsza transmisja została już zakończona, czyli czekamy aż bit TC (Transit Complete Flag) rejestru UART5_S1 będzie miał wartość 1, tę operację wykonuje w naszym przykładzie funkcja UART5SendString.
void UART5SendString(char * buffer) { while(*buffer != 0) { while (!(UART5->S1 & UART_S1_TC_MASK)); UART5->D = *(buffer++); } }
Odbiorem danych zajmuje się funkcja UART5_RX_TX_IRQHandler. Głównym zadaniem funkcji jest zapalanie/gaszenie odpowiedniej diody w zależności od odebranych danych, ale jest tam wykonana jeszcze jedna bardzo ważna operacja, mianowicie odczyt rejestru UART5_S1. Z pozoru nie ma on sensu, jednak jest konieczny, ponieważ odczyt rejestru UART_S1 a potem UART5_D powoduje wyzerowanie flagi wywołanego przerwania.
void UART5_RX_TX_IRQHandler() { char inData; UART5->S1; inData = UART5->D; switch (inData) { case '4': PTA->PTOR |= (1 << 14); break; case '5': PTA->PTOR |= (1 << 15); break; case '6': PTA->PTOR |= (1 << 16); break; case '7': PTA->PTOR |= (1 << 17); break; } }
W innym przypadku po odebraniu pierwszego bajtu funkcja byłaby wywoływana bez przerwy, ponieważ kontroler przerwań „nie wiedziałby”, że przerwanie zostało już obsłużone.