wtorek, 29 marca 2011

ADC - Prezentacja wyniku na LCD

Autor: drzasiek
Redakcja: dondu


Drzaśkowy pamiętnik: Spis treści

Uruchomiłem już przetwornik, udało się zmierzyć poziomy napięć i odczytać je za pomocą LED. Jednak odczyt napięcia za pomocą diod ma zbyt małą rozdzielczość i jest bardzo niewygodny, gdy chce się zmierzyć dokładnie wartość napięcia.

Postanowiłem zatem wykorzystać popularny, tani i łatwo dostępny alfanumeryczny LCD 2x16 znaków z najpopularniejszym sterownikiem HD44780. Nie będę tutaj opisywał działania i komunikacji z tym sterownikiem. Jest tego całe mnóstwo w sieci, więc skorzystałem z biblioteki i opisu autora tej strony: radzio.dxp.pl

Problem znaku zapytania
Jeżeli zamiast poprawnego wyniku na LCD otrzymujesz znak zapytania powinieneś w opcjach kompilatora dodać odpowiednie biblioteki i parametry. Jak to zrobić opisuje ten artykuł: Problem znaku zapytania podczas konwersji float do znaków ASCII w celu wyświetlenia na np. LCD itp.

W oparciu o schemat na stronie i mój poprzedni układ do pomiaru napięcia zaprojektowałem schemat całości:


Pobierz schemat: schemat1.rar

Bardzo istotną sprawą dla dokładności pomiarów jest sposób podłączenia mikrokontrolera i filtracja zakłóceń. Wszystko omówione jest tutaj: ADC - Dokładność vs podłączanie

Na początek postanowiłem spróbować wyświetlić na LCD 10 bitową wartość pomiaru:

//Pomiar napięcia przetwornikiem A/C i prezentacja wyniku na LCD 2x16 HD44780

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

//definicja ADCIN (wejście ADC)
#define ADCIN PC5 

void main(void)
{
   char wynik[4];//bufor

   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)    //włączenie ADC
            |(1<<ADPS0)  //ADPS2:0: ustawienie preskalera na 128
            |(1<<ADPS1)
            |(1<<ADPS2); 
                      

   //Wybór napięcia referencyjnego
   //wewnętrzne 2.56V z zewnętrznym kondensatorem na pinie AREF
   ADMUX = (1<<REFS1) | (1<<REFS0) 
             
    //wybór kanału pomiarowego na pinie ADC5
    |(1<<MUX2) | (1<<MUX0); 


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


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

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

   LCD_GoTo(5, 1);         //Ustawienie kursora w pozycji (5,1)
   LCD_WriteText("    ");   //Czyszczenie poprzednij wartości
   itoa(ADC,wynik,10);      //konwersja wyniku do tablicy char
   LCD_GoTo(5, 1);         //Ustawienie kursora w pozycji (5,1)
   LCD_WriteText(wynik);   //Wyświetlenie wyniku
   _delay_ms(500);         //opóźnienie
  }
}
Projekt składa się z 2 plików źródłowych main.c i HD44780.c i jednego pliku nagłówkowego HD44780.h z wyżej podanej strony. Pobierz cały projekt: prog1.rar


W efekcie na wyświetlaczu LCD wyświetlana była wartość pomiaru w zakresie 0-1023.



Ale to ciągle są tylko wartości wyniku z ADC. Jak to się ma do napięcia na wejściu przetwornika?

W datasheet mikrokontrolera odnalazłem wzór określający w jaki sposób przetwornik ADC oblicza wynik pomiaru:




Zatem po przekształceniu otrzymuję wzór na obliczenie wartości napięcia mierzonego:




Przy 10 bitowej rozdzielczości i Vref=2,56V wartość napięcia zmierzonego wyniesie:




Korzystając z wewnętrznego napięcia referencyjnego 2,56V mogłem mierzyć napięcia z zakresu: 0-2,56V przy 10 bitowej rozdzielczości, co daje rozdzielczość napięciową:




Zatem mogłem sobie pozwolić na pomiar napięcia praktycznie z dokładnością do 3 miejsc po przecinku.

Napięcie referencyjne wynosi 2,56V, więc jak widać ze wzoru musiałbym mnożyć wartość całkowitą przez 2,56 czyli kompilator zaokrągliłby to do 2. Następnie dzielenie małej liczby przez 1024 znowu spowoduje dość spore zaokrąglenia i w efekcie uzyskałbym zły pomiar.

