Forum: Mikrocontroller und Digitale Elektronik ADC Conversion


von Sascha B. (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,
habe eine Frage bezüglich des ADC.
Und zwar möchte ich eine Temperaturregelung mit einem Lüfter 
realisieren.
In der Endversion soll ein ATTiny24 zum Einsatz kommen, doch zuerst wird 
die Schaltung Testweise mit einem ATMega16 aufgebaut.
Dabei ist halt nur der AREF-Pin woanders...

Die Register beim ATMega16 habe ich wie folgt eingestellt:
//ADMUX  |=  0x00; //Alles auf 0, also Init-Werte
ADCSRA  |=  0x88;

Jetzt wird alle 5 Sekunden das Bit ADSC aus dem ADCSRA Register auf High 
gesetzt, das bedeutet, alle 5 Sekunden startet eine Conversion und ADSC 
wird am Ende automatisch auf 0 zurück gesetzt.

Aber ich muss doch noch eine Referenz haben, mit der ich dann die 
tatsächliche Temp berechnen kann, oder ?
Also messe ich mit dem Temperaturfühler KTY 83-110 einmal bei 20°C und 
einmal bei 100°C. So da hab ich meine Bezugswerte, die ich in beliebigen 
Variablen, sagen wir RefTemp1 und RefTemp2 speicher.

So jetzt weiß ich weiter, das das Ergebnis in ADCL und ADCH zu finden 
ist.

Wie genau muss ich diese jetzt auslesen (ich habs auf right adjusted)
und mit den Werten aus RefTempN verrechnen ?


Danke schonmal im Vorraus für Ratschläge

von Sascha B. (Gast)


Lesenswert?

Hallo nochmal,
ahbe noch selber einen Fehler gefunden !
Und zwar beim Prescaling des ADCs, da habe ich gelesen, das der Takt für
den ADC zwischen 50kHz und 200kHz liegen sollte, ode drunter je nachdem 
welche Samplerate ich will!

Also da mein Mega16 mit 8MHz rennt hab ich den Scalingfaktor auf 64 
gesetzt, so komm ich auf 125kHz !
Also
ADCSRA  |=  0x8E;
Anstatt
ADCSRA  |=  0x88;


Aber wie komme ich jetzt z.B. an meine Referenzvalues ?
Display hab ich am laufen, könnte theor. die Werte darauf ausgeben,
müste halt nur wissen wie ich die ADCL und ADCH auslese....

Danke

von Hannes L. (hannes)


Lesenswert?

Wie machst Du einen 16-Bit Lese-Zugriff auf den I/O-Bereich?
xyz=adc

(oder adcw, musst mal in der Doku zu AVR-C nachschaun, ich mach' in ASM)

...

von Stefan Salewski (Gast)


Lesenswert?

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#ADC_.28Analog_Digital_Converter.29

x = ADCL;       // mit uint16_t x
x += (ADCH<<8); // in zwei Zeilen (LSB/MSB-Reihenfolge und
                // C-Operatorpriorität sichergestellt)

oder

x = ADCW; // je nach AVR auch x = ADC (siehe avr/ioxxx.h)

von Sascha B. (Gast)


Lesenswert?

Hi Hannes Lux,

also ich hab noch einen Fehler bei mir gefunden und zwar hatte ich Kanal 
0 ausgewählt, aber Sensor ist an Kanal 1 (also ADC1, PortA1).
Daher ADMUX  |=  0x01;
so und das Auslesen habe ich jetzt mal so angenommen (weiß nicht obs 
richtig ist)

======================================================================== 
====
int adc_read()
{
int Temp = 0x00;

/*
switch(channel)
{
  case 1: ADMUX |= 0b00000001; break;  //Kanal waehlen
  case 2: ADMUX |= 0b00000010; break;  //Kanal waehlen
}
*/

ADCSRA |=(1<<ADSC);  // Start Conversion
//ADCSRA |=(1<<ADEN);  // Enable ADC
while ( (ADCSRA & (1<<ADSC)) != 0)//Warten bis konvertierung beendet
{
  //Mal ne Runde nix tun (ca. 15 Clk-Cycles)
}

Temp= ADCL;
Temp+=(ADCH <<8);  // Ergebnis zusammenbauen

return Temp;
}
======================================================================== 
====

den switsch hab ich direkt mit eingebaut, falls ich mal mehrere Sensoren 
abfragen möchte, da an ADC0 (PORTA0) beim ATTiny24 AREF liegt, hab ich 
beim Programm für den ATMega16 auch diesen Port direkt freigelassen...

Wenn das alles so richtig ist, müsste ich nur noch das Ergebnis des 
Auslesens aufs Display ausgeben, vorher vielleciht noch eine itoa 
Anweisung mit den Werten machen...

Ist denn die Abfrage soweit in Ordnung, oder hat sich da noch ein Fehler 
eingeschlichen ?

von Hannes L. (hannes)


Lesenswert?

Nur weil Du mich direkt angesprochen hast:

Ich kann Dir da nicht helfen, denn ich kann kein C. Ich schreibe meine 
bescheidenen Progrämmchen in Assembler.

Jedenfalls solltest Du dem ADC genügend Zeit zur Wandlung lassen. Wenn 
ich mehrere Kanäle einlesen muss, dann mach' ich das meist in einem 
Timer-Interrupt neben der eigentlichen Arbeit oder im 
ADC-Complete-Interrupt. Dabei lese ich den Wert aus (mir reichen meist 8 
Bit linksbündig), schaffe ihn in Sicherheit und schalte dann auf die 
zunächst auszulesende Quelle um. Danach wird bis zum nächsten Int das 
gemacht, was sonst noch so ansteht. Es muss nicht unbedingt ein 
Interrupt sein, es geht auch eine andere zyklisch aufgerufene Routine, 
z.B. Tastenentprellung, LCD-Update oder ähnliches.

...

von Sascha B. (Gast)


Lesenswert?

Guten morgen zusammen,

also zur Zeit läuft es folgendermaßen in meinem Programm:
Es laufen Timer/Counter0 und Timer/Counter1
Der T/C0 ist nur ist für eine spätere Uhr vorgesehen.
T/C1 steuert ca. alle 5s die Funktion adc_read(); an, wo dann die
Werte ausgelesen werden sollen. In dieser Schleife wird das ADSC Bit
auf ein gesetzt (also conversion gestartet) und mittels einer schleife 
wird
solange nichts getan, bis dieses Bit wieder auf 0 ist, also die 
conversion beendet ist.

Könnte jemand mit C-Erfahrung bitte kurz drüber schauen ?

-Danke-

von Sonic (Gast)


Lesenswert?

Hi Sascha,
vielleicht kannste mit meiner Funktion für single-ended-Messung was 
anfangen:
1
double ADC_conversion(unsigned char mux, unsigned char MW) // Spannung messen (single ended)
2
{  
3
  ADMUX = mux;   // Multiplexer-Modus einstellen
4
  _delay_us(40); // Pause bis Multiplexer eingestellt ist
5
  double Messwert = 0;
6
  unsigned int ADC_temp;
7
  unsigned char i = 1;
8
    
9
  do
10
   {
11
     ADCSRA |= (1<<ADSC);     // 'single conversion' einleiten
12
     while(!(ADCSRA & 0x10)); // auf Ende der Wandlung warten, ADIF flag '1'
13
     ADC_temp = ADCL;         // ADCL Register lesen
14
     ADC_temp += (ADCH << 8); // ADCH Register lesen      
15
     Messwert += ADC_temp;    // Ergebnisse der Messungen addieren
16
     i++;                     // Schleifenzähler erhöhen
17
    }
18
   while (i <= MW);           // MW Messungen für bessere Genauigkeit 
19
   Messwert = Messwert/MW;    // Mittelwert der Messungen der globalen Variable zuweisen
20
  
21
 return (Messwert);
22
}

Die Pause von 40µs habe ich deshalb 'reingemacht, weil ich feststellte, 
dass nach dem Umschalten des MUX die Werte nicht stimmten. Der 
Analogschalter braucht wohl auch seine Zeit.

Aufgerufen wird die Funktion z.B. für ADC0 und 32 Mittelwerte:
1
ADC_conversion(0, 32);

von Sascha B. (Gast)


Angehängte Dateien:

Lesenswert?

Hallo nochmal,

also ich hab es jetzt folgendermaßen gelöst mit der Funktion 
ADC_conversion(1, 32) vom Sonic.


char Buffer_ADC[4];
...
DDRA  &=  0xFD;    //PortA1 ist Eingang
...
if(...) //Wenn 5s vorbei sind
{
  Buffer_ADC[4] = ADC_conversion(1, 32);
  lcd_gotoxy(0,0);
  lcd_puts(Buffer_ADC);
}

kommt leider nix ausser dem "Ready" in der zweiten Zeile des Displays 
(wird bei der Displayinitialisierung geschrieben)...

Im Anhang befindet sich die ganze *.c Datei

von Sascha B. (Gast)


Lesenswert?

@Sonic:

Gibts du deine ADC Werte irgenwie aufm Display aus ?
Ich hab leider keinerlei Kontrolle, ob die ADC wirklich funktioniert....

Hat jemand ne Idee ?

von Hannes L. (hannes)


Lesenswert?

> also zur Zeit läuft es folgendermaßen in meinem Programm:
> Es laufen Timer/Counter0 und Timer/Counter1
> Der T/C0 ist nur ist für eine spätere Uhr vorgesehen.

Jeder Interrupt benötigt neben der Rechenzeit für die Arbeit in der ISR 
auch etwas Rechenzeit für den Aufruf und Rücksprung (und 
Registersicherung usw.). Das ist zwar nicht die Welt, kann sich aber bei 
häufig aufgerufenen ISRs schon summieren.

Wenn Du aber schon einen Interrupt für eine Uhr einplanst, dann kannst 
Du diesen doch auch zum Synchronisieren anderer zyklisch laufender Jobs 
verwenden. Lass den Uhren-Interrupt z.B. alle 10ms zuschlagen. In dessen 
ISR setzt Du ein Flag für die Mainloop (eine Boolsche Variable) und 
zählst die Hundertstelsekunden hoch. Bei Erreichen von 100 setzt Du sie 
auf 0 zurück und setzt ein weiteres Flag für die Mainloop.

Die Mainloop wertet die Flags aus. Bei gesetztem Sekundenflag zählt sie 
die Sekunden (und den ganzen Kalender) hoch, löscht das Sekundenflag 
(Job wird ja gemacht), vergleicht vielleicht noch irgendwelche 
Schaltzeiten und löst Schaltvorgänge aus usw...
Bei gesetztem Hundertstel-Flag wird in eine Routine verzweigt (oder eine 
Funktion aufgerufen, wenn man in C denkt), die alle Jobs erledigt, die 
zyklisch fällig sind. Z.B. Tastenentprellung, ADC-Abfrage usw. Wenn der 
ADC-Vorteiler (Free-Run-Betrieb) so eingestellt ist, dass bei jeder 
Abfrage mindestens zwei neue Werte ermittelt (aber nicht abgeholt) 
wurden, dann kann man (wie oben beschrieben) ohne Weiteres den Wert 
auslesen (und gemäß der zuletzt eingestellten Quelle sichern und dann 
ADMUX auf die demnächst benötigte Quelle umschalten. Der erste Messwert 
geht ins Leere, da erst wieder abgefragt wird, wenn bereits mehrere 
Wandlungen erfolgt sind. Das erschlägt z.B. auch Sonic's Problem, ohne 
dafür Rechenzeit durch eine Warteschleife vernichten zu müssen.

> T/C1 steuert ca. alle 5s die Funktion adc_read(); an, wo dann die
> Werte ausgelesen werden sollen. In dieser Schleife wird das ADSC Bit
> auf ein gesetzt (also conversion gestartet) und mittels einer schleife
> wird
> solange nichts getan, bis dieses Bit wieder auf 0 ist, also die
> conversion beendet ist.

Eben diese Busy-Warterei kannst Du Dir sparen.
Entweder Free-Run und beim gelegentlichen Vorbeischaun (Timersynchron, 
um einen Mindestabstand einzuhalten) den Wert nebenbei mitnehmen oder 
Einzelwandlungen per ADC-Interrupt, bei der erst der Wert ausgelesen 
wird und dann die Quelle umgeschaltet wird und der ADC neu gestartet 
wird. Letzteres ist aber nur sinnvoll, wenn man eine schnelle Messfolge 
braucht.

Für genaues (störungsarmes) Messen muss man sowiso anders herangehen, 
dann muss das Timing so aufeinander abgeglichen werden, dass die 
Wandlung bei angehaltenen Timern (Sleep-Mode ADC-Noise-Reduction) 
erfolgen kann. Dies muss natürlich bei den Timern berücksichtigt werden.

>
> Könnte jemand mit C-Erfahrung bitte kurz drüber schauen ?
>

Das überlasse ich mangels C-Wissen jemand Anderes.

> -Danke-

---------

> vielleicht kannste mit meiner Funktion für single-ended-Messung was
> anfangen

Ich glaube nicht, dass es sinnvoll ist, eine solche Routine als Beispiel 
zu empfehlen. Denn Du startest den ADC, wartest auf sein Busy-Flag und 
liest dann den Wert aus. Das kostet unnötig Rechenzeit und behindert 
andere Prozesse des Programms. Denn wenn das Programm schon "klappert" 
und dabei Störungen verursacht, dann kann es auch sinnvolle Arbeit 
erledigen. Deine Routine ist also ein gutes Beispiel für schlechtes 
Timing, sorry.

...

von Stefan Salewski (Gast)


Lesenswert?

>Hat jemand ne Idee ?

Nur ganz kurz:
Du solltest nicht erwarten, dass jede Zeile deines Programms hier von 
kompetenten Leuten sorgfältig analysiert wird. Sowas hätte ich für meine 
Programme zwar auch manchmal gerne, aber kostenlos gibt es so etwas nur 
ganz selten.

Wenn man so ein Projekt halbwegs professionell durchführen will, und 
sich aber nicht völlig sicher ist, wie man es machen muss, sollte man es 
in Einzelschritte zerlegen und diese sorgfältig prüfen.

Einige Leute wursteln einfach drauflos und hoffen das irgendetwas 
halbwegs sinnvolles rauskommt. Das ist stümperhaft.

1. Teste das LCD separat, also Zahlen und Buchstaben ausgeben!

2. Teste den ADC separat. Definierte Spannung anlegen und Messwerte (auf 
LCD) ausgeben.

3. Überlege dir sorgfältig, wie du den Temperaturfühler beschalten musst 
(Datenblatt) und wie du die Messwerte in Temperatur umrechnen kannst.

4. Teste die Temperatur-Messwerte

5. Überlege Dir, wie Du den Lüfter ansteuern kannst.

6. Teste die Lüfteransteuerung.

7 ....

8. Teste ob alles zusammen funktioniert.

9 . Schreibe eine gute Dokumentation, damit Du auch Jahre später deinen 
Aufbau noch verstehst und reparieren/erweitern kannst. Durch die 
Dokumentation kann der Aufbau auch leicht von anderen nachgebaut werden, 
wenn Du das möchtest.

Gruß

Stefan Salewski

von Sonic (Gast)


Lesenswert?

Ja, teste dein LCD separat und gib nur eine Variable aus. Wenn das 
klappt kannst du weitermachen. Und wenn du mit dem ADC1 misst solltest 
du den Pullup für diesen Pin deaktivieren. Sonst kommt nix gescheites 
'raus.

von Sascha B. (Gast)


Lesenswert?

Hallo nochmal,
also hab mein ADC jetzt so eingestellt, das er im Freerun Mode läuft und 
immer wenn eine Conversion zuende ist ein Interrupt ausgelöst wird,
in dem die Daten aus ADCL und ADCH gelesen werden sollen.
So direkt am Anfang der ISR vom ADC schalte ich eine LED ein, die an 
PORTD7 hängt. Die LED geht auch an, was bedeutet, das diese ISR 
aufgerufen wird.
Also muss eine Convertion beendet worden sein, denn sonst wäre der 
Interrupt ja nicht ausgelöst worden...
Nur Ausgabe auf mein Display der Werte klapt noch nicht, das Display 
zeigt aber Ready an, es ist also korrekt initialisiert.
Hier nochmal meine ISR des ADCs
===============================
/////  ISR  ADC Complete  /////
SIGNAL(SIG_ADC)
{
  PORTD |= 0x80;      //LED Rt an
  _delay_us(40); // Pause bis Multiplexer eingestellt ist

  unsigned int ADC_temp;

  //ADCSRA |= (1<<ADSC);     // conversion einleiten

  ADC_temp = ADCL;         // ADCL Register lesen
  ADC_temp += (ADCH << 8); // ADCH Register lesen
  Messwert = ADC_temp;    // Ergebnisse der Messungen addieren, Messwert 
ist eine globale Variable
}
===============================


So dann im Hauptprogramm:
===============================
  disp_init();
  lcd_gotoxy(0,1);
  lcd_puts("+Ready+");
  ADCSRA  |=  0x40;  //Starte die erste Konvertierung,
  PORTD |= 0x80;      //LED Rt an
  Buffer_ADC[4] = Messwert;
  lcd_gotoxy(0,0);
  lcd_puts(Buffer_ADC);
===============================


leider steht ausser dem +Ready+ nichts auf dem Display :(
Aber die Rote LED an PD7 leuchtet

von Sascha B. (Gast)


Lesenswert?

es ist vielleicht ein Problem der Variablen ?

Also die globale Variable Messwert ist vom Ty double
double Messwert = 0;

und die zur Ausgabe auf dem Display benötigte ist eine char Variable
char Buffer_ADC[4];

Die Variable ADC_temp ist vom Typ unsigned int
unsigned int ADC_temp;


ich denke darin liegt ein weiteres Problem, oder ?

von Sascha B. (Gast)


Lesenswert?

Ich hab nochmal einige Beiträge hier ausm Forum zum Thema ADC gelesen
und mich wirklich intensiv mit dem Kapitel ADC im Datasheet beschäftigt 
und fummle nun schon seit 3 Tagen dadran herum, leider immer noch 
erfolglos.
Ich hab es bisher nichteinmal geschafft, überhaupt die Werte aus ADCH 
und ADCL auf dem Display anzuzeigen !

Ich bin da wirklich auf eure Hilfe angewiesen und hoffe ich kann mit 
eurer Unterstützung rechnen.
Ich bin mir sicher, das es nur ein ganz kleiner doofer Fehler ist...
da ja die beendete Conversion ja einen Interrupt auslöst und die LED 
angeht, die ich in dieser ISR setze.....

Ich bitte euch um eure Hilfe, alleine komme ich da jetzt nicht mehr 
weiter, bin total am verzweifeln...

von Sonic (Gast)


Lesenswert?

Versuche doch mal einen beliebigen Text oder eine Variable in der 
ADC-INT-Routine auszugeben (da wo die LED eigeschaltet wird). Dann bist 
du sicher dass deine Ausgabefunktion überhaupt angesprungen wird. Das 
soll man zwar nicht machen, aber zu Testzwecken geht's schon mal.

von Sonic (Gast)


Angehängte Dateien:

Lesenswert?

Nochmal ich.
Ich poste dir mal einen ganz einfachen Displaytreiber. Damit kannst du 
das Display initialisieren, löschen, den Cursor auf eine bestimmte 
Position setzen (Zeile 1 und Zeile2 ) und den Text byteweise ausgeben.
Das Ganze für ein 2x16-Zeichen-Display, kann aber auf andere angepasst 
werden.

von Sascha B. (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Sonic,

also ich habe in die ADC Interruptroutine jetzt folgendes ergänzt:

lcd_gotoxy(0,1);
lcd_puts("ADC ISR");

das macht er auch, geht an die Stelle 0,1 und gibt den Text aus, 
genauso, wie die LED angeht....


Aber ich habe noch folgendes geändert:
//      Globale Variablen      //
unsigned int Messwert = 0;
char Buffer_ADC[8];

so in der Endlosschleife
wird dann folgendes gemacht:
  itoa(Messwert,Buffer_ADC,8);
  lcd_gotoxy(0,0);
  lcd_puts(Buffer_ADC);

das führt zu folgender Ausgabe auf dem Display:
=========================
=1777      =
=ADC ISR    =
=========================

Die = Striche sind nur die Displayberahmung...
aber egal was ich mache, der Wert 1777 ändert sich nicht, auch nicht 
wenn ich mit einem Feuerzeug in die Nähe des KTY Temperaturfühlers 
komme, auch nicht wenn ich dann den uC Resette, es kommt immer nur 
dieser Wert....

Im Anhang mal das ganze C-Programm


Ich hoffe echt das ihr mir alle dabei helfen könnt, so schwer kann das 
mit dem ADC doch nicht sein. Egal wie ich zum ersten Ergebnis komme, 
kann ruhig richtig dirty programmiert sein, hauptsache es tut sich 
überhaupt mal was....

von Sonic (Gast)


Lesenswert?

Setze
Messwert =  ADCL;
Messwert += (ADCH << 8);
mal an den Anfang der ISR. Da sind irgendwelche Werte in den registern, 
wenn ADCL und ADCH noch nicht ausgelesen sind.

von Sascha B. (Gast)


Angehängte Dateien:

Lesenswert?

Hab ich gemacht, passiert immer noch das gleiche...
ich habe parallel zum KTY... Temperaturfühler mein Multimeter 
angeklemmt.
Also wenn ich mit einer Hitzequelle in die Nähe komme, dann ändert sich 
die Spannung so wie es soll.. Nur der ADC-Wert, bzw. das was mir auf dem 
LCD angezeigt wird (die 1777) ändert sich nicht, auch nicht nach 
reset....

Also denke ich, das dieser Wert 1777 irgendein nsinn ist und nichts 
besonderes aussagt...

Was könnte noch falsch sein ?

von Sonic (Gast)


Lesenswert?

Also 1777 kann definitiv nichts mit ADC-Werten zu tun haben.
Kannst du nicht mal versuchen, die Bytes ADCL und ADCH OHNE das itoa auf 
das Display auszugeben? Oder irgendwelche definierten Bytes? Dem itoa 
traue ich nicht immer über den Weg!

von Sascha B. (Gast)


Lesenswert?

Auch wenn ich es direkt ausgebe, also folgendermaßen:

  lcd_gotoxy(0,0);
  lcd_puts(Messwert);

erscheint immer wieder diese 1777 in der ersten Zeile und ändert sich 
immer noch nicht..... ?!?!

Muss ich vll noch irgendwas bei den Fuse-Bits beachten, wenn ich mit dem 
ADC hantieren will ? Eigentlich doch nicht, oder hab ich was übersehen ?

von Sonic (Gast)


Lesenswert?

An den Fuses sicher nichts.
Aber da der Messwert in der ISR (außerhalb sub main) benutzt wird 
initialisiere den mal mit
volatile unsigned int Messwert = 0;

von Sascha B. (Gast)


Lesenswert?

Hmm passiert leider auch nichts spannenderes, es bleibt also alles bei 
1777.
der Quersumme der Weltformel...

von Sonic (Gast)


Lesenswert?

Mit Buffer_ADC ist's das Gleiche. Muss 'volatile' sein (weiß jetzt 
nicht, oder Compiler da meckert). Ansonsten wie gesagt: gib mal nur die 
einzelnen Bytes aus, kein 16-bit-Wort. Also ADCH und ADCL getrennt.

von Sascha B. (Gast)


Lesenswert?

wenn ich die beiden Werte aus ADCL und ADCH getrennt ausgebe, dann habe 
ich folgende Werte:
300 aus ADCL
377 aus ADCH

so sieht die Ausgabe jetzt aus:
  Messwert =  ADCL;
  itoa(Messwert,Buffer_ADC,8);
  lcd_gotoxy(0,0);
  lcd_puts(Buffer_ADC);

  Messwert =  ADCH;
  itoa(Messwert,Buffer_ADC,8);
  lcd_gotoxy(0,1);
  lcd_puts(Buffer_ADC);

von Sascha B. (Gast)


Angehängte Dateien:

Lesenswert?

Hier nochmal die ganze *.c Datei

von Sonic (Gast)


Lesenswert?

Also 300 und 377 können keine ASCII-Codes sein! Deshalb, versuche OHNE 
das itoa auszukommen, das Teil ist etwas komliziert zu handeln. Baue 
lieber deine LCD-Ausgabe so um, dass du itoa nicht mehr brauchst. Den 
Display-Treiber den ich gepostet habe kannste ja mal testen. Den kann 
man als stdout benutzen und mit printf die Ausgaben machen.

von Copperhead (Gast)


Lesenswert?

Ersetze mal bei Itoa die 8 durch eine 10, also 
itoa(Messwert,Buffer_ADC,10).

Ist soweit ich weiß das Format für die Umwandlung. 10 für Dezimal, 8 für 
Octal, 16 für Hex. 1777 Octal entspricht 1023 Dezimal, maximalwert vom 
ADC.

von Sascha B. (Gast)


Lesenswert?

Hallo Copperhead,
erstmal Danke für Deinen Tipp.
Nur leider steht da jetzt anstelle von den alten Werten
300
377

jetzt folgendes da
255
3

von Copperhead (Gast)


Lesenswert?

Die 3 aus ADCH und 255 aus ADCL sind zusammen 1023 (3x256 + 255).

von Sascha B. (Gast)


Lesenswert?

Ja das weiß ich, aber leider bringt mich das auch nicht weiter,
denn dieser Wert steht immer da drin, auch wenn ich mit nem Feuerzeug in 
der Nähe des Temperaturfühlers herumwedele. Der Wert ändert sich 
niemals, nicht nach RESET, nicht mit Feuer nach RESET, garnicht..... der 
will einfach nicht und das obwohl eine Spannungsänderung mit dem 
Multimeter deutlich zu messen ist....

von Sonic (Gast)


Lesenswert?

Hast du mal nachgemessen ob das Signal am Eingangspin passt? Welche 
Referenzspannung hattest du angewählt? Kann gut sein dass der ADC das 
Zeitliche gesegnet hat.

von Copperhead (Gast)


Lesenswert?

Wird die SIGNAL(SIG_ADC) mehr als einmal aufgerufen? Vielleicht einen 
Zähler einbauen und am Display ausgeben.

Man kann auch feste Spannungen anstatt eines Kanals wählen (MUX4..0 = 
11110 => 1,22V, 11111 => GND). Vielleicht hilft dir das noch weiter.

von Sascha B. (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,
das Signal am Eingangspin passt leider genau mit der Spannung am 
Temp-Sensor überein... Ändert sich somit auch, wenn ich ein kleines 
Feuerchen in die Nähe bringe... Logisch, weil das ja genau der gleiche 
Abgriff ist...

Das mit dem Zähler war eine gute Idee....
nun kann ich sehen, wie eine Zahl ziemlich schnell hochgezählt wird.
das bedeutet, das die ISR ständig ausgeführt wird, jedoch ändern sich 
die werte nie.....
Aus der Tatsache, das die ISR ständig aufgerufen wird, schließe ich, das 
ständig irgendwelche convertions beendet werden (das ist vorraussetzung 
für den ADC Interrupt), nur das komische ist, das sich der Wert nie 
ändert...



hier die ISR
============================
SIGNAL(SIG_ADC)
{
  Aufrufe++;
  //Messwert += (ADCH << 8);

  PORTD |= 0x80;      //LED Rt an
  /*lcd_gotoxy(0,1);
  lcd_puts("ADC ISR");
  */

  Messwert =  ADCL;
  itoa(Messwert,Buffer_ADCL,10);
  lcd_gotoxy(0,0);
  lcd_puts(Buffer_ADCL);

  Messwert =  ADCH;
  itoa(Messwert,Buffer_ADCH,10);
  lcd_gotoxy(0,1);
  lcd_puts(Buffer_ADCH);

  itoa(Aufrufe,Buffer_ADCA,10);
  lcd_gotoxy(9,1);
  lcd_puts(Buffer_ADCA);
}
============================


und im Anhang das ganze .c-File

von Sascha B. (Gast)


Lesenswert?

Achja da fällt mir ein,
als MUX4..0 hab ich 0001 eingestellt, da ich ja laut Table84 Single 
Ended Input ADC1 haben will. Aber ich lasse den ADC im Frerun-Mode 
laufen, könnte das eine Fehlerquelle sein ??
Das ich dann die MUX bits anders setzen muss,z.b. auf positive oder 
negative differential input ?

von Sascha B. (Gast)


Angehängte Dateien:

Lesenswert?

hmm nöö scheint sich nichts zu ändern, also daran leigt es auch nicht...

Aber die Beschaltung des ADC ist doch soweit in Ordnung oder ?

Siehe Picture im Anhang (Es ist nur die Beschaltung des ADC 
eingezeichnet)

Als Voltage Referenz Selection wurde natürlich GND eingestellt, sowie 
AREF auch auf GND liegt im Plan !

von Hauke R. (lafkaschar) Benutzerseite


Lesenswert?

>Als Voltage Referenz Selection wurde natürlich GND eingestellt, sowie
>AREF auch auf GND liegt im Plan !

Wie du hast GND eingestellt? Mir ist nicht bewusst, das das geht.

Die Referenzspannung stellt die Obere Grenze da, wienn diese  GND ist, 
sind alle angelegten Spannungen = 1023

von Sascha B. (Gast)


Lesenswert?

Also wenn du in den Schaltplan schaust, dann siehst du, das ich zwischen 
AREF und GND einen 100nF drin hab...

von Hauke R. (lafkaschar) Benutzerseite


Lesenswert?

Ja sorry, nich weiter auf den Schaltplan geguckt :/ entsprechend 
Editiert.
Aber wie hast du als Referenz GND ausgewählt? Etwa externe Referenz? 
Dann kann das aber so nicht mit dem Kondensator gehen.

von Sascha B. (Gast)


Angehängte Dateien:

Lesenswert?

Die Referenz GND habe ich laut Datenblatt Table 83 eingestellt.
Also die Bits REFS1 und REFS0 im Register ADMUX beide auf 0 gesetzt...
Damit wird laut Datenblatt die Referenz auf GND gezogen,
und der Temp.sensor liegt ja in Spannungsteilerbeschaltung an GND und 
über einen Widerstand von 1k an +5V, oder ist das so nicht erlaubt ??

Siehe Anhang

von Dieter Werner (Gast)


Lesenswert?

Da liegt ein Missverständnis vor.
Die Referenz muss gleich oder größer als die maximal zu messende 
Spannung sein.

Also entweder 00 aber dann eine passende Spannung an AREF einspeisen
oder 01, dann wäre AVCC die Referenz
oder 11, dann darf aber die Eingangsspannung nicht über 2,56V steigen.

von Sascha B. (Gast)


Lesenswert?

Also gut,
habe die Beschaltung nun so geändert, wie auf dem Schaltplan zu erkennen 
ist und auch die Bits dementsprechend gesetzt, also
REFS1 = 0    und
REFS0 = 1

So und wenn ich nun mein Display beobachte, dann stelle ich fest, das 
sich die Werte mit der Temperatur ändern :)
Normalerweies zappelt der obere Wert (der aus ADCL) immer so um die 103 
herum, wenn ich nicht mit Wärmequelle in die Nähe komme,
aber der untere Wert (der von ADCH) bleibt immer konstant bei 2 stehen, 
auch wenn ich sehr lange mit einem Feuerzeug in der Nähe bleibe.
Dann ändert sich nur der obere Wert also der von ADCL von ~103 bis auf 
190,
aber Wert in ADCH bleibt gleich, ist das normal ?

Aber soweit schonmal herzlichen Dank an alle die "ihren Senf" dazu 
gegeben haben !

von Sascha B. (Gast)


Angehängte Dateien:

Lesenswert?

den Schaltplan vor lauter Aufregung & Freude vergessen :P

von Sascha B. (Gast)


Lesenswert?

Achja, noch ein etwas merkwürdiges Phänomen:
Wert von ADCL
~103    bei Raumtemperatur
halte ich ein Stück gefrorenes Hähnchenbrustfilet (oder was auch immer) 
dran, dann geht der Wert schlagartig auf ~900 und geht dann langsam mit 
der Abkühlung bis auf ~700 herunter...

Halte ich eine Feuerquelle in die Nähe, geht der Wert von den ~103 bei 
Raumtemperatur bis auf ~200 hoch.....

Ist das normal ?
Der KTY-irgendwas Temperaturfühler hat einen Temperaturbereich von -55 
bis 150°C
Also sollte das doch innerhalb des möglichen liegen.

Ok kann es sein, das ich dafür dann den Widerstand (also diesen 1k) 
anpassen muss?
Eigentlich will ich ja eh nur im Bereich von 0° - 150°C messen...

von Hauke R. (lafkaschar) Benutzerseite


Lesenswert?

Du kannst jetzt auch wieder den Wert als einen anzeigen lassen. Die 
"geringe" veränderung liegt einfach daran, dass der KTY seinen 
Widerstand nicht stark genug ändert. Wenn der Widerstand vom KTY nicht 
größer als 1k wird, kannst du auch mal die 2,56V probieren (11) Dann 
hast du eine höhere Auflösung. (Der Widerstand vom KTY darf bzw sollte 
nicht über 1k steigen, da sonst die Eingangsspannung > Referenzspannung 
wird und du nur noch 1023 rausbekommst)

von Sonic (Gast)


Lesenswert?

Da der Widerstand des KTY ja nie 0 Ohm wird, und somit 0V gemessen 
werden kann, ist es ratsam das Messignal aufzubereiten, z.B. mit einem 
OP. Mit diesem kann ein Offset (Nullpunkt) und die Verstärkung (Spanne) 
eingestellt werden. Dann kannst du dir den Temperaturbereich einstellen 
den du benötigst und hast die vole Auflösung des ADC.

von Sascha B. (Gast)


Angehängte Dateien:

Lesenswert?

Morgen zusammen...
Im Anhang befindet sich die Widerstands-Temperatur Kennlinie, aus der zu 
erkennen ist, das der Widerstand des KTY schon bei 25°C die 1k Grenze 
überschreitet.

Leider habe ich keinerlei Ahnung bezüglich Op-Amps, da ich noch nie 
damit hantiert habe. Folgende Bauteile habe ich zur Verfügung:

1)  LM 311 DIP  Voltage Comparator
2)  74HC 14    6xINV.SCHMITT-TRIGGE
3)  LM 324 DIL  Op-amp, DIL-14
4)  LS 163    SCHOTTKY-TTL

