Hallo!
Die Funktionen für den ADC sind aus der Procyon-Library. Wenn ich
folgende Schleife ausführe, kommt als Ergebnis nur für den ersten
Messwert ein einigermassen korrektes Ergebnis. Die anderen Messwerte
verwenden anscheinend immer einen Teil der vorhergehenden Wandlung.
Verwende ich für jeden Messwert eine eigene Schleife ist das Ergebnis
weitaus besser, eine Dummykonvertierung vor dem eigentlichen Aufruf der
kty_measure() routine führt dagegen zu keiner Verbesserung.
Hat jemand eine Idee was ich da falsch mache? Ich komme da nicht weiter
:-(
Die Messwerte sind als structs definiert und mit malloc initialisiert
worden.
Hier der Code (die wichtigsten Teile):
a2dInit();
a2dSetPrescaler(ADC_PRESCALE_DIV32);
for(lcount = 0; lcount < 65; lcount++){
kty_measure(TempMotor);
kty_measure(TempController);
kty_measure(TempFahrakku);
}
void kty_measure(measureT * m)
{
uint16_t tmp;
if (m->count) {
tmp = a2dConvert10bit(m->ioPin);
m->tval += tmp;
m->count--;
} else {
m->tval = m->tval / 101;
m->tval = m->tval - 150;
m->value = m->tval;
m->count = 64;
m->tval = 82;
}
}
Gruss,
Stephan
Hallo Stephan,
>Hat jemand eine Idee was ich da falsch mache?
Dein Programm-Code verstehe ich leider nicht,
aber ich vermute, Dein Mess-Prinzip hat einen gedanklichen Fehler.
Du machst folgendes:
Kanal umschalten
Messen
Kanal umschalten
Messen
usw.
besser wäre:
Kanal umschalten
Messen und Ergebnis verwerfen
Messen
Kanal umschalten
Messen und Ergebnis verwerfen
Messen
usw.
Bernhard
Hallo Bernhard,
du meinst sicher folgendes:
for(lcount = 0; lcount < 65; lcount++){
a2dConvert10bit(TempMotor->ioPin);
kty_measure(TempMotor);
a2dConvert10bit(TempController->ioPin);
kty_measure(TempController);
a2dConvert10bit(TempFahrakku->ioPin);
kty_measure(TempFahrakku);
}
Das habe ich bereits probiert da ich den Hinweis schon irgendwo im
Forum gefunden hatte. Leider tritt dadurch keine (sichtbare)
Verbesserung ein :-(
Gruss,
Stephan
> du meinst sicher folgendes:
Da kann ich leider nicht mitdiskutieren
>Leider tritt dadurch keine (sichtbare) Verbesserung ein
Und wenn Du längere Pausen zwischen den Messungen einlegst?
Aber wenn Du nur einen einzigen Kanal misst, dann stimmte das Ergebnis?
Ich denke, ich habe das Problem gefunden.
Die Eingänge für ADC1/2 (TempController/TempFahrakku) sind derzeit
offen. Ich hatte erwartet, dass beim Kanalwechsel das gleiche Ergebnis
wie bei einer Wandlung auf nur einem Kanal erscheind. DIES IST
ANSCHEINEND NICHT DER FALL grummel. Steht das im Datenblatt vom
ATmega128? Ich habs dann wohl beim überfliegen übersehen.
Wenn ich einen der nicht benutzten Messwerte auf ADC_CH_AGND lege,
stimmt das Ergebnis.
Danke Bernhard! Bin dadurch auf die Idee gekommen einen Kanal mal auf
GND zu legen.
HURRA :-)
Gruss,
Stephan
>Danke Bernhard! Bin dadurch auf die Idee gekommen einen Kanal mal auf>GND zu legen.
Mein Bankverbindung gebe ich Dir später ;)
>Die Eingänge für ADC1/2 (TempController/TempFahrakku) sind derzeit>offen.
Offene Eingänge sollte man vermeiden, habe auch schon diese
zeitraubende Erfahrung machen müssen.
Es entstehen undefinierte Spannungswerte an diesen Pins und diese sind
sogar noch abhängig von den Pegeln der anderen Pins anderer Ports.
Bernhard
Hallo,
ich weiß der Threat ist schon etwas älter ....
aber ich habe das selbe Problem nur ich verstehe die Lösung nicht denke
ich...
Ich habe alle Pins (außer den den ich messen will) an GND angelötet.
Seltsamerweise bekomme ich aber an allen Pins den selben Messwert...
Was ist gemeint mit:
Wenn ich einen der nicht benutzten Messwerte auf ADC_CH_AGND lege,
stimmt das Ergebnis.
Was genau hast du da im Code gemacht?
Gruß
Michael
@Michael
> Was genau hast du da im Code gemacht?
Kanal umschalten
Messen und Ergebnis "verwerfen"
Messen
Kanal umschalten
Messen und Ergebnis "verwerfen"
Messen
usw.
Bernhard
>Was meinst du mit ergebniss verwerfen?
Es wird gemessen, das Messergebnis wird aber ignoriert (Dummy-Messung),
erst die nächste Messung bringt das richtige Ergebnis
Hi,
code könnte helfen stimmt :-)
also ich hab zwei Versionen.
Die eine auf die es mir ankommt mißt nur an einem Pin.
Die andere hab ich aus dem Example der Lib und die misst alle
AD-Eingänge.
Ich wille einen LM35 auslesen. Der ist aber im Moment noch nicht da.
Deshalb habe ich ein Potentiometer an AD0 angeschlossen. Ich hab auch
mit einem Messgerät nachgemessen. Es ist also alles richtig
angeschlossen.
Die Hauptschleife sieht so aus:
while(1)
{
rprintf("Gemessener ADC-Wert : %d \r\n",getLM35ADCValue());
//gemessene Spannung
short voltage = (short)getLM35MeasuredVoltage();
rprintf("Gemessene Spannung : %d \r\n", voltage);
//Gemessene Temperatur
short temperature = (short)getLM35MeasuredTemperature();
rprintf("Gemessene Temperatur: %d \r\n",temperature);
}
**********************************************
**Die Methoden die ich benutzte kommen hier:**
**********************************************
void initLM35(){
// turn on and initialize A/D converter
a2dInit();
// configure a2d port pin (PORTA) as input
unsigned char mask = ~(0x01 << LM35_ADC_CHANNEL);
DDRA = DDRA & mask;
// pull-up resistor off
PORTA = PORTA & mask;
//AD-Cahannel wählen
a2dSetChannel (LM35_ADC_CHANNEL);
//set prescaler
a2dSetPrescaler(ADC_PRESCALE_DIV128);
//set adc reference
a2dSetReference(ADC_REFERENCE_AVCC);
}
short getLM35ADCValue(){
short adcValue = a2dConvert10bit(LM35_ADC_CHANNEL);
return(adcValue);
}
float getLM35MeasuredVoltage(){
short adcValue = getLM35ADCValue();
float measuredVoltage = (adcValue * REFERENCE_VOLTAGE)/1024;
return(measuredVoltage);
}
float getLM35MeasuredTemperature(){
float LM35MeasuredVoltage = getLM35MeasuredVoltage();
float measuredTemperature = LM35MeasuredVoltage *
DIRECTLY_PROPORTIONAL_FACTOR;
return(measuredTemperature);
}
void a2dInit(void)
{
sbi(ADCSR, ADEN); // enable ADC (turn on ADC power)
cbi(ADCSR, ADFR); // default to single sample convert mode
a2dSetPrescaler(ADC_PRESCALE); // set default prescaler
a2dSetReference(ADC_REFERENCE); // set default reference
cbi(ADMUX, ADLAR); // set to right-adjusted result
sbi(ADCSR, ADIE); // enable ADC interrupts
a2dCompleteFlag = FALSE; // clear conversion complete flag
sei(); // turn on interrupts (if not already on)
}
// configure A2D converter clock division (prescaling)
void a2dSetPrescaler(unsigned char prescale)
{
outb(ADCSR, ((inb(ADCSR) & ~ADC_PRESCALE_MASK) | prescale));
}
// configure A2D converter voltage reference
void a2dSetReference(unsigned char ref)
{
outb(ADMUX, ((inb(ADMUX) & ~ADC_REFERENCE_MASK) | (ref<<6)));
}
// sets the a2d input channel
void a2dSetChannel(unsigned char ch)
{
outb(ADMUX, (inb(ADMUX) & ~ADC_MUX_MASK) | (ch & ADC_MUX_MASK)); //
set channel
}
// Perform a 10-bit conversion
// starts conversion, waits until conversion is done, and returns result
unsigned short a2dConvert10bit(unsigned char ch)
{
a2dCompleteFlag = FALSE; // clear conversion complete flag
outb(ADMUX, (inb(ADMUX) & ~ADC_MUX_MASK) | (ch & ADC_MUX_MASK)); //
set channel
sbi(ADCSR, ADIF); // clear hardware "conversion complete"
flag
sbi(ADCSR, ADSC); // start conversion
//while(!a2dCompleteFlag); // wait until conversion complete
//while( bit_is_clear(ADCSR, ADIF) ); // wait until conversion
complete
while( bit_is_set(ADCSR, ADSC) ); // wait until conversion complete
// CAUTION: MUST READ ADCL BEFORE ADCH!!!
return (inb(ADCL) | (inb(ADCH)<<8)); // read ADC (full 10 bits);
}
Ich hoffe das ist nicht zu unübersichtlich .....
schonmal vielen Dank
Michael
Hallo,
ich geb ja zu es ist jede Menge code....
aber im Prinzip rufe ich nur Methoden aus der ARLib auf.
Dabei setze ich einen festen Kanal in die Methoden ein weil
der LM35 immer am selben Pin sein wird.
Ich glaube ich mache einen Fehler bei der Benutzung der AVRLib.
1) Ich muß doch eigentlich nur die Init Methode aufufen.
2)Dann setze ich die Referenzspannung
3) und den Prescaler.
4) dann setze ich noch den channel
5)Danach kann ich messen
1) a2dInit();
2)a2dSetReference(ADC_REFERENCE_AVCC);
3)a2dSetPrescaler(ADC_PRESCALE_DIV128);
4)a2dSetChannel (0);
5)a2dConvert10bit(LM35_ADC_CHANNEL);
Wo ist mein Fehler?!
Gruß
Michael
Hallo,
das hat leider nichts gebracht...
ich messe jetzt ganz seltsame werte ...
an GND ist jetzt nichtmehr 0 sondern was zwischen 30 und 40 ....
Noch jemand ideen?
Gruß
Michael
Hi,
das hatte ich schon probiert....
Ich hab gemessen .... den Wert in einer Variablen gespeichert ...
(dummy)
und dann nochmal gemessen und den Wert in einer anderen Variablen
gespeichert.. Der Wert hat dann einfach nicht gestimmt ....
Weitere Tipps? Also wie gesgat das meißte aus meinem Code ist aus der
AVR-Lib.
Hat damit mal jemand erfolgreich A/D gewandelt?
Gruß
Michael
Hallo,
ich habe eben mal den Code aus dem Tutorial verwendet um zu messen. Es
geht immernoch nicht....
Das sollte doch heißen dass ich einen Fehler bei der Beschaltung mache
oder?
Gruß
Michael
Hi,
ich habe einen Poti angeschlossen ....
ATMEGA128 Poti
GND ------- links
AD0 ------- mitte
VCC ------- rechts
AREF = AVCC = VCC
AGND = GND
Es klappt auch nicht wenn ich nur einen Kanal messe ...
Ich benutze jetzt eins zu eins den Code aus den Code aus dem
AVR-GCC-Tutorial ....
Ich erhalte immer die selben Werte ...
Egal ob ich an einem Kanal messe ..
Oder an allen....
Ich messe immer ADCW ungefähr 450 (+/- 20)
Gruß
Michael
Hallo,
ich hab das gesammte Projekt mal in ein Zip gesteckt...
Evtl hat ja jemand den Nerv es sich mal anzuschauen...
Die main steckt in a2dtest ...
Gruß
Michael
Hat evtl. jemand schon fertigen code zum A/D wandeln mit dem ATMEGA128
...?
wäre schön wenn man den posten könnte ...
dann könnte ich vergleichen wo der Unterschied ist!?
Hat wirklich keiner eine fertige routine in C?
Ich hab in der Codesammlung leider auch nichts entsprechendes gefunden.
Sowas muß doch jemand haben oder?