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

Co z przerwaniem i deklarowaniemzmiennych WinAvr

20 Mar 2007 22:48 948 6
  • Poziom 10  
    Proźba o wytłumaczenie mi dlaczego nie działa wyświetlanie czasu:
    w drugiej linijce na LCD chcę wyświetlać godzinę, czas jest obliczany dzięki przerwaniu z TC1 (co 1 sekundę ma generować przerwanie)
    Niestety na LCD mam cały czas 00:00:00 tak jakby nie działało inkrementowanie w funkcji aktualizuj_czas lub jakby zmienne w głównej pętli nie były te same co w funkcji aktualizuj_czas
    Nie pomaga przeniesienie części kodu odpowiedzialnej za wyświetlanie czasu do funkcji aktualizuj_czas z main(), nie pomaga też zdeklarowanie zmiennych: jednostki_sekund, dzięsiątki_sekund ... jako volatile
    Z góry dziękuję za pomoc

    #define F_CPU 6000000
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <util/delay.h>
    #include <stdlib.h>
    #include <ctype.h>
    #include <stdio.h>
    #define DDR_DB4 DDRA
    #define PORT_DB4 PORTA
    #define DB4 PA2
    #define DDR_DB5 DDRA
    #define PORT_DB5 PORTA
    #define DB5 PA3
    #define DDR_DB6 DDRA
    #define PORT_DB6 PORTA
    #define DB6 PA4
    #define DDR_DB7 DDRA
    #define PORT_DB7 PORTA
    #define DB7 PA5
    #define DDR_RS DDRA
    #define PORT_RS PORTA
    #define RS PA0
    #define DDR_E DDRA
    #define PORT_E PORTA
    #define E PA1
    #define SET_DB4 PORT_DB4 |= _BV(DB4)
    #define CLR_DB4 PORT_DB4 &= ~_BV(DB4)
    #define SET_DB5 PORT_DB5 |= _BV(DB5)
    #define CLR_DB5 PORT_DB5 &= ~_BV(DB5)
    #define SET_DB6 PORT_DB6 |= _BV(DB6)
    #define CLR_DB6 PORT_DB6 &= ~_BV(DB6)
    #define SET_DB7 PORT_DB7 |= _BV(DB7)
    #define CLR_DB7 PORT_DB7 &= ~_BV(DB7)
    #define SET_E PORT_E |= _BV(E)
    #define CLR_E PORT_E &= ~_BV(E)
    #define SET_RS PORT_RS |= _BV(RS)
    #define CLR_RS PORT_RS &= ~_BV(RS)
    #define TIMER0_INIT 0
    #define OSC 6

    void waitms(unsigned char x)
    {
    unsigned char a, b; // zmnienne licznikowe
    for( ; x > 0; --x) // ta pętla zostanie wykonana x-razy
    for(b = 10; b > 0; --b) // a ta 10 razy
    for(a = 25 * OSC; a > 0; --a) // natomiast ta 100 razy
    __asm("nop"); // dodatkowa instrukcja opóźniająca o 1 cykl
    // razem to da opóźnienie ok. x * 1ms
    // x od 0 do 255
    // gdy x = 0 to opóźnienie = 256ms
    }

    void waits(char x)
    {
    unsigned char a;
    for(; x>0 ; x--)
    {
    for(a=4; a>0; a--)
    {
    waitms(250);
    }
    }

    }

    void write_to_lcd(char x)
    {
    SET_E;
    if(x & _BV(4)) SET_DB4; else CLR_DB4;
    if(x & _BV(5)) SET_DB5; else CLR_DB5;
    if(x & _BV(6)) SET_DB6; else CLR_DB6;
    if(x & _BV(7)) SET_DB7; else CLR_DB7;
    CLR_E;
    SET_E;
    if(x & _BV(0)) SET_DB4; else CLR_DB4;
    if(x & _BV(1)) SET_DB5; else CLR_DB5;
    if(x & _BV(2)) SET_DB6; else CLR_DB6;
    if(x & _BV(3)) SET_DB7; else CLR_DB7;
    CLR_E;
    waitms(1);
    }

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

    void lcd_init(void)
    {
    DDR_DB4 |= _BV(DB4);
    DDR_DB5 |= _BV(DB5);
    DDR_DB6 |= _BV(DB6);
    DDR_DB7 |= _BV(DB7);
    DDR_E |= _BV(E);
    DDR_RS |= _BV(RS);

    waitms(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
    SET_DB4;
    SET_DB5;
    CLR_DB6;
    CLR_DB7;
    CLR_E; // E = 0
    waitms(5); // czekaj 5ms
    }
    SET_E;
    CLR_DB4;
    SET_DB5;
    CLR_DB6;
    CLR_DB7;
    CLR_E; // E = 0
    waitms(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 write_char(char x)
    {
    SET_RS; // wysoki stan na RS -> zapis danej
    write_to_lcd(x); // zapis do LCD
    }


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

    void locate(char y, char x)
    {

    switch (y) // obliczenie o ile nalezy zwiekszyc x w zaleznosci od wartosci y
    {
    case 1:
    x += 0x7F; // x = x + 0x80 - 1
    break;
    case 2:
    x += 0xBF; // x = x + 0xA8 - 1
    break;
    }
    write_command(x);
    }

    void lcd_cls(void)
    {

    write_command(0x01);

    }

    void aktualizuj_czas(void);

    SIGNAL (SIG_OVERFLOW1)
    {
    TCNT1L = 0xDC; // załadowanie do licznika TIMER1 wartości początkowych
    TCNT1H = 0x0B; // określających częstotliwość występowania przerwania
    aktualizuj_czas(); // wywołanie procedury aktualizującej czas
    }

    // zmianne licznikowe do odmierzania czasu
    volatile int dziesiatki_godzin;
    volatile int jednostki_godzin;
    volatile int dziesiatki_minut;
    volatile int jednostki_minut;
    volatile int dziesiatki_sekund;
    volatile int jednostki_sekund;

    void aktualizuj_czas(void)
    {
    jednostki_sekund = 9;
    dziesiatki_sekund = 5;
    jednostki_minut = 9;
    dziesiatki_minut = 5;
    jednostki_godzin = 3;
    dziesiatki_godzin = 2;

    jednostki_sekund++; // zwiększ licznik jednostek sekund o 1
    if(jednostki_sekund == 10) // jeśli licznik jednostek sekund osiągnął wartość 10 to
    {
    jednostki_sekund = 0; // wyzeruj licznik jednostek sekund
    dziesiatki_sekund++; // zwiększ licznik dziesiątek sekund o 1
    if(dziesiatki_sekund == 6) // jeśli licznik dziesiątek sekund osiągnął wartość 6 to
    {
    dziesiatki_sekund = 0; // wyzeruj licznik dziesiątek sekund
    jednostki_minut++; // zwiększ licznik jednostek minut o 1
    if(jednostki_minut == 10) //jeśli licznik jednostek minut osiągnął wartość 10 to
    {
    jednostki_minut = 0; // wyzeruj licznik jednostek minut
    dziesiatki_minut++; // zwiększ licznik dzieisątekminut o 1
    if(dziesiatki_minut == 6) // jeśli licznik dziesiątek minut osiągnął wartość 6 to
    {
    dziesiatki_minut = 0; // wyzeruj licznik dziesiątek minut
    jednostki_godzin++; // zwiększ licznik jednostek godzin o 1
    if((dziesiatki_godzin == 2) && (jednostki_godzin == 4)) // jeżeli jest północ to
    {
    dziesiatki_godzin = jednostki_godzin = 0; // zeruj licznik dziesiątek i jednostek godzin
    }
    if(jednostki_godzin == 10) // jeśli licznik jednostek godzin osiągnął wartość 10 to
    {
    jednostki_godzin = 0; // wyzeruj licznik jednostek godzin
    dziesiatki_godzin++; // zwiększ licznik dziesiątek godzin o 1
    }
    }
    }
    }
    }
    }

    // Program główny
    int main(void)
    {
    lcd_init();
    int www;
    www = 1;
    int aaa;
    aaa = 7;
    DDRB = 0xFF;
    PORTB = 0xFF;
    TCCR1B = 0x03;
    TIMSK = 130; // globalne odblokowanie przerwań

    while(1)
    {

    sei();
    if (www <= 7)
    {
    www++;
    }

    if ( www > 7)
    {
    www ++;
    aaa --;
    }

    if (www == 14)
    {
    www = 1;
    aaa = 7;
    }

    char bb[3];
    itoa(www,bb,10);

    if (www <= 7)
    {
    write_command(0x01);
    locate(1,www);
    write_text(bb);
    waitms(50);
    }

    if (www > 7)
    {
    write_command(0x01);
    locate(1,aaa);
    write_text(bb);
    waitms(50);
    }

    char a[2];
    itoa(dziesiatki_godzin,a,2);
    char b[2];
    itoa(jednostki_godzin,b,2);
    char c[2];
    itoa(dziesiatki_minut,c,2);
    char d[2];
    itoa(jednostki_minut,d,2);
    char e[2];
    itoa(dziesiatki_sekund,e,2);
    char f[2];
    itoa(jednostki_sekund,f,2);

    locate(2,2);
    write_text(a);
    locate(2,3);
    write_text(b);
    locate(2,4);
    write_text(":");
    locate(2,5);
    write_text(c);
    locate(2,6);
    write_text(d);
    locate(2,7);
    write_text(":");
    locate(2,8);
    write_text(e);
    locate(2,9);
    write_text(f);
    waitms(250);

    }
    return 0;
    }
  • Poziom 10  
    Problem tkwi w miejscu gdzie są inicjowane wartości zmiennych do odnierzania czasu.
    Wyglądając tak
    Code:

    void aktualizuj_czas(void)
    {
    jednostki_sekund = 9;
    dziesiatki_sekund = 5;
    jednostki_minut = 9;
    dziesiatki_minut = 5;
    jednostki_godzin = 3;
    dziesiatki_godzin = 2;
    ...

    przy każdym uruchomieniu funkcji [przerwania] zmienne te są ustawiana od nowa na te same wartości.
    Dopiero potem zwiększana jest wartość sekund.
    Na wyświetlaczu uzyskując 00:00:00, otrzymujesz jak najbardziej poprawne wartości, przy takich wartościach początkowych.

    Proponuję przenieść fragment deklaracji i ustawienia tych zmiennych przed main, aby były widziane globalnie. Aby wywołane zostały raz.
    Powinno pomóc.
  • Poziom 10  
    Dzięki kolego Zielec
    Tego też próbowałem ale efekt dalej ten sam - 00 :00 :00
  • Pomocny post
    Poziom 39  
    zielec napisał:
    Problem tkwi w miejscu gdzie są inicjowane wartości zmiennych do odnierzania czasu.

    Niestety nie :(
    Problem tkwi tu:
    Code:

    /*    TIMSK = 130; // globalne odblokowanie przerwań  /*
    TIMSK |=(1<<TOIE1);

    Skąd wytrzasnąłeś te 130 :?:

    Piotrek

    PS
    A jaki to proc :?:
  • Poziom 10  
    Zumek masz rację problem jest z występowaniem przerwań
    niestety TIMSK |=(1<<TOIE1); też nic nie zmienia ale dzięki - utwierdziłeś mnie w tym że problem tkwi w przerwaniu
    Pozdrawiam
  • Poziom 39  
    PiotrKA1 napisał:
    Zumek masz rację problem jest z występowaniem przerwań
    niestety TIMSK |=(1<<TOIE1); też nic nie zmienia ale dzięki - utwierdziłeś mnie w tym że problem tkwi w przerwaniu
    Pozdrawiam

    To przyjrzyj się również temu ...
    Code:

    TCNT1L = 0xDC; // załadowanie do licznika TIMER1 wartości początkowych
    TCNT1H = 0x0B; // określających częstotliwość występowania przerwania

    ... i sprawdź w dokumentacji , w jakiej kolejności zapisywać rejestry licznika i dlaczego to ma znaczenie :D

    Piotrek
  • Poziom 10  
    Jednak Zumek miał rację - to było to
    Jeszcze przed while{ } trzeba było wsadzić sei(); i działa
    Dziękuję wszystkim, teraz mogę się spokojnie położyć spać