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.

Woltomierz cyfrowy - prośba o sprawdzenie

AsKeR 14 Sty 2010 18:24 2347 0
  • #1
    AsKeR
    Poziom 10  
    Przerobiłem trochę program z książki "Mikrokontrolery Avr W Praktyce" (Doliński) w taki sposób, by napięcie mierzone było wyświetlane na wyświetlaczu LCD. Używałem modułu uruchomieniowego ZL3AVR wyposażonego m.in. w mikrokontroler Atmel ATMEGA32 16PU, wyświetlacz LCD HD444780 2x16 oraz 16-sto przyciskową klawiaturę. Układ podłączyłem jak na rysunku:
    Woltomierz cyfrowy - prośba o sprawdzenie

    Do obsługi wyświetlacza użyto uniwersalnej biblioteki tAvrLib.

    Cykl pomiarowy rozpoczyna się od ustawienia stanu wysokiego na wyjściu PD4, w wyniku czego kondensator C zaczyna się ładować przez opornik R na do napięcia zasilającego Vcc. W tym samym czasie mikrokontroler uruchamia pomiar czasu. W momencie, gdy napięcie na kondensatorze osiągnie wartość mierzonego napięcia wejściowego, na wyjściu komparatora nastąpi zmiana stanu, co powoduje zatrzymanie pomiaru czasu (zatrzaśnięcie wyniku w rejestrach ICR1H i ICR1L), który jest proporcjonalny do napięcia wejściowego (błąd jest niewielki). Cykl pomiarowy kończy się podaniem stanu niskiego na wyjściu PD4,
    w wyniku czego kondensator jest rozładowywany przez rezystor R i niewielką oporność wyjściową portu PD4 w tym stanie.
    Napięcie wejściowe woltomierza będące jednocześnie napięciem w stanie ustalonym na kondensatorze wylicza się z zależności:
    $$U_{c}=\frac{I*t}{C}=\frac{V{cc}-U_{BEP}}{R_{1}}*\frac{t}{C}$$
    Założono spadek napięcia na złączu baza-emiter w stanie przewodzenia 0,7 V.
    Otrzymany wynik jest przysłany na wyświetlacz LCD.
    Na początku programu deklaruje się wartości pojemności C oraz rezystancji rezystora R1.
    Do wyliczenia napięcia referencyjnego zastosowano procedurę kalibracyjną. Jest ona uruchamiana gdy zaraz po restarcie mikrokontrolera zostanie wykryte wciśnięcie klawisza S5 (bit_is_clear(PIND,1)). W pętli do...while jest realizowany cykliczny pomiar napięcia wejściowego. Wyjście z pętli jest możliwe po naciśnięciu klawisza S1. Powoduje to wyliczenie współczynnika kalibracyjnego i zapisanie go w pamięci EEPROM mikrokontrolera.
    Do pisania i kompilowania programu użyto środowiska AVR Studio 4.18 połączone z WinAVR-20090313 natomiast do przesyłania skompilowanego programu (pliku HEX) używano ISP Programmer 1.2.0.52.

    Code:

     Konfiguracja połączeń:
     - PORTA4-PORTA7 - piny DATA4-DATA7 kontrolera HD44780
     - PORTA1 - pin RS
     - PORTA2 - pin E
     - PORTB2 - wejście nieodwracające komparatora +
     - PORTB3 - wejście odwracające komparatora -
     - PORTD4 - wejście służące do rozładowywania kondensatora
     - PORTD0 - wejście z podciąganiem z klawiatury
     - PORTD1 - wejście z podciąganiem z klawiatury

     Należy zadać wartości:
    - pojemności C
    - rezystora R1
    - napięcie zasilania Vcc
    */

    float rezystorR1=1; //1 Ohm
    float kondensatorC=0.001; //1 mF
    float napieciezasilania = 5; //5 V
    double prad;

    #define F_CPU 16000000 //częstotliwość taktowania
    #define HD44780_DATA_GPIO A // pod którym portem jest szyna danych
    #define HD44780_DATA_HIGHHALFBYTE 1
    #define HD44780_RS_GPIO A
    #define HD44780_RS_BIT 1
    #define HD44780_E1_GPIO A
    #define HD44780_E1_BIT 2
    #define HD44780_WIDTH 16 //liczba kolumn wyświetlacza
    #define HD44780_HEIGHT 2 //liczba wierszy wyświetlacza
    #define HD44780_CHARSET HD44780_CHARSET_PL
    #define HD44780_CODEPAGE HD44780_CODEPAGE_UTF8

    #include <tAvrLib/hd44780.h>       //biblioteka do obsługi wyświetlacza
    #include <avr/io.h>          //biblioteka plikowych operacji wejścia - wyjścia
    #include <avr/signal.h>       //biblioteka umożliwiająca obsługę sygnałów
    #include <avr/eeprom.h>       //biblioteka umożliwiająca korzystanie z pamięci EEPROM
    #include <compat/deprecated.h>    //biblioteka umożliwiająca kompatybilność z starszymi wersjami kompilatora


    unsigned char liczt0;
    volatile unsigned char pomiar;      //flaga dokonania pomiaru
    union{
          unsigned int wspkal;           //współczynnik kalibracji
          unsigned char wspkalb[2];
         } uwspkal;


    void czekaj(unsigned long zt)    //procedura wytracania czasu
    {
       #define tau 10.38
       unsigned char zt1;
        for(;zt>0;zt--)
        {
            for(zt1=255;zt1!=0;zt1--);
        }
    }


    SIGNAL (SIG_INPUT_CAPTURE1)        //obsługa przerwania od przechwycenia
    {
        union {
          unsigned int czas;
          unsigned char czasb[2];
           } uczas;

        uczas.czasb[0]=ICR1L;          //zatrzaśnij rejestry przechwytywania
        uczas.czasb[1]=ICR1H;

        float WYNIK=(uczas.czas/uwspkal.wspkal)*(prad/kondensatorC);
       int cyf0 = WYNIK;      // wyznacz cyfrę przy pozycji 1V
       int cyf1 = (WYNIK-cyf0)*100;   // pozycja po przecinku

       // początek kodu odpowiedzialnego za wyświetlenie dolnego napisu
       hd44780_goto(1, 1);
       HD44780_PUTPSTR("    ");
       hd44780_putInt(cyf0, 10, 0);
       hd44780_putChar('.');
       hd44780_putInt(cyf1, 10, 0);
       HD44780_PUTPSTR(" V");;
       // koniec kodu odpowiedzialnego za wyświetlenie dolnego napisu

        pomiar=1;                   //pomiar dokonany (zapal flagę)
        sbi(PORTD,4);               //zacznij rozładowywać kondensator pomiarowy
    }


    int main(void)
    {

       hd44780_init();          //inicjacja wyświetlacza
       HD44780_BIND_STREAM(stdout);      //powiązanie wyświetlacza ze standardowym wyjściem
       hd44780_goto(0, 0);          //przejście do początku górnej linii wyświetlacza
       HD44780_PUTPSTR("Napiecie wynosi:"); //wyświetlenie górnego napisu

       DDRD=0x13;   //PORTD we oprócz PD4, PD1 i PD0 - wy
        PORTD=0xff;   //z podciąganiem
        PORTB=0x04;   //PB2 z podciąganiem
       DDRB=0xF3;   //PORT B0,B1,B4-B7 - wy, PORTB2 i PORTB3-0 - we
        TCCR1A=0;   //funkcje porównania i PWM wyłączone
        TCCR1B=0x41;   //preskaler XTAL/1 dla TC1, przechwytywanie na narastającym zboczu
       TIMSK=0x08;   //zezwolenie na przerwania od przechwytywania
        ACSR=1<<ACIC;   //zezwolenie na wyzwalanie przechwytywania komparatorem
        czekaj(10*tau);
        TIFR=0xff;   //kasuj przerwania od timerów
     
     

        if(bit_is_clear(PIND,1)) //wciśnięty S5 - kalibracja
           {     
          hd44780_goto(1, 1);
          HD44780_PUTPSTR("  KALIBRACJA");   //wyświetl napis „KALIBARCJA”
             do
                  {
    prad=((napieciezasilania-(0.7))/(rezystorR1));
                   cbi(PORTD,4);    //ładuj kondensator pomiarowy (stan wysokiej impedancji na PD4
                   TCNT1H=0;    //zeruj licznik 1 pomiar czasu ładowania
                   TCNT1L=0;
                 sbi(TIFR,ICF1); //ustawienie bitu ICF1 w rejestrze TIFR
                   while(bit_is_clear(TIFR,ICF1));      //czekaj aż napięcie mierzone zrówna się
           //z napięciem wejściowym
    uwspkal.wspkalb[0] = ICR1H; //zapisanie do zmiennej 16 bitowej wspkal wartość 16 bitowego rejestru przechwytywania (ICR1H do starszej części 16 bitowej danej)
    uwspkal.wspkalb[1] = ICR1L;   // ICR1L do młodszej części 16 bitowej danej
                      //uwspkal.wspkal=(ICR1L+256*ICR1H); // inny sposób zapisania powyższych operacji

                   sbi(PORTD,4);       //zacznij rozładowywać kondensator pomiarowy
                      czekaj(1*tau);        //opóźnienie związane z częstotliwością odświeżania
                  } while(bit_is_set(PIND,0));
            uwspkal.wspkal = uwspkal.wspkal / 64;

            eeprom_write_byte(1,uwspkal.wspkalb[0]);   //zapisz współczynnik kalibracji
            eeprom_write_byte(2,uwspkal.wspkalb[1]);   //do pamięci EEPROM
            sbi(TIFR,ICF1);             //ustawienie bitu ICF1 w rejestrze TIFR
           }
        else
           {
           uwspkal.wspkal=eeprom_read_byte(1);  //odczytaj współczynnik kalibracji z EEPROM-u
           }
        sei();      //odblokuj globalne przerwania
        while(1)   //główna pętla pomiarowa
        {
           cbi(PORTD,4);        //ładuj kondensator pomiarowy
           TCNT1H=0;            //zeruj licznik 1 - pomiar czasu ładowania
           TCNT1L=0;
           pomiar=0;
           while(pomiar==0);    //czekaj aż napięcie mierzone zrówna się z napięciem
                                 //na kondensatorze pomiarowym
            czekaj(23*tau);      //opóźnienie związane z częstotliwością odświeżania LCD
       }
    }


    Czy mógłby ktoś sprawdzić czy to w ogóle ruszy? Płytkę miałem pożyczoną więc teraz już nie mam jak samemu? W załączniku biblioteka tAvrLib oraz program wraz z HEXem