Forum: Mikrocontroller und Digitale Elektronik ADC vom Attiny verhält sich seltsam


von Peter Z. (Gast)


Angehängte Dateien:

Lesenswert?

Hallo allerseits,
ich versuche mit einem ATtiny84, LC-Display und einem PT1000 die 
Temperatur anzuzeigen.
Einen Teil vom Schaltplan habe ich hier im Anhang.
An X3 & X4 angeschlossen ist im Moment ein 1k Widerstand in Reihe mit 
einem 500 Ohm Poti. Dies ist zu Testzwecken eine PT1000 Simulation.

Hier ein Teil von meinem Code:
1
while(1)
2
{
3
    LCD_Anzeige(get_adc(2));// Poti an PA2 anzeigen
4
    LCD_Anzeige(100+get_adc(0b00001001));// Temperatur anzeigen
5
    _delay_ms(200);
6
}
7
//*********************************************************************
8
unsigned short int get_adc(unsigned char adc_mode)
9
{
10
  unsigned short int ADC_Wert = 0;
11
  ADMUX = adc_mode;
12
  
13
  _delay_us(500); //unbedingt notwendig für Differential Input channel!!!
14
15
  ADCSRA = 0b11000111;  // Start Conversation  
16
  while(ADCSRA & 1 << ADSC){}; // Wait for End of Conversation
17
  ADC_Wert += ADCL;
18
  ADC_Wert += ADCH << 8;
19
  return ADC_Wert;
20
}
Ich bin erst nach endlosem Gefummel zufällig darauf gekommen, das dieses 
_delay in der get_adc Routine bei differentiellen Eingänge (PA0 & PA1) 
notwendig ist.
Warum ist das so?

Jetzt geht es, aber bei Temperaturen unter ca 30°C schwankt die Anzeige 
um ca. 10°! Woran mag das liegen?

von Uwe (de0508)


Lesenswert?

Hallo,

hier ist noch ein Schreibfehler:
1
while(ADCSRA & 1 << ADSC){};

Was soll das bedeuten ?
Das kann doch keiner lesen !
1
ADCSRA = 0b11000111;

von Uwe (de0508)


Lesenswert?

Hallo Peter,

dann gibt es noch als Vereinfachung ADCW, damit ergibt sich:
1
ADC_Wert += ADCL;
2
ADC_Wert += ADCH << 8;
3
return ADC_Wert;

zu
1
return ADCW;

von Uwe (de0508)


Lesenswert?

Hallo Peter,

dann wäre noch interessant welche CPU Frequenz du verwendest, das sieht 
man nicht alles.

Wenn Du einen atTiny84 @16MHz verwendest, dann passt ja der "ADC 
Prescaler" ADPS2:0 = [111] mit 16MHz /128 = 125kHz.

: Bearbeitet durch User
von Bitflüsterer (Gast)


Lesenswert?

Tut mir leid, aber diesmal landest Du in meinem CSS-File.

Kein kompletter, kompilierbarer Code. Selbst der Codeschnipsel wäre 
überahaupt nicht kompilierbar. Falsche Variablennamen. Keine Schaltung. 
Nichtmal der Typ des Sensors. Kein noch so laienhafter Ansatz einer 
Analyse. Das langt.

Schönes Leben noch.

von Uwe (de0508)


Lesenswert?

Hallo Peter,

wie sieht die Initialisierung des ADC aus?

wird eine "Dummy" ADC-Wandlung mit verwerfen des Ergebnisses, wie im 
Datenblatt angegeben ist, durchgeführt ?

von Peter Z. (Gast)


Lesenswert?

Uwe S. schrieb:
> Hallo,
>
> hier ist noch ein Schreibfehler:while(ADCSRA & 1 << ADSC){};
> Was soll das bedeuten ?

Steht im Kommentar:// Wait for End of Conversation

> Das kann doch keiner lesen !
> ADCSRA = 0b11000111;

wie soll ich das besser schreiben?
z.B.
1
ADCSRA = (1<<ADEN)|(1<<ADSC)|ADC_Prescaler_128;
so zufrieden?

von Peter Z. (Gast)


Lesenswert?

Uwe S. schrieb:
> dann wäre noch interessant welche CPU Frequenz du verwendest, das sieht
> man nicht alles.
>

#define F_CPU 8000000

> Wenn Du einen atTiny84 @16MHz verwendest, dann passt ja der "ADC
> Prescaler" ADPS2:0 = [111] mit 16MHz /128 = 125kHz.

äh, versteh ich nicht ganz. Will Temperaturen und langsame Sachen 
messen, deshalb hatte ich den ADC so langsam wie möglich gemacht.

von Peter Z. (Gast)


Lesenswert?

Uwe S. schrieb:
> Hallo Peter,
>
> wie sieht die Initialisierung des ADC aus?

Es gibt keine Init_ADC, dies ist in der get_adc Routine enthalten.

> wird eine "Dummy" ADC-Wandlung mit verwerfen des Ergebnisses, wie im
> Datenblatt angegeben ist, durchgeführt ?

Öh wenn der erste Messwert falsch sein sollte, ist mir das bisher nicht 
aufgefallen.

von Peter Z. (Gast)


Lesenswert?

