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.

Zegar na zewn. kw.+przyciski [Atmega32]+LCD w C (AVRStudio)

czumi 03 Gru 2008 23:34 1634 1
  • #1 03 Gru 2008 23:34
    czumi
    Poziom 1  

    Witam
    Mam problem z zegarem na lcd. Wyświetlacz mi działa. Działa nawet zegar, lecz jest on napisany bardzo łopatologicznie i używa, delaya, a to nie jest wg mnie najlepszym pomysłem.
    Chciałbym,żeby zegar wyliczał sekunde z zewn kwarca 32.768 kHz. Tak podobno najlepiej.
    Poniżej przedstawiam program, który aktualnie używam.
    Próbowałem wklejać proste przerwania wyzwalania jednej sekundy wykorzystując ISR(TIMER2_OVF_vect) , jednak one nie działały.
    Proszę o pomoc.
    Chciałbym się również zapytać jakie fusebits trzeba ustawić aby kwarc działał z zewnetrznego kwarca?
    Jesli czegoś nie dodałem to proszę pisać ( to mój pierwszy post, mogłem czegoś ważnego nie dodać)
    Z góry dziękuję.

    P.S. To pierwszy mój problem, bez niego nie mogę przeskoczyć do dalszego planu jakim jest zmienianie daty i godziny za pomocą dwóch przycisków ( jeden ustawia kursor na danej, a drugi ją zmienia )

    Code:

    #include "lcd4bit.h"
    #include <avr/io.h>
    #include <compat/deprecated.h>
    #include <avr/interrupt.h>
    #include <inttypes.h>

    // definicje pomocniczych makroinstrukcji
    #define SET_DB4 PORT_DB4 |= (1 << DB4)
    #define CLR_DB4 PORT_DB4 &= ~(1 << DB4)

    #define SET_DB5 PORT_DB5 |= (1 << DB5)
    #define CLR_DB5 PORT_DB5 &= ~(1 << DB5)

    #define SET_DB6 PORT_DB6 |= (1 << DB6)
    #define CLR_DB6 PORT_DB6 &= ~(1 << DB6)

    #define SET_DB7 PORT_DB7 |= (1 << DB7)
    #define CLR_DB7 PORT_DB7 &= ~(1 << DB7)

    #define SET_E PORT_E |= (1 << E)
    #define CLR_E PORT_E &= ~(1 << E)

    #define SET_RS PORT_RS |= (1 << RS)
    #define CLR_RS PORT_RS &= ~(1 << RS)

    char godzina = 23;
    char minuta = 59;
    char sekunda = 35;
    char rok = 07;
    char miesiac = 12;
    char dzien = 04;

    // funkcja wystawiajšca na szynę danych połówkę bajtu
    // pod uwagę brana jest młodsza połówka parametru
    void out_nibble(char x)
    {
    CLR_DB4;CLR_DB5;CLR_DB6;CLR_DB7;
    if(x & (1 << 0)) SET_DB4;// else  CLR_DB4;
    if(x & (1 << 1)) SET_DB5;// else  CLR_DB5;
    if(x & (1 << 2)) SET_DB6;// else  CLR_DB6;
    if(x & (1 << 3)) SET_DB7;// else  CLR_DB7;
    }

    // funkcja zapisujšca do LCD bajt danych
    void write_to_lcd(char x)
    {
    SET_E;
    out_nibble(x >> 4); // wystawienie na szynę danych starszej połówki bajtu
    CLR_E; // opadajšce zbocze na E powoduje zapis do wy?wietlacza
    SET_E;
    out_nibble(x); // wystawienie na szynę danych młodszej połówki bajtu




    CLR_E; // opadajšce zbocze na E powoduje zapis do wy?wietlacza
    _delay_ms(1); // opó?nienie ok 1 ms
    }

    // funkcja zapisujšca do LCD rozkaz
    void write_command(char x)
    {
    CLR_RS; // niski stan na RS -> zapis instrukcji
    write_to_lcd(x); // zapis do LCD
    }

    // funkcja zapisujaca do LCD znak
    void write_char(char x)
    {
    SET_RS; // wysoki stan na RS -> zapis danej
    write_to_lcd(x); // zapis do LCD
    }

    // funkcja zapisu tekstu do wy?wietlacza LCD
    void write_text(char * s)
    {
    while(*s) // do napotkania 0
      {
      write_char(*s); // zapisz znak wskazywany przez s na LCD
      s++; // zwiększ s (przygotuj nastepny znak)
      }
    }

    // funkcja czyszczšca ekran wy?wietlacza
    void lcd_clr(void)
    {
    write_command(CLEAR);
    }

    // funkcja ustawiajaca adres zapisu w drugim wierszu wy?wieltacza
    void lowerline(void)
    {
    write_command(0xA8);
    }


    // funkcja inicjujšca LCD
    void lcd_init(void)
    {
    // ustawienie wszystkich linii sterujšcych LCD jako wyj?cia
    DDR_DB4 |= _BV(DB4);
    DDR_DB5 |= _BV(DB5);
    DDR_DB6 |= _BV(DB6);
    DDR_DB7 |= _BV(DB7);
    DDR_E |= _BV(E);
    DDR_RS |= _BV(RS);
    //
    _delay_ms(15); // czekaj 15ms na ustabilizowanie się napięcia zasilajšcego
    CLR_E; // E = 0
    CLR_RS; // RS = 0
    char i; // zmianna licznikowa
    for(i = 0; i < 3; i++) // trzykrotne powtórzenie bloku instrukcji
      {
      SET_E; // E = 1
      out_nibble(0x03);
      CLR_E; // E = 0
      _delay_ms(5); // czekaj 5ms
      }
    SET_E; // E = 1
    out_nibble(0x02);
    CLR_E; // E = 0
    _delay_ms(1); // czekaj 1ms
    write_command(0x28); // interfejs 4-bity, 2-linie, znak 5x7
    write_command(0x08); // wyłšcz LCD, kursor i miganie
    write_command(0x01); // czy?ć LCD
    write_command(0x06); // bez przesuwania w prawo
    write_command(0x0C); // włšcz LCD, bez kursora i mrugania
    }

    void LCDxy(char x,char y)
    {
       unsigned char com=0x80;
       com|=(x|(y<<6));
       write_command(com);
    }

    int main(void)
    {

    // konfiguracja portów we/wy
    DDRB = 0xFF;
    PORTB = 0xFF;

    // inicjalizacja LCD
    lcd_init();

    // zapisz na LCD przykładowy tekst
    write_text("godzina:");
    LCDxy(0,1);
    write_text("data:");

    while (1)
    {

       LCDxy(14,0);
       write_char((sekunda/10)+0x30); //wyświetla jeden znak
       write_char((sekunda%10)+0x30); //+0x30 - konwersja na ASCI
       LCDxy(13,0);
       write_char(':');
       LCDxy(11,0);
       write_char((minuta/10)+0x30);
       write_char((minuta%10)+0x30);
       LCDxy(10,0);
       write_char(':');
       LCDxy(8,0);
       write_char((godzina/10)+0x30);
       write_char((godzina%10)+0x30);

        LCDxy(14,1);
       write_char((dzien/10)+0x30); //wyświetla jeden znak
       write_char((dzien%10)+0x30); //+0x30 - konwersja na ASCI
       LCDxy(13,1);
       write_char('.');
       LCDxy(11,1);
       write_char((miesiac/10)+0x30);
       write_char((miesiac%10)+0x30);
       LCDxy(10,1);
       write_char('.');
       LCDxy(8,1);
       write_char((rok/10)+0x30);
       write_char((rok%10)+0x30);

       sekunda++;

       if (sekunda==60)
       {
          sekunda = 0;
          minuta++;
          if (minuta == 60)
          minuta = 0;
          if (minuta == 0)
          {
             godzina++;
             if (godzina == 24)
             {
                godzina = 0;   
                if (godzina == 0)
                {
                   dzien++;
                   if (dzien == 30)
                   {
                      dzien = 0;
                      if (dzien == 0)
                      {
                         miesiac++;            
                         if (miesiac == 12)
                         {
                            miesiac = 0;                     
                            if (miesiac == 0)
                            {
                               rok++;
                            }
                         }
                      }
                   }
                }
             }   
             
          }
       
       }
       _delay_ms(1000);
       
    }
    return 0;
    }

    0 1
  • #2 04 Gru 2008 00:33
    hotdog
    Poziom 26  

    jeżeli chodzi o fuse'y to zajrzyj tutaj. Wybierasz rodzaj procesora i później odpowiednio jakie opcje Ciebie interesują. PAMIĘTAJ, sprawdź wszystko 3 razy, bo jak sobie usuniesz możliwość programowania proca przez SPI, lub reset (akurat przy Twoim procku to nie grozi) to uC idzie na półeczkę póki HVProga sobie nie zrobisz.

    Na stronie 131 dokumentacji do megi32 masz napisane, że Timer2 jest zoptymalizowany do tego aby wykorzystać go jako RTC, kwarc podłączasz do nóżek TOSC1 i TOSC2. Następnie ustawiasz bit AS2 w rejestrze ASSR. Włączasz przerwanie Timer2. Włączasz globalnie przerwania. Dopiero wtedy deklaracja funkcji w poniższy sposób ma sens:

    ISR(TIMER2_OVF_vect)
    {
    ...
    }

    Pisząc to deklarujesz funkcję której adres będzie się znajdował w tablicy wektorów przerwań procesora (łopatologicznie, za każdym razem jak Timer2 się przepełni funkcja się wywoła), a ponieważ Timer2 jest 8 bitowy więc będzie to co 256 drgań kwarca. O ile się nie mylę to jeżeli wszystko dobrze zrobisz to bez preskalera funkcja ta wykona się 128 razy na sekundę. Ustawiając prescaler na 128 (dzieląc częstotliwość przez 128) powyższa funkcja wykona się dokładnie raz na sekundę.

    Proponuje zainteresować się układami RTC, są tanie biorą bardzo mało prądu i można w łatwy sposób zrobić podtrzymanie bateryjne.

    Jeżeli się mylę to niech mnie ktoś poprawi...

    pozdrawiam

    0