ATMega ADC Problem

M

Martin Laabs

Guest
Hallo,

ich möchte von einem ADC Eingang meines ATMega128
lesen.
Ich habe ein ganz kleines Progamm geschrieben welches
die Werte alle paar Zentelsekunden via "Single Conversion mode".
Leider kann ich nur das erste mal einen Wert auslesen.
Die folgenden Werte sind immer gleich dem ersten.
Hat jemand eine Idee woran es liegen kann?
Hier ist mein (etwas gekürzter) Code:

---------------:<------------------
void init(void)
{
lcd_init(LCD_DISP_ON_CURSOR);
lcd_clrscr();
ADMUX=BV(REFS1)|BV(REFS0)|0x6; //internal bandgap;channel 6
ADCSRA=BV(ADEN); //enable adc
}

int main(void)
{
char buffer[33];
unsigned int result;

init();

while(1){
sbi(ADCSRA,ADSC); //start sm adc
loop_until_bit_is_clear( ADCSRA, ADSC );
result=ADCL|(ADCH<<8);
itoa(ADCL,buffer,10);
_delay_loop_2(0xffff);
lcd_clrscr();
lcd_puts("ADC Wert: ");
lcd_puts(buffer);
}
}
-----------------:<-----------------------------

Danke
Martin Laabs
 
Hi
ich hab zwar deinen Quelltext nicht so genau gelesen (Schande über mich) ,
aber ne Idee hätte ich:
Es gibt wohl 2 betriebsmodi.
Der eine ist wohl dafür das der Wert der am ADC eingang liegt laufend
akutalisiert wird und beim anderen
muss man wohl selbst immer wieder dem Prozessor sagen wann er einen neuen
wert einlesen soll.
Kann es sein, das du im zweiten gelandet bist und nicht den
aktualisierungsbefehl ausgibst?

Gruß
Tobi (Der entschieden zu müde ist den C Text zu lesen)
 
In article <bgc099$s6b$00$1@news.t-online.com>,
"Tobias Aurand" <Tobias.Aurand@ei.fh-giessen.de> writes:

Der eine ist wohl dafür das der Wert der am ADC eingang liegt laufend
akutalisiert wird und beim anderen
muss man wohl selbst immer wieder dem Prozessor sagen wann er einen neuen
wert einlesen soll.

Kann es sein, das du im zweiten gelandet bist und nicht den
aktualisierungsbefehl ausgibst?
Das wird wohl irgendwie so sein. Aber so viel wie ich dem
Datenbalt entnehmen konnte muss man zum anstoßen eines neune
ADC Vorganges nur das ADSC Bit in ADCSRA auf 1 setzen.
(Natürlich muss man vorher im ADMUX die richtigen
Werte gesetzt haben)

Aber das habe ich alles gemacht. Evt. ist es auch
einfach zu spät. Gestern nacht habe ich den Fehler
mit dem LCD Display nicht gefunde. Heute morgen habe
ich keine 15 minuten gebraucht um festzustellen
das der ATMega128 noch im Kompatibilitätsmodus arbeitet,
mein Compiler jedoch Code für den 128 liefert.

Tschüss
Martin L.
 
Martin Laabs wrote:

Hallo,

ich möchte von einem ADC Eingang meines ATMega128
lesen.
Ich habe ein ganz kleines Progamm geschrieben welches
die Werte alle paar Zentelsekunden via "Single Conversion mode".
Leider kann ich nur das erste mal einen Wert auslesen.
Die folgenden Werte sind immer gleich dem ersten.
Genau das Problem hatte ich diese Woche mit dem Mega8 unter GCC
( so lange bis er krepiert ist: anderer Thread :)
Ich hatte die Messung auch im Hauptprogramm und hab'
sie dann 1:1 in eine Funktion verpackt, danach ging's.
Verstehen muss man sowas wohl nicht.
Meine Funktion sieht wie folgt aus:

u16 readAnalog(u08 adc_channel) {

// init
outp(0x00,PORTC);
outp(0x00,DDRC);


outp(0xC0 | adc_channel ,ADMUX); // select Channel
outp( (1<<ADEN) | (1<<ADSC) | 0x03, ADCSRA); // start conversion IRQ
disabled division 128

loop_until_bit_is_clear(ADCSRA,ADSC);

return ( inw( ADCL ) );

}