Davon am besten eignen würde sich dich doch Nr. 3) oder ?
Aber wenn ich nun ins Datenblatt schaue, sehe ich da stehen:
VCC Supply voltage 32 or ±16 VDC
Aber solche Spannungen kriege ich in meiner Endgültigen Schaltung später 
nicht hin, da gibts maximal 12V, also fällt das schonmal weg, oder gibts 
noch ne Möglichkeit ???

von Sonic (Gast)


Angehängte Dateien:

Lesenswert?

Ok, das ist vom Wiki die Schalteung eines OPs als Summierer 
(Invertierend).
Vor R1 ein Poti (Schleifer), Eingang auf +15V, Ausgang auf -15V (das ist 
der Offset-Einsteller).
R12 weglassen.
R13 ist der Eingang vom KTY-Spannungsteiler.
R2 als Poti ausfühern, damit wird die Spanne (Verstärkung) eingestellt.

von Sonic (Gast)


Angehängte Dateien:

Lesenswert?

Scheiß Wiki...
hab's kurz geEAGLEt.

von Marco S. (masterof)


Angehängte Dateien:

Lesenswert?

Wäre die schaltung nicht besser. Da man die "virtuelle Masse" jetzte 
verschieben kann ?

von Uhu U. (uhu)


Lesenswert?

@ Marco Schwan: Bist Du sicher, daß Du den OP mitkoppeln willst?

von Power (Gast)


Lesenswert?

Sieht eher nach Schmitt-Trigger mit einstellbarer Hysterese aus?!

von Marco S. (masterof)


Lesenswert?

Da sind die beide Pins vertauscht.
Sollte eigentlich ein Invertierter Verstärker sein.

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.