Timer do lampki

W pokoju córeczki, gdy idzie spać, zostawiamy małą lampeczkę włączoną. Potem, gdy nam się o niej przypomni, należy ją wyłączyć. Owo „gdy nam się o niej przypomni” trwa od godziny do 6 godzin 😉 Problem nie jest w poborze prądu, którego ta lampeczka pożera naprawdę niewiele, ale w tym, że jeśli się przebudzi w czasie, gdy lampka wciąż będzie się świecić, to albo się rozbudza, albo zabrania jej gasić – na kolejny okres czasu. Gdy się przebudzi przy zgaszonej już lampce – nie ma problemu. Dlatego też postanowiłem zbudować małego pomocnika w słusznej sprawie: timer dla urządzeń zasilanych z sieci 230V.

Schemat elektryczny tego urządzenia jest zwyczajnie banalny – ot, standardowe połączenie multipleksowanych dwóch cyfr 7-segmentowego wyświetlacza LED do mikrokontrolera PIC16F628A. Jako interfejs ustawiania zadanego czasu, można było zastosować dwa przyciski, ale ja u siebie wstawiłem enkoder obrotowy, który w obsłudze końcowej jest nieporównywalnie przyjemniejszy od przycisków – zwłaszcza, gdy przyjdzie nam ustawić czas rzędu np. 90 minut 😉 Zastosowanie enkodera pociąga za sobą zmiany w programie, gdyż działa on tak, że za pomocą dwu-bitowego kodu Graya odczytujemy stan urządzenia – a stany mogą być trzy: w lewo, w prawo i nieokreślony. Dlatego też oprogramowanie wewnętrzne mikrokontrolera nie będzie niestety pasować do zwykłych przycisków.

Modułem wykonawczym może być dowolna realizacja… może to być przekaźnik z cewką 5V, może być z własnym zasilaniem (np. 12V), może też to być zestaw optotriak-triak. Tę ostatnią opcję wybrałem dla swojej realizacji, jako, że z powodu swojego charakteru pasuje tutaj najbardziej do projektu. Poniżej możecie zobaczyć schematy pokazujące, jak zrealizować takie moduły wykonawcze.

Wsad do mikrokontrolera można pobrać tutaj. W razie jakichkolwiek problemów, czy to ze schematem, czy z oprogramowaniem – pytać 🙂 Jeżeli macie jakieś pomysły na usprawnienie urządzonka – pisać. Miłego odliczania czasu!

Facebooktwittergoogle_plusredditpinterestlinkedinmail
twitterlinkedin

PIC16F – Realizacja software’owego buforu odbioru USART

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.

Facebooktwittergoogle_plusredditpinterestlinkedinmail
twitterlinkedin