Uznałem więc, że wygodnie będzie mi przechowywać i obliczać wynik na zmiennej typu float. I choć operacje na typach zmiennopozycyjnych są dość wolne, tutaj nie miałem jakichś wygórowanych wymagań, co do szybkości działania więc mogłem sobie na to pozwolić.

Procedury obliczeń na liczbach zmiennopozycyjnych znajdują się w bibliotece libm.a.

Dowiedziałem się też o ciekawej (choć „zasobożernej”) funkcji sprintf() formatującej różne typy zmiennych (w tym float) do łańcucha znakowego.

Do tego potrzebne było dodanie do projektu biblioteki np. libprintf_flt.a

Instrukcję jak dodać dwie powyższe biblioteki znajdziesz w tym artykule: Problem znaku zapytania podczas konwersji float do znaków ASCII w celu wyświetlenia na np. LCD itp.


Nowy kod:
//Pomiar napięcia przetwornikiem A/C i prezentacja wyniku na LCD 2x16 HD44780

#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 PC5 

void main(void)
{
   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) //włączenie ADC
            |(1<<ADPS0) //ADPS2:0: ustawienie preskalera na 128
            |(1<<ADPS1)
            |(1<<ADPS2);
   
   //- wybór wewnętrznego napięcia referencyjnego 2,56V z zewnętrznym 
   //   kondensatorem na pinie AREF
   //- wybór kanału pomiarowego na pinie ADC5 
   ADMUX  =    (1<<REFS1) | (1<<REFS0) // 2,56V + kondensator
             |(1<<MUX2) | (1<<MUX0);   // wybór kanału ADC5

   
   DDRC &=~ (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.3f [V]",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
  }
}
Pobierz program: prog2.rar

W ten sposób uzyskałem prosty woltomierz:



Zauważyłem, że wynik jednak troszkę odbiega od prawdziwego. Spowodowane jest to niedokładnością wewnętrznego napięcia referencyjnego Vref, o czym możesz przeczytać tutaj: ADC - Dokładność vs podłączanie

Dokonałem zatem kalibracji pomiarów poprzez podłączenie do wejścia znanego mi napięcia i następnie doświadczalnie zmieniłem wartość napięcia referencyjnego w programie:

#define VREF 2.56

na taką wartość, by wynik prezentowany na wyświetlaczu był jak najbliższy wartości prawdziwej. Można także zmierzyć multimetrem napięcie na pinie AREF i podstawić do powyższej definicji.


Jak zwiększyć zakres pomiarowy?
Zakres napięcia wejściowego jest jednak dość mały: 0-2.56V. By móc mierzyć większe napięcia zdecydowałem się zwiększyć wartość napięcia referencyjnego.

Zerknąłem więc do datasheet i sprawdziłem jakie mam możliwości:




Jak widać mogę albo podłączyć zewnętrzne napięcie referencyjne (nie przekraczające napięcia zasilania mikrokontrolera), albo wybrać programowo napięcie zasilania jako napięcie referencyjne, czyli w moim przypadku 5V.

I znowu sporo na ten temat można przeczytać tutaj: ADC - Dokładność vs podłączanie

Wybrałem więc programowo napięcie zasilania AVcc, jako napięcie odniesienia Vref.

Zmiany w programie to:

zmiana
#define VREF 2.56
na
#define VREF 5.0


oraz zmiana
ADMUX  =    (1<<REFS1) | (1<<REFS0) | (1<<MUX2) | (1<<MUX0);
na
ADMUX  =    (1<<REFS0) | (1<<MUX2) | (1<<MUX0);


Kod po zmianach:
//Pomiar napięcia przetwornikiem A/C i prezentacja wyniku na LCD 2x16 HD44780

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


//definicja napięcia referencyjnego
#define VREF 5.0
//definicja ADCIN (wejście ADC)
#define ADCIN PC5 

void main(void)
{
   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) //włączenie ADC
            |(1<<ADPS0) //ADPS2:0 ustawienie preskalera na 128
            |(1<<ADPS1)
            |(1<<ADPS2);
                      

   ADMUX  =    (1<<REFS0)          //VCC jako napięcie referencyjne
            |(1<<MUX2) | (1<<MUX0); //wybór kanału pomiarowego ADC5

   DDRC &=~ (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.3f [V]",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
  }
}
Pobierz program: prog3.rar


Czy coś  Ci się "rzuciło w oczy"?
Skoro zwiększyłem zakres mierzonego napięcia, ale nadal mierzę je z 10 bitową rozdzielczością, to coś musiało ulec zmianie. Tym czymś jest:




Mała modyfikacja schematu
Skoro mogłem mierzyć już napiecia z zakresu 0-5V usunąłem rezystor R2, który był w szeregu z potencjometrem, aby uyskać pełny zakres napięć na potencjometrze:



