Skocz do zawartości

[C] Atmega 328p - problem z uruchomieniem ADC


Pomocna odpowiedź

Napisano

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!

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

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!

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.

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...