Bitflüsterer schrieb:
> Tut mir leid, aber diesmal landest Du in meinem CSS-File.
>
> Kein kompletter, kompilierbarer Code. Selbst der Codeschnipsel wäre
> überahaupt nicht kompilierbar. Falsche Variablennamen. Keine Schaltung.
> Nichtmal der Typ des Sensors. Kein noch so laienhafter Ansatz einer
> Analyse. Das langt.
>
> Schönes Leben noch.

Wer kann mir das erklären?
Muß ich wissen was ein CSS_file ist?
Was will mir Bitflüsterer damit sagen?
Ist mein Thread wirklich so blöd?

von Uwe (de0508)


Lesenswert?

Hallo Peter,

Danke.

Peter Zz schrieb:
> Uwe S. schrieb:
>> Hallo,
>>
>> hier ist noch ein Schreibfehler:while(ADCSRA & 1 << ADSC){};
>> Was soll das bedeuten ?
>
> Steht im Kommentar:// Wait for End of Conversation

Ja ich weiss, wie der ADC läuft und wie man ihn benützt.
Ok, du hast es nicht gesehen:
1
{};
Ist unsinnig.
Ein
1
while (ADCSRA & 1 << ADSC){ }
 reicht.

>> Das kann doch keiner lesen !
>> ADCSRA = 0b11000111;
>
> wie soll ich das besser schreiben?
> z.B.
>
1
> ADCSRA = (1<<ADEN)|(1<<ADSC)|ADC_Prescaler_128;
2
>
> so zufrieden?

Super, so kann jeder schnell sehen, was gewollt ist und es entstehen 
keine Kodierungsfehler.

von Peter Z. (Gast)


Lesenswert?

1
#define ADC_Prescaler_128 0b111
2
unsigned short int get_adc(unsigned char adc_mode)
3
{
4
  ADMUX = adc_mode;
5
  
6
  _delay_us(500); //unbedingt notwendig für Differential Input channel!!!
7
8
  ADCSRA = (1<<ADEN)|(1<<ADSC)|ADC_Prescaler_128;// Start Conversation
9
  while(ADCSRA & (1 << ADSC)){}; // Wait for End of Conversation
10
  return ADCW;
11
}
Habe jetzt dieses, "return ADCW" spart 10 Byte!
Thx!

Aber das Hauptproblem, warum brauche ich bei differentieller Wandlung 
dieses _delay_us(500) und warum die Anzeige bei unter 30° schwankt ist 
nicht gelöst.

von Uwe (de0508)


Lesenswert?

Hallo Peter,

Peter Zz schrieb:
> Uwe S. schrieb:
>> dann wäre noch interessant welche CPU Frequenz du verwendest, das sieht
>> man nicht alles.

> #define F_CPU 8000000
Ok, dann weiß ich bescheid.

>
>> Wenn Du einen atTiny84 @16MHz verwendest, dann passt ja der "ADC
>> Prescaler" ADPS2:0 = [111] mit 16MHz /128 = 125kHz.
>
> äh, versteh ich nicht ganz. Will Temperaturen und langsame Sachen
> messen, deshalb hatte ich den ADC so langsam wie möglich gemacht.

Nun man sollte nicht einfach etwas machen, ohne zu wissen ob es 
funktioniert.

Aber hier passt die ADC Clockfrequzenz mit den Vorgaben überein:
Datenblatt S.135
---------------
By default, the successive approximation circuitry requires an input 
clock frequency between 50 kHz and 200 kHz to get maximum resolution. If 
a lower resolution than 10 bits is needed, the input clock frequency to 
the ADC can be higher than 200 kHz to get a higher sample rate. It is 
not recommended to use a higher input clock frequency than 1 MHz.
---------------

von Ulrich (Gast)


Lesenswert?

while(ADCSRA & 1 << ADSC){};
sieht mir Verdächtig aus.
Besser vielleicht noch ein Klammer:
while(ADCSRA & (1 << ADSC)){};


Wenn man die zeit hat, könnte man noch über 1/50 s Sekunde mitteln, um 
50 Hz Störungen zu unterdrücken. Mit der Verstärkung können da schon 
relativ kleine 50 Hz Störungen stören, die man so nicht unbedingt sieht.

von Uwe (de0508)


Lesenswert?

Hallo Peter,

Peter Zz schrieb:
> Habe jetzt dieses, "return ADCW" spart 10 Byte!
> Thx!
>
> Aber das Hauptproblem, warum brauche ich bei differentieller Wandlung
> dieses _delay_us(500) und warum die Anzeige bei unter 30° schwankt ist
> nicht gelöst.

Da gibt es mehrere Dinge, die ich anders mache.
a) ich mache immer 8-32 Messungen nacheinander und bilde daraus einen 
Mittelwert.
b) ich verwende eine Referenzspannungsquelle
c) NICHT die +5V = AVcc eines Spannungsreglers, der schwankt !
d) AVcc wird durch eine C-L-C Filter mit +5V versorgt.
e) durch einen 2 Punktabgleich werden die beiden geläufigsten Messfehler 
heraus gerechnet: das ist der Offset- und der Linearitätsfehler.

Das steht in den Application Notes von Atmel zu der AVR ADC-Nutzung.

Ich würde nur in deinem Fall - single ended und danach eine 
Differentialmessung -
nach dem Wechsel der ADC-Eingänge immer eine Dummywandlung machen und 
den Wert verwerfen.

Ich finde gerade keine Anmerkung zum Zeitverhalten für die 
Differentialmessung.

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
Noch kein Account? Hier anmelden.