PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : ADC Probleme



alecs
07.12.2005, 22:11
Hallo, ich hab folgende Funktion geschrieben um von einem PIN von Port a den ADC Wert zu erhalten, aber ich erhalte komischer weise auch wenn nix dran ist werte um ca 486, aber warum ????



int getADC(uint8_t pin)
{
int adc_value = 0;

ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0); // Prescalar 8

ADMUX = pin;
ADMUX |= (1<<REFS1) | (1<<REFS0); // use internal voltage
ADCSRA |= (1<<ADSC);

while (!(ADCSRA & (1<<ADIF))); // wait for finish converting ADIF bit
adc_value = ADCW; // read result
ADCSRA = (1<<ADIF); // delete ADIF, cause it could trigger ISR

ADCSRA &= (1<<ADEN); // deactivating ADC
return adc_value; // return result
}

Felix G
07.12.2005, 22:46
heisst "nix dran" dass der Pin in der Luft hängt, oder liegt er auf Masse?

wenn er auf Masse liegt stimmt was nicht, denn dann sollte der Wert 0 sein
(mal abgesehen von minimalsten Abweichungen)


In der Funktion habe ich jetzt auf den ersten Blick keine groben Fehler gefunden, die müsste eigentlich funktionieren.
(allerdings würde ich empfehlen einen Interrupt zu benutzen, dann ist der µC beim Warten auf das Messergebnis nicht komplett blockiert)

alecs
07.12.2005, 23:09
Hallo Felix,
ich habe an Porta.1 eine 5 Taster in einer Widerstandskombination, wenn keiner gedrückt ist, dann liegt 0 (Masse) an diesem an, wenn ein Taster gedrück wird eine Spannung an den Port gelegt.

An was könnte es liegen und wie meinst du das mit den Interrupts?

alecs
07.12.2005, 23:20
Hi, hab noch mal alles überprüft, und ich hatte leider nen peinlichen Flüchtigkeitsfehler gemacht, denn Porta1 ist nicht gleich pin1 an port a :)
Sorry!!!

Aber dennoch ist es komisch das der niedrigste Wert = 130 ist, kann das sein ?

linux_80
07.12.2005, 23:23
Hallo,

diese beiden Zeilen machen nicht das wie es gemeint war:

ADCSRA = (1<<ADIF); // delete ADIF, cause it could trigger ISR

ADCSRA &= (1<<ADEN); // deactivating ADC

die erste Zuweisung löscht alle anderen Bits,
sodass die 2. eigentlich nix mehr zu tun hat.

Dann würde ich nicht jedesmal den ganzen ADC deaktivieren, dann gehts beim 2. mal etwas schneller.

Wie schnell Taktet der AVR, hast Du den Prescaler richtig berechnet?
Wie ist der ADC extern beschaltet, also AVCC/VRef usw. bei interner Ref muss da aussen was mit Kondensator anders sein ?
Welchen Wert übergibts Du der Funktion bei pin ?
Welchen AVR hast Du ?

alecs
07.12.2005, 23:38
Hallo Linux_80,

also ich hab einen Mega32..
Berechnung des Prescaler, gute Frage ich hab 8 benutzt,
wenn ich den Prescaler auf 128 setze nix mehr passiert, erhängt einfach, aber ich hab keine Ahnung wo :(

Prescalar auf 8

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

und Prescaler auf 128

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

laut meiner berechnung müsste er ja min bei 80 und max bei 320 liegen mit 16 Mhz aber warum funktioniert er nur bei Prescaler 8 ?

mit pin übergebe ich an welchen pin gemessen werden soll...

alecs
07.12.2005, 23:50
Hallo, hab jetzt auch das Problem mit dem Prescaler gefunden ... wieder einer der vielen Flüchtigkeitsfehler... denn da fehlte : (1<<ADEN) , nun funktioniert es :)

Danke \:D/

Felix G
08.12.2005, 00:13
wie meinst du das mit den Interrupts?Naja...
momentan startet deine Funktion den ADC, wartet dann bis er endlich fertig ist und liefert schliesslich das Ergebnis zurück.
In der Zeit in der der µC auf den ADC wartet könnte er eigentlich noch eine Menge anderer Dinge tun,
aber so ist er gezwungen für eine recht lange Zeit einfach garnichts zu machen.


Ein Interrupt tut genau das was der Name besagt: er unterbricht das Programm
d.h. sobald ein bestimmtes Ereignis auftritt, wird das Programm an der momentanen Stelle unterbrochen,
und eine bestimmte Funktion (ISR - Interrupt Service Routine) ausgeführt.
Sobald diese Funktion fertig ist, läuft das Programm an der alten Stelle weiter.

Der ADC kann einen Interrupt auslösen wenn er mit einer Wandlung fertig ist.
In der passenden ISR kann man dann z.B. den Wert in irgendeiner Variable speichern
(ISRs sollten möglichst kurz sein, aufwändige Berechnungen haben da nichts zu suchen).


