Guten Tag,
und zwar habe ich folgendes Problem: Ich benutze einen ATmega128L und
möchte damit einen AD-Wandler realisieren. Nun liegt beim AREF-Pin eine
Spannung von 3,27 V und beim ADC0-Pin eine Spannung von 0,22 V an.
Bisher auch noch alles ok. Nur wenn ich mir die Registerwerte von ADCL
und ADCH am Display anzeigen lasse, dann sehe ich dass im ADCH eine 3
und im ADCL 255 steht. Demnach sind alle 10 Bits des ADC-Wert-Registers
mit einer 1 besetzt. Was eigentlich bedeuten müsste, dass eine Spannung
von 3,27 Volt (oder höher?) anliegt. Was aber laut Multimeter nicht der
Fall ist.
Die Konfiguration des ADC's sieht wie folgt aus:
ADMUX=0x00;
ADCSRA=0x80;
Desweiteren gibt es noch eine Besonderheit, welche ich mir nicht ganz
erklären kann. Denn wenn ich das Multimeter an Ground und ADC0 anlege,
so messe ich die 0,22 Volt, allerdings wechselt dann der Registerwert
von ADCH auf 0, und der Wert von ADCL schwankt in etwa zwischen 20 und
160. Warum schwankt dann der ADC-Wert? Ich messe die Spannung ja
parallel, da dürfte sich doch eigentlich nichts ändern oder?!
Ich stelle nun noch den kompletten Programmcode hier rein, auch wenn ich
denke dass vielen mein Programmierstil nicht wirklich gefallen wird:
Kurze Beschreibung noch:
Ein Timer startet alle paar ms die ISR des ADC's. Dort wird solange
gewartet bis die Umwandlung abgeschlossen ist, und anschließend werden
die Registerwerte am LCD ausgegeben.
Florian Z. schrieb:> und ADCH am Display anzeigen lasse, dann sehe ich dass im ADCH eine 3> und im ADCL 255 steht.
Fass die beiden zusammen und lass sie dir als Zahl zwischen 0 und 1023
anzeigen. Das ist doch Unsinn sich in C die Einzelbytes anzeigen zu
lassen. SChmeiss dir doch nicht selber Prügel zwischen die Beine wenn es
nicht sein muss
1
while((ADCSRA&0x40)==0x40)//Warten bis Umwandlung abgeschlossen ist
2
{
3
}
4
unsignedintvalue=ADC;
5
chartemp[10];
6
sprintf(temp," %d ",value);
7
lcd_puts(temp);
8
}
und definiere die das nächste mal dein Array temp groß genug, dass du
auch einen String der länger als 0 Zeichen ist, da reinbringst.
> Ich stelle nun noch den kompletten Programmcode hier rein, auch wenn ich> denke dass vielen mein Programmierstil nicht wirklich gefallen wird:
Fang damit an, die Hex-Werte durch eine vernünftige Bit-Schreibweise zu
ersetzen. Hier im Forum werden nicht viele Lust dazu haben, sich das
Datenblatt deines Prozessors zu holen und zu kontrollieren was du da
eigentlich bei den Hex-Zahlen für Bits gesetzt hast und ob die beim M128
eventuell an anderer Stelle sitzen als du denkst.
Hi
>ADCSRA=0x80
-Keine Interruptfreigabe für den ADC
-Vorteiler 2, also mit Sicherheit viel zu schnell
> SREG|=0x80;
Kryptischer geht es kaum.
> while((ADCSRA&0x40)==0x40) //Warten bis Umwandlung abgeschlossen ist
Blödsinn. Der Interrupt kommt wenn die Wandlung abgeschlossen ist.
....
MfG Spess
spess53 schrieb:> Hi>>>ADCSRA=0x80>> -Keine Interruptfreigabe für den ADC> -Vorteiler 2, also mit Sicherheit viel zu schnell
Du hast den hier übersehen.
#define adc_get_temperature ADCSRA|=0x4C
(und ich habs auch erst gesehen, nachdem ich 20 mal zwischen dem
Datenblatt und dem Code hin und her gewechselt habe)
Alles in allem ein deutlicher Hinweis für den TO, dass seine
Schreibweise scheisse ist.
Anstatt zu lametieren, dass sie uns nicht gefallen wird, sollte er sie
lieber ändern. Es gibt schon einen Grund dafür, warum wir das nicht so
schreiben.
Florian Z. schrieb:> Desweiteren gibt es noch eine Besonderheit, welche ich mir nicht ganz> erklären kann. Denn wenn ich das Multimeter an Ground und ADC0 anlege,> so messe ich die 0,22 Volt, allerdings wechselt dann der Registerwert> von ADCH auf 0, und der Wert von ADCL schwankt in etwa zwischen 20 und> 160. Warum schwankt dann der ADC-Wert? Ich messe die Spannung ja> parallel, da dürfte sich doch eigentlich nichts ändern oder?!
klingt, als ob dir irgendwas sehr hochohmiges den Eingang hochzieht. So
hochohmig, dass dein Messgerät es wieder runterziehen kann.
grüß euch,
zu meiner kryptischen hex-registerwert-setzung: unser lehrer hat es uns
drei jahre so beigebracht. in der letzten klasse hätte ich es auch mit
der anderen variante (einzelne bits setzen) versucht - allerdings meinte
er dann ich soll es so weiter handhaben wie er es uns beigebracht hat -
und ehrlich gesagt finde ich diese schreibweise auch nicht
allzuschlecht, zumindest wenn man sich daran gewöhnt hat. für jemand
anderen ist es natürlich schlechter nachvollziehbar. ihr könnt diesen
absatz eventuell als "quasi-entschuldigung" oder auf jeden fall als
kurze erklärung hinnehmen.
@ Karl heinz Buchegger:
danke für den tipp - wusste gar nicht dass ich den adc als ganzes
auslesen kann.
@ Klaus T.:
werde ich mir gleich mal anschaun, danke!
ich glaube ich habe den fehler gefunden (hardwareseitig), bin mir zwar
noch nicht sicher ob es die lösung des gesamten problems ist, allerdings
ist es ein fehler. müsst euch also einstweilen nicht mehr mit meinem
code quälen. falls ich doch noch fragen habe werde ich mich nochmal
melden, und dementsprechend auch den code in eine besser lesliche form
bringen. danke soweit!
Florian Z. schrieb:> ser lehrer hat es uns> drei jahre so beigebracht
Wie soll ich mir das Vorstellen?
Ihr nehmt das Datenblatt, kreuzt die zu setzenden Bits an und rechnet
euch den Hex-Wert aus?
Oder könnt ihr das inzwischen aus dem 0xFF?
Florian Z. schrieb:> ich glaube ich habe den fehler gefunden (hardwareseitig)
Schön für dich, dürfen wir auch wissen woran es denn lag?
Glauben ist nicht wissen....
Florian Z. schrieb:> grüß euch,>> zu meiner kryptischen hex-registerwert-setzung: unser lehrer hat es uns> drei jahre so beigebracht.
Schick deinen Lehrer hier ins Forum.
Dann waschen wir ihm den Kopf.
Der ist doch gemeingefährlich!
Ein Lehrer sollte ein Vorbild sein. Aber kein schlechtes Vorbild. Wer
selbst nicht vernünftig programmierern kann, sollte nicht in die Lehre
gehen, sondern vielleicht selbst erst einmal einen Kurs machen.
Und nein. Dafür gibt es für deinen Lehrer keine wie immer geartete
Entschuldigung. Wer so etwas macht, dem sollte man mit dem nassen Fetzen
eine drüberziehen. Und wenn er es dann immer noch nicht geschnallt hat,
dann gehört ihm die Lehrbefugnis entzogen.
Es geht ja auch nicht unbedingt darum, was schneller geht. Je nach Übung
geht die Hexadezimal-Variante ja auch schneller, keine Frage.
Allerdings ist die Namen-Methode weitaus fehlerunanfälliger, portabler
und falls man mal den rückwärtigen Weg beschreitet (Aus dem Code wieder
wissen will, welche Bits gesetzt werden), geht es damit auch schneller.
Florian Z. schrieb:>> und zwar habe ich folgendes Problem: Ich benutze einen ATmega128L und> möchte damit einen AD-Wandler realisieren. Nun liegt beim AREF-Pin eine> Spannung von 3,27 V und beim ADC0-Pin eine Spannung von 0,22 V an.
Wie kommen die 3.27 V auf den AREF-Pin? Schaltschema?
>> Desweiteren gibt es noch eine Besonderheit, welche ich mir nicht ganz> erklären kann. Denn wenn ich das Multimeter an Ground und ADC0 anlege,> so messe ich die 0,22 Volt, allerdings wechselt dann der Registerwert> von ADCH auf 0, und der Wert von ADCL schwankt in etwa zwischen 20 und> 160. Warum schwankt dann der ADC-Wert? Ich messe die Spannung ja> parallel, da dürfte sich doch eigentlich nichts ändern oder?!>
ADC0 ist doch ein Eingang. Da musst du erst mal eine zu messende
Spannung anlegen. (Zum ersten Austesten vielleicht ein Spannungsteiler
mittels 2 Widerstaenden zwischen Vcc und Gnd)
> Ich stelle nun noch den kompletten Programmcode hier rein, auch wenn ich> denke dass vielen mein Programmierstil nicht wirklich gefallen wird:>
Wenn du den Programmcode so umschreibst dass er gefaellt, findest du
bestimmt selbst noch einige Fehler ;-)
> Kurze Beschreibung noch:> Ein Timer startet alle paar ms die ISR des ADC's. Dort wird solange> gewartet bis die Umwandlung abgeschlossen ist, und anschließend werden> die Registerwerte am LCD ausgegeben.>
Anscheinend hast du das Prinzip der Interrupts noch nicht so ganz
verstanden. In deinem Programm brauchst du den Timer gar nicht.
Wenn du den Interrupt fuer den AD-Wandler benutzt, dann wird
die entsprechende Interruptroutine automatisch aufgerufen sobald
die AD-Wandlung fertig ist. Um Interrupts einzuschalten musst
du im Hauptprogramm noch ein sei() einfuegen.
In einer Interrrup-Routine (also in ISR(ADC_vect) zum Beispiel)
macht man niemals irgendwelche langen Berechnungen wie z.B.
ein sprintf() oder lcd_puts().
Definiere doch einfach eine globale Variable, in die du den
neuen Wert reinschreibst. Dann noch ein Flag setzen dass der
Wert jetzt gueltig ist. Dann kannst du im Hauptprogramm auf
einen gueltigen Wert warten, den du dann ausgibst.
Also vielleicht etwa so:
<progcode>
static volatile unsigned char adc_low,adc_high; //neuer Messwert
static volatile char adc_flag=0; //1=gueltiger Wert vorhanden
//Das volatile wird gebraucht da verschiedene Pragrammteile
//darauf zugreifen sollen.
ISR(ADC_vect)
{
adc_low=ADCL;
adc_high=ADCH;
adc_flag=1; //Wert als gueltig markieren
ADCSRA |= (1<<ADSC);//naechste Wandlung starten (AD Start Conversion)
}
</progcode>
und im Hauptprogramm:
<progcode>
sei();
while(1)
{if(adc_flag==1) //falls gueltiger Wert vorhanden
{unsigned int value=(adc_high<<8)+adc_low;
flag=0; //Flag wieder ruecksetzen
sprintf(temp, "%d", value);
lcd_puts(temp);
}
}
</progcode>
Ich hoffe diese Hinweise helfen dir weiter.
Rolf
Hi
>Stimmt, habe ich uebersehen.
Auf so eine Idee muss man auch erst mal kommen.
Wenn man nach 3 Jahren Informatik (oder was auch immer) sei() nicht
kennt, kann es nicht nur am Lehrer liegen.
MfG Spess