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.
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.56na
#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:
Witam Panie Drzaśku :) Piszę do pana z następującym pytaniem.
OdpowiedzUsuń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? :)
Nie znam specyfikacji tego czujnika, nie używałem go więc nie powiem wprost.
OdpowiedzUsuń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.
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ń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ń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ńMówimy o tym samym, tylko innymi słowami :)
OdpowiedzUsuń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ł.
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ń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 :)
OdpowiedzUsuń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ć :)
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ń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ń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
OdpowiedzUsuń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.
To pokaż zdjęcie, bo nie wiem co wg ciebie znaczy, "i nic" albo "wyświetlacz strasznie ciemny".
OdpowiedzUsuń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.
OdpowiedzUsuńhttp://imageshack.us/a/img692/1852/dscf9316d.jpg
Skoro masz uszkodzone podświetlenie to ja Ci go niestety nie naprawię :)
OdpowiedzUsuńKontrast regulowałeś?
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ń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ńNie rozumiem tylko jednego zapisu U=%1.3f Dlaczego akurat tyle?
OdpowiedzUsuń%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.
OdpowiedzUsuńWięcej na ten temat znajdziesz tutaj: instrukcja printf( )
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ńA dodadłeś do projektu biblioteki?
OdpowiedzUsuńlibm.a.
libprintf_flt.a
Przygotowałem artykuł na ten temat, by nie było wątpliwości: Problem znaku zapytania podczas konwersji float do znaków ASCII w celu wyświetlenia na np. LCD itp.
Usuń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ńMiało być #define ale coś mi to wycięło ;)
OdpowiedzUsuńNo coż, tak to wychodzi jak się pisze w nocy...
OdpowiedzUsuńMiałem na myśli włączenie pliku stdio.h, więc powinno to wyglądać tak: #include <stdio.h>
Przepraszam za zamieszanie.
Witam,
OdpowiedzUsuń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 :)
Czy w opcjach zmieniłeś wartość kwarcu? Link: F_CPU – gdzie definiować?
OdpowiedzUsuńNiestety, niewiele to pomogło. Chociaż teraz zamiast losowych w różnych miejscach mam jeden zawsze w tym samym ^^'
OdpowiedzUsuńSzkoda, że nie masz kwarcu 16MHz bo mógłbyś sprawdzić wgrywając plik HEX znajdujący się w spakowanym pliku.
OdpowiedzUsuń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).
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'
OdpowiedzUsuńa na wyświetlaczu U=?
Witam,
OdpowiedzUsuń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:)
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ń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ńKoledzy, może mi ktoś powiedzieć skąd mogę pobrać biblioteki libm.a oraz libprintf_flt.a, bo nie mogę ich znaleźć.
OdpowiedzUsuńAnonimowy z 14 marca 2013 17:08:
OdpowiedzUsuń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?
Witam.
OdpowiedzUsuń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 ?
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ń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ńA może tak napisz coś więcej?
OdpowiedzUsuńCo zrobiłeś? napisałeś własny program? To pokaz kod.. wróżyć niestety nie umiemy.
Mam takie pytanie? Co dokładnie robi parametr %1.3f w sprintf? Niestety nie mogę do tego dojść.
OdpowiedzUsuń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ńWitam,
OdpowiedzUsuń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;
}
Zapomniałem zadać pytania ;)
Usuń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...
Zadałeś pytanie na forum więc tam rozwiążemy Twój problem: [ATMEGA8A / L] - oraz HD44780 i Atmel Studio 6, brak wyświetlanych znaków
Usuń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.
OdpowiedzUsuńPozdrawiam
Witaj.
UsuńPrzeczytaj ten artykuł: Problem znaku zapytania podczas konwersji float do znaków ASCII w celu wyświetlenia na np. LCD itp.
Pozdrawiam!
Dzięki! Już działa jak należy:)
Usuń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:(
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ńTak, można takich cudów dokonać przy pomocy sprintf.
Usuń... a ja dodam, że szczegółów dowiesz się w artykule: Kurs języka C: Printf() i funkcje pochodne
Usuń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 ?
OdpowiedzUsuńWystępuje taki błąd przy kompilacji:
main.c:59: warning: format '%1.3f' expects type 'double', but argument 3 has type 'float'
Czy jest możliwość określenia wartości rezystancji zamiast napięcia ? Jeżeli tak jakiego wzoru użyć ?
OdpowiedzUsuńDzień dobry,
OdpowiedzUsuń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
Anonimowy z godziny 10:53
OdpowiedzUsuń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.
(Anonimowy z godziny 16:23)
Usuń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
Dodatkowe zdjęcie z drugiej strony - https://www.dropbox.com/s/8umdc2yyug9czmf/IMAG0176.jpg
Usuńk. elektrolityczny - 22nf
reszta ceramiki - 100nF
rezystor do ds18b20 - 4,7kOm
reset - 10kOm
A pokaż program z trybem single, który Ci działa. Porównam.
OdpowiedzUsuńhttp://wklej.org/hash/d0dd87e9dee/
UsuńZrzut LCD z single mode - https://www.dropbox.com/s/3q0ma9jsr8z6z5n/IMAG0183.jpg
UsuńZrzut z Free mode -
https://www.dropbox.com/s/as5ft556gvy9iog/IMAG0178.jpg
https://www.dropbox.com/s/0ewmlyb06seneqh/IMAG0177.jpg
I jest jakiś pomysł, w czym może tkwić błąd
UsuńZałóż proszę temat na forum Elektrody i wrzuć tutaj link do niego.
UsuńCzy usunięcie rezystora R2 10k nie doprowadzi do zwarcia, kiedy potencjometr "zjedzie" do zera?
OdpowiedzUsuńNie, gdyż +5V to dozwolone napięcie na wejściu ADC.
UsuńChodzi mi o zwarcie między punktem A i E
UsuńNa schemacie "A" to +5V "E" to masa, opór na potencjometrze 0 om ?
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ńŹle podłączyłem potencjometr, między A i E jest stale 10Kom, i oczywiście nie ma mowy o zwarciu.
UsuńProszę moderatora o usunięcie tego "żenującego" wątku.
Każdy popełnia błędy - nie ma czego się wstydzić :-)
Usuń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.
OdpowiedzUsuńZamiast
adc=ADC*VREF/1024;
można spokojnie dać
adc = ADC*10/4;
otrzymując wartość w mV
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ńTen komentarz został usunięty przez autora.
OdpowiedzUsuń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ńProblem rozwiązany, ściągnąłem bibliotekę do LCD bezpośrednio od autora, więc wymagała kilku zmian :).
OdpowiedzUsuńWitam jakich zmian dokonałeś w bibliotece mam podobny problem :)
UsuńNazwy portów trzeba zmienić, szybciej będzie jak weźmiesz biblioteki z załączonych przykładów.
UsuńNie działają linki z kodami oraz schematami. Jest szansa na naprawę?
OdpowiedzUsuń