PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : ADC - Ich finde den/die Fehler nicht



Christoph2
04.08.2007, 14:14
Hallo!
Ich habe mein erstes Programm mit dem Internen ADC Wandler des mega8 geschrieben, aber es funktioniert noch nicht ganz.


#include <avr/io.h>
#include <stdint.h>

#define F_CPU 3686400UL
#include <util/delay.h>


// LEDs:
// - Grün: PORT C 0
// - Gelb: PORT C 3
// - Rot: PORT C 5
// POTI an PORT B 0

//================================================== ================================================== =======

int adc (uint8_t mux)

{ uint8_t i;
uint16_t ergebnis=0;

ADCSRA=(1<<ADEN); // ADC ein
ADCSRA=(1<<ADPS2)|(1<<ADPS0); // Frequenzteiler 32

ADMUX|=(1<<REFS1)|(1<<REFS0); // Interne Refrerenzspg ein
ADMUX=mux; // ADC an Pin mux

ADCSRA|=(1<<ADSC); // Dummy Load
while(ADCSRA&(1<<ADSC)) {} // Warten bis Messung fertig

for(i=0;i<5;i++) // 5 Mal messen
{ ADCSRA|=(1<<ADSC);
while(ADCSRA&(1<<ADSC)) {} // Warten bis messung fertig
ergebnis=ergebnis+ADC; // Mittelwert bestimmen
}

ADCSRA&=~(1<<ADEN); // ADC ausschalten

ergebnis=ergebnis/5;
return ergebnis; // Ergebnis zurückgeben
}

//================================================== ================================================== =====

int main (void)

{ DDRD=0x00;
DDRB=0x00;
DDRC=0xff;
PORTC=0x00;

uint16_t wandlung;
while(1)
{ wandlung=adc(0);

if(wandlung<21845)
{ PORTC|=(1<<0);
PORTC&=~(1<<3);
PORTC&=~(1<<5);
}

if(wandlung>21845 && wandlung<43690)
{ PORTC|=(1<<3);
PORTC&=~(1<<0);
PORTC&=~(1<<5);
}

if(wandlung>43690 && wandlung<65535)
{ PORTC|=(1<<5);
PORTC&=~(1<<0);
PORTC&=~(1<<3);
}

else{}

}
}

//================================================== ================================================== ======


Wenn ich das Programm in den Controller brenne, leuchtet nur die Rote Led, d.h. es wird immer der else-Zweig im Hauptprogramm ausgeführt.

Ich glaube es liegt daran, dass ich nicht weiß, wie man dem uC sagt, dass das Poti auf PORT B ist, mit ADMUX=0 sagt man ihm ja nur, dass der ADC Pin der Pin 0 ist.

Außerdem kenn ich mich mit der Referenzspg. nicht so gut aus. Man kann also nur Spannungen von 0-2,54 Volt in den Controller schicken, das halte ich auch ein, aber ich weiß nicht, ob die Einstellungen ADMUX|=(1<<REFS1)|(1<<REFS0); stimmen.

Grüße,
Christoph

uwegw
04.08.2007, 14:41
Nur die mit ADC0..7 bezeichneten Eingänge eines AVRs sind Analogeingänge! Beim Mega8 liegen sie an PortC.

ADMUX|=(1<<REFS1)|(1<<REFS0); schaltet auf intern 2,56V Referenz.

Um die Referenz auf die Betriebsspannung zu setzen (praktisch wenn man Potis zwischen VCC und GND schaltet) nimmt man
ADMUX|=1<<REFS0);
Wenn VCC=5V kann man dann auch bis 5V messen.

Christoph2
05.08.2007, 17:23
Danke, ich habe das jetzt ausgebessert. Jetzt sieht mein Programm so aus:


#include <avr/io.h>
#include <stdint.h>

#define F_CPU 3686400UL
#include <util/delay.h>


// LEDs an PORT B 3, 4, 5
// POTI an PORT C 0

//================================================== ================================================== =======

int adc (uint8_t mux)

