Hallo zusammen,
ich habe ein Problem mit meinem ADC und ATmega8. Ich will mit dem ADC
eine Durchschnittsberechnung durchführen, um das Flackern auf meinen
7-Segementen zu verringern. Da meine Versuche mit einer for-Schleife
nicht fruchteten, habe ich aus dem Tutorial die ADC_Read_Avg genommen.
Allerdings funktioniert auch das nicht. Meine Anzeigen, zeigen nun nur
"8" an.
Ich habe mit dem AVR Simulator (Studio 6) eine Simulation durchgeführt
und es scheint mir, als ob er bei
1
while(ADCSRA&(1<<ADSC))
hängen bleibt. Ich habe für den ADC viel aus dem Tutorial genommen aber
genau diese while bei der Init ebenfalls weggelassen, weil es scheinbar
an diesem Teil hing. Nach dem entfernen dieses Teils, lief alles rund.
Ich kann diesen Teil noch nicht so recht nachvollziehen, was dort
passiert bzw. wann sich das ADSC ändert.
Mein ADC lief ursprünglich im Free-Mode, weil ich mich da noch nicht
festlegen wollte, dies wird durch die Teile aus dem Tutorial ja zum
Single-Mode gemacht, wenn ich das korrekt sehe.
Grüße krusti
krusti schrieb:> Ich habe mit dem AVR Simulator (Studio 6) eine Simulation durchgeführt> und es scheint mir, als ob er bei
1
while(ADCSRA&(1<<ADSC))
> hängen bleibt.
Das ist ein 'Problem' im Simulator der nun mal keine reale ADC Hardware
hat.
> Ich habe für den ADC viel aus dem Tutorial genommen aber> genau diese while bei der Init ebenfalls weggelassen, weil es scheinbar> an diesem Teil hing.
Nicht wirklich.
> Nach dem entfernen dieses Teils, lief alles rund.
Im Simulator.
Aber auf dem µC brauchst du den Teil
> Ich kann diesen Teil noch nicht so recht nachvollziehen, was dort> passiert bzw. wann sich das ADSC ändert.
Das ist eigentlich ganz einfach.
Du setzt das Bit um dem ADC zu signalisieren: Mach mal
Und wenn der ADC fertig ist, dann zieht er das Bit wieder auf 0 zurück.
Deshalb
1
ADCSRA|=(1<<ADSC);// mach mal
2
while(ADCSRA&(1<<ADSC)){// ich warte solange, bis du fertig bist
3
}
> Mein ADC lief ursprünglich im Free-Mode, weil ich mich da noch nicht> festlegen wollte,
Der Free Modus hat meistens keinen wirklichen Sinn. Zumindest solange,
solange du in der Hauptschleife ein delay mit 500ms drinnen hast, kannst
du den ADC auch dauernd neu starten und aufs Fertig werden warten.
Zeitmässig sind das Peanuts in Relation zum delay.
Allerdings ist es keine sehr gute Idee, das Multilexing der Anzeige am
selben Port zu machen, auf dem auch der ADC beheimatet ist. Der ADC hat
es ganz gerne, wenn auf 'seinem' Port eher Ruhe herrscht. Wenn du da
dauernd Pins umschaltest, dann ist das ... sagen wir mal ... eher
suboptimal.
Dein Anzeige Multiplex ist getestet und für gut befunden? Ebenso die
Zahlenausgabe?
Als Mittelwert verwendet man optimalerweise einen exponentiellen
Mittelwert. Siehe auch :
http://www.ibrtses.com/embedded/exponential.html
Der benoetigt nur eine einzelne Speicherstelle, und ist konfigurierbar
Du hast ihn ja immer noch im Free Running Modus!
Dann brauchst du allerdings den ADC weder dauernd starten noch auf die
Beendigung warten.
Nur ist das in deinem Fall eher suboptimal, weil du nie genau weisst,
wann denn der ADC ein neues Ergebnis fertig hat. Es kann dir daher
passieren, dass du in deiner ausleserei x mal den immer gleichen Wert
ausliest, weil der ADC noch gar kein neues Ergebnis vorrätig hat sondern
noch an der Arbeit ist.
Nimm den Free Run raus.
Free Run macht nur dann Sinn wenn
man ihn zb an einen Timer zur Triggerung koppelt
man die Ergebnisse per Interrupt abholt
man jeden Taktzyklus braucht
Danke schon mal vorab für die Antworten.
Der 500ms delay ist nur zum Test drin um zu sehen, ob die Werte trotz
flackern einigermassen stimmen.
An PC0 hängt derzeit meine Spannung, welche ich auf dem ADC geben will.
Ein Labornetzteil. Später soll dort ein Drucksensor mit 0,5 bis 4,5V
seinen Dienst tun.
Ich habe jetzt den ADC-Modus verändert. Die Init wie im Tutorial
angepasst:
/* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
4
also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
5
ADCSRA|=(1<<ADSC);//eine ADC-Wandlung
6
while(ADCSRA&(1<<ADSC))// auf Abschluss der Konvertierung warten
7
{}
8
/* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
9
Wandlung nicht übernommen. */
10
(void)ADCW;
Und in der Main:
1
ADCSRA|=(1<<ADSC);// eine Wandlung "single conversion"
2
while(ADCSRA&(1<<ADSC)){// auf Abschluss der Konvertierung warten
3
}
4
adcvalue=ADCW;
Das ADC auslesen werde ich später noch in eine eigene Funktion packen
denke ich. Mal sehen was noch alles dazu kommt. Denke es kommt noch eine
Maximalwertanzeige dazu, aber das ist ein anderes Thema
Woran es jetzt noch scheitert ist die Mittelwertbestimmung. Ich werde
jetzt nochmal die Lösung aus dem Tutorial versuchen. Jetzt wo der ADC in
Single zu laufen scheint.
krusti schrieb:> Ich werde> jetzt nochmal die Lösung aus dem Tutorial versuchen.
Das einzige, was du an den Tutorialsroutinen anpassen musst ist die
Einstellung der Referenzspannung auf deine Bedürfnisse und mglw. die
Taktteiler des ADC an deine Prozessor-Taktfrequenz
Alles andere brauchst du nicht verändern und lässt es so wie es ist.
Und ehe du da gross mit einer Umrechnung auf Volt künstelst (die
ihrerseits fehlerhaft sein kann), lässt du dir den ADC Wert direkt auf
deiner Anzeige ausgeben.
Da du nur eine 3 stellige Anzeige hast, lässt du dir eben die Hälfte des
ADC Wertes ausgeben. Der ADC Wert kann nicht größer als 1023 sein, die
Hälfte davon sind 511, dann passt das auf deine Anzeige.
Und für die Ausgabe machst du dir gleich mal eine Funktion, die den
Kleinkram erledigt. Das willst du alles nicht in der Hauptschleife haben
1
intmain()
2
{
3
....
4
5
while(1)//Endlosschleife
6
{
7
adcvalue=ADC_Read_Avg(0,5);
8
outValue(adcValue/2);
9
10
_delay_ms(500);
11
}
12
}
13
14
15
voidoutValue(uint16_twert)
16
{
17
uint8_thunderter,zehner,einer;
18
19
if(value>999)// sicherheitshalber
20
value=999;
21
22
hunderter=wert/100;
23
zehner=wert/10%10;
24
einer=wert%10;
25
26
digit[0]=numbers[einer];
27
digit[1]=numbers[zehner];
28
digit[2]=numbers[hunderter];
29
}
das befreit dich davon, dauernd beim experimentieren darüber nachdenken
zu müssen, wie die Aufbereitung für deine Anzeige funktioniert.
Du willst nach jedem ADC Wert 777 ausgeben, damit du erkennst wann die
nächste Messung stattfindet? Kein Problem
1
while(1)//Endlosschleife
2
{
3
adcvalue=ADC_Read_Avg(0,5);
4
outValue(adcValue/2);
5
6
_delay_ms(500);
7
outValue(777);
8
_delay_ms(100);
9
}
macht das.
Du willst deine 7_Segment Anzeige testen, weil dir das komisch vorkommt,
dass da nur noch lauter 8 angezeigt werden.
Kein Problem:
1
uint16_ti=0;
2
3
while(1)//Endlosschleife
4
{
5
outValue(i);
6
7
i++;
8
if(i==200)
9
i=0;
10
11
_delay_ms(500);
12
}
macht das.
Du musst dir selbst Hilfsfunktionen für Dinge schreiben, die förmlich
danach schreien, dass du sie universell einsetzen kannst. Eine
Zahlenausgabe ist genau so etwas. Braucht man immer. Daher macht man
sich da ein für allemal eine Funktion dafür.
Diese Hilfsfunktion ist eine tolle Sache. Aber lass ich die auch final
drin? Ich muss ja später den ADC-Wert in eine Spannung wandeln bzw dann
in einen Druck. Da bräuchte ich sie ja nicht mehr.
Ich habe noch nicht den Blick dafür zu sehen, wie ich etwas in
Funktionen zusammenfassen kann und vor allem wie ich es universell
gestallte.
Solche Universalfunktionen, wie mache ich das wenn ich diese in mehreren
Projekten nutzen will? Speicher ich mir die irgendwo ab? Mach ich mich
ein C-File auf welches ich dann zugreife?
Ich habe mein Programm nochmal angehängt, Stand jetzt ohne diese
Hilfsvariablen aber mit einer Max-Wert Ausgabe und einem Reset (wo ich
glaube das dieser entweder prellt oder ich ihn schaltungstechnisch
falsch angeschlossen habe)
krusti schrieb:> Diese Hilfsfunktion ist eine tolle Sache. Aber lass ich die auch final> drin?
Natürlich
> Ich muss ja später den ADC-Wert in eine Spannung wandeln
Und?
Dann wandelst du das eben und bereitest es so auf, dass du sie als
Zahlenwert von 0 bis 999 an outValue übergeben kannst.
> bzw dann> in einen Druck.
deto.
> Da bräuchte ich sie ja nicht mehr.
Oh, die wirst du immer wieder brauchen.
> Solche Universalfunktionen
Hier zb
uint16_tdruck;//Variable für den anstehenden Druck
5
uint8_thunderter,zehner,einer;//Variabel für den Stellen auf den 7-Segemnt
6
7
druck=max_adcvalue*(V_REF/MAXVALUE);//Berechnung des Druckes mit Hilfe der Respannung
8
//und der maximalen Anzahl an Tastwerten des ADC
9
hunderter=druck/10000;//Berechnung der Hunderterstelle aud dem Display
10
zehner=druck/1000%10;//Berechnung der Zehnerstelle auf dem Display
11
einer=druck/100%10;//Berechnung der Einerstelle auf dem Display
12
13
digit[0]=numbers[einer];//Übergabe der hinterlegten Zahl an das Digit
14
digit[1]=numbers[zehner];//Übergabe der hinterlegten Zahl an das Digit
15
digit[2]=numbers[hunderter];//Übergabe der hinterlegten Zahl an das Digit
16
}
vermischt du 2 Konzepte.
Das eine ist die Berechnung des maximalen Wertes. Das andere ist die
Ausgabe. Das sind 2 verschiedene Dinge, die erst mal nichts miteinander
zu tun haben.
, wie mache ich das wenn ich diese in mehreren
> Projekten nutzen will? Speicher ich mir die irgendwo ab? Mach ich mich> ein C-File auf welches ich dann zugreife?
Im einfachsten Fall: ja
Die sammelt man zb in einem Verzeichnis, in dem sich im Laufe der Zeit
viele derartige Funktionalitäten ansammeln. Man will ja nicht das Rad
immer wieder neu erfinden.
krusti schrieb:> (wo ich> glaube das dieser entweder prellt oder ich ihn schaltungstechnisch> falsch angeschlossen habe)
Wie hast du sie angeschlossen?
Laut COde
1
if((PINB&TASTE_1))
ist das dann ein Taster, der beim Drücken gegen Vcc schliest.
Dann allerdings brauchst du einen externen Pulldown-Widerstand.
Drum schliesst man Taster normalerweise anders herum an, weil der AVR
eingebaute Pullup Widerstände hat.
D.h der Taster stellt beim Drücken eine Verbindung nach Masse her.
Programmtechnisch ist das kein Problem. Dreht sich halt die ABfrage um.
1
if(!(PINB&TASTE_1))
Aber wenn du in deiner Verschaltung keinen Pulldown Widerstand hast,
dann hängt der Pin bei nicht gedrücktem Taster in der Luft. Ein in der
Luft hängender EIngang hat aber mitnichten zuverlässig den Wert 0. Der
kann je nach Tageszeit (und elektrischen Feldern rundum) wahlweise 0
oder 1 sein. Je nachdem ob der Kühlschrank läuft oder nebenan der
Staubsauger in Betrieb ist oder du auch nur mit deinen Händen zu nahe am
Pin bist.
Lass dieses krampfhafte Festhalten an "ein gedrückter Taster muss 1
liefern" bleiben.
Erstens ist das nur eine Konvention, die dir genau gesehen nicht viel
bringt. Denn im Programm ist das umdrehen pipifax.
Zum anderen brauchst du dann ein externes Bauteil mehr, das du nicht
benötigst, wenn du einfach von dieser Konvention ablässt.
Portpin auf Eingang schalten, Pullup Widerstand zuschalten und den
Taster so verschalten, dass er beim Drücken eine Verbindung nach GND
herstellt.
Danke für die vielen Tipps und die Hilfe. Da merkt man die 4 Jahre doch
seit ich das letzte mal einen AVR in der Hand hatte. Das war noch zu
Ausbildungszeiten, da war ich froh wenn es lief, da habe ich noch nicht
so viel mit #define gearbeitet. Das es den Code aber doch verständlicher
macht, will ich doch versuchen mir das anzueignen.
> vermischt du 2 Konzepte.> Das eine ist die Berechnung des maximalen Wertes. Das andere ist die> Ausgabe. Das sind 2 verschiedene Dinge, die erst mal nichts miteinander> zu tun haben.
D.h. du würdest auch diesen Teil von mir trennen und in zwei Funktionen
packen? Max-Ermittlung und die reine Ausgabe der ermittelten Werte für
jedes Digit?
> Im einfachsten Fall: ja> Die sammelt man zb in einem Verzeichnis, in dem sich im Laufe der Zeit> viele derartige Funktionalitäten ansammeln. Man will ja nicht das Rad> immer wieder neu erfinden.
Das heißt ich speicher mir jede Universalfunktion als c-File ab und
binde die Datei in Studio mit ein. Oder mach ich copy-paste? Ich weiß
nicht wie ich mehrere c-Files in einem Projekt miteinander verknüpfen
könnte, falls es geht. Habe mich dazu aber auch noch nicht schlau
gemacht.
Karl H. schrieb:> Drum schliesst man Taster normalerweise anders herum an, weil der AVR> eingebaute Pullup Widerstände hat.> D.h der Taster stellt beim Drücken eine Verbindung nach Masse her.> Programmtechnisch ist das kein Problem. Dreht sich halt die ABfrage um.> Lass dieses krampfhafte Festhalten an "ein gedrückter Taster muss 1> liefern" bleiben.> Erstens ist das nur eine Konvention, die dir genau gesehen nicht viel> bringt. Denn im Programm ist das umdrehen pipifax.
Ja was soll ich sagen, es ist schon etwas her bei mir, auch das letzte
Platinendesign. Ich hab es total verpeilt und einen Widerstand in Reihe
zum Schalter eingebaut. Ich denke ich wollte den Strom zum µC begrenzen.
Keine Ahnung was mich da geritten hat. Auch warum ich nicht auf die Idee
mit den Pull-Ups gekommen bin, verpeilt. Eigentlich dachte ich, ich weiß
diese Basics. Nun gut, das nächste Mal denk ich bestimmt dran.
Ich bin dabei die Platine so zu bearbeiten, dass ich aus den
Widerständen wenigstens einen Pull-Down mache. Das werde ich morgen
testen.
krusti schrieb:> Danke für die vielen Tipps und die Hilfe. Da merkt man die 4 Jahre doch> seit ich das letzte mal einen AVR in der Hand hatte. Das war noch zu> Ausbildungszeiten, da war ich froh wenn es lief, da habe ich noch nicht> so viel mit #define gearbeitet. Das es den Code aber doch verständlicher> macht, will ich doch versuchen mir das anzueignen.>>> vermischt du 2 Konzepte.>> Das eine ist die Berechnung des maximalen Wertes. Das andere ist die>> Ausgabe. Das sind 2 verschiedene Dinge, die erst mal nichts miteinander>> zu tun haben.>> D.h. du würdest auch diesen Teil von mir trennen und in zwei Funktionen> packen? Max-Ermittlung und die reine Ausgabe der ermittelten Werte für> jedes Digit?
Die reine Ausgabe hast du ja schon.
Ich setz mich doch nicht hin und mach den ganzen Kram mit den digits,
wenn ich genausogut auch
1
voidBerechnung_Max(uint16_tmax_adcvalue)
2
{
3
uint16_tdruck;//Variable für den anstehenden Druck
4
5
druck=max_adcvalue*(V_REF/MAXVALUE);//Berechnung des Druckes mit Hilfe der Respannung
6
outValue(druck/100);
7
}
schreiben kann. Und genau genommen braucht auch die Variable keiner.
1
voidBerechnung_Max(uint16_tmax_adcvalue)
2
{
3
outValue(max_adcvalue*(V_REF/MAXVALUE)/100);
4
}
... aber lass sie ruhig drinn. Dir als Programmierer mag das helfen um
zu erkennen was da passiert und der Compiler optimiert sie sowieso raus.
Bitte, bitte, bitte. Vergiss diesen Müll mit "ein Funktionsaufruf kostet
aber Zeit".
Ja, er kostet Zeit. Der Prozessor hat da ein bischen was zu tun.
Und? Wen kümmerts? WIe schnell kannst du eine Anzeige ablesen? Wie viele
Anzeige-Updates in der Minute kannst du verarbeiten. 3? 4? 5? Wenn du
bei mehr als 5 sich verändernden WErten pro Sekunde noch mitkommst, zieh
ich meinen Hut vor dir. Kein Mensch kann das. Ok, Juck Norris
vielleicht.
D.h. in deiner Anwendung ist Zeit überhaupt kein Faktor. Dein µC macht
bei 6Mhz über den Daumen ca vier einhalb MILLIONEN Befehle. Was denkst
du was es den kümmert, wenn er für eine Runde durch die Hauptschleife 10
Befehle mehr abarbeiten muss? Völlig uninteressant. Als Mensch wirst du
das nie merken, dass er anstatt 5212 Updates pro Sekunde nur 5211
zustande bringt. Das ist alles weit jenseits der 4 Updates, die dein
Gehirn gerade noch so mit Ach und Krach registrieren kann.
> Das heißt ich speicher mir jede Universalfunktion
na ja. Nicht unbedingt jede. Man wird sie natürlich sinnvoll nach
Themenkreisen sortiert in jeweilige C-Files stecken. Und sich natürlich
ein Header File dazu bauen.
> Oder mach ich copy-paste? Ich weiß> nicht wie ich mehrere c-Files in einem Projekt miteinander verknüpfen> könnte, falls es geht. Habe mich dazu aber auch noch nicht schlau> gemacht.
Du teilst dem Studio einfach mit, das dieses C-File auch mit zum Projekt
gehören. Fertig. Im verwendenden Code noch das zugehörige Header File
inkludieren und ab geht die Luzi.
uint16_tdruck;//Variable für den anstehenden Druck
ist ein völlig sinnloser Kommentar.
Wenn jemand nicht sieht, dass es sich hier um eine Variablendefinition
handelt, dann soll er sich einen Blindenhund kaufen.
Die Variable hast du sinnigerweise 'druck' genannt. Was also wird wohl
die Aufgabe dieser Variablen sein. Du wirst da sicherlich nicht die
Anzahl der Pflaumenknödel von letzter Woche drinn speichern.
Was also erzählt mir der Kommentar, was ich nicht sowieso schon im Code
sehe?
Nichts. Gar nichts.
Ein derartiger Kommentar ist sinnlos. Im besten Fall trägt er nichts zum
Verständnis des Programmes bei. Im schlimmsten Fall ist er nur
hinderlich, weil er falsch ist.
Kommentiere nicht Dinge, die ich sowieso im Code sehen kann. Ein
1
i=sqrt(x*x+y*y);// i berechnen
erzählt mir nichts. Dass hier i berechnet wird, das sehe ich im Code
auch. Aber WAS wird da berechnet. WARUM wird es berechnet. Das sind
Dinge, die ich um Code unter Umständen nicht sehen kann. OK, einen
Pythagoras sollte man aus 5 Meter Entfernung erkennen können, damit kann
man über das WAS streiten. Aber nicht über das WARUM.
In diesem Sinne
1
druck=max_adcvalue*(V_REF/MAXVALUE);//Berechnung des Druckes mit Hilfe der Respannung
Ach. Das hätte ich jetzt nicht gedacht, dass hier ein Druck berechnet
wird. :-) Darum wird ja auch das Ergebnis der Berechnung an eine
Variable namens 'druck' zugewiesen, weil hier die Anzahl der geparkten
Autos bestimmt wird.
'Restspannung' (wohl ein Tippfehler). Welche Restspannung? Wo kommt da
jetzt auf einemal eine Restspannung her? Im Code steht max_adcvalue. Da
steckt ein 'max' wie Maximum drinnen. 'Rest' ist aber nicht dasselbe wie
'Maximum'.
Siehst du wie verwirrend es sein kann, wenn der Kommentar so überhaupt
nicht zur Anweisung passt, neben der er steht?
Und das ist noch ein harmloses Beispiel.
Ein Kommentar soll mir auf jeden Fall das WARUM erzählen. WIE das
dann gemacht wird, das steht im Code direkt.
Karl H. schrieb:> Welche Restspannung?
Ich vermute, im Kommentar sollte es RefSpannung heissen, und nicht
Restspannung. Gemeint ist wohl VREF des ADC.
Noch ein bisschen was zur Mittelung. Es gibt viele Ansätze, einer der
einfachsten ist einfach das simple Aufaddieren und Teilen durch die
Anzahl der Messwerte.
1
uint16_tADCValue;
2
ADCValue=(ADCValue+ADCW)/2;
Hier wird der vorherige Wert aufaddiert und das Ergebnis durch 2
geteilt, der Wert ist der Mittelwert aus der aktuellen und der
vorherigen Messung. Hilft schon ein wenig.
Karl H. schrieb:> krusti schrieb:>> Das heißt ich speicher mir jede Universalfunktion>> na ja. Nicht unbedingt jede. Man wird sie natürlich sinnvoll nach> Themenkreisen sortiert in jeweilige C-Files stecken. Und sich natürlich> ein Header File dazu bauen.
Ok, das mit dem "auslagern" der Funktionen werde ich probieren, wenn das
alles soweit fertig ist. Ich lass das alles jetzt erstmal noch in einer
Datei drin. Und eine thematische Zuordnung muss ich mir dann auch noch
einfallen lassen.
>Siehst du wie verwirrend es sein kann, wenn der Kommentar so überhaupt>nicht zur Anweisung passt, neben der er steht?
Das mit den Kommentaren ist nicht so einfach, was da sinnvoll ist und
was nicht. Aber ich werde versuchen die Frage nach dem warum mehr zu
berücksichtigen.
Ich finde es echt cool, was ich jetzt doch neues gelernt habe in den
letzten 24 Std. Das kann ich gar nicht so schnell umsetzen und
verinnerlichen. Das werde ich mir in aller Ruhe nochmal anschauen
müssen, gegebenfalls mehrmals, aber ich finds gut.
Matthias S. schrieb:> Karl H. schrieb:>> Welche Restspannung?>> Ich vermute, im Kommentar sollte es RefSpannung heissen, und nicht> Restspannung. Gemeint ist wohl VREF des ADC.
Richtig, ein kleiner Tippfehler. Aber den Kommentar habe ich jetzt
entfernt.
> Noch ein bisschen was zur Mittelung. Es gibt viele Ansätze, einer der> einfachsten ist einfach das simple Aufaddieren und Teilen durch die> Anzahl der Messwerte.uint16_t ADCValue;> ADCValue = (ADCValue + ADCW) / 2;> Hier wird der vorherige Wert aufaddiert und das Ergebnis durch 2> geteilt, der Wert ist der Mittelwert aus der aktuellen und der> vorherigen Messung. Hilft schon ein wenig.
Ich wollte es ja eigentlich so einfach mit einer for-Schleife
realisieren. Aber das funktionierte nicht. Inzwischen weiß ich, dass das
Problem am ADC lag und nicht an der for-Schleife. Trotzdem nutze ich
weiter die ADC-Read-Funktion. Der Grund ist, dass ich dort gut noch mit
der Anzahl der zu mittelnden Werte spielen kann.
Hallo,
ich packe einfach nochmal diesen Thread wieder aus. Es ist zwar nicht
mehr das gleiche Thema, aber noch das selbe Projekt.
Ich habe inzwischen die Anzige und den ADC soweit, dass ich die Spannung
vom Labornetzzteil 1:1 auf den Anzeigen ausgeben kann. Nun will ich den
Drucksenor einbinden, erstmal weiterhin in Form des Labornetzteils.
Problem ist, in meiner Berechnung geht irgendetwas schief oder ich habe
einen Denkfehler drin. Es scheint als würden keine 3 Ziffern an meine
Ausgabefunktion übergeben werden. Mit einem Taschenrechner bekomme ich
eine 3stellige Zahl. Wenn ich in outValue eine Zahl eingebe (z.B. 123)
wird diese sauber angezeigt, scheint also an der Berechnung zu liegen.
Bei meinem berechneten Wert ist die hunderter Stelle total falsch. Das
ist keine Zahl, sondern einfach wilde Zeichen. Die beiden letzten
Stellen passen, zumindest optisch.
Ich habe auch mal auskommentiert drin, wie ich die Spannung auf die
Anzeigen gebracht habe. Dort musste ich den Wert / 100 machen, weil
sonst ähnliches passierte. Das konnte ich aber mit einem Taschenrechner
nachvollziehen, beim jetztigen Problem wie gesagt nicht.
Ich habe schon mit den Datentypen gespielt, weil ich dachte ich habe
einen Überlauf oder sonst etwas. Wäre dankbar für weitere Hilfe.
krusti schrieb:> Problem ist, in meiner Berechnung geht irgendetwas schief oder ich habe> einen Denkfehler drin. Es scheint als würden keine 3 Ziffern an meine> Ausgabefunktion übergeben werden. Mit einem Taschenrechner bekomme ich> eine 3stellige Zahl. Wenn ich in outValue eine Zahl eingebe (z.B. 123)> wird diese sauber angezeigt, scheint also an der Berechnung zu liegen.> Bei meinem berechneten Wert ist die hunderter Stelle total falsch. Das> ist keine Zahl, sondern einfach wilde Zeichen.
Ich hatte in der Funktion nicht ohne Grund am Anfang ein
1
....
2
3
if(wert>999)
4
wert=999;
5
...
drinnen.
In deiner Berechnung kommt offensichtlich kein Wert zwischen 0 und 999
raus sondern etwas mit mindestens einer Tausenderstelle.
Oder D. schrieb:> Ahhhhh. ADC Mitteln mit einer For Schleife....>> Sowas macht man anders.
Man kann es anders machen, man muss es aber nicht.
Rechenzeit spielt bei ihm keine Rolle.
darf kein einziges Zwischenergebnis den Wert 65535 übersteigen.
Also nochmal den Taschenrechner gezückt und die Berechnung noch einmal
genau so durchspielen, wie sie auch vom AVR gerechnet werden. Jedes
einzelne Zwischenergebnis kontrollieren.
Karl H. schrieb:> krusti schrieb:>>> Mit einem Taschenrechner bekomme ich>> eine 3stellige Zahl.>> Das reicht nicht.> In deiner Berechnung druck = (max_adcValue V_REF maxDruck) /> ((V_REF-5000) * MAXVALUE);> darf kein einziges Zwischenergebnis den Wert 65535 übersteigen.>> Also nochmal den Taschenrechner gezückt und die Berechnung noch einmal> genau so durchspielen, wie sie auch vom AVR gerechnet werden. Jedes> einzelne Zwischenergebnis kontrollieren.
Ja das habe ich dann auch festgestellt, als ich nach einer Pause
nochmals ran bin. Habe dann max_adcValue und druck auf 64 bit
umgestellt. Allerdings ist mein Speicher dann statt 20% ganze 77%
belegt. Habe es jetzt mit float laufen. Scheint das selbe Ergebnis zu
sein, nur eben wieder bei ca. 20% Speicherbelegung.
Wobei ich ja eigentlich extra mit Integer arbeiten wollte.
Was spricht denn gegen einen exponentiellen Average, auch Tiefpass
genannt ? Der braucht genau eine Speicherstelle, etwas Schieben und
Addieren. Dazu muss man nicht grad eine Library einbinden.
krusti schrieb:> Ja das habe ich dann auch festgestellt, als ich nach einer Pause> nochmals ran bin. Habe dann max_adcValue und druck auf 64 bit> umgestellt.
Hätte es gar nicht gebraucht.
Es hätte gereicht nur in dieser einen Berechnung zwischendurch einen
oder zwei Zwischenschritte über long zu gehen. Zwischen 16 Bit und 64
Bit ist noch viel Luft dazwischen.
Aber dazu muss man erst mal wissen, welche Berechnung bei 16 Bit
überlaufen wird. Genau das wäre der Sinn der Übung gewesen, dir das
bewusst zu machen. Einfach alle Variablen auf einen anderen Datentyp zu
wechseln, war nicht der Sinn der Sache. Du fährst ja auch nicht mit dem
LKW Brötchen holen.
Oder D. schrieb:> Was spricht denn gegen einen exponentiellen Average, auch Tiefpass> genannt ?
Das das jetzt nicht sein eigentliches Problem ist und sein Problem, dass
er mit C-Grundlagen bezüglich Datentypen in Operationen hat, nicht löst.
Du verlagerst die Diskussion auf einen Nebenschauplatz, der momentan
kein Problem darstellt.
Karl H. schrieb:> Es hätte gereicht nur in dieser einen Berechnung zwischendurch einen> oder zwei Zwischenschritte über long zu gehen. Zwischen 16 Bit und 64> Bit ist noch viel Luft dazwischen.>> Aber dazu muss man erst mal wissen, welche Berechnung bei 16 Bit> überlaufen wird. Genau das wäre der Sinn der Übung gewesen, dir das> bewusst zu machen. Einfach alle Variablen auf einen anderen Datentyp zu> wechseln, war nicht der Sinn der Sache. Du fährst ja auch nicht mit dem> LKW Brötchen holen.
Habe mich mal etwas schlau gemacht. Und habe es mal versucht. Habe mal
die Ergebnisse mit dem maximalen ADC-Wert von 1024 berechnet und dazu
geschrieben.
Ein Prblem ist aber weiterhin, dass der mein Programmspeicher mega
überladen ist.
Program Memory Usage : 5464 bytes 66,7 % Full
Data Memory Usage : 271 bytes 26,5 % Full
Habe ich etwas falsch gemacht bei der Berechnung und den Datentypen?
Oder D. schrieb:> Als Mittelwert verwendet man optimalerweise einen exponentiellen> Mittelwert
Dieser "exponnentielle Mittelwert" ist einfach ein gleitender Mittelwert
über die N letzten Stellen. Keine Ahnung, warum der jetzt einen neuen
Namen braucht.
krusti schrieb:> druck = temp1 / temp2; //11738880000 / 52075520 => 225,..
Du solltest dir mal überlegen, ob du da die Berechnung nicht ein wenig
zusammenkürzen willst. Es macht keinen Sinn, wenn du einen Bruch
anschreibst, der theoretisch auf 5 Nachkommastellen genau ist, wenn du
dann sowieso alle Nachkommastellen wegwirfst. 117000 / 520 ist immer
noch genau genug. Und von da an kann man das Rad nach hinten aufzäumen
und sich die notwendigen Konstanten für die Schritte davor bestimmen.
> Ein Prblem ist aber weiterhin, dass der mein Programmspeicher mega> überladen ist.
67% ist nicht überladen. Das sind die 64 Bit Routinen, die
zugegebenermassen nicht gerade die speichersparendsten sind.
-> 64 Bit willst du nicht verwenden wenn es nicht sein muss. Bei dir
muss es nicht sein. Man kann die Berechnung auch so umformen und kürzen,
dass zwischendurch keine so großen Zahlen entstehen und trotzdem hinten
das richtige rauskommt.
Karl H. schrieb:> Und von da an kann man das Rad nach hinten aufzäumen
Du zäumst ein Rad von hinten auf? Kenne den Spass ja nur mit dem Pferd,
das Rad erfinden wir hier nur immer wieder neu ;) :D
>Dieser "exponnentielle Mittelwert" ist einfach ein gleitender Mittelwert
über die N letzten Stellen. Keine Ahnung, warum der jetzt einen neuen
Namen braucht.
Nein. Ein gleitender Mittelwert, mittelt ueber die jeweils N letzten
Werte. Dazu verwendet man einen Ringbuffer und geht pro neuem Wert
einmal mit MAC (Multiply & Accumulate) drueber. Wenn der Controller
diese Funktionalitaet nicht bietet, zB kein DSP ist, wuerd ich sowieso
nicht in Betracht ziehen.
Der Name exponentieller Mittelwert kommt daher, dass die Gewichtung des
jetzigen Wertes im Mittelwert mit der Zeit exponentiell abnimmt. Man
kann zeigen, dass er identisch einem Tiefpass ist. Sehr schnell und
effizient zu rechnen. Machen die Oszilloskope sogar in Echtzeit.
Ich habe endlich wieder ewtwas Zeit für meine Sache und habe mal
versucht die Berechnung umzusetzen. Meine Speicherbelegung konnte ich
wieder aug knapp 17% damit drücken. Es scheint im groben auch alles zu
passen. Aber eben nur im Groben.
Ich will ja, wie schon einmal erwähnt einen Drucksensor 0,5V - 4,5V
verwenden. Somit habe ich die Formeln erarbeitet und umgestellt.
daraus habe ich dann eine große Formel gemacht:
Ich bin mir nicht sicher ob ich im Nenner + oder - machen muss. Bin mir
bei Formelumstellen immer etwas unsicher. Denke aber es muss - sein.
Das Problem ist, dass meine 000 auf dem Display erst bei ca. 0,74V statt
0,5V beginnt.
krusti schrieb:> Das Problem ist, dass meine 000 auf dem Display erst bei ca. 0,74V statt> 0,5V beginnt.
Dann wird deine Gesamt-Formel wohl nicht stimmen.
Wenn das ein Polynom 4-ten Grades wäre, dann könnte ich das ja noch
verstehen. Aber einfache UMformungen sollte man eigentlich schon können,
wenn man Messsysteme programmieren will. Natürlich kann es schon mal
sein, dass sich wo ein Vorzeichenfehler einschleicht, aber so Dinge wie
Klammern ausmultiplizieren, Dinge aus einer Klammer herausheben und
Terme von der rechten auf die linke Seite bringen (bzw. umgekehrt)
dürfen keine Probleme machen.
Hinweis: dem Computer ist es erst mal egal, ob du gleich mit einer
riesigen Formel kommst, oder ob du die Einzelteile einzeln errechnst und
die Dinge nach und nach zusammensetzt.
Frei nach dem Muster: zusammenfassen kann man immer noch.
Aber wenn man die Einzelteile einzeln errechnet, dann kann man sich die
auch ausgeben lassen und kontrollieren, ob die Ergebnisse plausibel
sind. Soll heissen: Fängst du mit Einzelformeln an und kriegst du das
richtige Ergebnis, dann kannst du mit deinem Programm auch deine ganze
am Papier stattfindende Formelumformung bzw. Einsetzterei kontrollieren.
Denn egal wie du eine Formel umformst, das Endergebnis muss ja dasselbe
sein. :-)
Ich mache eine Beobachtung, wo ich nicht weiß ob ich da richtig liege.
Ich lasse den ADC-Wert auf dem Display anzeigen. Die Anzeige dort ist
z.B. 50 Bit was einer Spannung von 0,22V entspricht. Der Multimeter
zeigt aber 0,16V an, was ungefähr 37 oder 38 Bit enstprechen würde.
Ich habe meine Formel nochmal überprüft und denke, dass diese korrekt
sein sollte. Wenn man dann die Bits in die Formel eintragen würde, wäre
es ein Unterschied von 3 bar. Ist auf den gesamten Bereich nur 1% aber
ich hätte es natürlich schon gerne genau. Also irgendwie kommt das
Signal falsch rein. Meine Refspannung stimmt aber.
krusti schrieb:> Ich lasse den ADC-Wert auf dem Display anzeigen. Die Anzeige dort ist> z.B. 50 Bit was einer Spannung von 0,22V entspricht. Der Multimeter> zeigt aber 0,16V an, was ungefähr 37 oder 38 Bit enstprechen würde.
50 bit? Ja ne, is klar. Also 24 bit sind ja schon sehr sportlich aber 50
bit?
krusti schrieb:> Ich habe meine Formel nochmal überprüft und denke, dass diese korrekt> sein sollte.
Auf keinen Fall. Du hast nie und nimmer 50 bit. Und auch keine 37 oder
38 bit.
@ krusti (Gast)
>ich habe ein Problem mit meinem ADC und ATmega8. Ich will mit dem ADC>eine Durchschnittsberechnung durchführen, um das Flackern auf meinen>7-Segementen zu verringern.
Wahrscheinlich sollte man das Problem erstmal in Hardware untersuchen.
Möglicherweise ist dort was faul.
>Ich habe endlich wieder ewtwas Zeit für meine Sache und habe mal>versucht die Berechnung umzusetzen. Meine Speicherbelegung konnte ich>wieder aug knapp 17% damit drücken.
Klingt doch super!
>Ich will ja, wie schon einmal erwähnt einen Drucksensor 0,5V - 4,5V>verwenden. Somit habe ich die Formeln erarbeitet und umgestellt.
Das kann ja nicht so schwer sein.
>daraus habe ich dann eine große Formel gemacht:>gesuchter Druck = \frac{ADCwert*RefSpannung*Max Druck-Offset Sensor}>{MaxSpannung Sensor-+Offset Sensor*maximale Bit}
Die sieht komisch und falsch aus.
>Ich bin mir nicht sicher ob ich im Nenner + oder - machen muss.
???
> Bin mir>bei Formelumstellen immer etwas unsicher. Denke aber es muss - sein.>Das Problem ist, dass meine 000 auf dem Display erst bei ca. 0,74V statt>0,5V beginnt.
Dann ist deine Formel falsch.
Mach es schrittweise und nicht in einer Formel.
1.) Spannung in mV berechen, siehe Festkommaartihmetik Dafür reichen
32 Bit locker
2.) Damit den Druck ausrechnen. Offset abziehen und passend skalieren.
@ krusti (Gast)
>Ich lasse den ADC-Wert auf dem Display anzeigen. Die Anzeige dort ist>z.B. 50 Bit was einer Spannung von 0,22V entspricht.
Nein. Die Formulierung "50 Bit" ist falsch. Du hast 50 LSB, sprich 50
Einheiten. Denn dein Messwert hat nur 10 Bit Breite.
> Der Multimeter>zeigt aber 0,16V an, was ungefähr 37 oder 38 Bit enstprechen würde.>Ich habe meine Formel nochmal überprüft und denke, dass diese korrekt>sein sollte.
Ist es aber nicht. Ausserdem sehe ich bei dir keine Kalibrierung.
> Wenn man dann die Bits in die Formel eintragen würde, wäre>es ein Unterschied von 3 bar. Ist auf den gesamten Bereich nur 1% aber>ich hätte es natürlich schon gerne genau. Also irgendwie kommt das>Signal falsch rein. Meine Refspannung stimmt aber.
Wie hast du das gemessen?
Falk B. schrieb:> Nein. Die Formulierung "50 Bit" ist falsch. Du hast 50 LSB, sprich 50> Einheiten. Denn dein Messwert hat nur 10 Bit Breite.
Ja ich weiß, die Formulierung war nicht ganz glücklich. Hätte ich besser
sagen sollen ADC-Wert 50?
>> Der Multimeter>>zeigt aber 0,16V an, was ungefähr 37 oder 38 Bit enstprechen würde.>>>Ich habe meine Formel nochmal überprüft und denke, dass diese korrekt>>sein sollte.>> Ist es aber nicht. Ausserdem sehe ich bei dir keine Kalibrierung.
>> Wenn man dann die Bits in die Formel eintragen würde, wäre>>es ein Unterschied von 3 bar. Ist auf den gesamten Bereich nur 1% aber>>ich hätte es natürlich schon gerne genau. Also irgendwie kommt das>>Signal falsch rein. Meine Refspannung stimmt aber.>> Wie hast du das gemessen?
Ich habe eine Excel-Liste erstellt, welche mir angibt, welchen ADC-Wert
welche Spannung hat.
Auf meiner Anzeige lasse ich den ADC-Wert des µC ausgeben und
kontrolliere die Spannung mit einem Multimeter. Dadurch habe ich eben
einen Versatz festgestellt.
@ krusti (Gast)
>Ja ich weiß, die Formulierung war nicht ganz glücklich. Hätte ich besser>sagen sollen ADC-Wert 50?
Ja.
>> Ist es aber nicht. Ausserdem sehe ich bei dir keine Kalibrierung.>void init_ADC()
Das ist keine Kalibrirung, sagt ja schon der Name. Es wird nur der ADC
eingestellt, neudeutsch initialisiert.
Kalibrieren heißt, den Fehler der Referenzspannung per "Mogelfaktor"
auszugleichen.
>Ich habe eine Excel-Liste erstellt, welche mir angibt, welchen ADC-Wert>welche Spannung hat.>Auf meiner Anzeige lasse ich den ADC-Wert des µC ausgeben und>kontrolliere die Spannung mit einem Multimeter.
Das ist schon mal gut.
> Dadurch habe ich eben>einen Versatz festgestellt.
Dann hast du einen Fehler. Denn musst du erst einmal finden und
beseitigen, ohne mit der Druckumrechung zu hantieren. Zuerst muss die
Umrechung in Spannung fehlerfrei sein.
krusti schrieb:>> Wie sieht deine Referenzspannung aus?> Wie genau? Schaltungstechnisch? Programmiertechnisch oder der> Spannungswert?
Mich würde die Schaltung insgesamt interessieren, speziell die
Referenzspannung. Der gemessene Wert wäre auch wichtig.
Bei einem ADC-Wert von 50 und einer gemessenen Spannung von 0,16V,
sollte die zurückgerechnete Referenzspannung 3,3V sein.
Da stellt sich schon die Frage was da stimmt, oder auch nicht.
Hubert G. schrieb:> Bei einem ADC-Wert von 50 und einer gemessenen Spannung von 0,16V,> sollte die zurückgerechnete Referenzspannung 3,3V sein.> Da stellt sich schon die Frage was da stimmt, oder auch nicht.
3.3V wäre jetzt aber keine soo ungewöhnliche Spannung bei einem µC ;)
Hubert G. schrieb:> Michael K. schrieb:>> 3.3V wäre jetzt aber keine soo ungewöhnliche Spannung bei einem µC ;)>> Es beißt sich nur etwas wenn der Sensor bis 4,5V ausgibt.
Yo, Spannungsteiler sind ja auch soo komplizierte Schaltungen…also ich
benutze auch oft 3.3V bei meinen µCs und hab die Sensoren dann ggf. an
einem Spannungsteiler dran.
Michael K. schrieb:> Hubert G. schrieb:>> Michael K. schrieb:>>> 3.3V wäre jetzt aber keine soo ungewöhnliche Spannung bei einem µC ;)>>>> Es beißt sich nur etwas wenn der Sensor bis 4,5V ausgibt.>> Yo, Spannungsteiler sind ja auch soo komplizierte Schaltungen…also ich> benutze auch oft 3.3V bei meinen µCs und hab die Sensoren dann ggf. an> einem Spannungsteiler dran.
Ist ja schön und richtig, aber dann sollte man nicht mit 4,5V rechnen.
Um die ganzen Spekulationen auszuräumen habe ich mal einen Teil der
Schaltung hier eingestellt.
Die Versorgung sind 5V, die Referenzspannung für den ADC habe ich auf
4,585V eingestellt. Somit nutze ich den Sensor maximal aus, so dachte
ich es mir zumindest.
Nur ist jetzt leider irgendetwas hardwareseitg mit meiner Platine
passiert, sodass derzeit keine korrekte Funktion mehr da ist. Eventuell
ist der ADC-Eingang hopps gegangen. Der Controller braucht plötzlich
mehr Strom und wird warm. Da muss ich noch dahinter steigen was da
passiert ist, hatte aber irgendwann keine Lust mehr.
krusti schrieb:> Die Versorgung sind 5V, die Referenzspannung für den ADC habe ich auf> 4,585V eingestellt. Somit nutze ich den Sensor maximal aus, so dachte> ich es mir zumindest.
Hm, also so wie du das eingestellt hast, nur mit Widerständen, da
könntest du den Kontroller auch gleich auf Vcc einstellen, dann bist du
genauso genau in der Messung. Zumindest die Spule hättest du AVcc gönnen
können.
AREF und AVCC wurden schon erwähnt.
Die Versorgungsspannung des Sensor sollte von der 5V Versorgung des
Kontroller entkoppelt sein. Wenn der Ausgangswiderstand des Sensor mehr
als 5k ist, sollte man einen 1n Kondensator vom ADC-Eingang nach GND
schalten.
Es sollte weiters sichergestellt sein, das während der ADC-Messung keine
weitere Aktivität auf den anderen Pin des PortC ist (Siebensegment).
Alles so Kleinigkeiten die aber die Genauigkeit der Messung wesentlich
beeinflussen können.
Michael K. schrieb:> Hm, also so wie du das eingestellt hast, nur mit Widerständen, da> könntest du den Kontroller auch gleich auf Vcc einstellen, dann bist du> genauso genau in der Messung.
Verstehe jetzt ehrlich gesagt nicht, was du mir damit sagen willst.
Ich weiß dass es nicht die eleganteste Lösung ist. Wie gesagt,ich wollte
knapp über 4,5V kommen um den Bereich voll mitzunehmen. Soll ich das
Umbauen?
Wenn ich die 5V nehm, dann verliere ich aber insgesamt 1V (0 - 0,5V und
4,5V - 5V) an meine ADC den ich ja nicht nutzen kann.
>Zumindest die Spule hättest du AVcc gönnen> können.
Ja das habe ich nicht beachtet. Versuche mir einen zu organisieren und
einzubauen.
Bei einer Schlatung, welche schon Jahre her ist, ging es auch ohne (wohl
damals auch schon nicht beachtet.)
krusti schrieb:> Verstehe jetzt ehrlich gesagt nicht, was du mir damit sagen willst.> Ich weiß dass es nicht die eleganteste Lösung ist. Wie gesagt,ich wollte> knapp über 4,5V kommen um den Bereich voll mitzunehmen. Soll ich das> Umbauen?> Wenn ich die 5V nehm, dann verliere ich aber insgesamt 1V (0 - 0,5V und> 4,5V - 5V) an meine ADC den ich ja nicht nutzen kann.
Du solltest zumindest noch eine Induktivität dazu packen gemäß
Datenblattangabe damit dein Vcc auch stabiler wird. Eine
Referenzspannung, die im Bereich von 10 K (z.B. zwischen 10°C und 20°C)
noch auf 10 bit genau sein soll braucht mindestens eine Stabilität bzgl.
Temperatur von 50 ppm. Versorgst du Vcc z.B. durch einen LM317 bist du
vielleicht bei 100 ppm, das reicht nicht für 10 bit.
Und jetzt nur mal den Rest noch bedenken…also 5 mV ist nicht viel bei
unterschiedlichen Belastungen kann man die schnell verlieren (LM317 hat
meine ich 25 mV Genauigkeit, das reicht kaum noch für 8 bit). Deshalb
solltest du dir da vielleicht noch Gedanken drum machen.
@ krusti (Gast)
>Verstehe jetzt ehrlich gesagt nicht, was du mir damit sagen willst.>Ich weiß dass es nicht die eleganteste Lösung ist. Wie gesagt,ich wollte>knapp über 4,5V kommen um den Bereich voll mitzunehmen. Soll ich das>Umbauen?
Du MUSST es umbauen! An AREF gehören 100nF gegen GND, sonst NIX!
Das dürfte auch der Grund für deinen zappelnden Messwert sein!
>Wenn ich die 5V nehm, dann verliere ich aber insgesamt 1V (0 - 0,5V und>4,5V - 5V) an meine ADC den ich ja nicht nutzen kann.
Das ist weniger als 1 Bit Auflösung Verlust, das kann man
vernachlässigen.
>>Zumindest die Spule hättest du AVcc gönnen>> können.>Ja das habe ich nicht beachtet. Versuche mir einen zu organisieren und>einzubauen.
Es reichen ggf. auch 10-47 Ohm.
Falk B. schrieb:> Du MUSST es umbauen! An AREF gehören 100nF gegen GND, sonst NIX!
Oder halt eine vernünftige Referenzspannungsquelle. ;)
Falk B. schrieb:> Das ist weniger als 1 Bit Auflösung Verlust, das kann man> vernachlässigen.
Deshalb auch meine Anmerkungen zur Stabilität der aktuellen
Referenzspannungsquelle. Die wird wahrscheinlich nicht mal 8 bit
genügen, geschweige denn 10 bit.
Falk B. schrieb:> Es reichen ggf. auch 10-47 Ohm.
Das geht zur Not wahrscheinlich auch. Ich hab 10 uH Spulen die gleich
groß wie Widerstände sind und preislich hat sich das auch nichts getan,
daher setze ich immer die ein. ;)
mach doch die Referenzspannung 4.096 Volt (4096 mV). Das durch 10bit
geteilt ergibt Vier(millivolt). Eine ADC-Einheit (Digit) sind dann exakt
4mV.
Jetzt brauchst Du deinen ADC-Wert nur noch mal Vier nehmen und hast
schonmal die Spannung in millivolt aus deinem Sensor. So einfach :)
Wenn Du die Sensorspannung nun noch mit einem Spannungsteiler viertelst
(33K + 11K), sind deine Anzeigewerte des ADCs die Millivolts, die der
Drucksensor liefert und du musst nichts mehr rechnen, um von den
Anzeigeeinheiten auf deine Sensorspannung zu schließen.
Um das mit dem Druck jetzt richtig zu rechnen, hatte ich schon zu viele
Cuba im Glas.
Gruß
Axel
Vielen Dank schon mal für die Hilfe. Irgendwie merke ich gerade, dass
mein Aufbau nicht ganz so gut war wie gedacht bzw gehofft. Bin in der
Schaltungsentwicklung zwar in den Basics ganz gut, bei solchen sachen
mit Sensoren fehlt mir allerdings dann doch die Erfahrung.
Es kommt mir nachher nicht auf 100% Genauigkeit an aber wenn ich mit dem
Netzteil, als Simulation des Sensors, schon 12 Digits daneben liege, ist
eben was falsch.
Werde mir jetzt eine Induktivität besorgen und diese zwischen AVcc und
Vcc hauen.
>Du MUSST es umbauen! An AREF gehören 100nF gegen GND, sonst NIX!
Damit ich das richtig verstehe, das gilt nur für den Fall, wenn ich die
Vcc als Referenz nehme.
>Wenn der Ausgangswiderstand des Sensor mehr>als 5k ist, sollte man einen 1n Kondensator vom ADC-Eingang nach GND>schalten.
Der Widerstand beträgt laut Datenblatt max. 5k
>Es sollte weiters sichergestellt sein, das während der ADC-Messung keine>weitere Aktivität auf den anderen Pin des PortC ist (Siebensegment).
Das werde ich ebenfalls versuchen umzusetzen.
>Deshalb auch meine Anmerkungen zur Stabilität der aktuellen>Referenzspannungsquelle. Die wird wahrscheinlich nicht mal 8 bit>genügen, geschweige denn 10 bit.
Sorry verstehe ich eventuell nicht. Soll heißen, mein aktueller Aufbau
hat eine so schlechte Referenz bzw diese schwankt so sehr, dass damit
keine geneue Messung möglich ist?
Es ist nicht so einfach bei mir noch einen weiteren Baustein einzubauen,
der eine Referenzspannung erzeugen könnte.
Habe als Spannungsquelle den TSR 1-2450 von Traco genommen. Ich vermute
mal, dass auch dies nicht die beste Wahl war?
Langsam verliere ich den Überblick und kapiere gar nichts mehr.
krusti schrieb:> Soll heißen, mein aktueller Aufbau> hat eine so schlechte Referenz bzw diese schwankt so sehr, dass damit> keine geneue Messung möglich ist?
So isses. Da du AREF direkt aus VCC generierst, welche mit den Spitzen
des arbeitenden MC 'verseucht' ist, ist da nichts stabiles zu erwarten.
Sowohl AVCC als auch AREF sollten so entkoppelt sein, das Störungen auf
VCC nicht bis zum ADC Teil durchkommen. Ein 10µF Elko an VCC und GND ist
auch nicht dumm, direkt am MC.
> Habe als Spannungsquelle den TSR 1-2450 von Traco genommen. Ich vermute> mal, dass auch dies nicht die beste Wahl war?
Das Dings ist eben ein Schaltnetzteil. Ob und wieweit Traco die Spitzen
der Schaltvorgänge vom 5V Ausgang fernhält, verrät dir am besten ein
Oszilloskop. Ein LC Filter jedenfalls kann auch hier helfen.
krusti schrieb:>>Du MUSST es umbauen! An AREF gehören 100nF gegen GND, sonst NIX!> Damit ich das richtig verstehe, das gilt nur für den Fall, wenn ich die> Vcc als Referenz nehme.
Ja
krusti schrieb:> Habe als Spannungsquelle den TSR 1-2450 von Traco genommen. Ich vermute> mal, dass auch dies nicht die beste Wahl war?
Das Teil hat ne Restwelligkeit von 50 mV peak2peak. 8 bit auf 5 V
gerechnet bedeutet, dass ein Count schon etwa 20 mV entspricht. Bei 7
bit ist man bei knapp 40 mV und bei 6 bit bei etwa 78 mV, d.h. bzgl. der
Restwelligkeit reicht dieser Regler grad mal für 6 bit. Die
Lastabhängigkeit noch nicht berücksichtigt. Und die Temperaturstabilität
beträgt bei dem Gerät auch "nur" 0,015%, also 150 ppm (genügt bei 10K
Temperaturschwankung auch nur für 8 bit).
@ krusti (Gast)
>>Du MUSST es umbauen! An AREF gehören 100nF gegen GND, sonst NIX!>Damit ich das richtig verstehe, das gilt nur für den Fall, wenn ich die>Vcc als Referenz nehme.
Nein, auch wenn man die interne Referenz nutzen will. Man kann auch eine
externe Referenz an Aref anschließen, dann werden die 100nF aber auch
gebraucht.
>Habe als Spannungsquelle den TSR 1-2450 von Traco genommen. Ich vermute>mal, dass auch dies nicht die beste Wahl war?
Das Ding ist eine DRECKSCHLEUDER! Dort gibt es ordentlich HF-Störungen!
Als ADC-Referenz sowie AVCC vollkommen ungeeignet. Man muss dort massiv
filtern. Besser noch, man gewinnt die Versorgungsspannung aus einem
Linearregler.
Falk B. schrieb:> Das Ding ist eine DRECKSCHLEUDER! Dort gibt es ordentlich HF-Störungen!> Als ADC-Referenz sowie AVCC vollkommen ungeeignet. Man muss dort massiv> filtern. Besser noch, man gewinnt die Versorgungsspannung aus einem> Linearregler.
Sehe ich auch so, und wenn man auf 10 bit will kann ein LT1021-5
sinnvoll sein.
Ok, vielen Dank schon mal. Klingt alles sehr einleuchtend. Dass diese
Faktoren mit Temperaturdrift und der Restwelligkeit so starke
Auswirkungen haben, habe ich nicht bedacht. Wieder wichtige Grundlagen
gelernt. Gerade wie ich so etwas berechne, war mir nicht klar. Wobei ich
das mit dem ppm und der Temperatur im Zusammenhang mit den Bit noch
nicht verstehe.
Dann wird es wohl das Beste sein, ich mache die Platine nochmals neu,
mit dem LT1021-5. Reicht der dann auch um die ganze Schaltung zu
treiben? Kann ich den quasi als Spannungsversorgung nutzen? Im
Datenblatt steh was von gerade mal 1,2mA. Oder baue ich den quasi
parallel zu meiner andern Spannungsversorgung ein, und Versorge den
damit nur den ADC-Teil + Sensor mit Strom?
Trotzdem hätte ich gerne eine Referenzspannung nah an meinem Sensor von
4,5 V. Um das ganze eben, wenn ich schon umbaue, möglichst genau zu
machen.
krusti schrieb:> Reicht der dann auch um die ganze Schaltung zu> treiben?
Der LT1021-5 ist nur für Ströme bis 10 mA geeignet, braucht deine
Schaltung mehr Strom würde ich an deiner Stelle den LT1021-5 nur für
ARef benutzen (pass aber nicht die Spannung für ARef mittels
Spannungsteiler auf, so würdest du alle Vorteile des LT1021-5 bzgl.
Temperaturstabilität zunichte machen) und den Rest der Schaltung mittels
L7805 bzw. LM317 versorgen. Auch ein Schaltregler wie der von dir schon
gewählte von Traco ginge, bedenke aber, dass du für den noch einen
LC-Filter vorsehen solltest wie er im Datenblatt beschrieben ist.
krusti schrieb:> Trotzdem hätte ich gerne eine Referenzspannung nah an meinem Sensor von> 4,5 V. Um das ganze eben, wenn ich schon umbaue, möglichst genau zu> machen.
Dann baue dir dafür eine Referenzspannungsquelle, lies dir dafür z.B.
das hier mal durch: http://sprut.de/electronic/referenz/index.htm
Also habe die Scchaltung mal umgezeichnet. Ich stelle Sie mal im
gesamten hoch. Es wäre nett, wenn man mir das jemand beurteilen könnte,
damit ich nicht schon wieder einen Fehler einbaue. Außerdem lerne ich
gerne was dazu.
Werde jetzt doch die 5V nehmen, weil es einfacher ist. Ich will nicht
noch mehr Bauteile verbauen müssen.
Die Mosfets habe ich bei der Gelegenheit auch rein. Vorher waren
Transistoren drin, es sind Logik-Mosfets.
N-Kanal Mosfets sollten gegen GND geschaltet sein, nicht gegen Vcc.
Überlege dir einfach mal wie hoch die Gate-Spannung sein muss damit der
Mosfet durchschalten kann ;)
Bei den Tastern sind die Widerstände unnötig, dafür könntest du da ein
paar Kondensatoren vorsehen um einem Tastenprellen hardwaremäßig zu
begegnen.
@ krusti (Gast)
>Also habe die Scchaltung mal umgezeichnet. Ich stelle Sie mal im>gesamten hoch. Es wäre nett, wenn man mir das jemand beurteilen könnte,>damit ich nicht schon wieder einen Fehler einbaue. Außerdem lerne ich>gerne was dazu.
C3 gehört direkt an das Reset-Pin!
Q1, Q2, Q3, Q4 und Q6 sind falsch! Dort braucht man P-Kanal MOSFETs und
Source geht an +5V!
>Werde jetzt doch die 5V nehmen, weil es einfacher ist. Ich will nicht>noch mehr Bauteile verbauen müssen.
Wenn der Spannungsregler sauber und halbwegs temperaturstabil ist, geht
das auch.
>Die Mosfets habe ich bei der Gelegenheit auch rein. Vorher waren>Transistoren drin, es sind Logik-Mosfets.
Was glaubst du sind MOSFETs?
Oh man, langsam wirds peinlich für mich. Seit ich den Sensor umsetzen
will, gibt es nur noch Probleme und ich mache gefühlt ständig einen
Schritt rückwärts.
Arbeite das erste mal mit MOSFETs. Habe mir jetzt schon extra MOSFETs
organisiert, natürlich die Falschen. Dann lass ich jetzt doch erstmal
die Transistoren drin. Die funktionierten ja (Ich weiß MOSFETs sind auch
von der Art her Transistoren). Wollte eben eine Lösung realiseren wo ich
meinen µC nicht noch unnötig belaste aber das ist jetzt meine kleinste
Sorge. Ich organisiere mir jetzt noch eine Referenzspannung und
LC-Filter für meinen Traco.
>Bei den Tastern sind die Widerstände unnötig, dafür könntest du da ein>paar Kondensatoren vorsehen um einem Tastenprellen hardwaremäßig zu>begegnen.
Aber hängen die dann nicht in der Luft? Ich ersetze einfach die
Widerstände durch Kondensatoren.
Sorry, dass ich mich jetzt da so blöd anstelle. Ich bin langsam total
verunsichert.
krusti schrieb:> Aber hängen die dann nicht in der Luft? Ich ersetze einfach die> Widerstände durch Kondensatoren.
Du kannst die Pull-Ups des Ports einschalten und die Taster gegen GND
schalten lassen. Damit sparst du dir die Pull-Downs ;)
Michael K. schrieb:> Sehe ich auch so, und wenn man auf 10 bit will kann ein LT1021-5> sinnvoll sein.
Jetzt schaue ich mir gerade das Datenblatt des LT1021-5 an und sehe,
dass LT1021B-5 und LT1021D-5 eine Schwankung von 100mVpp haben. Das wäre
ja schlechter als beim Traco-Bauteil, sehe ich das richtig?
Müsste also ein LT1021C-5 nehmen, welcher nur 5mVpp hat. Den würde es
aber nicht als SMD geben. Müsste ich also bei die DIL-Variante nehmen.
@ krusti (Gast)
>Jetzt schaue ich mir gerade das Datenblatt des LT1021-5 an und sehe,>dass LT1021B-5 und LT1021D-5 eine Schwankung von 100mVpp haben.
Niemals! Wo soll das stehen?
Im Gegenteil
Output Voltage Noise 10-1000Hz max. 3,5uV RMS!
> Das wäre>ja schlechter als beim Traco-Bauteil, sehe ich das richtig?
Nein!
>Müsste also ein LT1021C-5 nehmen, welcher nur 5mVpp hat. Den würde es>aber nicht als SMD geben. Müsste ich also bei die DIL-Variante nehmen.
Du machst das alles viel zu kompliziert für so ein bisschen
ADC-Auslesen.
Falk B. schrieb:> Niemals! Wo soll das stehen?>> Im Gegenteil>> Output Voltage Noise 10-1000Hz max. 3,5uV RMS!>
Habe bei Output Voltage geschaut und mich davon irritieren lassen.
> Du machst das alles viel zu kompliziert für so ein bisschen> ADC-Auslesen.
Ja, das Gefühl habe ich so langsam auch.
krusti schrieb:> Müsste also ein LT1021C-5 nehmen, welcher nur 5mVpp hat. Den würde es> aber nicht als SMD geben. Müsste ich also bei die DIL-Variante nehmen.
Ob DIL oder SMD ist wurscht, beide sind für deine Anwendung geeignet.
Falk B. schrieb:> Du machst das alles viel zu kompliziert für so ein bisschen> ADC-Auslesen
Es geht ja nicht ums auslesen sondern wie genau es sein soll ;)
Hallo zusammen,
ich habe es nach einer Weile geschafft meine Platine umzubauen und habe
statt Transitoren MOSFETs eingebaut und für den ADC eine
Referenzspannungsquelle angeschlossen. Es paast zwar alles weiterhin
nicht mit dem Labornetzteil und Multimeter überein aber meine Ergebnisse
scheinen zu stimmen.
Programmtechnisch bin ich auch ein gutes Stuck voran gekommen.
Hauptfunktion tut, kleine nebeneinbauten funktionieren auch.
Nun habe ich aber ein neues PRoblem, welches ich nicht derzeit nicht
beheben kann.
Ich will bein meiner Anzeige eine Art Wartungsanzeige für die Mechanik
einbauen. D.h. nach x Tagen sollen die LED's blinken (1. Warnung). Nach
weiteren x Tagen soll zusätzlich das Display blinken (möglichst
gleichzeitig; 2. Warnung) Nach weiteren Tagen soll das Display eine
Meldung bringen und nicht mehr zulassen, quasi Sperren. Der Zahle kann
mit einer Tastenkombi zurückgesetzt werden.
Das Sperren und das Rücksetzen klappt einwandfrei. Mein Problem ist
mehr, dass ich das blinken der LED's nicht schaffe. Die LED's (rot,
grün) sollen auch Anzeigen ob der Bereich eingehalten wird.
1
voidLEDmode(uint16_txyz)
2
{
3
switch(led_mode)
4
{
5
case0:
6
if((LED_RANGE_MIN<xyz)&&(xyz<=LED_RANGE_MAX))
7
{
8
PORTC&=~LED_GREEN;
9
}
10
else
11
{
12
PORTC&=~LED_RED;
13
}
14
break;
15
case1:
16
if((LED_RANGE_MIN<xyz)&&(xyz<=LED_RANGE_MAX))
17
{
18
timer2_wert=0;
19
20
while(1){
21
if(timer2_wert>=200)
22
{
23
PORTC&=~LED_GREEN;
24
break;
25
}
26
}
27
timer2_wert=0;
28
29
while(1){
30
if(timer2_wert>=200){
31
PORTC&=~LED_GREEN;
32
break;
33
}
34
}
35
}
36
else
37
{
38
PORTC&=~LED_RED;
39
}
40
break;
41
}
42
}
Ich weiß ich habe dort eine while drin und das ist nicht so
wünschenswert. -> Stichwort Multitasking. Mir fällt aber keine weitere
Idee ein.
Alle Timer des ATmegas sind in Benutzung. 1 für die 7-Seg (Timer0 -
8bit), 1 für meine Zählung der Arbeitstage (Timer1 - 16bit) und ein
Universaltimer (Timer2 -8 bit) der immer 10 ms läuft. Ich baue mir
daraus eben dann meine gewünschte Zeit.
Vernküft ist damit
//Elektronik sperren. Keine weitere Nutzung mehr möglich
22
digit[2]=S;
23
digit[1]=E;
24
digit[0]=r;
25
while(1){}
26
}
27
}
Hänge aber den gesamten Code auch an, was inzwischen gut 500 Zeilen
sind. Ich weiß es ist vllt nicht alles super programmiert. Bin eben kein
gelernter Programmierer, lerne aber gern dazu. Meine Prgrammteile sind
leider sehr statisch, nehme ich mal an und für andere spätere Projekte
wohl nicht einfach nutzbar. Ich versuche aber eben viel mit #define zu
machen, dass wenn ich etwas ändere, nicht der Ganze Code durchforstet
werden muss. Mehr so in der Art OOP (so kenn ich es zumindest aus dem
C#-Unterricht) wäre bestimmt nicht schlecht.
Christian M. schrieb:> Alle Timer des ATmegas sind in Benutzung. 1 für die 7-Seg (Timer0 -> 8bit), 1 für meine Zählung der Arbeitstage (Timer1 - 16bit) und ein> Universaltimer (Timer2 -8 bit) der immer 10 ms läuft. Ich baue mir> daraus eben dann meine gewünschte Zeit.
Und warum kann der Timer 2 dann nicht die Verwaltung der LED mitmachen?
So viel Arbeit ist das dann in der ISR auch wieder nicht, als das man
das auf Biegen und Brechen da raushalten muss.
1
ISR(TIMER2_COMP_vect)
2
{
3
/*Der Compare Interrupt Handler
4
wird aufgerufen, wenn
5
TCNT2 = OCR2 = 233-1
6
ist (233 Schritte), d.h. genau alle 9,984ms
7
*/
8
timer2_wert++;
9
}
Da ist noch viel Spielraum. Wenn die ISR alle 10ms aufgerufen wird, dann
ist es ein Kinderspiel, alle 500 ms eine LED umzuschalten.
1
uint8_tblinkCnt;
2
3
ISR(TIMER2_COMP_vect)
4
{
5
6
/*Der Compare Interrupt Handler
7
wird aufgerufen, wenn
8
TCNT2 = OCR2 = 233-1
9
ist (233 Schritte), d.h. genau alle 9,984ms
10
*/
11
timer2_wert++;
12
13
14
blinkCnt++;
15
if(blinkCnt==100){
16
blinkCnt=0;
17
18
if(blinkCnt<50)
19
PORTC&=~LED_RED;
20
else
21
PORTC|=LED_RED;
22
}
23
}
und das ganze natürlich nur dann, wenn die restlichen Programmteile sich
auf einen ledMode geeinigt haben, der im Falle eines blinkens, wenn ich
das recht sehe auf 1 stehen wird.
1
volatileuint8_tledMode;
2
uint8_tblinkCnt;
3
4
ISR(TIMER2_COMP_vect)
5
{
6
7
/*Der Compare Interrupt Handler
8
wird aufgerufen, wenn
9
TCNT2 = OCR2 = 233-1
10
ist (233 Schritte), d.h. genau alle 9,984ms
11
*/
12
timer2_wert++;
13
14
15
if(ledMode==1){
16
blinkCnt++;
17
if(blinkCnt==100){
18
blinkCnt=0;
19
20
if(blinkCnt<50)
21
PORTC&=~LED_RED;
22
else
23
PORTC|=LED_RED;
24
}
25
}
26
}
und wenn wir schon dabei sind, dann kann in der ISR auch die Auswertung
des ledMode für ALLE Led passieren. Die paar Taktzyklen hast du dort
allemal, dass die Timer ISR die jeweiligen LED anhand des ledMode
schaltet. Keine Angst.
Man könnte auch den ledMode Bitcodieren. Bit 0 steht grundsätzlich für
'rot oder grün', Bit 1 steht für 'rote LED auf jeden Fall blinken
lassen.
D.h. der ledMode kann 4 Werte annehmen
1
0 grün leuchtet
2
1 rot leuchtet
3
2 grün leuchtet und rot blinkt
4
3 rot blinkt
Bit 0 setzt oder löscht du zb in der main() je nach Ergebnis des ADC
Vergleiches. Und Bit 1 setzt bzw. löscht du je nachdem ob dein
Wartungszyklus abgelaufen ist oder nicht. Um den Rest kümmert sich dann
die ISR. In einem gewissen Sinne genau identisch zur Ansteuerung der
7-Segment Anzeige, bei der du auch ein paar Variablen hast, in die du
das auszugebende Muster schreibst und die ISR kümmert sich um den Rest
(und das könnte sogar ein und dieselbe ISR sein. Kein Mensch sagt, dass
1 ISR auch nur 1 Aufgabe bearbeiten darf)
1
volatileuint8_tledMode;
2
uint8_tblinkCnt;
3
4
ISR(TIMER2_COMP_vect)
5
{
6
7
/*Der Compare Interrupt Handler
8
wird aufgerufen, wenn
9
TCNT2 = OCR2 = 233-1
10
ist (233 Schritte), d.h. genau alle 9,984ms
11
*/
12
timer2_wert++;
13
14
if(!(ledMode&0x01))// grün einschalten?
15
PORTC&=~LED_GREEN;
16
else
17
PORTC|=LED_GREEN;
18
19
if(ledMode&0x02){// rot soll also auf jeden Fall blinken
20
blinkCnt++;
21
if(blinkCnt==100){
22
blinkCnt=0;
23
24
if(blinkCnt<50)
25
PORTC&=~LED_RED;
26
else
27
PORTC|=LED_RED;
28
}
29
}
30
31
else{// rot ist nicht auf blinken geschaltet
32
// wie soll es stehen. Wenn grün aus ist
33
// dann muss rot ein sein
34
if(ledMode&0x01)
35
PORTC&=~LED_RED;
36
else
37
PORTC|=LED_RED;
38
}
39
}
Auch wenn es immer wieder heisst, eine ISR soll so kurz wie möglich
sein - das bedeutet nicht, dass man gar nichts in einer ISR machen darf.
Das sieht zwar in C alles recht langatmig aus, aber in Maschinencode
sind das pro ISR Durchlauf nur ein paar Zyklen. Nichts worüber man sich
gross Gedanken machen muss, zumal in deinem Programm nichts wirklich
zeitkritisch ist.
Das restliche Programm setzt den ledMode so wie es der Situation
angemessen ist und die Timer-ISR realisiert das dann an den
physikalischen LED. Auf die Art bleibt dann alles beisammen und du hast
die LED Steuerung nur an einer einzigen Stelle im Code. Und da die ISR
alle 10ms aufgerufen wird, realisieren die physikalischen LED das was du
über ledMode eingestellt hast, spätestens nach 10ms und ein paar
zerquetschten (je nachdem wie lange eine eventuelle andere ISR noch
dazwischen gefunkt hat). Also schnell genug für einen menschlichen
Benutzer, der das Umschalten als aus seiner Sicht 'sofort' einstufen
wird.
Michael K. schrieb:> Geht auch einfacher:
viele Wege führen nach Rom.
ICh wollte die % Operation vermeiden und ihm einen Hinweis geben, dass
das Blinken nicht unbedingt symetrisch sein muss. Auch 20% ein und 80%
aus sind möglich um einen Kontrast zu schaffen. Aber das muss er selbst
entscheiden.
>
1
volatileuint8_tledMode;
2
>//fehlt da nicht ein volatile?
3
>volatileuint8_tblinkCnt;
4
>
nein. Wozu soll das volatile hier gut sein. der blinkCnt wird ja nur in
der ISR verwendet. Man hätte ihn genausogut auch als static Variable in
die ISR hineinziehen können.
1
ISR(TIMER2_COMP_vect)
2
{
3
staticuint8_tblinkCnt;
4
5
...
(aber dann wären wahrscheinlich wieder Fragen gekommen, was das static
an dieser Stelle bedeutet :-)
Karl H. schrieb:> viele Wege führen nach Rom.> ICh wollte die % Operation vermeiden und ihm einen Hinweis geben, dass> das Blinken nicht unbedingt symetrisch sein muss. Auch 20% ein und 80%> aus sind möglich um einen Kontrast zu schaffen. Aber das muss er selbst> entscheiden.
Auch wieder wahr ;)
Michael K. schrieb:> PORTC ^= (1 << LED_RED);
Das sollte man in einer ISR vermeiden, da nicht atomar!
Zumindest dann, wenn man auf den selben PORT auch wo anders zugreift
(Hauptprogramm).
Wenn dann sollte man das mit
chris schrieb:> Das sollte man in einer ISR vermeiden, da nicht atomar!
Hm, da gabs bei mir zwar noch nie Problem mit aber OK, danke für den
Tipp. Das war mir nicht bekannt.
Hallo,
es ist wieder etwas Zeit vergangen und teilweise auch ein paar Nerven.
Aber mein Projekt ist, zumindest programmiertechnisch beinahe fertig
gestellt.
Allerdings habe ich noch zwei Probleme, welche ich nicht lösen kann.
Ich habe das Gefühle, wenn der ISP-Programmer nicht mehr steckt, dass
falsche Werte stärker reinkommen als wenn ich den Programmer dran lasse.
Wenn ich z.B. die Max-Hold-Funktion nutze, wandert der Max-Wert auf
Dauer ohne den Programmer weiter hoch als mit dem Programmer.
Im "Live"-Modus schwankt die Zahl etwas mehr. Es ist nicht viel und ich
habe die Aktualisierung der Anzeige durch eine Zeitfunktion etwas
entstresst. Trotzdem würde mich interessieren warum es so ist.
Vermute mal es hat etwas mit meinen offenen Pins der ISP-Schnittstelle
zu tun. Muss ich diese irgendwie am Controller speziell programmieren
oder beschalten?
Zweites Problem, was mich mehr nervt:
Meine LED's flackern, also unabhängig vom Blinken, mit schneller aber
sichtbarer Frequenz. Ich bin mir auch ziemlich sicher, dass es an PORTC
= ~(1 << (stelle + 3)) liegt:
Schließlich überschreibe ich ja auch meine LED's damit kurzzeitig. Aber
ich habe diverse Bitmanipulationen probiert und finde einfach keine
Lösung. Meist blieben die LED's dann aus. Vielleicht bin ich in diesem
Punkt schon zu sehr verhirnt.
AREF auf AVCC legen ist eine schlechte Lösung. Du bekommst alle kleinen
Spannungsschwankungen auf das Messergebnis übertragen. Besser ist AREG
trennen und über 100n auf GND legen. In die Leitung zu AVCC eine kleine
Induktivität, 10µ, einfügen.
Wenn man genau messen will, ist es auch schlecht auf PORTC
Schaltfunktionen zu tätigen, da diese ebenfalls das Messergebnis
beeinflussen.
Danke für die Antwort.
Im Datenblatt steht ja:
If the ADC is used, it should be connected to VCC through a low-pass
filter.
Also wenn ich es richtig verstehe, so?
5V-ADC---- 5V--
| |
AREF------ VCC----10µH---AVCC
| |
100nF 100nF (an jeden entsprechenden Pin)
| |
GND GND
Und jetzt wo ich es schreibe, merke ich, dass ich das selber schon mal
im Datenblatt gesehen habe.
Ich weiß, dass am ADC keine Schaltfunktionen ausgeführt werden sollen,
aber ich habe keine Pins mehr frei.
Außer es funktioniert folgender Gedanke. Ich will später einen
SMD-Baustein verwenden, TQFP. Wenn ich mir die Pinbelegung anschaue gibt
es zwei reine ADC-Ports. ADC6 und ADC7 an Pin 19 und 22. Sind diese dann
von PortC getrennt und kann ich da mein Auslesen hin verlegen? Oder
hängen diese ADC's trotzdem an PortC irgendwie mit dran?
Jetzt noch schnell eine Frage. Bisher hatte ich einen Mega8 drin,
bekomme aber auf die schnelle als SMD nur einen Mega8A. Wenn ich das
richtig recherchiert habe, sollte es da keine Probleme für meinen Code
geben korrekt?
Hallo Christian M. ,
an AREF liegt i.a. nur einem 100nF Kondensator nach Masse.
Wenn ich wilklich mit dem ADC messen will, verbinde ich diesen Anschluss
mit einer Referensopannungsquelle von 2,56V, 4,096V o.ä.
Aber niemals mit +5V der Vcc, das ist die Versorgungsspannung und diese
ist nicht geeignet und es könnte zu Probleme mit der Internen ADC
Referenzspannung kommen.
Ich habe noch einige neue TQFP atemga8, atmega88pa, atmega168 und
atmega328P da.
Die ich zu meinem EK abgeben kann.
Die TQFP atmega162 kommen dann für dich sicherlich nicht in Frage?
Aber ich habe ja 2x 5V. Einmal zur Versorgung aller Bauteile. Und einmal
extra eine externe Referenzspannung mit glatten 5V (LT1021).
Deswegen habe ich in dem kleinen Bild einen Post vorher ja einmal die
Spannung 5V-ADC genannt und einmal 5V. War eventuell etwas verwirrend
und misszuverstehen, gebe ich im Nachhinein zu.
Danke Uwe für dein Angebot. Habe aber einen Atmega8 gefunden als SMD. Es
war nur eine kleine Frage ob ich auch den mega8A hätte direkt weiter
nutzen können, vielmehr auch aus Neugier eine Frage nebenbei.
Christian M. schrieb:> Im Datenblatt steht ja:> If the ADC is used, it should be connected to VCC through a low-pass> filter.> Also wenn ich es richtig verstehe, so?> 5V-ADC---- 5V--> | |> AREF------ VCC----10µH---AVCC> | |> 100nF 100nF (an jeden entsprechenden Pin)> | |> GND GND>> Und jetzt wo ich es schreibe, merke ich, dass ich das selber schon mal> im Datenblatt gesehen habe.
An den ARef-Pin gehört lediglich eine Referenzspannung und ein
Kondensator gegen GND, sonst nichts. Wenn also die 5V-ADC keine
besonders stabilisierte Spannung darstellen haben die am ARef-Pin nicht
zu suchen.
Da du ja als Referenzquelle ja einen LT1021 benutzt und dass die 5V-ADC
darstellen ist das also so völlig in Ordnung.
Michael K. schrieb:> Da du ja als Referenzquelle ja einen LT1021 benutzt und dass die 5V-ADC> darstellen ist das also so völlig in Ordnung.
Danke, das wollte ich wissen. Hoffe das wird den ADC etwas beruhigen.
Dann bleibt nur noch das flackern der LED's übrig, was ich nicht gelöst
bekomme.