Redakcja: dondu
Drzaśkowy pamiętnik: Spis treści
Mając już za sobą zabawę z diodami, zmianę częstotliwości i źródła zegara przyszła pora zatrudnić uC do czegoś poważniejszego. Bo przecież mruganie diodami, to żadna atrakcja. Czas coś zmierzyć!!!
Większość wielkości w przyrodzie zmienia się w sposób ciągły-analogowy. Światło, temperatura, ciśnienie, wilgotność, prąd, napięcie, rezystancja, pojemność, indukcyjność itd. Wszystkie te wielkości przyjmują pewną wartość w danej chwili czasu. Zmieniają się, albo narastają, albo maleją, albo też utrzymują się na pewnym poziomie przez jakiś czas.
Jak więc wielkość analogową przetworzyć do postaci cyfrowej?
Tutaj z pomocą przychodzi Przetwornik Analogowo-Cyfrowy (ADC - ang. Analog to Digital Converter)
Przetwornik ogólnie mierzy napięcie i przedstawia je w postaci cyfrowej. Każdą wielkość w przyrodzie można przedstawić w postaci napięciowej, a zatem zmierzyć przetwornikiem A/C.
Większość mikrokontrolerów AVR ma na swoim pokładzie ADC. Co prawda nie są to jakieś super szybkie i dokładne przetworniki, ale do większości amatorskich zastosowań w zupełności wystarczają.
Jak skorzystać z wbudowanego przetwornika?
Jak zwykle w przypadku uruchamiania nowych peryferii najlepszym i najpewniejszym źródłem wiedzy jest datasheet. ATmega8, z której korzystałem do tej pory, posiada przetwornik ADC więc pora na lekturę noty katalogowej mojego mikrokontrolera: ATmega8 datasheet
Dobrym źródłem bardziej ogólniejszej wiedzy jest także dokument firmy Atmel o symbolu AVR120:
AVR120: Characterization and Calibration of the ADC on an AVR
Na samym początku rozdziału dotyczącego ADC (w datasheet Atmegi) jest ogólny opis parametrów przetwornika:
Rys. 1 - Parametry przetwornika ADC ATmega8 |
Wychwyciłem najważniejsze informacje:
- max 10 bitowa rozdzielczość
- czas konwersji 13-260us
- max częstotliwość próbkowaniu przy 10 bitach rozdzielczości to 15 kHz
- 6 lub 8 multipleksowanych wejść, w zależności od typu obudowy
Które to wejścia i ile ich jest?
Najlepiej widać to na samym początku datasheet-a, gdzie przedstawiony jest zarys poszczególnych typów obudów wraz z opisem pinów (nóżek):
Rys. 2 - "Pinologia" ATmega8 |
ATmega8 w obudowie DIP, którą zastosowałem, jak widać posiada 6 multipleksowanych wejść na pinach 0-5 portu C:
Rys. 3 - Wyprowadzenia ATmega8 dla obudowy typu DIP. |
Kolejna ważna informacja to zakres napięć wejściowych wynoszący 0-VCC.
Jednym słowem NIE WOLNO mierzyć za pomocą ADC sygnałów przekraczających napięcie zasilania mikrokontrolera.
Możliwe jest uruchomienie przetwornika w jednym z dwóch trybów pracy:
- Single Conversion – jak sama nazwa wskazuje jest to pojedyncza konwersja (pomiar).
- Free Running- ciągła konwersja (pomiary jeden po drugim)
Skoro znam już możliwości ADC w Atmega8 to pora spróbować go uruchomić.
Skorzystałem z tego samego układu który stosowałem do tej pory, czyli ATmega8, 16MHz kwarc, 2 diody i klawisz jako interfejs.
Pozostała kwestia zasilania części analogowej mikrokontrolera oraz podłączenia źródła napięcia mierzonego. Warto więc zajrzeć co datasheet, mówi o podłączeniu zasilania do ADC:
Rys. 4 - Zasilanie części analogowej ATmega8. |
Pora więc zaprojektować schemat:
Rys. 5 - Schemat mojego projektu. |
Pobierz schemat w wersji Eagle: schemat.rar
Na początek uruchomiłem przetwornik ADC z wewnętrznym napięciem referencyjnym (dla Atmega8 jest to 2.56V) dlatego pin AREF pozostał podłączony przez kondensator do masy.
W celu eliminacji zakłóceń zasilanie przetwornika (AVCC) zgodnie z DS zostało podłączone (zgodnie z rys. 4) przez filtr LC(10µH/100nF). Więcej szczegółów w tej sprawie znalazłem tutaj: ADC - Dokładność vs podłączanie
Jako źródło napięcia mierzonego użyłem potencjometr 10k w szeregu z rezystorem 10k.
Potencjometr z rezystorem będący dzielnikiem napięcia w takiej konfiguracji będzie regulował napięcie wejściowe dla ADC na Pinie 5 Pirtu C w zakresie 0-2.5V.
Dlaczego tak?
Ponieważ napięcie może być mierzone z zakresu 0-VREF i bezwzględnie nie może przekraczać VCC Stąd dodałem rezystor 10K w szeregu z potencjometrem, by nie tracić na rozdzielczości potencjometru.
Każda wartość napięcia w zakresie VREF-VCC podana na wejście ADC będzie odczytywana jako wartość max dla danej rozdzielczości przetwornika, czyli dla 10 bitów będzie to 1023, a więc 0x3FF.
Przy doborze takiego dzielnika napięcia na wejściu należy stosować nie duże wartości rezystancji, aby wynik konwersji był jak najlepszy. Cytat z noty Atmel-a: Atmel AVR120:
Dlatego przy dzielnikach napięcia lub źródłach napięcia o dużej impedancji wyjściowej dobrym przyzwyczajeniem jest stosowanie buforów wejściowych o niskiej impedancji wyjściowej, np wtórnik napięcia na WO. Jednak dla tak prostego doświadczenie jakie tutaj chciałem wykonać, dzielnik na takich rezystorach wystarczy.
Następnie musiałem podjąć decyzję z jaką częstotliwością ma ADC dokonywać pomiaru. Z dokumentacji dowiedziałem się, że zegar "napędzający" przetwornik ADC ma pewne ograniczenia:
Ponieważ mój mikrokontroler jest taktowany przez zewnętrzny kwarc 16MHz, stąd musiałem użyć prescalera ADC (patrz. rys. 6). Musiałem więc się dowiedzieć coś na ten temat i znalazłem to:
Prescaler, postscaler - Co to takiego?
Postanowiłem użyć największego prescalera ADC czyli 128. Po policzeniu:
okazało się, że mieszczę się w prawidłowym zakresie 50-200kHz dla 10 bitowej dokładności pomiaru.
Start konwersji (pomiaru)
Do projektu dodałem klawisz na pinie 0 portu C (PC0), który posłużył mi do wyzwalania pojedynczej konwersji (pomiaru). Diody wyświetlać będą zdeklarowane w programie poziomy napięcia.
Teraz przyszła pora na wydawać, by się mogło najtrudniejszą część zabawy z przetwornikiem - napisanie programu. :-)
Strasznie to tylko wyglądało na początku. Nie trzeba jednak korzystać nawet z żadnych gotowców, wszystko jest bardzo jasno i czytelnie wyjaśnione w datasheet.
Rzut okiem na schemat blokowy:
Rys. 6 - ADC w ATmega8 |
Jak widać ADC posiada 3 rejestry:
- 8 bitowy rejestr ADMUX jak widać ze schematu oraz nazwy służy do ustawiania multiplekserów,
- 8 bitowy rejestr ADCSRA – ADC Control and Status Register A,
- 16 bitowy rejestr ADC (ADCH/ADCL) - The ADC Data Register, w którym przechowywana jest zmierzona wartość napięcia.
Zacząłem od rejestru ADCSRA:
W opisie pod tabelką znalazłem informację, że:
- dla preskalera 128 powinienem ustawić jedynkę na bitach ADPS2, ADPS1 i ADPS0.
- ustawić jedynkę na bicie ADEN, by włączyć przetwornik ADC.
ADCSRA = (1<<ADEN) //ADEN=1 włączenie przetwornika ADC) |(1<<ADPS0) // ustawienie preskalera na 128 |(1<<ADPS1) |(1<<ADPS2)
Następnie przyszła kolej na rejestr ADMUX.
ADMUX = (1<<REFS1) | (1<<REFS0) // REFS1:0: wybór napięcia odniesienia ADC //na wewnętrzne źródło 2,56V //z zewnętrznym kondensatorem na pinie AREF |(1<<MUX2) | (1<<MUX0);// wybór kanału ADC5 na pinie PC5
Teraz pozostało tylko scalić program i dopisać obsługę ma na celu przetestowanie trybu pojedynczej konwersji na żądanie (wciśniecie klawisza).
Cały kod programu:
#include <avr/io.h> #define LED1 PB0 //definicja LED1 (do którego pinu podłączony LED1) #define LED2 PB1 //definicja LED2 (do którego pinu podłączony LED2) #define KLAWISZ PC0 //definicja KLAWISZ (do którego pinu podłączony klawisz) #define ADCIN PC5 //definicja ADCIN (wejście ADC) int main(void) { //Uruchomienie ADC, wewnętrzne napiecie odniesienia, tryb pojedynczej konwersji, preskaler 128, wejście PIN5, wynik do prawej ADCSRA = (1<<ADEN) //ADEN: ADC Enable (uruchomienie przetwornika) //ADPS2:0: ustawienie preskalera, preskaler= 128 |(1<<ADPS0) |(1<<ADPS1) |(1<<ADPS2); ADMUX = (1<<REFS1) | (1<<REFS0) //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 ) //ustawienie wejśc/wyjść DDRB |= (1<<LED1) | (1<<LED2); //Ustawienie pinów sterujących diodami jako wyjścia DDRC=0xff; //Nieużywane Piny na porcie C jako wyjścia DDRC &=~ (1<<KLAWISZ); //Ustawienie pinu klawisza jako wejście DDRC &=~ (1<<ADCIN); //Ustawienie Wejścia ADC PORTC |= (1<<KLAWISZ); //Pull_up klawisz for(;;)//pętla główna { if(!(PINC & (1<<KLAWISZ)))//jeśli klawisz wciśniety { ADCSRA |= (1<<ADSC); //ADSC: uruchomienie pojedynczej konwersji while(ADCSRA & (1<<ADSC)); //czeka na zakończenie konwersji if(ADC<350)//jeśli wynik ADC mniejszy od 350 gasi obydwie diody { PORTB &=~ (1<<LED1); PORTB &=~ (1<<LED2); } else if(ADC<700)//jeśli 700>ADC>=350 LED1 świeci { PORTB |= (1<<LED1); PORTB &=~ (1<<LED2); } else //jeśli ADC>=700 świecą obydwie diody { PORTB |= (1<<LED1); PORTB |= (1<<LED2); } } } }Pobierz program: adc.rar
Program działa w następujący sposób:
Po uruchomieniu programu obydwie diody nie świecą się, ponieważ nie było żadnego uruchomienia konwersji. Naciśnięcie klawisza powoduje porównanie 10 bitowego wyniku z rejestru ADC z zdeklarowanymi wartościami i odpowiednie zapalenie/zgaszenie diod. Konwersja jest pojedyncza za każdym razem, kiedy nastąpi naciśnięcie klawisza.
Przeczytaj także:
Nie rozumiem. Wynik ADC tutaj zależy od mierzonego napięcia? Np. dioda LED zapali się po osiągnięciu 7v?
OdpowiedzUsuńPisałem, że wartość napięcia mierzonego nie może przekraczać napięcia referencyjnego czyli w powyższym przypadku 2.56V.
OdpowiedzUsuńWartości w warunkach if() są to wartości z rejestru ADC, nie są one wartościami napięcia w Voltach.
Przetwornik 10 bitowy a więc może zmierzyć 2^10 stanów a więc 1024.
Czyli od 0 do 1023.
Wartość max przetwornika a więc 1023 w powyższym przypadku odpowiada napięciu referencyjnemu.
Jak z otrzymanej wartości z przetwornika obliczyć napięcie jest wyjaśnione w DS ale będę o tym pisał w kolejnych częściach artykułu o ADC.
Witam. Mam mały problem ;) Korzystam z trybu free run. Program działa tak: po przyłożeniu do pinu ADC napięcia 0,625V zapala się dioda 1, przy 1,25V zapala dwie diody, przy 1,875V zapala trzy diody. Tu program działa ok. Przy zdjęciu napięcia z ADC np dla 1,875V diody gasną po kolei od ostatniej do pierwszej, a chcę uzyskać działanie takie, że po zdjęciu napięcia z ADC mają gasnąć od razu wszystkie.
OdpowiedzUsuńWarunki na wartość ADC mam podobnie jak w artykule w if-ach, ale korzystam z przerwania ISR(ADC_vect), w którym mam te warunki.
Witam.
OdpowiedzUsuńTrudno jest cokolwiek doradzić nie widząc kodu programu.
No tak ;)
OdpowiedzUsuń#define F_CPU 1000000UL
#include
#include
#include
#define led0 (PB0 << 1)
#define led1 (PB1 << 1)
#define led2 (PB2 << 1)
#define led3 (PB3 << 1)
#define led4 (PB4 << 1)
#define led5 (PB5 << 1)
#define led6 (PB6 << 1)
#define led7 (PB7 << 1)
float fConvResult;
uint8_t pomiar;
ISR(ADC_vect)
{
if ((ADC > 240) && (ADC <= 470)) PORTB = 0b00000001; //zmierzone napięcie 0.63V - wartość 252
else if ((ADC > 470) && (ADC <= 720)) PORTB = 0b00000011; //zmierzone napięcie 1.24V - wartość 496
else if ((ADC > 720) && (ADC <= 770)) PORTB = 0b00000111; //zmierzone napięcie 1.86V - wartość 744
else PORTB = 0x00;
}
void InitADC(void)
{
ADMUX = _BV(REFS0) | _BV(REFS1);
ADCSR = _BV(ADEN) | _BV(ADIE) | _BV(ADFR) | _BV(ADSC)
| _BV(ADPS0) | _BV(ADPS1);
}
main()
{
DDRB = 0xff;
InitADC();
sei();
while(1)
{
}
}
Tak jak pisałem przykładanie napięcia działa ok. Podczas zdejmowania go z pinu ADC diody gasną po kolei, a chcę aby zgasły wszystkie na raz.
Witam.
OdpowiedzUsuńPo pierwsze, to definicje ledów masz źle napisane.
Np:
#define led3 (PB3 << 1)
wbrew temu co myślisz to nie jest
00001000
ale
00000110
A dlaczego?
Bo tak napisałeś.
PB3 to liczba 3.
Liczba 3 binarnie to 00000011
ale ty ją przesuwasz w lewo o 1 więc dlatego masz 00000110.
Najpierw powinieneś dać 1 czyli 00000001 a potem przesuwać w lewo o x pozycji czyli np:
#define led3 (1 << PB3)
Co do tego gaśnięcia powoli, to jaki mniej więcej jest odstęp czasowy między wygaszaniem kolejnych diod?
Spróbuj wyciągnąć te warunki z przerwania do pętli głównej, a w przerwaniu tylko przepisuj wynik ADC do jakiejś zmiennej.
Rzeczywiście z tą deklaracją led zrobiłem źle :)
OdpowiedzUsuńPomimo dania warunków do pętli głównej while(1) efekt pozostał taki sam.
Jeżeli podam 1,875V i zdejmę to diody gasną po kolei w sumarycznym czasie około 1-2 sekund. Wygląda to tak jakby rozładowywał się jakiś kondensator podłączony do diod.
Jeżeli chodzi o podłączenie to zwarłem przez 100nF AREF z GND oraz AVCC z GND (też przez 100 nF).
Jak zmienię w warunkach na
if ((ADC> 240) && (ADC <= 470)) PORTB = 0b00000001;
else if ((ADC > 470) && (ADC <= 720))PORTB = 0b00000010;
else if ((ADC > 720) && (ADC <= 770))PORTB = 0b00000100;
else PORTB = 0x00;
to po zdjęciu napięcia z pinu ADC gaśnie led2, zapala i gaśnie led1, zapala i gaśnie led0. Trwa to około 1-2 sekund.
Jak podłączasz to napięcie? Bezpośrednio do nogi procesora, czy przez jakiś dzielnik/bufor?
OdpowiedzUsuńI w jaki sposób je odłączasz? Odłączając całkowicie przewód od nogi uC pozostawiając ją wolną?
Układ mam zbudowany na płytce stykowej. Napięcie podaję bezpośrednio przewodem na nogę ADC z dzielnika napięcia. Dzielę Vcc na 8 rezystorach, czyli mam na jednym 0,625V. Podłączam i odłączam napięcie do ADC przewodem, tzn dotykam bądź nie dotykam pinu ADC. Czyli tak jak piszesz, odłączając zostawiam pin uC wolny.
OdpowiedzUsuńWystarczyło ściągnąć pin ADC do masy przez 100kOhm ;)
OdpowiedzUsuńWitam, mam mały problem ponieważ ten program (ani żaden inny do obsługi ADC) mi nie działa :( Posiadam płytkę testową od Kamami ZL2AVR, podłączone jest wszystko ok, kod dosłownie skopiowany żywcem, a mimo to ADC nie pracuje. Jakieś pomysły dlaczego?
OdpowiedzUsuńa jak zrobić żeby cały czas mi odczytywało wartość z potencjometru bez przyciskania przyciska?
OdpowiedzUsuńPoczytaj następne części pamiętnika.
OdpowiedzUsuńPanie Drzaśku zapomniał Pan dodać, jak się wybiera dane porty. Np. że coś mam podłączone pod PC0 a nie pod z góry założony port PC5
OdpowiedzUsuńNoto czytaj następne części artykułów, jest tam również wybór wejść.
OdpowiedzUsuńChyba coś jest nie tak z tym kodem, przekopiowałem na ,,żywca'' i nie działa tak jak powinien. W tekście jest napisane: ,,Po uruchomieniu programu obydwie diody nie świecą się''
OdpowiedzUsuńu mnie od razu się świecą, a przycisk nie działa (przetestowałem go na innym kodzie czy jest dobrze podłączony, zapalał i gasił diody). Nie ważne, czy mam włożony potek i rezystor, czy nie, one i tak świecą. Przestają jedynie jeśli zmieniam warunki w if'ie. Układ mam zbudowany na Atmedze 8A
Musisz pokazać kompletny schemat podłączenia. Coś mogłeś pokręcić, uszkodzić uC.Diody nie mogą świecić, jeśli nie zostaje wciśnięty przycisk, bo wartość początkowa rejestru ADC jest 0.
OdpowiedzUsuńhttp://imageshack.us/photo/my-images/138/dscf9313k.jpg/
OdpowiedzUsuńhttp://imageshack.us/photo/my-images/854/dscf9311p.jpg/
http://imageshack.us/photo/my-images/222/dscf9310h.jpg/
Proszę, zdjęcia z trzech różnych ujęć.
Kurcze, straszny bałagan tam masz, ciężko się poznać.
OdpowiedzUsuńMasz po obydwu stronach płytki szyny zasilające (czerwona - czyli jak wiadomo +) i niebieska/czarna czyli -/masa itd. A ty używasz jakoś na przemian ich, masz je razem chyba połączone czy coś. Nie wiem, ale ciężko się takie coś analizuje.
uC daje się bez problemu programować?
Skompiluj i wgraj następujący program i daj znać o efektach:
#include
#define LED1 PB0
#define LED2 PB1
void main(void)
{
DDRB |= (1<<LED1) | (1<<LED2); for(;;);
}
NO procesor bez problemu daje się programować. A ten kod to nic nie robi ;p chyba chodziło Ci o coś takiego?:
OdpowiedzUsuń#include
#define LED1 PB0
#define LED2 PB1
void main(void)
{
DDRB |= (1<<LED1) | (1<<LED2);
for(;;){
PORTB |= (1<<LED1);
PORTB |= (1<<LED2);
}
}
Diody mi świecą, pisałem już wcześniej, że testowałem też przycisk i działał. Co do masy to zrobiłem ją na szynach, a + mam tak jakby na środku, widać, że wszystkie czerwone(pomarańczowe) kabelki zbiegają się w jednym punkcie za stabilizatorem.
Tak, program miał nic nie robić.
OdpowiedzUsuńChodziło mi o to, abyś sprawdził, czy diody mimo tego, że nie powinny się zaświecać, się zaświecają.
Z kodem ma być wszystko w porządku, nie wrzucam tutaj niesprawdzonych programów. Jak widać wyżej w komentarzach, układ zadziałał u innych osób, jedyne problemy to właśnie ich błędy w podłączeniu itd.
Więc musisz narysować mi dokładnych schemat z wszystkimi elementami jakie masz na płytce. Ale nie przerysowując z mojego schematu, ale patrząc na płytkę po kablach, narysuj tak jak to podłączyłeś. Najprawdopodobniej coś poknociłeś w podłączeniu.
W czym narysować, np. w Eaglu? Pierw spróbuje połączyć jeszcze raz a jak nie pójdzie, to wtedy narysuję.
OdpowiedzUsuńOdpowiem za Drzaśka: Tak w Eaglu.
OdpowiedzUsuńDobra działa ;D Potencjometr zwierał dwiema nóżkami. Należało go obrócić o 90 stopni. W międzyczasie zdążyłem usmażyć już jedną Atmegę ;p
OdpowiedzUsuńWitam,
OdpowiedzUsuńmam takie pytanie (może lamerskie, ale dopiero zaczynam - to mój pierwszy projekt).
Chciałbym odczytać rezystancję termistora (podłączonego pod Vcc=5V). Intersuje mnie odczyt z przedziału 10 K Ohm - 900 K Ohm.
W jaki sposób go podłączyć do mikrokontrolera, i jak dobrać rezystory, tak, żeby otrzymać napięcie z przedziału 0 - 5V (lub 0V - 2.5V)?
Sposobów jest wiele.
OdpowiedzUsuńMożesz dobrać rezystor równy wartości maksymalnej rezystancji termistora czyli 900 kOhm.
Połącz równolegle rezystor z termistorem. Wolną nogę termistora podłącz do masy a wolną nogę rezystora do 5V. Ustaw napięcie referencyjne 2.56V. Jeśli termistor będzie miał rezystancję 900 kOhm to dostaniesz dzielnik napięcia przez połowę więc napięcie w punkcie połączenia rezystorów wyniesie 2.5V.
Jeśli termistor będzie zmniejszał swoją rezystancję to napięcie będzie malało.
Poczytaj jak działa dzielnik napięcia.
Taki sposób jest prosty i będzie działał, ale wprowadzi pewne błędy w pomiar ADC, bo jest to dzielnik napięcia na dużych rezystorach. W praktyce dobrze byłoby zastosować wtórnik napięcia na jakimś WO.
Dzięki za odpowiedź!
OdpowiedzUsuńNiebawem sprawdzę, czy dokładność jest wystarczająca i ewentualnie kombinował na wtórniku.
Przymierzam sie do tego projektu. Pytanie czy na Attiny dobrze ustawione bity to:
OdpowiedzUsuń1.Prescaler adc na 8 przy 1Mhz czyli 125kzh bo 13.260qs resolution
czyli ADPS0, ADPS1 ustawić
2.Właczenie kompaktora
ustawić ADEN
3.ADMUX czyli MUX1 ustawic aby wykorzystywac kanal 1 na PB2
4.Czy REFS0 to wybór napiecia odniesienia, które wybrać aby działało przy tym schemacie?
VCC used as analog reference.
Internal Voltage Reference
Witam, na wstępie wielgachne dzięki za te artykuły. Bardzo pomocne:-)
OdpowiedzUsuńA pytanie mam takie, ponieważ rozkręciłem swoje radio RC, a tam atmelek: Mega48PA. Bardzo proste radio, sterowanie tylko serwomechanizmami, bez dodatkowych opcji.
Przyglądam się podłączenim potencjometrów i o dziwo jest tam dodatkowy opornik wraz z kondesatorem.
Opornik oznaczony jako 101, czyli 1kOhm podłączony jest w miejscu wyjścia zmiennego napięcia z potencjometru do ADC.
Kondensator bez opisu, jest on podłączony do linii mierzonego napięcia (ADC) i GND.
No i teraz nasuwa mi się pytania czy one są tam potrzebne zawsze (bez względu na projekt),
czy widocznie w tym projekcie są wymagane?
Przeglądnąłem trochę internetu w poszukiwaniu tej odpowiedzi i zawsze jak coś znalazłem to potencjometr
był "wprost" podłączony pod mikrokontroler (w szczegółności w przypadku arduino).
Zygmunt
Witaj.
Usuń101 to 10 x 10¹ = 100Ω, a nie 1kΩ
Jeśli dobrze zrozumiałem to rezystor ten wraz z kondensatorem i potencjometrem tworzy filtr RC, na wejściu pomiarowym ADC. Sądzę, że osoba która zaprojektowała to urządzenie chciała zabezpieczyć się przed sytuacją, gdy potencjometr zostanie ustawiony w takim położeniu, że będzie bez jakiejkolwiek rezystancji zwierał do wyjścia napięcia zmiennego, o którym piszesz.
Innymi słowy w takiej sytuacji będziesz miał zawsze filtr RC złożony co najmniej z rezystora 101 i kondensatora. To dobrze świadczy o projektancie :-)
> 101 to 10 x 10¹ = 100Ω, a nie 1kΩ
UsuńRacja, coś pomieszałem.
Dzięki za informacje:-)
Zygmunt
Witam, mam problem z uruchomieniem pańskiego programu, podobny jak kolega Chwali Chwallus, z tym że po załadowaniu do mojej atmegi (atmega8) programu który pan polecił diody się świecą mimo iż nie powinny czy to ozancza, że mój procesor jest już uszkodzony? czy są jakieś inne powody?
OdpowiedzUsuńPrawdopodobnie robisz jednak coś nie tak. Niestety odpowiadam z wielkim opóźnieniem (przegapiłem Twój post) stąd pewnie już temat jest rozwiązany.
UsuńWitam, mam pewien dziwny problem z ADC. Działa 0-1 o_0.
OdpowiedzUsuńMam złożone wszystko według schematu (jedynie potek mam 5k a rezystor 7,5 co daje maks 2v na wejściu ADC. Nie ma reakcji na klawisz, jedynie reset sprzętowy budzi ADC do życia ale i tak tylko albo gasną wszystkie ledy albo świecą. Dodam iż moja atmega przeżyła odwrotną polaryzację. Czy to mogło uszkodzić ADC?
Odwrotna polaryzacja niestety mogła uszkodzić spor w mikrokontrolerze.
UsuńDobrze byłoby byś pokazał schemat i zdjęcia, stąd najlepiej załóż temat na naszym forum, a tutaj wklej link, bym wiedział gdzie zaglądnąć.
OdpowiedzUsuńWitam, wykonałem taki sam schemat jedyne co to usunąłem przycisk i wprowadziłem adekwatne do tego zmian w programie. Układ jest dobrze podłączony, sprawdziłem miernikiem na pini PC5 uzyskuję od 0 do 4,3 V kręcąc potencjometrem, a co bym nie zrobił to cały czas palą mi się diody.
OdpowiedzUsuńOto mój kod.
#include
#define LED1 PB0
#define LED2 PB2
#define ADCIN PC5
int main(void)
{
ADCSRA = (1<<ADEN)|(1<<ADPS1)|(1<<ADPS0);
ADMUX =(1<<REFS0)|(1<<MUX2)|(1<<MUX0);
DDRB |= (1<<LED1)|(1<<LED2);
DDRC &=~ (1<<ADCIN);
while(1)
{
ADCSRA |= (1<<ADSC);
while(ADCSRA & (1<<ADSC));
if(ADC<350)
{
PORTB &=~ (1<<LED1);
PORTB &=~ (1<<LED2);
}
else if(ADC<700)
{
PORTB |= (1<<LED1);
PORTB &=~ (1<<LED2);
}
else
{
PORTB |= (1<<LED1);
PORTB |= (1<<LED2);
}
}
}
Twój program wygląda na poprawnie przerobiony. Powinien więc działać. Skoro na PC5 masz poprawne napięcia, to ... hmm, dobrze byłoby rzucić na to okiem. Załóż może temat na forum, a tutaj wklej link, bym wiedział gdzie trafić.
UsuńNa forum zamieść kod, zdjęcia, link do tego tematu i schemat z poprawkami - możesz zrobić je na tej grafice Paint'em.
Proszę bardzo
Usuńhttp://www.elektroda.pl/rtvforum/viewtopic.php?p=14403119#14403119
... a przyczyną było podłączenie pinu AREF do masy co powodowało, że napięcie odniesienia wynosuło 0V, i dlatego przetwornik zawsze odczytywał maksymalną wartość. Zdjęcia to potwierdziły ... tak czasami bywa :-)
UsuńZgubiłem się gdzieś podczas czytania tego.Miejsce zapisu odczytanej wartości jest jedno dla wszystkich wejść w i gdy chcemy po sobie zmierzyć kilka wartości musimy zrobić odczyt i potem zapis odczytanej wartości do ustalonej wcześniej zmiennej potem znowu odczyt i zapis do kolejnej zmiennej ... Tak ?
OdpowiedzUsuńJeśli masz taką potrzebę to tak. Może to być np. zmienna tablicowa.
UsuńInnymi słowy rejestr ADC może przechowywać wartość tylko ostatniego pomiaru.
Czy teraz jest już jasne?
Witam serdecznie.
OdpowiedzUsuńZacznę od tego, że rozpoczynanie nauki po czterdziestce nie jest łatwe ale bez Was byłoby jeszcze trudniejsze. Wielkie dzięki!
Od kilku tygodni praktykuję z Arduino i stopniowo zaczynam używać "prawdziwego C" w szkicach.
A oto pytania:
Czy po pojedynczej konwersji praktykuje się wyłączenie ADC (wyzerowanie ADEN)?
Czy wyłączenie ADC spowoduje utratę wyniku konwersji (ADCH/ADCL)?
Czy zerowanie ADEN po instrukcji return ma sens?
unsigned int ADCreadPinA0(void)
{
ADMUX = (1<<REFS0);
ADCSRA = (1<<ADEN) |(1<<ADPS0) |(1<<ADPS1) |(1<<ADPS2);
DIDR0 |= (1<<ADC0D);
ADCSRA |= (1<<ADSC);
while(ADCSRA & (1<<ADSC));
return(256*ADCH +ADCL);
ADCSRA &= ~(1<<ADEN);
}
Nie, ne ma sensu po konwersji wyłączać ADC, chyba, że chodzi o oszczędzanie energii. Niema też sensu wstawiać instrukcji po return - nie są one wykonywane i kompilator zapewne pisze ostrzeżenie o kodzie, który nie zostanie wykonany. Po wyłączeniu ADC rezultat konwersji njest tracony.
UsuńJak należałoby zmodyfikować program gdy wybraliśmy ZEWNĘTRZNE napięcie odniesienia?
OdpowiedzUsuńUprzejmie proszę o odpowiedź.
Należy tylko wybrać zewnętrzne napięcie odniesienia i tyle - zobacz opis rejestru ADMUX.
UsuńFajny artykuł. Szkoda tylko, że autor co chwilę odsyła do angielskiego datashed. Jakbym dobrze znał angielski i potrafił go przeczytać, to bym nie szukał informacji na polskich stronach.
OdpowiedzUsuńTen komentarz został usunięty przez autora.
OdpowiedzUsuńTen komentarz został usunięty przez autora.
OdpowiedzUsuńLink do "AVR120: Characterization and Calibration of the ADC on an AVR" nie działa.
OdpowiedzUsuńA co jak mam 1.1V napięcie referencyjne?
OdpowiedzUsuń