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
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
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) ...
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)
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 ?
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. ...
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-
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); |
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
@Sonic: Gibts du deine ADC Werte irgenwie aufm Display aus ? Ich hab leider keinerlei Kontrolle, ob die ADC wirklich funktioniert.... Hat jemand ne Idee ?
> 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. ...
>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
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.
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
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 ?
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...
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.
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.
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....
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.
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 ?
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!
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 ?
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;
Hmm passiert leider auch nichts spannenderes, es bleibt also alles bei 1777. der Quersumme der Weltformel...
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.
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);
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.
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.
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
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....
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.
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.
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
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 ?
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 !
>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
Also wenn du in den Schaltplan schaust, dann siehst du, das ich zwischen AREF und GND einen 100nF drin hab...
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.
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
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.
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 !
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...
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)
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.
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 ???
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.
Wäre die schaltung nicht besser. Da man die "virtuelle Masse" jetzte verschieben kann ?
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.