{ uint8_t i;
uint16_t ergebnis=0;

ADCSRA=(1<<ADEN); // ADC ein
ADCSRA=(1<<ADPS2)|(1<<ADPS0); // Frequenzteiler 32

ADMUX=(1<<REFS0); // Interne Refrerenzspg 5V
ADMUX=mux; // ADC an Pin mux

ADCSRA|=(1<<ADSC); // Dummy Load
while(ADCSRA&(1<<ADSC)) {} // Warten bis Messung fertig

for(i=0;i<5;i++) // 5 Mal messen
{ ADCSRA|=(1<<ADSC);
while(ADCSRA&(1<<ADSC)) {} // Warten bis messung fertig
ergebnis=ergebnis+ADCW; // zusammenzählen
}

ADCSRA&=~(1<<ADEN); // ADC ausschalten

ergebnis=ergebnis/5; // Mittelwert bestimmen
return ergebnis; // Ergebnis zurückgeben
}

//================================================== ================================================== =====

int main (void)

{ uint16_t wandlung;

DDRC=0x00;
DDRB=0xff;
PORTB=0xff;

while(1)
{
wandlung=adc(0);
_delay_ms(50);
if(wandlung<341)
{ PORTB|=(1<<3);
PORTB&=~(1<<4);
PORTB&=~(1<<5);
}

if(wandlung>341 && wandlung<682)
{ PORTB|=(1<<4);
PORTB&=~(1<<3);
PORTB&=~(1<<5);
}

if(wandlung>682 && wandlung<1024)
{ PORTB|=(1<<5);
PORTB&=~(1<<3);
PORTB&=~(1<<4);
}

}
}

//================================================== ================================================== ======

Jetzt leuchtet nur die grüne led, die auf B3 hängt, das heißt, es wird immer die erste if anweisung ausgeführt, egal wie ich das poti drehe, aber ich weiß nicht warum. Im tutorial von microcontroller.net steht, dass ADCW den wert 0-1024 annehmen kann. Diese Menge habe ich gedrittelt, und auf die 3 if anweisungen aufgeteilt.
Ich verstehe nicht ganz warum 1024, ein 16 bit Datentyp geht ja bis 2^16 = 65536. Oder hat das garnichts mit den 16 bit zu tun?

MfG
Christoph

wanderer
05.08.2007, 17:59
Es sind 10Bit ;) und nicht 16 bit, deswegen 1024...

SprinterSB
05.08.2007, 18:14
Es müsste heissen


ADMUX = (1<<REFS0) | mux;

ansonsten überschreibst du ADMUX.

Der Wert des ersten ADC-Ergebnisses nach Aktivierung des ADC sollte man laut Handbuch in die Tonne kloppen. Also nach Aktivierung erst eine Blind-Wandlung machen.

uwegw
05.08.2007, 19:15
@SprinterSB:
die Kanalwahl wird ja erst danach reingeschrieben, daher ist das egal. Es stellt zudem sicher, dass kein Reste einer alten Kanalauswahl mehr übrigbleiben. Die Routine scheint aus dem µc.net-Tutorial zu stammen. Und die 1. wandlung zum Warmlaufen ist auch enthalten...

EDIT: sorry, hast recht. Ich hab das fehlende | übersehen!

@Christoph2:setz mal um die einzelnen Abfragen Klammern.

SprinterSB
06.08.2007, 09:59
Gleiches gilt für ADCSRA: Entweder



ADCSRA = (1<<ADEN);
ADCSRA |= (1<<ADPS2) | (1<<ADPS0);

oder


ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS0);


wobei ich hier der 2. Variante den Vorzug gebe

Christoph2
07.08.2007, 17:32
Danke, ich habe jetzt alles ausgebessert, und jetzt funktioniert das programm!!

Kann mir noch jemand erklären, wie das mit den Strichen | funktioniert?
Ich verstehe nicht ganz, wann man |= und wann man nur = schreiben muss.

MfG
Christoph

Hubert.G
07.08.2007, 18:03
Sieh mal hier, vieleicht hilft dir das: www.mikrocontroller.net/articles/Bitmanipulation

Christoph2
07.08.2007, 19:34
ich verstehe es!!! danke!!!