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.

Pomiar napięcia akumulatora na atmega16 w c

mirek1968 27 Kwi 2012 21:59 3302 15
  • #1 27 Kwi 2012 21:59
    mirek1968
    Poziom 13  

    Mam prośbę chciałbym kontrolować napięcie mojego akumulatora w samochodzie i nie wiem jak to poprawnie zrobić oraz jak oprogramować w c .Chciałbym do tego wykorzystać atmegę16 bo taki posiadam.Proszę o proste przykłady działające i pomoc w tym temacie.Jestem początkującym amatorem w programowaniu avr.Ogólnie chodzi mi o schemat podłączenia bezpiecznego napięcia akumulatora do pinu atmegi16 i prosty program w c do jego wyświetlenia na LCD 2X16.

    0 15
  • #2 28 Kwi 2012 09:27
    tmf
    Moderator Mikrokontrolery Projektowanie

    Podłączenie aku to po prostu dzielnik na rezystorach. Jak masz 12V to robisz dzielnik np. 1:3 i po kłopocie. Co do programu - ściągnij przykłady do książki z mojej stopki (są za darmo) i tam masz m.in. przykłądy obsługi ADC i wyświetlania na LCD.

    0
  • #3 28 Kwi 2012 10:14
    kaczart
    Poziom 14  

    Jeżeli zastosujesz dzielnik napięcia na wejściu to zastosuj rezystory o dużej dokładności (np. 0,5%) lub potencjometr, którym sobie skalibrujesz wskazania.

    Wystarczającą dokładność otrzymasz z wbudowanego ADC, jednak ważne jest, abyś zastosował jak najdokładniejsze napięcie referencyjne.

    0
  • #4 28 Kwi 2012 11:03
    tmf
    Moderator Mikrokontrolery Projektowanie

    No właśnie, stosowanie superdokładnych rezystorów jest bez znaczenia, jeśli nie zastosuje zewnętrznego napięcia referencyjnego. Z drugiej strony kalibrację można zrobić programowo i zapisać wynik w EEPROM przy pierwszym uruchomieniu. Wyjdzie taniej i prościej.

    0
  • #5 28 Kwi 2012 19:10
    mirek1968
    Poziom 13  

    Powiedzmy że podam plus z akumulatora samochodowego na połączone szeregowo rezystory 10K i 4,7K lub zastosuję potencjometr ,połączę masę akumulatora z moją płytką avr ,potem ustawię dokładnie napięcie 1/3 z 12V na pin ADC1 tj.PA1 atmegi16 .
    Pytanie do TMF gdzie znajdę przykłady w c dla tego dzielnika napięcie 1/3 ,jak mam rozumieć ten opis- "ściągnij przykłady do książki z mojej stopki " .Proszę jeszcze o przykład prostego programiku w c tak abym mógł wyświetlić wynik pomiaru na LCD 2X16.

    0
  • Pomocny post
    #7 28 Kwi 2012 21:26
    tmf
    Moderator Mikrokontrolery Projektowanie

    mirek1968 napisał:
    Powiedzmy że podam plus z akumulatora samochodowego na połączone szeregowo rezystory 10K i 4,7K lub zastosuję potencjometr ,połączę masę akumulatora z moją płytką avr ,potem ustawię dokładnie napięcie 1/3 z 12V na pin ADC1 tj.PA1 atmegi16 .
    Pytanie do TMF gdzie znajdę przykłady w c dla tego dzielnika napięcie 1/3 ,jak mam rozumieć ten opis- "ściągnij przykłady do książki z mojej stopki " .Proszę jeszcze o przykład prostego programiku w c tak abym mógł wyświetlić wynik pomiaru na LCD 2X16.


    W c przykładów do dzielnika napięcia raczej nie znajdziesz :) Dzielnik powoduje, że napięcie z aku jest dzielone na 3, czyli zamiast 12 V masz 4, zamiast 9 V masz 3 itd. Dzięki temu możesz aku bezpiecznie podpiąć pod wejście ADC procesora. To co musisz zrobić, to wynik pomiaru z ADC pomnożyć razy wartość dzielnika, czyli np. 3. Co do przykładów - w mojej stopce jest link. Jak go klikniesz to cię przekieruje na stronę Helionu, gdzie jest ksiażka do której możesz ściągnąć przykłądy - jeden z linków na tej stronie. Po ich rozpakowaniu masz przykłady wykorzystania LCD i ADC. Polecam też wcześniejszy link do blogu o mikrokontrolerach kolegi Dondu. Z pewnością dużo zyskasz jeśli go całego przejrzysz.

    0
  • #8 29 Kwi 2012 13:36
    mirek1968
    Poziom 13  

    Mam kilka pytań bo nie do końca mogę zrozumieć kilka terminów dotyczących funkcji przetwornika ADC atmega16.Powiedzmy że ustawiam sobie na dzielniku napięcia poprzez potencjometr dokładnie napięcie 1/3 napięcia akumulatora i podpinam do do pinu ADC1czyli PA1 mojej atmegi16.
    Czy wtedy w VREF wpisuję np. 4.0(tzn.1/3 napięcia akumulatora) ?.czy mam wpisać VREF 2,56 ? bez względu na tej mój dzielnik 1/3
    Bardzo proszę spojrzeć na mój plik main.c i poprawić błędy.Wykorzystuję pin ADC1 na pinie PA1 i nie rozumię także tego fragmentu programu.

    Kod: c
    Zaloguj się, aby zobaczyć kod

    //Inicjalizacja ADC
    ADCSRA = (1<<ADEN) //Bit 7 - ADEN: ADC Enable (uruchomienie przetwornika)
    |(1<<ADPS0)
    |(1<<ADPS1)
    |(1<<ADPS2); //ADPS2:0: ADC Prescaler Select Bits
    //(ustawienie preskalera) preskaler= 128

    ADMUX = (1<<REFS1) | (1<<REFS0) //Bit 7:6 - REFS1:0: Reference Selection Bits
    //Internal 2.56V Voltage Reference with external
    //capacitor at AREF pin
    |(1<<MUX2) | (1<<MUX0); //Input Channel Selections (ADC5 - Pin 5 )

    [/syntax]




    A to jest cały mój plik main.c proszę o poprawki.
    Kod: c
    Zaloguj się, aby zobaczyć kod


    #include <avr/io.h>
    #include <util/delay.h>
    #include "HD44780.h"


    //definicja napiecia referencyjnego
    #define VREF 2.56
    //definicja ADCIN (wejście ADC)
    #define ADCIN PA1
    //##############################################################################
    void main(void)
    {
    DDRB |=(1<<PB3); //enable backlight
    PORTB|=(1<<PB3);

    char wynik[]=" ";//bufor tekstowy, wyczyszczenie bufora
    float adc;//zmienna do obliczeń napięcia



    LCD_Initalize(); //inicjalizacja LCD
    LCD_GoTo(0, 0); //Ustawienie kursora w pozycji (0,0)
    LCD_WriteText("ADC test: 10 bit");

    //Inicjalizacja ADC
    ADCSRA = (1<<ADEN) //Bit 7 - ADEN: ADC Enable (uruchomienie przetwornika)
    |(1<<ADPS0)
    |(1<<ADPS1)
    |(1<<ADPS2); //ADPS2:0: ADC Prescaler Select Bits
    //(ustawienie preskalera) preskaler= 128

    ADMUX = (1<<REFS1) | (1<<REFS0) //Bit 7:6 - REFS1:0: Reference Selection Bits
    //Internal 2.56V Voltage Reference with external
    //capacitor at AREF pin
    |(1<<MUX2) | (1<<MUX0); //Input Channel Selections (ADC5 - Pin 5 )

    DDRA &=~ (1<<ADCIN); //Ustawienie Wejścia ADC

    for(;;)
    {
    ADCSRA |= (1<<ADSC);//ADSC: Uruchomienie pojedynczej konwersji

    while(ADCSRA & (1<<ADSC));//czeka na zakończenie konwersji

    adc=ADC*VREF/1024; //przeliczenie wartości na napięcie
    sprintf(wynik,"U=%1.1fV",adc); //konwersja na łańcuch znakowy
    LCD_GoTo(3, 1); //Ustawienie kursora w pozycji (1,1)
    LCD_WriteText(wynik); //Wyświetlenie wyniku
    _delay_ms(500); //opóźnienie
    }
    }[/syntax]

    0
  • #9 29 Kwi 2012 14:00
    miszczo997
    Poziom 27  

    Vref to napięcie odniesienia i nie może być większe od mierzonego napięcia. W twoim przypadku możesz wybrać wewnętrzne napięcie odniesienia 2,56v albo zewnętrzne np napięcie zasilania. Przy wyborze vcc pomiar będzie wynosił (5V/1024)*ADCW.
    W 10 bitowym rejestrze ADCW=((ADCL | (ADCH<<8)) przetrzymywany jest 10 bitowy wynik pomiaru, bitami ADPS ustawiasz preskaler, REFS -napięcie odniesienia, MUX - wybór pinu do którego podłączysz sygnał, a ustawienie bitu ADSC spowoduje uruchomienie pojedynczej konwersji.
    //
    W zasadzie to głupoty piszę. Nie ma 10bitowego rejestru ADCW, a to jedynie makro upraszczające. Są dwa 8 bitowe rejestry ADCW i ADCH w których przetrzymywany jest pomiar, który można wyrównać do lewej albo do prawej.

    0
  • #10 29 Kwi 2012 22:34
    mirek1968
    Poziom 13  

    Mam jeszcze pytanie dotyczące

    Kod: c
    Zaloguj się, aby zobaczyć kod

    //Inicjalizacja ADC
    ADCSRA = (1<<ADEN) //Bit 7 - ADEN: ADC Enable (uruchomienie przetwornika)
    |(1<<ADPS0)
    |(1<<ADPS1)
    |(1<<ADPS2); //ADPS2:0: ADC Prescaler Select Bits
    //(ustawienie preskalera) preskaler= 128
    Kod: c
    Zaloguj się, aby zobaczyć kod


    Chodzi mi jak w moim przypadku powinienem ustawić preskaler= 128? czy tak jest ok?
    Drugie pytanie dotyczy tego że jak ustawiłem napięcie 1,5V na pin PA1 i następnie pomnożyłem to *3 to wyświetla mi na LCD 4,6V? zamiast 4,5V-dlaczego?.
    Kod: c
    Zaloguj się, aby zobaczyć kod

    adc=ADC*VREF/1024; //przeliczenie wartości na napięcie
    sprintf(wynik,"U=%1.1fV",adc*3); //konwersja na łańcuch znakowy
    Kod: c
    Zaloguj się, aby zobaczyć kod


    Proszę jeszcze o pomoc w tych pytaniach.

    0
  • Pomocny post
    #11 29 Kwi 2012 22:45
    miszczo997
    Poziom 27  

    Zależy jaka częstotliwością taktujesz procesor. Ogólnie wg datasheeta dla 10 bitowego pomiaru ma być z przedziału 50-200khz. Dobierz taki preskaler, że jak podzielisz przez niego częstotliwość taktowania procesora to zmieścisz się w przedziale 50-200khz. Z drugim pytaniem niech ktoś inny pomoże.

    0
  • #12 30 Kwi 2012 10:47
    tmf
    Moderator Mikrokontrolery Projektowanie

    mirek1968 napisał:

    Drugie pytanie dotyczy tego że jak ustawiłem napięcie 1,5V na pin PA1 i następnie pomnożyłem to *3 to wyświetla mi na LCD 4,6V? zamiast 4,5V-dlaczego?.
    Kod: c
    Zaloguj się, aby zobaczyć kod

    adc=ADC*VREF/1024; //przeliczenie wartości na napięcie
    sprintf(wynik,"U=%1.1fV",adc*3); //konwersja na łańcuch znakowy
    Kod: c
    Zaloguj się, aby zobaczyć kod


    Proszę jeszcze o pomoc w tych pytaniach.


    Dlatego, że napięcie referencyjne nie jest dokładne, jest tylko stabilne. W zależności od jego konkretnej wartości wynik może nieznacznie się różnić, jeśli potrzebujesz dużej dokładności to musisz zastosować zewnętrzne źródło napięcia referencyjnego.

    0
  • #13 03 Maj 2012 14:19
    mirek1968
    Poziom 13  

    Mam takie pytanie troszkę na inny temat ale też dotyczący AVR.
    W jakim celu stosuje się układ pamięci 24C32 na jednej płytce z układem zegara ds1307.
    Czy ta pamięć jest konieczna? do pracy układu zegara?
    Pytam o to ponieważ chciałbym sobie taki układ zegara ds1307 kupić i zastanawiam się czy przy okazji kupić za jedną wysyłką pamięć i nie wiem czy jest to konieczne.
    Proszę o pomoc w tym pytaniu.

    0
  • #14 03 Maj 2012 14:26
    tmf
    Moderator Mikrokontrolery Projektowanie

    Nie, żadna dodatkowa pamięć nie jest potrzebna, ds1307 ma w sobie wszystko co jest potrzebne.

    0
  • #15 16 Maj 2012 16:37
    mirek1968
    Poziom 13  

    Dzięki tmf z odpowiedź.
    Mam pytanie dotyczące łączenia instrukcji programów w całość .
    Chodzi mi o to że robię sobie termometr w którym odczytam sobie temperaturę wewnętrzną ,zewnętrzną a także napięcie swojego akumulatora i czas,datę z układu DS1307.W jaki sposób połączyć kilka plików to ze sobą w sposób profesjonalny?
    Czy wszystko ująć w jednej pętli "while"?.ale wtedy są opóźnienia w realizacji programu które nie są wpisane na początku pętli programowej.
    Poniżej przedstawiam mój program w którym mam na początku komunikat powitalny potem odczyt temperatury i pomiar napięcia akumulatora proszę o poprawienie błędów w łączeniu instrukcji lub o inne cenne uwagi i przykłady poprawnego łączenia najlepiej na przykładzie mojego działającego main.c .
    W przedstawionym poniżej programie mam podzielone na kawałki i wymieszane części programu na termometr i woltomierz bo nie wiedziałem jak mam to zrobić profesjonalnie.Proszę o cenne konkretne rady.

    Kod: c
    Zaloguj się, aby zobaczyć kod

    /*
    Plik main.c

    KURS AVR-GCC cz.5
    Wyswietlacz alfanumeryczny LCD HD44780
    (schemat i opis dzialania w artykule)

    uklad atmega16 (16MHz)
    */
    #define F_CPU 16000000L
    #define VREF 5.00
    #define ADCIN PA1
    #include <avr/io.h>
    #include <util/delay.h>
    #include <stdio.h>
    #include "hd44780.h"
    #include "ds18b20.h"

    char str[17]="Temp zew";



    int main(void)
    {


    DDRB = 0b11111101; // linie PB0,2,3,4,5,6,7 są wyjściami ,linia PB1 jest wejściem//
    PORTB = 0b00001010; // podświetlenie LCD poprzez PB3//

    /* Napisy przechowujemy w tablicach */
    char str1[] = "SKODA";
    char str2[] = " FABIA";
    char str3[] = "HATCHBACK CLAS";
    char str4[] = "U=";

    //Komunikat powitalny//


    /* Funkcja inicjalizuje wyswietlacz */
    lcd_init();


    // Wlacza wyswietlanie z widocznym kursorem
    LCD_DISPLAY(LCDDISPLAY|LCDCURSOR);

    //Ustawia kursor w pozycji:
    //pierwszy wiersz, szosta kolumna
    LCD_LOCATE(5,0);

    // Wysyla do wyswietlacza jeden znak
    LCD_WRITE_DATA('W');
    _delay_ms(300);

    LCD_WRITE_DATA('I');
    _delay_ms(300);

    LCD_WRITE_DATA('T');
    _delay_ms(300);

    LCD_WRITE_DATA('A');
    _delay_ms(300);

    LCD_WRITE_DATA('M');


    _delay_ms(800);

    // Ukrywa kursor
    LCD_DISPLAY(LCDDISPLAY);

    LCD_CLEAR;
    LCD_LOCATE(2,0);

    //Funkcja lcd_puts wysyla do
    //wyswietlacza ciag znakow
    lcd_puts(str1);
    _delay_ms(1000);





    lcd_puts(str2);
    _delay_ms(1000);

    LCD_LOCATE(1,1);
    lcd_puts(str3);
    _delay_ms(1000);

    LCD_CLEAR;
    LCD_LOCATE(0,0);

    lcd_puts("Nr.Rejestracyjny");
    _delay_ms(1000);

    LCD_LOCATE(4,1);
    lcd_puts("SRC 38YS ");

    // Czeka 2.5 sek.
    _delay_ms(1000);

    // Czysci ekran
    LCD_CLEAR;


    //Woltomierz//

    char wynik[]=" ";//bufor tekstowy, wyczyszczenie bufora
    float adc;//zmienna do obliczeń napięcia



    //Inicjalizacja ADC
    ADCSRA = (1<<ADEN) //Bit 7 - ADEN: ADC Enable (uruchomienie przetwornika)
    |(1<<ADPS0)
    |(1<<ADPS1)
    |(1<<ADPS2); //ADPS2:0: ADC Prescaler Select Bits
    //(ustawienie preskalera) preskaler= 128

    ADMUX = (1<<REFS0) //Bit 6 - REFS0:1: Reference Selection Bits
    ///VCC jako napięcie referencyjne with external
    //capacitor at AREF pin
    | (1<<MUX0); //Input Channel Selections (ADA1 - Pin 1 )

    DDRA &=~ (1<<ADCIN); //Ustawienie Wejścia ADC



    //Termometr//


    /* Zmienna przechowuje aktualną wartość temperatury */
    double temp;
    /* W tablicy zapisywane będą dane odczytane z układu ds18b20 */
    unsigned char ds18b20_pad[9];

    /* Funkcja inicjalizuje wyświetlacz */
    lcd_init();
    /* Włącza wyświetlanie */
    LCD_DISPLAY(LCDDISPLAY);
    /* Czyści ekran */
    LCD_CLEAR;

    /* Wyświetla tytuł */
    LCD_LOCATE(0,0);
    lcd_puts(str);

    while(1)
    {

    //Woltomierz//

    ADCSRA |= (1<<ADSC);//ADSC: Uruchomienie pojedynczej konwersji

    while(ADCSRA & (1<<ADSC));//czeka na zakończenie konwersji

    adc=ADC*VREF/1024; //przeliczenie wartości na napięcie
    sprintf(wynik,"%1.1fV",adc*3); //konwersja na łańcuch znakowy
    LCD_LOCATE(9, 1);
    lcd_puts(str4);
    LCD_LOCATE(11, 1); //Ustawienie kursora w pozycji (1,1)
    lcd_puts(wynik); //Wyświetlenie wyniku
    _delay_ms(500); //opóźnienie


    //Termometr//

    /* Funkcja 'ds18b20_ConvertT' wysyła do układu ds18b20
    polecenie pomiaru */

    if(ds18b20_ConvertT())

    {

    /* 750ms - czas konwersji */
    _delay_ms(750);

    /* Odczyt z układu ds18b20, dane zapisywane są w tablicy ds18b20_pad.
    Dwie pierwsze pozycje w tablicy to kolejno mniej znaczący bajt i bardziej
    znaczący bajt wartość zmierzonej temperatury */
    ds18b20_Read(ds18b20_pad);

    /* Składa dwa bajty wyniku pomiaru w całość. Cztery pierwsze bity mniej
    znaczącego bajtu to część ułamkowa wartości temperatury, więc całość
    dzielona jest przez 16 */
    temp = ((ds18b20_pad[1] << 8) + ds18b20_pad[0]) / 16.0 ;

    /* Formułuje komunikat w tablicy 'str' */
    sprintf(str,"%4.1f\xdf""C", temp);

    LCD_LOCATE(9,0);
    /* Wysyła komunikat do wyświetlacza */
    lcd_puts(str);
    }

    }

    }
    Kod: c
    Zaloguj się, aby zobaczyć kod

    /*

    0
  • #16 14 Lis 2012 11:51
    mirek1968
    Poziom 13  

    Mam jedno jeszcze pytanie na temat ustawienia pinu PA0 jako ADC
    W przypadku ustawienia PC5 jest to:

    Kod: c
    Zaloguj się, aby zobaczyć kod

    ADMUX = (1<<REFS0) //VCC jako napięcie referencyjne
    |(1<<MUX2) | (1<<MUX0); //wybór kanału pomiarowego ADC5
    Kod: c
    Zaloguj się, aby zobaczyć kod


    A jak powinno być w przypadku pinu PA0 czyli mojego ADC0 pytam bo nie rozumiem tego zapisu powyżej.

    0
  Szukaj w 5mln produktów