Bye Daniel


--
.~. Daniel Schramm Phone: +49 231 6108112 Mail:daniel.schramm@gmx.de
/V\ Bruehlweg 36 Mobile:+49 178 8839848 ICQ: 35816985
// \\ 44379 Dortmund Fax: +49 231 96989961 WWW: www.fset.de/~daniel
/( )\ Germany
^`~'^
 
Ich möchte mich als Dritter dieser Runde anschließen. Allerdings
hatte ich das Problem mit einem AT90S4433 und GCC. Zunächst
funktionierte alles wunderbar (AD auslesen...) dann habe ich einige
"Features" zusätzlich in das Programm eingebaut und der ADC wollte
partu nicht mehr messen. Erst als ich die gesamte Ansteuerung des
AD-Wandlers in eine Funktion gepackt habe funktionierte wieder alles.
Vielleicht sollte man sich den Assembler code mal genauer anschauen
der rausgeschrieben wurde....


Aber nun zu Deinem Problem: Bei meinem AT90S4433 muß ich die Messung
quittieren indem ich ein Bit im ADC-Register setze. Prüfe das mal in
der Spec vom ATMEGA. Außerdem muß zuerst das Highbyte, dann das
Low-Byte ausgelesen werden....


Gruß,
Artur
 
Hi

void init(void)
{
lcd_init(LCD_DISP_ON_CURSOR);
lcd_clrscr();
ADMUX=BV(REFS1)|BV(REFS0)|0x6; //internal bandgap;channel 6
ADCSRA=BV(ADEN); //enable adc
^^^^^^^^
Du setzt hier einen Teiler von 2 - das geht laut Datenblatt
nur bei Frequenzen bis 400kHz - laeuft den ATMega tatsaechlich so
langsam?

while(1){
sbi(ADCSRA,ADSC); //start sm adc
loop_until_bit_is_clear( ADCSRA, ADSC );
result=ADCL|(ADCH<<8);
Diese Zeile ignoriert der Compiler vermutlich, weil "result"
nie benutzt wird.

itoa(ADCL,buffer,10);
Und hier liest du nur ADCL - damit sind die Register verriegelt - das
naechste Wandlungsergebnis geht verloren. Du musst noch ADCH lesen und
dafuer sorgen, dass der Compiler das nicht wegschneidet.

HTH, bye
Thomas
 
In article <5i0dgb.eh6.ln@server.workgroup>,
Thomas Matern <my-spamcatcher@gmx.de> writes:
Hi
ADCSRA=BV(ADEN); //enable adc
^^^^^^^^
Du setzt hier einen Teiler von 2 - das geht laut Datenblatt
nur bei Frequenzen bis 400kHz - laeuft den ATMega tatsaechlich so
langsam?
Nein. Ich will ja eine singel conversion. Ich dachte
ich setzt so das Bit ADEN in ADCSRA.
Und das ist nach meinem Datenblatt:

"Bit 7 ADEN: ADC Enable
Writing this bit to one enables the ADC. By writing it to
zero, the ADC is turned off. Turning
the ADC off while a conversion is in
progress, will terminate this conversion."


result=ADCL|(ADCH<<8);

Diese Zeile ignoriert der Compiler vermutlich, weil "result"
nie benutzt wird.
Oh. Das war mein Fehler. result wird dann weiter unten
anstatt itoa(ADCL,buffer,10); benutzt.

itoa(ADCL,buffer,10);

Und hier liest du nur ADCL - damit sind die Register verriegelt - das
naechste Wandlungsergebnis geht verloren. Du musst noch ADCH lesen und
dafuer sorgen, dass der Compiler das nicht wegschneidet.
Jupp. Ich hatte ursprünglich result gewandelt. Dann nur
zum testen mal ADCL eingesetzt.
Ging trotzdem nicht

Danke
Martin L.
 
Hoi Martin

Martin Laabs wrote:
Hallo,

ich möchte von einem ADC Eingang meines ATMega128
lesen.
Ich habe ein ganz kleines Progamm geschrieben welches
die Werte alle paar Zentelsekunden via "Single Conversion mode".
Leider kann ich nur das erste mal einen Wert auslesen.
Die folgenden Werte sind immer gleich dem ersten.
Hat jemand eine Idee woran es liegen kann?
Hier ist mein (etwas gekürzter) Code:

...

unsigned int result;
...
result=ADCL|(ADCH<<8);
...

Hast du schon mal versucht, das ganze als volatile zu deklarieren?
UU optimiert der Compiler erneute Speicherzugriffe weg,
weil er der Meinung ist, er kennt den Wert bereits.
Eigentlich sollte das bereits in den Macros stehen, zB
#define ADCL (*(unsigned int volatile *) 0x****)

Auch mal versuchen, ohne oprimize zu übersetzen, bze den
erzeugten asm-code angucken, ob der Compiler wirklich die
gewünschten Instruktionen emittiert.

Gruß, Georg-Johann


Danke
Martin Laabs
 
Hi

ADCSRA=BV(ADEN); //enable adc

^^^^^^^^
Du setzt hier einen Teiler von 2 - das geht laut Datenblatt
nur bei Frequenzen bis 400kHz - laeuft den ATMega tatsaechlich so
langsam?

Nein. Ich will ja eine singel conversion. Ich dachte
ich setzt so das Bit ADEN in ADCSRA.
Und das ist nach meinem Datenblatt:
...

Ja, aber in ADCSR stecken auch die Bits fuer den "ADC Prescaler". Setzt
du den denn an anderer Stelle? Ich habe diese Controller noch nie
in C programmiert, aber diese Zeile sieht fuer mich nach:

ldi R16, 0b10000000
out ADCSR, R16

aus und damit setzt du den Teiler auf 2 - das duerfte *etwas* zu
schnell sein...

Jupp. Ich hatte ursprünglich result gewandelt. Dann nur
zum testen mal ADCL eingesetzt.
Ging trotzdem nicht
Achso. Hmm, dann gehen mir auch die Ideen aus - variiert denn die
gemessene Spannung ueberhaupt? Und koennte der erste, gemessene Werte
denn in etwa stimmen?

Bye
Thomas
 
Artur Pundsack wrote:

Aber nun zu Deinem Problem: Bei meinem AT90S4433 muß ich die Messung
quittieren indem ich ein Bit im ADC-Register setze. Prüfe das mal in
der Spec vom ATMEGA. Außerdem muß zuerst das Highbyte, dann das
Low-Byte ausgelesen werden....
Beim Mega 8 ist das auf jeden Fall nicht so, das Auslesen von ADCL hat die
Funktion anscheinend uebernommen. Meine Funktion ist etwas leichtsinnig,
wie ich gerade sehe. Ich verlasse mich darauf, dass inw zuerst das high-
und dann das low-byte liest, eine kurze rechersche ergab, dass es je nach
Compiler auch die umgekehrte Implementierung gibt.

Also lieber die richtige Reihenfolge erzwingen!!!

Danke fuer die Anregungen.

Bye Daniel

--
.~. Daniel Schramm Phone: +49 231 6108112 Mail:daniel.schramm@gmx.de
/V\ Bruehlweg 36 Mobile:+49 178 8839848 ICQ: 35816985
// \\ 44379 Dortmund Fax: +49 231 96989961 WWW: www.fset.de/~daniel
/( )\ Germany
^`~'^
 
Martin Laabs <98malaab@gmx.de> wrote:

ADCSRA=BV(ADEN); //enable adc

Du setzt hier einen Teiler von 2 - das geht laut Datenblatt
nur bei Frequenzen bis 400kHz - laeuft den ATMega tatsaechlich so
langsam?

Nein. Ich will ja eine singel conversion. Ich dachte
ich setzt so das Bit ADEN in ADCSRA.
Dann solltest Du das aber auch tun. ;-)

ADCSRA |= _BV(ADEN); //enable adc
--
J"org Wunsch Unix support engineer
joerg_wunsch@interface-systems.de http://www.interface-systems.de/~j/
 

Welcome to EDABoard.com

Sponsor

Back
Top