Elektroda.pl
Elektroda.pl
X
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

[PIC][16F] Realizacja software'owego buforu odbioru USART

utak3r 21 Maj 2010 20:31 1246 2
  • #1 21 Maj 2010 20:31
    utak3r
    Poziom 25  

    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:

    Code:

    #define RX_BUFOR_MAX        32
    unsigned char buforRX[RX_BUFOR_MAX];
    unsigned char *buforRX_head, *buforRX_end, *RXreadstart, RXbajt;


    i podczas inicjalizacji programu:
    Code:

        // 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:
    Code:

       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ę:
    Code:

    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:




    Code:

    // 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:
    Code:

    // 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:
    Code:

    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).

    Powodzenia.

    0 2
  • #2 22 Maj 2010 00:24
    blue_17
    Poziom 32  

    Czy taki bufor posiada tylko ten procesor z tej rodziny czy wszystkie :?:

    0
  • #3 22 Maj 2010 01:08
    utak3r
    Poziom 25  

    Hm, na pewno 16f6xx i 16f87x mają taki "bufor"... co do reszty, jeszcze nie sprawdzałem, ale podejrzewam, że dopiero w 18fxxx dali większy.

    0