I to wszystko dało taki efekt:






Przetwornik w trybie free Run, obsługa w przerwaniu

Ciągłe wyzwalanie pomiaru w pętli głównej jak i oczekiwanie na zakończenie kolejnych konwersji może być trochę kłopotliwe. Dlatego następną rzeczą jaką zrobiłem było wykorzystanie trybu Free Run (pomiar ciągły) i odczyt wartości w przerwaniu.

Za tryb Free Run odpowiada bit ADFR rejestru ADCSRA:

Bit 5 – ADFR: ADC Free Running Select




Potrzeba też uruchomić zgłaszanie przerwań przez ADC po zakończonej konwersji za co odpowiada bit ADIE rejestru ADCSRA:

Bit 3 – ADIE: ADC Interrupt Enable



W trybie Free Run bit ADSC rozpoczyna pierwszą konwersję.


//Pomiar napięcia przetwornikiem A/C i prezentacja wyniku na LCD 2x16 HD44780

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


//definicja napiecia referencyjnego
#define VREF 5.05
//definicja ADCIN (wejście ADC)
#define ADCIN PC5 

volatile float adc;//zmienna do obliczeń napięcia

void main(void)
{
   char wynik[]="           ";//bufor tekstowy, wyczyszczenie bufora
   
   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) //włączenie ADC
            |(1<<ADFR) //włączenie trybu Free run
            |(1<<ADIE) //uruchomienie zgłaszania przerwań
            |(1<<ADSC) //rozpoczęcie konwersji
            |(1<<ADPS0)   //ADPS2:0: ustawienie preskalera na 128
            |(1<<ADPS1)
            |(1<<ADPS2);
                      

   ADMUX  =    (1<<REFS0) //VCC jako napięcie referencyjne
            |(1<<MUX2) | (1<<MUX0); //wybór kanału pomiarowego ADC5

   DDRC &=~ (1<<ADCIN); //ustawienie wejścia ADC

   sei(); //Globalne uruchomienie przerwań 

  for(;;)//główna pętla programu
  {
      sprintf(wynik,"U=%1.3f [V]",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
  }
}



ISR(ADC_vect)//obsługa przerwania po zakończeniu konwersji ADC
{
  adc=ADC*VREF/1024;      //przeliczenie wartości na napięcie
}
Pobierz program: prog4.rar

I w ten sposób nie musiałem w pętli głównej uruchamiać pomiaru za każdym razem i czekać, aż konwersja się zakończy. Na potrzeby takiego prostego woltomierza, to nie miało większego znaczenia, ale gdy liczy się ściśle określona częstotliwość zapisywania próbek np. do bufora jest to dość istotne.


Efekt końcowy
Przyjemny mały woltomierz, a satysfakcja wielka!





Co dalej?
W kolejnej części opiszę jak skorzystałem z wyniku w rozdzielczości 8 bitowej, jak multipleksować kanały oraz coś o szybkości próbkowania.



Przeczytaj także:

