Pracowałem ostatnimi dniami nad małym kontrolerkiem, sterowanym przez RS232. Obsługa niektórych poleceń, wydawanych do niego, trwała nawet po kilka milisekund i… okazało się, że użyty przeze mnie 16F628A ma bufor wejściowy USARTa rozmiaru… 2 bajtów. Tak, to nie pomyłka 😐 Dlatego postanowiłem napisać obsługę cyklicznego bufora wejściowego – o rozmiarze wg uznania 🙂 Poniżej przedstawiam wam, jak coś takiego zrealizować. Na początku, zmienne globalne:
#define RX_BUFOR_MAX 32 unsigned char buforRX[RX_BUFOR_MAX]; unsigned char *buforRX_head, *buforRX_end, *RXreadstart, RXbajt;
i podczas inicjalizacji programu:
// ustawiamy bufor odbioru danych z UARTa buforRX_head = buforRX; buforRX_end = buforRX + RX_BUFOR_MAX; RXreadstart = buforRX;
Tyle przygotowań. Proces odbioru danych i składowanie ich w cyklicznym buforze zrealizujemy w przerwaniu. Najpierw odpalamy przerwanie:
STATUS.RP0 = 1; PIE1.RCIE = 1; // przerwanie odbioru danych z UARTa STATUS.RP0 = 0; PIR1 = 0; INTCON.GIE = 1; INTCON.PEIE = 1;
I definiujemy obsługę:
void interrupt(void) { // przyszedł znak z UARTa if (PIR1.RCIF) { // cykliczny bufor z użyciem "indirect addressing" asm { movf RCREG,W movwf _RXbajt movf _buforRX_head, W movwf FSR movf _RXbajt, W movwf INDF incf _buforRX_head, f } if (buforRX_head == buforRX_end) // koniec buforu, buforRX_head = buforRX; // zawijamy ogon. PIR1.RCIF = 0; // koniec przerwania } }
Pozostało nam napisanie funkcji korzystających z owego bufora. Wpierw funkcja badająca, czy w buforze czeka na nas jakiś nieprzetworzony znak:
// czy w cyklicznym buforze czekają dane do odczytania? unsigned char BUFRS_Data_Ready() { if (RXreadstart == buforRX_head) return 0; else return 1; }
No i funkcja odczytująca kolejny znak:
// odczyt znaku z cyklicznego buforu unsigned char BUFRS_Read() { unsigned char bajt; asm { movf _RXreadstart, W movwf FSR movf INDF, W movwf BUFRS_Read_bajt_L0 incf _RXreadstart, f } if (RXreadstart == buforRX_end) RXreadstart = buforRX; return bajt; }
Na koniec przedstawię jeszcze moją małą funkcję odczytującą znak z określonym timeoutem operacji:
void BUFRS_Read_Timeout(unsigned char *bajt, unsigned char timeout) { unsigned char tout, read; tout = 0; read = 1; *bajt = 0; while ((read == 1) && (tout < timeout)) { if (BUFRS_Data_Ready() > 0) { *bajt = BUFRS_Read(); read = 0; } else tout++; } }
To tyle. U mnie – jak już pisałem, obsługa niektórych znaków zajmuje kilka milisekund, niektórych kilka mikrosekund – całość działa poprawnie przy 19200 (kwarc 20MHz). Oczywiście, powyższe działa tylko na mikrokontrolerach wyposażonych w sprzętowy moduł USART. Powodzenia.