Skocz do zawartości

[C] Atmega 328p - problem z uruchomieniem ADC


Dymek_117

Pomocna odpowiedź

Witam,
Drugi dzień już głowię się nad inicjalizacją ADC. Program, który napisałem zwyczajnie nie rusza.

ADC ma mierzyć spadek napięcia na fototranzystorze, czego jednak nie robi, dioda sygnalizacyjna spadku napięcia miga jednokrotnie, a potem gaśnie na dobre.

Co ciekawe, kiedy mierzę spadek napięcia na pinie multimetrem jest on jak najbardziej poprawny, problem leży więc po stronie ADC.

Błąd sprzętowy odrzucam, nie wstawiam schematu zasilania części analogowej, sprawdzałem ją wielokrotnie i porównywałem z wieloma wzorcami. Jest wszystko co potrzeba - kondensatory, dławik, itp. Połączenia również sprawdzone.


void adc_start(void)
{
ADCSRA |= (1<<ADEN);                               // inicjalizacja ADC
ADCSRA |= (1 << ADPS1) | (1 << ADPS0);             // prescaler = 8  ( dla 1MHz )
ADCSRA &= ~(1<<ADPS2);
ADMUX |= (1<<ADLAR);
ADMUX |= (1 << REFS0);                             // napiecie odniesienia jako wewnetrzne VCC
}

uint8_t dalmierz (uint8_t wejscie)                     // np. tranzystor 1
{ 
//PORTD |= (1<<dioda_ir_1);
ADMUX |= (wejscie);                                // ustawiam kanał
ADCSRA |= (1<<ADSC);                               // dokonanie pomiaru
return (ADCW);
}

int main(void)
{
DDRB |= (1<<dioda_niebieska);
adc_start();
_delay_ms(50);

int wynik;

while(1)
    {
    wynik = dalmierz(tranzystor_2);

        if( wynik < 900)  //sygnalizacja dioda
    {
      PORTB |= (1<<dioda_niebieska);
      _delay_ms(150);
      PORTB &= ~(1<<dioda_niebieska);
      _delay_ms(15);
     }
     }   
}

Podejrzewam, że w programie znalazł się chochlik, którego ja niestety nie potrafię wychwycić 🙁

Jak wspomniałem dioda sygnalizacyjna miga tylko raz przy inicjalizacji programu.

Z góry dziękuje za waszą pomoc!

Link do komentarza
Share on other sites

Po wystartowaniu konwersji musisz czekać na wynik. Przetwornik nie mierzy z prędkością światła więc po ustawieniu ADSC musisz poczekać na jego automatyczne zgaszenie przez ADC. Dopiero wtedy masz prawo odczytać rezultat. Oj nie zajrzało się do dokumentacji...

Moim zdaniem nadużywasz operatora |=. Przecież możesz jednym strzałem wpisać:

ADCSRA = (1<

To załatwia ustawienie wskazanych i wyzerowanie reszty bitów. To jest operacja jednorazowa, inicjalizacja wykonywana tylko raz. Nie obchodzi Cię co tam wcześniej w rejestrze było więc twardy zapis do ADCSRA jest OK.

I zastanów się co się stanie w ADMUX gdy funkcję dalmierz() wywołasz najpierw z argumentem 1 a potem 2.

  • Pomogłeś! 1
Link do komentarza
Share on other sites

Istotnie w funkcji dalmierz() jest błąd, poprawiłem.

Oprócz tego dodałem pętle która, czeka na zmianę wartości ADSC, niestety żadnego efektu 🙁

uint8_t dalmierz (uint8_t wejscie)                  // np. tranzystor 1 ma 0b11110001
{
ADMUX &= (wejscie);
ADCSRA |= (1<<ADSC);                     
while( ADCSRA & (1<<ADSC) );   //czekamy
return (ADCW);
}

Do tego uprościłem funkcje inicjalizacyjną, tak jak sugerowałeś 🙂

[ Dodano: 26-02-2016, 19:45 ]

Dodam tylko, że dioda sygnalizacyjna zapala się dla warunku (wynik < 198), wynik jest 8-bitowy jak sądzę. Skąd taka wartość nie wiem, jednak jej zapalenie w ogóle nie zależy od tego czy przykładam diodę IR do fototranzystora czy nie. :|

Multimetr pokazuje wartości z zakresy 2-5V na tym pinie w zależności od tego jak blisko ma dioda do fototranzystora, czyli pomiar zgodny z oczekiwaniem, jednak ADC tego nie wychwytuje 🙁

[ Dodano: 26-02-2016, 20:41 ]

Na chwilę obecną:

1. Jeden kondensatorek był uszkodzony, wymieniłem. Poprzedni zwierał AREF do masy, co paraliżowało ADC.

2. Na chwilę obecną wychwyciłem, że po wymianie elementu, ADC podaje wartości losowe o sporym rozrzucie w pełnym zakresie ośmiobitowym, bez względu na oświetlenie fototranzystora.

Program pozostawiłem bez zmian

Jakieś sugestie? :/

[ Dodano: 27-02-2016, 02:53 ]

[sOLVED]

EDIT:

Problem rozwiązany 🙂

Poprawienie ścieżek, oraz lutów kondensatorków rozwiązało problem zakłóceń.

Brak odczytu lub trwała wartość maksymalna (255) brały się stąd, że ustawiłem bit ADLAR, wyrównując wynik i nie uwzględniając tego w programie. Wystarczyło wyzerować bit 🙂

Dziękuje za porady, trochę się namęczyłem, ale przynajmniej program wyglada teraz solidnie.

Pozdrawiam!

Link do komentarza
Share on other sites

Nie uda Ci się wpisać zawartości pola bitowego do rejestru jedną operacją, wszystko jedno czy będzie to AND, OR czy XOR. Teraz dla odmiany zastanów się które wejście zmierzysz gdy swoją nową, lepszą funkcję wywołasz najpierw z parametrem np. 1, potem 0 a potem znowu 1.

Musisz najpierw wyzerować całe pole bitowe a dopiero potem wstawiać do niego liczbę:

ADMUX &= 0xF8;

ADMUX |= numer_wejscia & 0x07;

Teraz w rejestrze multipleksera na pewno jest otrzymany numer wejścia 0..7.

W jednym strzale to może wyglądać tak:

ADMUX = (ADMUX & 0xF8) | (numer_wejscia & 0x07);

i jest trochę szybsze, bo wymaga tylko jednego odczytu ADMUX i jednego zapisu do niego. Reszta operacji w tym wyrażeniu "dzieje się" w rejestrach procesora.

Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

Produkcja i montaż PCB - wybierz sprawdzone PCBWay!
   • Darmowe płytki dla studentów i projektów non-profit
   • Tylko 5$ za 10 prototypów PCB w 24 godziny
   • Usługa projektowania PCB na zlecenie
   • Montaż PCB od 30$ + bezpłatna dostawa i szablony
   • Darmowe narzędzie do podglądu plików Gerber
Zobacz również » Film z fabryki PCBWay

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.