74 komentarze:

  1. Witam Panie Drzaśku :) Piszę do pana z następującym pytaniem.
    Czy korzystając z tego artykułu który Pan tutaj umieścił uda mi się zmierzyć ciśnienie z tego czujnika? http://www.ge-mcs.com/en/pressure-mems/mems-sensors/npc-1210.html NPC 1210. Czy najlepiej będzie poczekać na Pana kolejny artykuł, bo w tych nie ma jeszcze wszystkiego? Mógłby Pan dać wskazówkę jak to w praktyce z tego typu układami wygląda? :)

    OdpowiedzUsuń
  2. Nie znam specyfikacji tego czujnika, nie używałem go więc nie powiem wprost.
    Wszystko zależy od Twojej wyobraźni, wiedzy i chęci.
    Co do ADC to jeszcze jeden artykuł będzie, myślę, że wkrótce.
    Jest już napisany, czeka tylko na zredagowanie.
    Ty musisz zdecydować, czy to co tutaj jest Ci wystarczy, czy potrzebujesz jeszcze czegoś więcej.

    OdpowiedzUsuń
  3. Mała uwaga, trochę czepliwa ale myślę że warto uściślić szczególnie w takim miejscu gdzie ludzie przychodzą się uczyć :) Pomiarów dokonuje Pan nie z dokładnością, tylko z rozdzielczością do 3 miejsc po przecinku.

    OdpowiedzUsuń
  4. No właśnie w rozdzielczości podaje się najmniejszy przyrost wielkości mierzonej, więc jeśli mówimy tutaj o rozdzielczości to jest to 2,5 mV.

    OdpowiedzUsuń
  5. Tak, ale ta rozdzielczość ma się ni jak do dokładności. Może posłużę się przykładem żeby wyjaśnić o co mi chodzi :) Mamy termometr cyfrowy kupiony w aptece za 10zł, pokazuje on temperaturę w Celsjusz aż dwa miejsca po przecinku(czyli ma rozdzielczość 0,01 stopnia), a jego dokładność to +-0.5 stopnia. To znaczy że np. odczytujemy temperaturę 36.61, nasza temperatura zawiera się gdzieś w przedziale 36.11 - 37.11, więc albo jesteśmy chorzy albo nie, nikt tego nie wie :)

    OdpowiedzUsuń
  6. Mówimy o tym samym, tylko innymi słowami :)
    Rozdzielczość w tym przypadku to jest 2,5 mV, a dokładność?
    Napisałem że prawie do 3 miejsc po przecinku czyli prawie +/-1 mV, ale jest to MOCNO naciągane.
    Chodziło tutaj o pokazanie, ile miejsc po przecinku można z tego uzyskać.
    I masz rację, nijak ma się to do dokładności.
    Dokładność zależy od wielu czynników, można o tym poczytać w DS i tak właściwie jest to temat na osobny artykuł.

    OdpowiedzUsuń
  7. Konrad to co piszesz jest słuszne. Tylko dla uściślenia. Rozdzielczość to zdolność do rozróżniania dwóch różnych pomiarów. Czyli w przykładzie z termometrem, jeśli rozdzielczość wynosi 0,01 stopnia to temperatury 36,71 i 36,72 będą rozróżnione. Czyli wyniki różniące się o owe 0,01 będziemy w stanie rozróżniać. Ale oczywiście nie znaczy to, że zmierzona temperatura 36,71 to będzie dokładnie taka temperatura. Tu wkracza drugi parametr - dokładność. Czyli to jak bardzo zmierzona wartość różni się od rzeczywistej wartości mierzonego parametru.

    OdpowiedzUsuń
  8. Tmf - Nie wiem co masz na myśli pisząc "zdolność do rozróżniania dwóch różnych pomiarów". Jeżeli to że dla stałej temperatury termometr będzie pokazywał cały czas taki sam wynik, to wydaje mi się że to nie jest prawda, wynik może pływać. A jeżeli chodzi Ci o rozróżnienie wyników z serii pomiarowej(ponumerowanie ich ?) to chyba nie potrzeba do tego dodatkowego miejsca po przecinku :)

    Proszę rozwiń to co napisałeś bo mam wrażenie że po prostu źle rozumiem to co napisałeś :)

    Drzasiek - jeżeli się ze mną zgadzasz to chyba rozumiesz że zdanie "Zatem mogłem sobie pozwolić na pomiar napięcia praktycznie z dokładnością do 3 miejsc po przecinku." jest trochę mylące i ktoś kto np. ma pojęcie o metrologi ale nie ma pojęcia o mikrokontrolerach może się na to nabrać :)

    OdpowiedzUsuń
  9. Oczywiście wynik będzie pływał, bo na to wszystko nakładają się szumy. Rozdzielczość pomiaru to nie ilość bitów ADC, tylko ilość bitów realnie do uzyskania, co ograniczają m.in. szumy. Dla ADC AVR to typowo 8 bitów, pomimo, że przetwornik jest 10-bitowy. Dopiero właściwie zaprojektowany układ, odpowiednie źródło sygnału umożliwiają niemalże uzyskanie deklarowanej przez producenta rozdzielczości.

    OdpowiedzUsuń
  10. Anonimie - no właśnie nie :) Rozdzielczość jest 10 bitowa chociaż by nawet na 5 bitach szumiało, to ona dalej będzie 10 bitowa. Dokładność mówi o tym które bity możemy "brać serio" a które sobie z nas jaj robią :)

    OdpowiedzUsuń
  11. Wszystko działa tylko wyświetlacz jest strasznie ciemny. Mam dokładnie taki http://lispol.com/p/2122/Wy%C5%9Bwietlacz%20LCD%202x20%20znak%C3%B3w,%20niebiesko-bia%C5%82y
    Ponoć piny 15 i 16 są od podświetlenia, więc podłączyłem 15 przez rez. 330 do +5V a 16 do masy i nic.

    OdpowiedzUsuń
  12. To pokaż zdjęcie, bo nie wiem co wg ciebie znaczy, "i nic" albo "wyświetlacz strasznie ciemny".

    OdpowiedzUsuń
  13. Trzeba praktycznie się nachylić do niego żeby coś zobaczyć. Podświetlenie (chyba) nie działa. Inne wyświetlacze to wręcz walą po oczach, nawet te niebiesko - białe.
    http://imageshack.us/a/img692/1852/dscf9316d.jpg

    OdpowiedzUsuń
  14. Skoro masz uszkodzone podświetlenie to ja Ci go niestety nie naprawię :)
    Kontrast regulowałeś?

    OdpowiedzUsuń
  15. Kontrast tak. Tylko ciekawi mnie dlaczego po podłączeniu pinu 15 (LED A) i pinu 16 (LED K)nie widać żadnych zmian, może faktycznie uszkodzony? Z boku po prawej stronie, widać na zdjęciu, mam jeszcze dwa wolne miejsca na wlutowanie czegoś, opisane są jako Anoda i Katoda. To może też trzeba jakoś wykorzystać żeby uruchomić podświetlenie?

    OdpowiedzUsuń
  16. Dobra sam sobie poradziłem. Pin 15 podłączyć do masy a 16 do +5V ( nie wiem dlaczego w necie jest odwrotnie pokazywane i jeszcze przez rezystor). Teraz nieźle daje po oczach.

    OdpowiedzUsuń
  17. Nie rozumiem tylko jednego zapisu U=%1.3f Dlaczego akurat tyle?

    OdpowiedzUsuń
  18. %1,3f to nie jest liczba tylko sposób formatowania ciągu znaków liczby, która w tym wypadku ma być wyświetlona na wyświetlaczu LCD.

    Więcej na ten temat znajdziesz tutaj: instrukcja printf( )

    OdpowiedzUsuń
  19. Witam, dziękuje serdecznie za wiedzę zawartą w artykułach:) Na LCD wyświetla mi się"U=? [V}". Natomiast wartość nieprzeliczona wyświetla się normalnie. Mogę liczyć na pomoc?

    OdpowiedzUsuń
  20. A dodadłeś do projektu biblioteki?
    libm.a.
    libprintf_flt.a

    OdpowiedzUsuń
  21. W Atmel Studio 6 aby skompilować przykłady bez ostrzeżeń musiałem dodać #define , zmieniłem void main na int main oraz typ zmiennej adc z float na double. Teraz wszystko działa bezbłędnie.

    OdpowiedzUsuń
  22. Miało być #define ale coś mi to wycięło ;)

    OdpowiedzUsuń
  23. No coż, tak to wychodzi jak się pisze w nocy...
    Miałem na myśli włączenie pliku stdio.h, więc powinno to wyglądać tak: #include <stdio.h>
    Przepraszam za zamieszanie.

    OdpowiedzUsuń
  24. Witam,
    złożyłem układ tak jak jest tutaj na schemacie z jedną różnicą: kwarc mam nie 16MHz a 12MHz. Kod jest identyczny. Ale układ nie działa tak jak powinien. Zamiast napisów, które powinny być, wyświetlacz pokazuje losowe znaczki w losowych miejscach...

    Pozdrawiam :)

    OdpowiedzUsuń
  25. Czy w opcjach zmieniłeś wartość kwarcu? Link: F_CPU – gdzie definiować?

    OdpowiedzUsuń
  26. Niestety, niewiele to pomogło. Chociaż teraz zamiast losowych w różnych miejscach mam jeden zawsze w tym samym ^^'

    OdpowiedzUsuń
  27. Szkoda, że nie masz kwarcu 16MHz bo mógłbyś sprawdzić wgrywając plik HEX znajdujący się w spakowanym pliku.

    Jeżeli poprawnie ustawiłeś zegar, zmontowałeś układ oraz zaprogramowałeś poprawnie, to musi działać.

    Zwróć szczególną uwagę na połączenia pomiędzy wyświetlaczem i mikrokontrolerem. Nie wiem jaką wersję układu masz, ale nie sugeruj się numerami pinów tylko ich nazwami, ponieważ w zależności od obudowy, piny mogą mieć różną numerację (nie sprawdzałem).

    OdpowiedzUsuń
  28. drugi kod w tym arcie skompilowany pod AVR Studio 4.0 wywala mi warning: ../main.c: warning: format '%1.3f' expects type 'double', but argument 3 has type 'float'
    a na wyświetlaczu U=?

    OdpowiedzUsuń
  29. Witam,
    Prośba o pomoc do kolegów, używam tego własnie wyświetlacza(oraz ATmega8) do wyświetlenia wyniku z ADC, który także przekazywany jest na wyjscie pwm, i steruje silnikiem za pomocą traznystora, układ działa poprawnie, sterowane są obroty silnika, jednak oraz na wyświtlaczu zanika przy wypełnieniu około 50%. Przy odłączonym silniku wyświetlacz działa, dlatego wiem że jest to spowodawane działaniem silnika. I tu mam pytanie, w jaki sposób pozbyć się tego efektu? Próbowałem stosować diodę na silniku, jednak to nie pomogło?
    Z góry dzieki za pomoc:)

    OdpowiedzUsuń
  30. Drzasiek czy mógłbyś mi podpowedzieć jak zwiększyć zakres pomiarowy do 20v. Dzielnik napięć już dobrałem, nie wiem tylko jak na początkowo zmodyfikować Twój kod żeby sprawdzić czy to wogóle mi ruszy. Z góry dzieki;)

    OdpowiedzUsuń
  31. Już sam sobie odpowiedziałem:) Wynik wyświetlany musimy przemnożyć przez (R2+R1)/R2. Jeżeli jestem w błędzie to proszę o poprawę. Pozdrawiam

    OdpowiedzUsuń
  32. Koledzy, może mi ktoś powiedzieć skąd mogę pobrać biblioteki libm.a oraz libprintf_flt.a, bo nie mogę ich znaleźć.

    OdpowiedzUsuń
  33. Anonimowy z 14 marca 2013 17:08:

    http://home.roboticlab.eu/en/examples/setup/eclipse
    Ogólnie to dodajesz biblioteki: 'printf_flt' i 'm' - przeczytaj link wyżej.

    Teraz ja mam pytanie - a mianowicie używam ECLIPSE i przy obsłudze przerwań (nie używałem liczb zmiennopozycyjnych) zauważyłem, ze w ISR(ADC_vect) jest mnożenie przez zmienną VREF, która wynosi dajmy na to 5,2. Procesor nie mnoży przez tą zmienną- dostaje wynik 0, lecz teraz jeżeli wynik z ADC przerzucę do jakiejś innej zmiennej poza przerwaniem i wykonam mnożenie przez VREF, to już wtedy działa. Może mi ktoś wyjaśnić dlaczego tak się dzieje?

    OdpowiedzUsuń
  34. Witam.
    Mógłby mi ktoś powiedzieć dlaczego oba wyniki różnią się?
    a=adc*VREF*10;  wynik 53195 VREF=5.2 dobrze
    b=adc*5.2*10;    wynik: -12341 źle
    i dlaczego, gdy wynik 'a' pomnożę nie przez 10, a przez 100 to dostaję także zakłamany wynik mimo ze 'a' jest uint32_t ?

    OdpowiedzUsuń
  35. Problemem jest domyślna promocja typów. c traktuje domyślnie literały liczbowe tak jakby były typu int, to, że przypisujesz to zmiennej o typie uint32_t nie ma nic do rzeczy, bo przypisanie jest wykonywane jako ostatnia operacja i dopiero wtedy nastęuje konwersja z int do uint32_t. Zamiast 100 napisz 100UL i będzie dobrze.

    OdpowiedzUsuń
  36. Mam taki mianowicie problem pokazuje mi dla napieć mniejszych niz 1v "1" a dla od 1.25v tylko zero co to może być

    OdpowiedzUsuń
  37. A może tak napisz coś więcej?
    Co zrobiłeś? napisałeś własny program? To pokaz kod.. wróżyć niestety nie umiemy.

    OdpowiedzUsuń
  38. Mam takie pytanie? Co dokładnie robi parametr %1.3f w sprintf? Niestety nie mogę do tego dojść.

    OdpowiedzUsuń
  39. Odpowiada za formatowanie wyniku do postaci znaków ASCII. Konkretnie oznacza jedną cyfrę całości i trzy po przecinku. Szczegółów szukaj w kursie C tutaj: Kurs języka C: Printf() i funkcje pochodne

    OdpowiedzUsuń
  40. Witam,
    mam problem z podpięciem tego wyśiwetlacza pod Atmega8. Używam Atmel Studio 6, wyświetlacz podłączyłem jak na schemacie powyżej (Każdy pin D do odpowiedniego D, piny E i RS jak na rysunku, RW do GND, zasilanie i rezystor 16K (nie miałem 10) do regulacji kontrastu). Przy regulacji kontrastu widziałem kwadraciki w jednej linii. Następnie po dodaniu do AS6 bibliotek c i h, stworzeniu najprostszego możliwego programu do wyświetlenia, na wyświetlaczu nic nie widać. Kod programu jaki używam:

    #include
    #include
    #include "HD44780.h"

    int main(void)
    {
    LCD_Initalize(); //inicjalizacja LCD
    LCD_GoTo(0, 0); //Ustawienie kursora w pozycji (0,0)
    LCD_WriteText("ADC");
    return 0;
    }

    OdpowiedzUsuń
    Odpowiedzi
    1. Zapomniałem zadać pytania ;)
      Czy ktoś ma jakiś pomysł co mogę robić źle? F_CPU jest zadeklarowane w Toolchain na 1MHz. Podłączenia sprawdzałem 100 razy, żadnych zwarć itp. brak. Nie mam już sił na ten wyświetlacz...

      Usuń
  41. Witam! Kod przerobiłem pod atmege32 taktowaną kwarcem 16MHz i wyświetlacz na ks0108. Na ekranie zamiast wartości napięcia pojawia się znak zapytania "U=? [V]" i nie mam pojęcia dlaczego. Dodam, że kompilacji dokonałem w Atmel Studio 6.
    Pozdrawiam

    OdpowiedzUsuń
    Odpowiedzi
    1. Dzięki! Już działa jak należy:)
      A może ktoś z was ma sposób jak to zrobić bez sprintf? Gdzieś widziałem takie rozwiązanie tylko nie mogę odnaleźć gdzie:(

      Usuń
  42. Mam pytanie ws wyświetlenia cyfr. Czy istnieje jakaś funkcja pozwalająca na wyświetlenie liczby w formacie dwucyfrowym czyli zamiast 2 żebym miał na wyświetlaczu 02. Potrzebuję użyć takiej funkcji do wyświetlenia daty i godziny. jak wiadomo godziny wyświetla sie w formacie hh:mm:ss np. 15:05:09 a nie 15:5:9. Pomógłby ktoś?

    OdpowiedzUsuń
    Odpowiedzi
    1. Tak, można takich cudów dokonać przy pomocy sprintf.

      Usuń
    2. ... a ja dodam, że szczegółów dowiesz się w artykule: Kurs języka C: Printf() i funkcje pochodne

      Usuń
  43. Witam. Mam pewien problem odnośnie pomiaru. Cały czas wyświetla się dla mnie skaczące napięcie w zakresie 0.000 - ok 0.160 potencjometr 5k mam podłączony między VCC i GND. Co może być problemem ?
    Występuje taki błąd przy kompilacji:
    main.c:59: warning: format '%1.3f' expects type 'double', but argument 3 has type 'float'

    OdpowiedzUsuń
  44. Czy jest możliwość określenia wartości rezystancji zamiast napięcia ? Jeżeli tak jakiego wzoru użyć ?

    OdpowiedzUsuń
  45. Dzień dobry,
    Borykam się z pewnym problemem.
    Zgodnie z kursem uruchomiłem ADC po kolei w trybach single conversion oraz free run.
    Na mojej płytce znajduje się również działający, wysyłający na LCD temperaturę termometr DS18b20.
    Kiedy uruchamiam przetwornik w trybie single conversion ( poprzez przycisk, bądź w pętli while(1)) problemu żadnego nie ma, jednak kiedy ADC pracuje w trybie free run w miejscu wyświetlania temperatury pojawiają się co jakiś czas różne 'dziwne' pomiary rzędu (100, 1300, -0.06), czasami uda się wskoczyć poprawnemu pomiarowi.
    Jest w stanie ktoś stwierdzić cóż to za zakłócenia występują w moim układzie?
    Pozdrawiam

    OdpowiedzUsuń
  46. Anonimowy z godziny 10:53
    Problemem jest źle napisany program lub źle fizycznie wykonany układ. Ponieważ nie pokazujesz ani kodu ani schematu, Pomóc Ci się nie da.

    Anonimowy z godziny 11:28
    Tak, poczytaj o dzielniku napięcia.

    Anonimowy z godziny 16:23
    Tak, masz źle napisany program. Ponieważ nie pokazujesz kodu źródłowego, nie można Ci pomóc.

    Swoją drogą moglibyście się jakoś podpisywać, byłoby o wiele łatwiej odpowiadać niż anonimowemu.

    OdpowiedzUsuń
    Odpowiedzi
    1. (Anonimowy z godziny 16:23)

      Proszę wybaczyć poprzednią anonimowość

      Kod źródłowy programu.
      main - http://wklej.org/id/1288953/
      ds18b20.c - http://wklej.org/hash/c27fc965eb1/
      ds18b20.h - http://wklej.org/id/1289013/
      obsługa lcd - biblioteka od radzia 4 bitowa bez flagi zajetosci

      Niestety nie posiadam schematu obwodu drukowanego. Jedynie zdjęcie poglądowe
      https://www.dropbox.com/s/45qahc433akxny3/IMAG0173a.jpg

      Z góry dziękuję za poświęcony czas i pomoc
      Pozdrawiam

      Usuń
    2. Dodatkowe zdjęcie z drugiej strony - https://www.dropbox.com/s/8umdc2yyug9czmf/IMAG0176.jpg
      k. elektrolityczny - 22nf
      reszta ceramiki - 100nF
      rezystor do ds18b20 - 4,7kOm
      reset - 10kOm

      Usuń
  47. A pokaż program z trybem single, który Ci działa. Porównam.

    OdpowiedzUsuń
    Odpowiedzi
    1. http://wklej.org/hash/d0dd87e9dee/

      Usuń
    2. Zrzut LCD z single mode - https://www.dropbox.com/s/3q0ma9jsr8z6z5n/IMAG0183.jpg
      Zrzut z Free mode -
      https://www.dropbox.com/s/as5ft556gvy9iog/IMAG0178.jpg
      https://www.dropbox.com/s/0ewmlyb06seneqh/IMAG0177.jpg

      Usuń
    3. I jest jakiś pomysł, w czym może tkwić błąd

      Usuń
    4. Załóż proszę temat na forum Elektrody i wrzuć tutaj link do niego.

      Usuń
  48. Czy usunięcie rezystora R2 10k nie doprowadzi do zwarcia, kiedy potencjometr "zjedzie" do zera?

    OdpowiedzUsuń
    Odpowiedzi
    1. Nie, gdyż +5V to dozwolone napięcie na wejściu ADC.

      Usuń
    2. Chodzi mi o zwarcie między punktem A i E
      Na schemacie "A" to +5V "E" to masa, opór na potencjometrze 0 om ?

      Usuń
    3. Ale to nie jest oddzielny rezystor tylko potencjometr - jeśli jest podłączony tak jak na schemacie to nie ma możliwości zwarcia A z E.

      Usuń
    4. Źle podłączyłem potencjometr, między A i E jest stale 10Kom, i oczywiście nie ma mowy o zwarciu.
      Proszę moderatora o usunięcie tego "żenującego" wątku.

      Usuń
    5. Każdy popełnia błędy - nie ma czego się wstydzić :-)

      Usuń
  49. Bardzo nie lubię używania arytmetyki zmiennoprzecinkowej gdzie ona jest niepotrzebna. W końcu po coś Atmel dał taką piękną wartość napięcia odniesienia jak 2,56V.
    Zamiast
    adc=ADC*VREF/1024;
    można spokojnie dać
    adc = ADC*10/4;
    otrzymując wartość w mV

    OdpowiedzUsuń
    Odpowiedzi
    1. Zgadza się lecz niestety należy pamiętać o fakcie, że napięcie odniesienia zwane potocznie 2,56V, może mieć np. w ATmega8 zakres od 2,3V do 2,9V - patrz parametr VINT (Internal Voltage Reference) w tabeli ADC Characteristics.

      Usuń
  50. Ten komentarz został usunięty przez autora.

    OdpowiedzUsuń
  51. Witam, korzystam z atmel studio 6.0, i żaden z przykładów nie chce mi się uruchomić. W pierwszym pojawia się komunikat „ ‘itoa’ was not declared in this scope „, oraz ostrzeżenie deprecated conversion from string constant to ‘char*’. Dodałem więc stdlib.h co spowodowało zniknięcie tego komunikatu i pojawienie się komunikatów typu: undefined reference to ‘LCD_WriteText(char*) kolejno do każdej z funkcji wyświetlacza. Powyższe komunikaty pojawiają się także w pozostałych przykładach. Plik HD4478.h znajduje się w folderze z plikiem zawierającym kod programu. Przeglądałem komentarze, i stosowałem te rozwiązania, ale nie pomagały. Tak więc proszę o cierpliwość i w miarę możliwości jakieś pomysły dot. tego co źle zrobiłem.

    OdpowiedzUsuń
  52. Problem rozwiązany, ściągnąłem bibliotekę do LCD bezpośrednio od autora, więc wymagała kilku zmian :).

    OdpowiedzUsuń
    Odpowiedzi
    1. Witam jakich zmian dokonałeś w bibliotece mam podobny problem :)

      Usuń
    2. Nazwy portów trzeba zmienić, szybciej będzie jak weźmiesz biblioteki z załączonych przykładów.

      Usuń
  53. Nie działają linki z kodami oraz schematami. Jest szansa na naprawę?

    OdpowiedzUsuń