Anstatt also den µC während der Wartezeit komplett zu blockieren, wird das Programm nur ganz kurz unterbrochen wenn wirklich ein neuer Wert da ist.

linux_80
08.12.2005, 00:38
Hi alecs,
der Prescaler ist abhängig von der Geschwindigkeit des µC, bei Dir 16MHz,
der Wert soll aber unter 200kHz sein, also geht bei 16MHz nur Teiler 128, das ergibt 125kHz.

Um gleich die Sache mit dem Interrrupt aufzugreifen, eine AD-Wandlung dauert 13 Takte des ADC, also 13*128 Takte des µC,
in dieser Zeit könnte man im günstigsten Fall 1664 Befehle ausführen (bei 16MHz).

Edit:
Mit Befehle meine ich Assemblerbefehle.

alecs
08.12.2005, 10:53
Was Interrupts tun, ist mir so weit eigentlich bewusst, nur im Moment wüßte ich nicht was der µC in dem Moment wo er auf das Ergebnis des ADC wartet noch erledigen könnte, denn ich benutze den ADC um meine Taster und 3 IR Sensoren auszuwerten. Könntet ihr mir da nen bisl unter die Arme greifen, wie man es besser machen könnte ?

Danke !!!

Felix G
08.12.2005, 14:24
Wenn der µC sonst nichts zu tun hat kann man natürlich auch auf Interrupts verzichten, stimmt schon

Ich ging halt davon aus, daß der µC mehr als eine Aufgabe hat ;-)

dark_flash01
08.01.2006, 00:52
Wie ist denn der COde für deine Funktion dann nun insgesamt?
Muss mit dem Teil möglichst schnell (innerhalb der nächsten Tage) einen sharp-entfernungsmesser auslesen und der µC soll auch noch was machen während er auf den ACD wartet... bitte helft mir

MfG dark_flash

alecs
08.01.2006, 10:56
Wie ist denn der COde für deine Funktion dann nun insgesamt?
Muss mit dem Teil möglichst schnell (innerhalb der nächsten Tage) einen sharp-entfernungsmesser auslesen und der µC soll auch noch was machen während er auf den ACD wartet... bitte helft mir

MfG dark_flash




uint16_t getADC(uint8_t pin);

* main program
*/
{
/* define port a as imput ( A/D-converter inputs ) */
DDRA = 0x00;
PORTA = 0x00;
int s1 = getADC(0);
}

uint16_t getADC(uint8_t pin)
{
uint16_t adc_value = 0;

// min Prescaler = µC Frequ / 200 KHz & max Prescaler = µC Freq. / 50 khz = min 80 & max 320
ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // Prescalar = 128

ADMUX = pin;
ADMUX |= (1<<REFS1) | (1<<REFS0); // use internal voltage
ADCSRA |= (1<<ADSC);

while (!(ADCSRA & (1<<ADIF))); // wait for finish converting ADIF bit
adc_value = ADCW; // read result
ADCSRA = (1<<ADIF); // delete ADIF, cause it could trigger an ISR

return adc_value; // return result
}


Also in der MAin wird die Methode mit dem Port aufgerufen, an welchem gemessen werden soll... sonst ist eigentlich alles kommentiert...oder gibt es nocht Fragen ?

MfG

Alex

PS: Allen Usern noch ein gesundes neues Jahr 2006 ! \:D/

dark_flash01
08.01.2006, 21:00
danke für die Funktion, aber der Wert der ausgegeben wird ist doch ein Integer oder? Wie kann ich den in einen String umwandeln, der mir auf einem LCD angezeigt wird?

alecs
09.01.2006, 09:40
danke für die Funktion, aber der Wert der ausgegeben wird ist doch ein Integer oder? Wie kann ich den in einen String umwandeln, der mir auf einem LCD angezeigt wird?

kommt drauf an wie du deine Ausgabe realisierst, ich habe zB. für eine ausgabe über die RS232 die Printf-funktion benutzt und somit kann man es wunderschön wzb. so benutzen:



int wert = 1234;
printf("Wert = %i", wert);


oder du benutzt



char mychar_array[4];
char *p_mychar_array = mychar_array;
itoa(wert,p_mychar_array,4);



ist jetzt nicht getestet aber sollte funktionieren ...

MfG

Alecs[/code]

dark_flash01
09.01.2006, 13:29
mmh werds ausprobieren wenn ich wieder zuhause bin...
Danke erstmal aber da fällt mir ein... Kann ich einenn SHarp-entfernungsmesser GP2D12 einfach so an den Pin des Mega 32 hängen?

Danke,MfG Sebastian

alecs
09.01.2006, 14:00
Kann ich einenn SHarp-entfernungsmesser GP2D12 einfach so an den Pin des Mega 32 hängen?

eigentlcih schon, hab gerade noch mal den Schaltplan vom RN-Control angeschaut und dort ist PORT A auch direkt auf den µC gezogen...

Viel Erfolg

MfG

Alecs

dark_flash01
17.01.2006, 15:08
Sooo wir haben den ADC jetzt am Laufen danke für die Tips...