Skocz do zawartości

Przetwornik ADC w pętli


mglowinski

Pomocna odpowiedź

Witam,
chciałem zrobić cykliczny odczyt wartości napięcia na mikrokontrolerze ATmega32.

Kod PRAWIE działa, aby odświeżyć pomiar muszę wgrać panownie program do ATmegi.

Gdzie może być problem?

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

volatile int a=0;
volatile float wynikV=0;
volatile int calosc=0;
volatile int reszta;
char wynik[4];
char wynik2[4];

int main(void)
{

ADMUX|=(1<<REFS0);
ADCSRA|=(1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(1<<MUX0)|(1<<MUX2);
ADCSRA|=(1<<ADSC);
  LCD_Initalize();   //inicjalizacja LCD


  LCD_GoTo(0, 0);      //Ustawienie kursora w pozycji (0,0)
  LCD_WriteText("Napiecie : ");
  LCD_GoTo(16,0);
  LCD_WriteText("Volt");
  LCD_GoTo(12,0);
  LCD_WriteText(",");



  while(1)
  {
   	   a=(0b00000011&ADCH)*256+ADCL;
   	   wynikV=a*5;
   	   wynikV=wynikV/1023;
   	   calosc=wynikV;
   	   reszta=wynikV*100-calosc*100;

   	   itoa(calosc,wynik,10);
   	   itoa(reszta,wynik2,10);
   	   LCD_GoTo(11,0);
   	   LCD_WriteText(wynik);

   	   LCD_GoTo(13,0);
   	   LCD_WriteText(wynik2);
   	  _delay_ms(500);
}
return 0;
}
Link do komentarza
Share on other sites

1. Coś pokręciłeś z bitami wyboru wejścia (MUXn) - one są w innym rejestrze.

2. Nie wolno robić czegoś takiego:

a=(0b00000011&ADCH)*256+ADCL

bo nie wiesz który rejestr kompilator odczyta wcześniej a kolejność ich odczytu jest ważna. AVR mają specjalny, niewidoczny rejestr buforowy przez który czytają wartości 16-bitowe więc musisz używać makr wbudowanych w kompilator:

a=ADC;

lub nie robić dwóch odczytów w jednej linii kodu (a wcześniej doczytać o prawidłowej ich kolejności).

3. O ile pamiętam po każdorazowym odczycie rejestru wyniku (czyli właśnie po operacji a=ADC) musisz wyzerować flagę przerwania ADIF przez wpisanie do niej jedynki. Inaczej rejestr wyjściowy ADC jest przyblokowany i niczego nowego Ci nie pokaże.

4. No i strasznie kombinujesz z tą arytmetyką zmiennoprzecinkową i konwersjami przez łapanie się prawą ręką za lewe ucho. Jaką masz skalę przetwarzania mV/LSB lub jakie masz AVCC?

Link do komentarza
Share on other sites

1. Masz rację, już poprawiłem

2. Ale wartości są odczytywane poprawnie:)

3. Umieściłem w pętli while ADCSRA|=(1<

4. Chciałem 10 bitowy przetwornik, aby pobawić się w odczytanie wyniku z dwóch rejestrów. Napięcie odniesienia to napięcie zasilania ATmegi.

[ Dodano: 10-11-2015, 10:01 ]

Próbowałem też coś takiego :

ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // podzial F_cpu przez 128, ma być 50-200KHz
ADMUX |= ((1 << REFS0)|(0<< REFS1)); 
ADMUX |= (0 << ADLAR); 
ADMUX |= ((0 << MUX1)|(0<< MUX2)|(0 << MUX3)|(0<< MUX4)|(0<<MUX1)); 
ADCSRA |= (1 << ADATE); 
ADCSRA |= (1 << ADEN);
ADCSRA |= (1 << ADSC); 

ale bezskutecznie

;-/

Link do komentarza
Share on other sites

2. To tylko oznacza, że miałeś szczęście i akurat tak zostało to wyrażenie skompilowane, że kolejność jest prawidłowa. Inna wersja GCC lub inaczej napisane to samo wyrażenie i leżysz. Masz zamiar opierać działanie swoich programów na takiej losowości?

3. Ej, coś motasz.

a. Po pierwsze możesz mieć dwa problemy: odczyty z ADC i sama konwersja na LCD. Uruchamiaj to osobno.

b. W pierwszej wersji kodu czytałeś wejście ADC5, teraz ADC0? Czy na obu jest coś sensownego do zmierzenia?

c. Najlepiej mrugaj jakąś diodką gdy odczytasz kolejny raz przetwornik. Przynajmniej będziesz wiedział, że pętla się kręci. Wyniki na LCD mogą być wciąż takie same z innego powodu. Możesz też wyświetlać np. licznik zrobionych pomiarów - powinien się inkrementować.

4. Pytałem o skalę przetwornika w mV/LSB lub o bezwzględną wartość napięcia odniesienia w V. Co mi z tego, że jest takie samo jak VCC procesora? Konwersję na postać pokazywaną na LCD robisz strasznie pokrętnie. Po co Ci do tego zmienny przecinek??? I nie rozumiem po co przy programowaniu wartości początkowych rejestrów używasz operatora "|="

Ten przetwornik jest trywialny. Nie kombinuj z takim dziwnym kodem. Działa tutaj najprostsza pętla:

ADMUX = (1<<REFS0) + numer_wejscia; 
ADCSRA =(1<<ADEN) | (1<<ADSC) | (1<<ADATE) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
while(1)
{
   if (ADCSRA & _BV(ADIF))
   {
       a = ADC;                // Odczyt przetwornika
                                    // Tutaj zrob cos z wynikiem...
       ADCSRA |= _BV(ADIF);      // Potwierdzenie odczytu wyniku
   }
}

Gdyby przyjąć, że masz VCC=AVCC=5V, to skala przetwornika wynosi 5V/1024=4.883mV/LSB. Wystarczy przecież pomnożyć odczyt ADC przez tę wartość i już masz wynik w mV. Wyświetlając to na LCD wypisujesz tylko kropkę dziesiętną przed trzema najmłodszymi cyframi i koniec - woltomierz gotowy. Jedno mnożenie, jedna konwersja i wyświetlenie stringu z prostą modyfikacją.

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

Problem rozwiązałem

Konfiguracja ADC :

ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (0 << ADPS0); //Podział 8MHz przez 64 (zakres musi byc miedzy 50kHz a 200kHz) 
ADMUX |= ((1 << REFS0)|(0<< REFS1)); //Vref to napięcie zasilania 
ADMUX |= (0 << ADLAR); // wynik przesuniety do lewej, caly wynik znaczacy w ADCH, ostatnie bity (po przecinku) w ADCL 
ADMUX |= ((0 << MUX1)|(0<< MUX2)|(0 << MUX3)|(0<< MUX4)|(0<<MUX1)); //Ustawiamy ADC0 jako aktywne 
ADCSRA |= (1 << ADATE); // to wlacza przetwornik w tryb dzialania ciaglego 
ADCSRA |= (1 << ADEN); // to wlacza przetwornik 
ADCSRA |= (1 << ADSC); // start przetwarzania od tego momentu adc mierzy w kolko

Zmieniłem również kod

a=(0b00000011&ADCH)*256+ADCL 

na

a=ADCW

Dodatkowo zmieniłem opóźnienie z 500ms na 1ms

Link do komentarza
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Gość
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.

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