hallo alle zusammen. Ich versuche gerade eine Temperaturmessung vorzunehmen und den ADC-wert an PORTD meines ATMEGA168 auszugeben. Benutze folgende schaltung: VCC(5V) | | R R R R=5,4K 1% für KTY-210 | ADCIN--- | | K T Y 8 1 | AGND und habe dazu folgenden code: (im avrStudio) #include <avr/io.h> #include <stdint.h> #include <avr/interrupt.h> uint8_t ReadChannel(uint8_t mux) { ADMUX = mux; // Kanal waehlen ADMUX = (1<<REFS0) | (1<<ADLAR); // AVCC als Referenzspannung wählen und Ergebniss ins HighRegister // ADC aktivieren und Frequenzvorteiler setzen auf 64 ADCSRA = (1<<ADEN) | (1<<ADPS2)| (1<<ADPS1) | (0<<ADPS0); ADCSRA |= (1<<ADSC); PORTD = ADCH; return PORTD; }//ende ADC // ENDE DEFINITIONEN int main(void){ DDRB = 0xff; //Port b als Ausgang definiert PORTB = 0x6; //RELAIS schalten DDRC = 0xC; //Pin2 und 3 des PortC als Ausgang definiert PORTC = 0xc; //LEDs einschalten DDRD = 0xFF; ReadChannel(0); }//ende Main doch ich sehe an PORT D keine Ausgabe. was mach ich falsch?
ok! mein fehler aber jetzt bin ich auf mein altes problem zurück gefallen. und zwar ist ein fühler kanal 0 drausen bei -2°C und ein Fühler drinnen bei zimmertemp 25°C doch beide geben den gleichen wert an PORT D aus. (einmal kommentier ich kanal 0 aus einmal kanal 1)
der ADC braucht etwas Zeit zur Wandlung. > ADCSRA |= (1<<ADSC); > PORTD = ADCH; ADCSR |= (1<<ADSC); while ( ADCSRA & (1<<ADSC) ) {;} // auf ende der Wandlung warten PORDD = ADCH; Im Datenblatt zum ATMEGA168 stehen seeeeehr interessante dinge über den ADC! MfG
ich habe meinen code etwas umgeschreiben aber es hilft alles nicht Single conversion: #include <avr/io.h> //In io.h sind die Registernamen definiert #include <stdint.h> //Standardisierte Datentypen werden in der Header-Datei stdint.h definiert #include <avr/interrupt.h> // DEFINITIONEN //ADC-Einstellungen uint8_t ReadChannel(unsigned char mux) { unsigned char adcwert; ADMUX = mux; // Kanal waehlen ADMUX = (1<<REFS0) | (1<<ADLAR); // AVCC als Referenzspannung wählen und Ergebniss ins HighRegister // ADC aktivieren und Frequenzvorteiler setzen auf 64 ADCSRA = (1<<ADEN) | (1<<ADIE) | (1<<ADPS2)| (1<<ADPS1) | (0<<ADPS0); ADCSRA |= (1<<ADSC); while ( (ADCSRA & (1<<ADIF))==0 ); // auf ende der Wandlung warten adcwert = ADCL; adcwert = ADCH; //ADCL verwerfen return adcwert; }//ende ADC // ENDE DEFINITIONEN int main(void){ DDRB = 0xff; //mit DDR wird der gesamte PortB als Ausgang definiert PORTB = 0x6; //in P0 und P1 wird eine 1 (entspricht einem High=vcc) geschrieben DDRC = 0xC; //Pin2 und 3 des PortC als Ausgang definiert PORTC = 0xc; DDRD = 0xFF; PORTD = ReadChannel(0); //PORTD = ReadChannel(1); while(1) { ; } //Ende Haupt-while schleife return 0; //wird nie erreicht! (siehe while schleife) }//ende Main
ich habe folgendes im datenblatt gefunden A single conversion is started by disabling the Power Reduction ADC bit, PRADC, in “Minimizing Power Consumption” on page 42 by writing a logical zero to it and writing a logical one to the ADC Start Conversion bit, ADSC. This bit stays high as long as the conversion is in progress and will be cleared by hardware when the conversion is completed. If a different data channel is selected while a conversion is in progress, the ADC will finish the current conversion before performing the channel change. aber das bit müsste doch standardmäßig null sein.
mach Feierabend, > ADCSRA = (1<<ADEN) | (1<<ADIE) | (1<<ADPS2)| (1<<ADPS1) | (1<<ADIE) schaltet den Interrupt frei. Eine ISR hast du aber nicht! >PORTD = ReadChannel(0); >//PORTD = ReadChannel(1); while(1) { PORTD = ReadChannel(0); ; } //Ende Haupt-while schleife MfG
den interrupt nutzte ich hier für while ( (ADCSRA & (1<<ADIF))==0 ); // auf ende der Wandlung aber du hast recht. komm heute wohl nicht mehr weiter. danke euch für die hilfe.
1 | ADMUX = mux; // Kanal waehlen |
2 | ADMUX = (1<<REFS0) | (1<<ADLAR); // AVCC als Referenzspannung wählen und Ergebniss ins HighRegister |
1. Du überschreibst mit dem 2. Befehl deinen vorher übergebenen Kanal. Es muss folgendermaßen heißen (beachte das |= anstatt des =):
1 | ADMUX = mux; // Kanal waehlen |
2 | ADMUX |= (1<<REFS0) | (1<<ADLAR); // AVCC als Referenzspannung wählen und Ergebniss ins HighRegister |
2. Wenn man einen ADC nicht kontinuierlich ausliest, sollte man dieses immer zwei Mal machen und das erste Ergebnis verwerfen. Ein ADC muss immer ein wenig "warmlaufen" bevor er richtige Ergebnisse ausspuckt. 3. Ich empfehle dir einfach mal ins GCC-Tutorial dieser Seite zu schauen, speziell hier: http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#ADC_.28Analog_Digital_Converter.29
Hallo, nicht getestet, aber versuche es mal: #define NUM_ADC 2 union BytesInWord{ struct{ uint8_t LoByte; uint8_t HiByte; }LH; uint16_t Word; }; static uint16_t AdcWerte[NUM_ADC]; static uint8_t Mux; void AdcStart(uint8_t Kanal) { ADMUX = Kanal | (0<<REFS0) ADCSRA = (1<<ADEN) | (1<<ADIE) | (1<<ADSC) | (1<<ADPS0) | (1<<ADPS1) | (1<<ADPS2); } void AdcNextChannel(void) { if(++Mux > NUM_ADC-1) Mux = 0; AdcStart(Mux); } ISR(ADC_vect) { union BytesInWord RetVal; RetVal.LH.LoByte = ADCL; RetVal.LH.HiByte = ADCH; AdcWerte[Mux] = RetVal.Word; AdcNextChannel(); } uint16_t AdcRead(uint8_t Kanal) { union BytesInWord RetVal; cli(); RetVal.Word = AdcWerte[Kanal]; sei(); return RetVal.Word; } // Aufrufreihenfolge in main() // // AdcNextChannel(); // // ... etwas warten // // while(1) // { // xyz = AdcRead(0); // zyx = AdcRead(1); // usw. // } solltest du nicht weiterkommen, sende mir eine Mail. Kann dir mit Funktionen und Rumrechnerei rund um den KTY an eimen AVR ADC weiterhelfen. schönen Feierabend Joachim Rath
ich versteh nicht, warum einige hier immer meinen, sie würden den Leuten helfen, wenn sie ihnen eine fertige Lösung bieten. So lernt doch keiner was, das Stichwort sollte "Hilfe zur Selbsthilfe" heißen.
Thorsten wrote: > ich versteh nicht, warum einige hier immer meinen, sie würden den Leuten > helfen, wenn sie ihnen eine fertige Lösung bieten. So lernt doch keiner > was, das Stichwort sollte "Hilfe zur Selbsthilfe" heißen. leichte Schläge auf den Hinterkopf fördern das Denkvermögen. Grüße aus dem Odenwald, Joachim Rath
...auf die Vor-''Schlaege'' aus dem Odenwald verzichtet die Welt sehr gerne !
Thorsten wrote: > ich versteh nicht, warum einige hier immer meinen, sie würden den Leuten > helfen, wenn sie ihnen eine fertige Lösung bieten. So lernt doch keiner > was, das Stichwort sollte "Hilfe zur Selbsthilfe" heißen. Ich kann auch mit einer fertigen Lösung lernen. Bisher war es bei mir meist so, dass ich in einer neuen Umgebung zuerst funktionierenden Beispielcode genommen habe, den analysiert habe und dann nach und nach verändert habe. Dann bin ich zu komplett eigenem Code gewechselt. Die fertige Lösung ist sowas wie der Lift auf die erste Bergstation. Man kann rasch den Berg runterfahren und sofort Spass haben oder von dort aus den grossen Aufstieg wagen.
Thorsten wrote: > [c] > ADMUX = mux; // Kanal waehlen > ADMUX |= (1<<REFS0) | (1<<ADLAR); // AVCC als Referenzspannung wählen > und Ergebniss ins HighRegister Danke dafür. problem besteht noch. ich erhalte am Eingang des ADC eine Spannung von 1.311 Volt, was bei einem festen Widerstand von 5600 ohm und dem KTY der bei zimmertemp (25°C) 2000 ohm wiedergibt, korrekt ist. Also muss es an dem Code liegen. was übersehe ich?
Amir B-a wrote:
> kann es eventuell an der Beschltung mit VCC statt AVCC liegen?
Naja, wenn Du Dir schon die Mühe machst, AVCC und VCC mit einem
LC-Tiefpass zu entkoppeln, ist es natürlich nicht wirklich sinnvoll, die
Sensoren mit dem ungefilterten VCC zu versorgen. Aber dass gar keine
Ausgabe kommt, kann daran eigentlich nicht liegen.
Übrigens:
Räum erstmal Deinen Code und v.a. die Kommentare auf. Ich gehe mal davon
aus, dass es sich immer noch um den zuletzt von Dir geposteten Code
handelt. Und Zeilen wie
1 | DDRC = 0xC; //Pin2 und 3 des PortC als Ausgang definiert |
sind schöne Beispiele für die Diskrepanz zwischen Code und Kommentar...
Der kommentar passt doch zu dem statement. hex C entspricht 1100 also pin 2 und 3 auf high. es kommt ja eine ausgabe aber die kann unmöglisch stimmen. erhalte eine 3 bei zimmertemp.
Amir B-a wrote: > Der kommentar passt doch zu dem statement. > hex C entspricht 1100 also pin 2 und 3 auf high. Ah ja, hast Recht. Ich schreibe Hex-Zahlen immer mindestens zweistellig (schließlich sind 8 Bit eh die kleinste Einheit), weshalb ich das falsch interpretiert habe. Bei mir hätte da ein 0x0C hingehört. > es kommt ja eine ausgabe aber die kann unmöglisch stimmen. > erhalte eine 3 bei zimmertemp. Tja, das ist seltsam.
>>1<<ADIE) schaltet den Interrupt frei. Eine ISR hast du aber nicht! >den interrupt nutzte ich hier für >while ( (ADCSRA & (1<<ADIF))==0 ); // auf ende der Wandlung Schau mal im GCC-Tutorial nach dem Unterschied Nutzung Interrupt/ISR und Interruptflags.
daran liegt es aber nicht. denn ich probiere es mit verschiedenen versionen. z.b folgenden #include <avr/io.h> //In io.h sind die Registernamen definiert #include <stdint.h> //Standardisierte Datentypen werden in der Header-Datei stdint.h definiert #include <avr/interrupt.h> int main(void){ //uint8_t adcwert; DDRB = 0xff; //mit DDR wird der gesamte PortB als Ausgang definiert PORTB = 0x2; //in P0 und P1 wird eine 1 (entspricht einem High=vcc) geschrieben DDRC = 0x0; //Pin2 und 3 des PortC als Ausgang definiert //PORTC = 0x8; DDRD = 0xFF; uint8_t adc(uint8_t admux) { uint8_t val; ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0); ADMUX = admux; ADMUX |= (1<<REFS1) | (1<<REFS0); ADCSRA |= (1<<ADSC); while (ADCSRA & (1<<ADSC)); val = ADCL; val = ADCH; ADCSRA &= ~(1<<ADEN); return val; } /*adcwert = ReadChannel(0); PORTD = adcwert;*/ //PORTD = ReadChannel(1); while(1) { PORTD=adc(1); } //Ende Haupt-while schleife return 0; //wird nie erreicht! (siehe while schleife) }//ende Main
Lutz wrote: > Schau mal im GCC-Tutorial nach dem Unterschied Nutzung Interrupt/ISR und > Interruptflags. Ist oben auch schon mal angesprochen worden. Ist aber in diesem Fall kein Porblem, da die Interrupts global gesperrt sind (kein sei(), zumindest habne ich keins gesehen). Das Abfragen des Flags kann man so machen, wobei man allerdings das ADIE tatsächlich nicht setzen sollte (auch wenn es wie gesagt in diesem Fall noch harmlos ist, aber nur so lange wie keine anderen Interrupts benötigt werden; dann knallt's). Es ist aber sinnvoller, das ADSC abzufragen. Das bleibt nämlich während der gesamten Wandlung gesetzt und wird am Ende automatisch gelöscht. Das Auslesen von ADCL kann man sich auch sparen, wenn man nur 8 Bit benötigt und ADLAR gesetzt ist.
Amir B-a wrote: > ADMUX = admux; > ADMUX |= (1<<REFS1) | (1<<REFS0); Öhhh, wo ist bitteschön das ADLAR geblieben? So bekommst Du tatsächlich maximal ne 3 als Ausgabe!
Übrigens: Was soll der Quatsch, die ADC-Funktion innerhalb von main zu definieren? Das ist Unsinn. Warum hast Du das geändert? Funktionen gehören außerhalb von anderen Funktionen!
Johannes M. wrote: > Amir B-a wrote: >> ADMUX = admux; >> ADMUX |= (1<<REFS1) | (1<<REFS0); > Öhhh, wo ist bitteschön das ADLAR geblieben? So bekommst Du tatsächlich > maximal ne 3 als Ausgabe! man das hab ich ja voll übersehen. ich teste das mal.
Habe den code bearbeitet und erhalte nun einen anderen wert an port D, der mich aber immer noch nicht "überzeugt", das es richtig ist. und zwar erhalte ich bei folgenden code den wert 01000011 = 67 dezimal. uint8_t adc(uint8_t admux) { ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0); ADMUX = admux; ADMUX |= (0<<REFS1) | (1<<REFS0) | (1<<ADLAR); ADCSRA |= (1<<ADSC); while (ADCSRA & (1<<ADSC)); uint8_t val = ADCL; val = ADCH; val = 0; val = ADCH; ADCSRA &= ~(1<<ADEN); return val; } int main(void){ //uint8_t adcwert; DDRB = 0xff; //mit DDR wird der gesamte PortB als Ausgang definiert PORTB = 0x2; //in P0 und P1 wird eine 1 (entspricht einem High=vcc) geschrieben DDRC = 0x0C; //Pin2 und 3 des PortC als Ausgang definiert PORTC = 0x0C; DDRD = 0xFF; /*adcwert = ReadChannel(0); PORTD = adcwert;*/ //PORTD = ReadChannel(1); while(1) { PORTD=adc(1); } //Ende Haupt-while schleife return 0; //wird nie erreicht! (siehe while schleife) }//ende Main das mit der funktion inerhalb der main war nicht beabsichtigt.
muss ich die pin explizit als eingang angeben oder ist es mit dem befehl DDRC = 0x0C; getan?
> uint8_t val = ADCL; > val = ADCH; > val = 0; > val = ADCH; Kannste mal erzählen, was der Mumpitz da soll? Du brauchst hier gar keine Hilfsvariable. Ein einfaches "return ADCH" am Ende genügt völlig.
Amir B-a wrote: > muss ich die pin explizit als eingang angeben oder ist es mit dem befehl > DDRC = 0x0C; > getan? Wie willst Du die denn anders "als Eingang angeben" als mit einer 0 im DDR?
> ADMUX |= (0<<REFS1) | (1<<REFS0) | (1<<ADLAR);
Und die Referenzspannung ist jetzt auch plötzlich wieder eine andere?
Naja, mit der Einstellung aus der letzten Version hättest Du
1,3irgendwas V auch nicht erfassen können. Trotzdem ist es insbesondere,
wenn man mit |= arbeitet, sinnvoll, die ganzen idiotischen "0 <<
irgendwas" wegzulassen. Eine Null kann man schieben sooft man will, das
bringt nichts.
Und nochwas: Bitte gewöhne Dir endlich an, den Code, den Du postest, anständig zu formatieren! Dann kann man das auch lesen und die ganzen Zeilenumbrüche in den Kommentaren gibt's auch nicht.
Ach ja, warum schaltest Du den ADC nach jeder Wandlung wieder ab? Es wird doch sowieso praktisch kontinuierlich gewandelt. Außerdem ist die jeweils erste Wandlung nach dem Einschalten des ADC für die Tonne. Da ist weiter oben auch schon mal drauf hingewiesen worden. Lass den ADC an oder mache eine Dummy-Wandlung nach jedem Einschalten.
das mit der formatierung werde ich in zukuunft übernehmen. die referenzspaunung sei AVCC ist wohl dur copy und paste durcheinander gekommen. die nullen waren für die bessere lesbarkeit. das abschlaten ist für die zukunft es kommt ja noch was zu den code hinzu. damit spar ich strom. ich habe nun folgenden code: das mit der holfsvariable dient zum auslesen des adc wertes ich habe gelesen das an ihn einmal "warmlaufen" lassen soll. neue version. nur für dich johnny :-)
1 | uint8_t adc(uint8_t admux) |
2 | {
|
3 | ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0); |
4 | ADMUX = admux; |
5 | ADMUX |= (1<<REFS0) | (1<<ADLAR); |
6 | ADCSRA |= (1<<ADSC); |
7 | while (ADCSRA & (1<<ADSC)); |
8 | uint8_t val = ADCL; |
9 | val = ADCH; |
10 | return ADCH; |
11 | }
|
12 | |
13 | int main(void){ |
14 | //uint8_t adcwert;
|
15 | |
16 | DDRB = 0xff; //mit DDR wird der gesamte PortB als Ausgang definiert |
17 | PORTB = 0x2; //in P0 und P1 wird eine 1 (entspricht einem High=vcc) geschrieben |
18 | |
19 | DDRC = 0x0C; //Pin2 und 3 des PortC als Ausgang definiert |
20 | PORTC = 0x0C; |
21 | |
22 | DDRD = 0xFF; |
23 | |
24 | |
25 | |
26 | |
27 | /*adcwert = ReadChannel(0);
|
28 | PORTD = adcwert;*/
|
29 | //PORTD = ReadChannel(1);
|
30 | while(1) { |
31 | |
32 | PORTD=adc(1); |
33 | |
34 | |
35 | } //Ende Haupt-while schleife |
36 | |
37 | return 0; //wird nie erreicht! (siehe while schleife) |
38 | |
39 | }//ende Main |
Der wert 67 scheint aber gar nicht mal so falsch zu sein oder? ich nutze ja nur 8-bit. also habe ich einen werte bereich von 0-255.
nimm einfach mal die Funktion aus... http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Aktivieren_des_ADC und schmeiss deine ADc fkt. dafür raus.. PS: dein Lesen des ADC Register lässt das Ding nicht im geringsten warmlaufen...aber das wird in dem Link schon mitgemacht... Aber aufpassen dort wird mit der interen Referenz gearbeitet (anderes Maximum)
Amir B-a wrote: > Der wert 67 scheint aber gar nicht mal so falsch zu sein oder? > ich nutze ja nur 8-bit. also habe ich einen werte bereich von 0-255. Ja, die 67 hatte ich oben übersehen. Das scheint ja zumindest ungefähr zu stimmen...
... ... wrote: > nimm einfach mal die Funktion aus... > http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Aktivieren_des_ADC > > und schmeiss deine ADc fkt. dafür raus.. > > PS: dein Lesen des ADC Register lässt das Ding nicht im geringsten > warmlaufen...aber das wird in dem Link schon mitgemacht... > > Aber aufpassen dort wird mit der interen Referenz gearbeitet (anderes > Maximum) glaubst du wirklisch das hätte ich nicht schon als erstes gemacht? ich werde nun einfach mal eis wasser und siedenes wasser messen um einen anhaltspunkt über die 67 zu haben. lasse euch wissen wat passiert ist. peace.
OK mal eine sache die mir gerade aufgefallen ist. ich erhalte an port D folgenden binären wert 01000010 = 67 dez aber das sind ja nur 8 bit die zwei LSB fehlen in der btrachtung, somit habe ich doch im grunde 268 dez als adc wert oder?
also der wert ist meiner meinung endlisch akzeptabel. ich habe das mal mittel des dreisatzes ausgerechnet 1,31V = bei zimmertemp
kann mir noch jemand einen algorythmus geben wie ich das in eine Temperatur umrechne Danke allen für die Hilfe
> kann mir noch jemand einen algorythmus geben wie ich das in eine > Temperatur umrechne Sieh dir mal folgenden Link an http://www.sprut.de/electronic/pic/projekte/thermo/thermo.htm Vergiss den PIC spezifischen Teil und lies einfach nur was Sprut zum Thema Umrechnung bzw. Linearisierung zu sagen hat.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.