Hallo uC-Freunde!
Ich habe folgendes Problem,
ich möchte mit einem ADC-Eingang eine Spannung einlesen und den gleichen
Spannungswert am DAC-Ausgang ausgeben.
Leider funktioniert dies noch nicht richtig.
Ich gebe 5 V an den Eingang und erhalte am Ausgang lediglich 2,62 V. DAC
und ADC lasse ich über die interne Vref 2,56 V laufen.
Kann mir jemand sagen, was ich in meinem Code falsch mache?!
daci schrieb:> Ich gebe 5 V an den Eingang und erhalte am Ausgang lediglich 2,62 V. DAC> und ADC lasse ich über die interne Vref 2,56 V laufen.
Wie soll da auch (wesentlich) mehr als 2,56V rauskommen?
daci schrieb:> ich möchte mit einem ADC-Eingang eine Spannung einlesen
Mit welchem?
> und den gleichen Spannungswert am DAC-Ausgang ausgeben.
Mit welchem?
> 5 V an den Eingang ... Vref 2,56 V
Kann das der ADC?
daci schrieb:> Ich gebe 5 V an den Eingang und erhalte am Ausgang lediglich 2,62 V. DAC> und ADC lasse ich über die interne Vref 2,56 V laufen.
Und wie soll das gehen?
Wenn du dem ADC eine 2.56V Referenz gibst, dann kann der schon mal
prinzipbedingt keine Spannungen größer als 2.56V feststellen. Alles was
darüber hinausgeht ist für den ADC genau so, als ob du die
Referenzspannung angelegt hättest.
> Kann mir jemand sagen, was ich in meinem Code falsch mache?!> while(1)> {> ADCSRA |=(1<<ADSC);//ADC_starting_conversation
Schön.
Denkst du nicht, dass es eine gute Idee wäre, wenn man dann auch darauf
warten würde, dass der ADC fertig gewandelt hat, ehe man sich das
Ergebnis abholt?
daci schrieb:> Laut Datenblatt: • 0 - VCC ADC Input Voltage Range (VCC = 5V)>> kann der uC 5V am ADC!
Ja, das kann er elektrisch ab.
Aber für das Wandlungsergebnis ist die Referenzspannung ausschlaggebend.
Sie definiert, was für den ADC 100% (also Voll-'Ausschlag') darstellt.
Der ADC tut im Grunde nichts anderes als die Eingangsspannung mit dieser
Referenzspannung zu vergleichen und er liefert dir eine Angabe, wie
dieses Verhältnis ist. Und mehr als 100% (oder eben 1023) geht nun mal
nicht.
daci schrieb:> Kann ich dann den DAC quasi nur von 0V bis 2,56V aussteueren?
Vermutlich ja, aber dein Fehler passiert schon früher:
du kannst das ADC nur bis Vref aussteuern.
daci schrieb:> Laut Datenblatt: • 0 - VCC ADC Input Voltage Range (VCC = 5V)> kann der uC 5V am ADC!
Man kuckt nicht bei "Absolute Maximum Values"!
> kann der uC 5V am ADC!
Er kann aber nur bis zur Vref wandeln, das steht weiter hinten im
Datenblatt...
daci schrieb:> Ist also mein Code richtig?
Wie kann man das wissen, wenn diese Fragen noch nicht beantwortet sind:
> daci schrieb:>> ich möchte mit einem ADC-Eingang eine Spannung einlesen> Mit welchem?>> und den gleichen Spannungswert am DAC-Ausgang ausgeben.> Mit welchem?
Bitte Ankreuzen:
[ ] ist geheim!
[ ] warum willst du das wissen?
[ ] darf ich nicht sagen.
[ ] sieht man doch!
Hallo!
Ich habe meine Vref auf 5 V erhöht und schau an, ich kann meine
eingelesene Spannung 1:1 ausgeben.
Jedoch müsste ich noch softwaremäßig die Wandlung und
Registerbeschreibung abwarten und dann erst die Spannung an D2A
ausgeben.
Kann mir jemand ein Bsp. geben, wie ich das in meinen vorhanden Code
noch einfügen kann?
void init_adc(void)
{
ADMUX |=
(0<<REFS1)|(0<<REFS0)|(1<<ADLAR)|(1<<MUX3)|(0<<MUX2)|(0<<MUX1)|(1<<MUX0)
; //External_Referencevoltage_used //Right_Adjust_ADC_result //Select
ADC_9
ADCSRA |= (1<<ADEN)|(1<<ADATE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
//ADC_enable
//ADC_Auto_trigger_enable//ADC_Prescaler_Division_128////ADIF/ADIE????
ADCSRB |=
(0<<ADTS3)|(0<<ADTS2)|(0<<ADTS1)|(0<<ADTS0);//Free_Running_Mode_enable
}
void get_adc_data(void)
{
while(1)
{
ADCSRA |=(1<<ADSC);//ADC_starting_conversation
DACH = ADCH; //ADC_H soll nach DAC_H kopiert werden
DACL = ADCL; //ADC_L soll nach DAC_L kopiert werden
DACON |= (1<<DALA)|(1<<DAOE)|(1<<DAEN); //DAC_starting_conversation
}
}
Lieg ich richtig, wenn diese Funktion mit folgendem Register bearbeiten
kann?
• Bit 4– ADIF: ADC Interrupt Flag
Set by hardware as soon as a conversion is complete and the Data
register are updated with the
conversion result.
Cleared by hardware when executing the corresponding interrupt handling
vector.
Alternatively, ADIF can be cleared by writing it to logical one.
Danke!
Gruss
daci schrieb:> @lkmiller>> Einlesen: ADC9 PC5> Ausgeben: D2A PC7>> Warum ist das so wichtig?!!!Das ist erst mal nicht so wichtig.
Aber: Es gibt auf der Welt mehr als nur einen Typ von ADC. Genauso wie
es auch mehr als nur einen Typ von DAC gibt.
Bis jetzt kann mun nur raten, dass du von einem ADC sprichst, der in
einen AVR eingebaut ist. Zumindest suggeriert das der Programmcode.
Ob dieser AVR dann auch einen DAC eingebaut hat oder nicht, kann man
mangels Wissen um welchen AVR es sich handelt, aber nicht sagen. Die
meisten (alle?) haben keinen DAC eingebaut, so dass man über das genaue
Verhalten deises DAC nur raten kann.
Wenn du exakte AUskünfte willst, dann komm auch mit exakten
Informationen rüber. Wir sitzen nicht hinter dir und sehen dir über die
Schulter, was du vor dir am Tisch liegen hast. Auf unserer Seite des
Monitors sieht man da eher schlecht, so dass wir des öfteren auf die
Kristallkugel angewiesen sind. Und das willst du eigentlich nicht
wirklich, dass wir raten müssen.
Karl Heinz Buchegger schrieb:> Und das willst du eigentlich nicht wirklich, dass wir raten müssen.
Und noch wichtiger: wir (oder zumindest ich) wollen das auch nicht...
Am einfachsten wäre es, immer gleich einen Schaltplan mitzuposten, dann
weiß jeder, von was da die Rede ist, und wie das Zeug zusammengeschaltet
ist.
Ich verwende eine AT90PWM3B - uC.
Dank eurer Tipps, funktioniert alles soweit ganz gut, bis auf diese ADIF
Interrupt-Flag um das Wandlungsende zu erfassen.
Meine Idee:
while(1)
{
if(ADIF Flag ist gesetzt)
{
-Kopiere ADC-Register ins DAC-Register
-Rücksetzen des Interrupflag
-ADC start conversation
}
else
{
-ADC start conversation
}
DAC start conversation
}
Gruss
daci schrieb:
> Lieg ich richtig, wenn diese Funktion mit folgendem Register bearbeiten> kann?>> • Bit 4– ADIF: ADC Int
Lass das Interrupt Flag in Ruhe.
Du setzt das ADSC Flag auf 1 um die Wandlung zu starten und der ADC
zieht es wieder zurück auf 0 wenn er fertig ist.
Ganz einfach und simpel.
@kbuchegg
Habe es jetzt so gemacht:
void get_adc_data(void)
{
while(1)
{
ADCSRA |=(1<<ADSC);//ADC_starting_conversation
while( ADCSRA & (1<<ADSC))
{
DACH = ADCH; //ADC_H soll nach DAC_H kopiert werden
DACL = ADCL; //ADC_L soll nach DAC_L kopiert werden
DACON |= (1<<DALA)|(1<<DAOE)|(1<<DAEN); //DAC_starting_conversation
}
}
}
Passt das, oder soll ich die DAC-starting-conversation aus der
while-schleife nehmen?
Vielen DANK!
Gruss
daci schrieb:> @kbuchegg>> Habe es jetzt so gemacht:>> void get_adc_data(void)> {>> while(1)> {>> ADCSRA |=(1<<ADSC);//ADC_starting_conversation>>> while( ADCSRA & (1<<ADSC))> {> DACH = ADCH; //ADC_H soll nach DAC_H kopiert werden> DACL = ADCL; //ADC_L soll nach DAC_L kopiert werden
Aha.
Da steht:
Solange der ADC #NICHT# fertig ist
{
Hole das Ergebnis
und bestücke den DAC damit
}
Das wird wohl nicht so wahnsinnig sinnvoll sein. Solange der ADC #NICHT#
fertig ist, hast du keine sinnvollen Werte zum Arbeiten.
Das ist Punkt 1.
Punkt 2 besteht darin, dass du eine Reihenfolge beim
Auslesen/Beschreiben von 16 Bit Registern einhalten musst.
@kbuchegg:
Du hast mir doch folgenden Tipp gegeben, dass ich es so machen soll!
Du setzt das ADSC Flag auf 1 um die Wandlung zu starten und der ADC
zieht es wieder zurück auf 0 wenn er fertig ist.
Ganz einfach und simpel.
ADCSRA |=(1<<ADSC);//ADC_starting_conversation
while( ADCSRA & (1<<ADSC))
;
...
und ich habe es so übernommen!
void get_adc_data(void)
{
ADCSRA |=(1<<ADSC);//ADC_starting_conversation
while( ADCSRA & (1<<ADSC))
{
DACH = ADCH; //ADC_H soll nach DAC_H kopiert werden
DACL = ADCL; //ADC_L soll nach DAC_L kopiert werden
DACON |= (1<<DALA)|(1<<DAOE)|(1<<DAEN); //DAC_starting_conversation
}
}
Danke!
daci schrieb:> @kbuchegg:>> Du hast mir doch folgenden Tipp gegeben, dass ich es so machen soll!>> Du setzt das ADSC Flag auf 1 um die Wandlung zu starten und der ADC> zieht es wieder zurück auf 0 wenn er fertig ist.>> Ganz einfach und simpel.> ADCSRA |=(1<<ADSC);//ADC_starting_conversation> while( ADCSRA & (1<<ADSC))> ;> ...>>>> und ich habe es so übernommen!
Nein hast du nicht.
Wenn du es übernommen hättest, dann hättest du geschrieben
Und mit ein wenig Nachdenken, was das ADSC Flag aussagt, kann man sich
leicht davon überzeugen, dass da steht
Starte den ADC
Warte, bis der ADC fertig ist
Verarbeite den ADC Wert
Bleibt noch Punkt 2:
Du kannst nicht einfach beliebig die Register lesen/schreiben, wie du
lustig bist. Du musst eine Reihenfolge High-Byte / Low-Byte einhalten.
Beim Auslesen von 16 Bit Register:
erst Low Byte lesen
dann High Byte lesen
Beim Schreiben von 16 Bit Registern
erst High-Byte schreiben
dann Low-Byte schreiben
Ich gehe mal davon aus, dass der gcc genauso wie für die meisten anderen
Dinge ein Pseudo-16 Bit Register für den DAC breitstellt. Dann kümmert
sich der Compiler bei
um die richtige Reihenfolge.
Ob du noch irgendwas spezielles für den DAC brauchst oder ob du dem
ständig Werte zuweisen kannst, entzieht sich meiner Kenntnis.
daci schrieb:> @kbuchegg:>> ich habe den code jetzt soweit verstanden.>> Leider verstehe ich Pkt.2 nicht, wie soll ich das machen,
Was ist da jetzt schwer drann
low_byte = ADCL;
high_byte = ADCH;
DACH = high_byte;
DACL = low_byte;
oder eben, wenn es ein Pseudo-16 Bit Register gibt: überlass es dem
Compiler das richtig zu machen
DACW = ADCW;
oder
DAC = ADC;
je nachdem, wie das Pseudo 16 Bit Register vom DAC heißt (DAC oder
DACW). Beim ADC geht beides: sowohl ADC als auch ADCW sind gültige Namen
für das Pseudo-16 BIt Register und der COmpiler liest es in der
korrekten Reihenfolge getrennt nach High-Byte und Low-Byte aus.
@kbuchegg:
Vielen Dank für deine Bemühungen!
Es funktioniert aber nur, wenn ich es so löse:
ADCSRA |=(1<<ADSC);//ADC_starting_conversation
while( ADCSRA & (1<<ADSC))
{
DAC = ADCW;
DACON |= (1<<DALA)|(1<<DAOE)|(1<<DAEN); //DAC_starting_conversation
}
und nicht wie vorgeschlagen:
ADCSRA |=(1<<ADSC);//ADC_starting_conversation
while( ADCSRA & (1<<ADSC))
;
DAC = ADCW;
DACON |= (1<<DALA)|(1<<DAOE)|(1<<DAEN); //DAC_starting_conversation
DANKE!
daci schrieb:> @kbuchegg:>> Vielen Dank für deine Bemühungen!>> Es funktioniert aber nur, wenn ich es so löse:
ist trotzdem falsch. (Der ADC Teil). Wenn du mir nicht glaubst, dann
sieh halt im Datenblatt nach. ADSC wird auf 0 gesetzt, wenn der ADC
fertig ist. Der Rest folgt daraus.
Dann gibt es eben noch eine Nebenbedingung. Wahrscheinlich irgendwas im
DAC.