Hallo zusammen, Bin neu auf dem Gebiet der Mikrocontroller, aber soweit klappt alles ganz gut! Jetzt bin ich auf ein seltsames Problem gestoßen. Ich benutze einen Atmel Mega8 und Bascom-Demo Ver. 1.11.8.7 Eine single-Variable (z.B. Temp1) enthält einen Wert ungleich 0. Nun kommt im Code Temp2 = Log(temp1) 'Temp2 ist ebenfalls als single deklariert Compilieren verläuft Fehlerfrei. Sobald nun der Mega8 an Diese Stelle im Code kommt wird der Controller in 95% der Fälle neugestartet, nur zu 5% wird die Berechnung korrekt durchgeführt... Einen vergleichbaren Wert von Temp1 direkt in das Log()-Argument zu schreiben funktioniert problemlos (z.B. "Temp2 = Log(1.2)") Meine Vermutung: Die Variable im Log()-Argument wird von Bascom automatisch kleingeschrieben, aus "Log(Temp1)" wird automatisch beim Verlassen der Zeile im BASCOM-Editor "Log(temp1)". Nun wird bei der Ausführung das Argument als "0" behandelt -> Überlauf -> Absturz. Kann es daran liegen? Andererseits funktioniert z.B. X = Int(r) problemlos, trotz ebenfalls kleingeschriebenem "r"? Bin absolut ratlos, vielleicht kann mir ja einer von Euch weiterhelfen? Danke und Grüße - Andre
@ Andre (Gast) >Temp2 = Log(temp1) 'Temp2 ist ebenfalls als single deklariert Solange temp1 grösser als Null ist, ist das OK. >Sobald nun der Mega8 an Diese Stelle im Code kommt wird der Controller >in 95% der Fälle neugestartet, nur zu 5% wird die Berechnung korrekt >durchgeführt... ??? Wie prüfst du das? Mit einem Debugger? Vielleicht wird zu 95% temp1 kleiner gleich Null. >Meine Vermutung: Die Variable im Log()-Argument wird von Bascom >automatisch kleingeschrieben, aus "Log(Temp1)" wird automatisch beim >Verlassen der Zeile im BASCOM-Editor "Log(temp1)". Sollte egal sein, BASCOM ist nicht Case sensitive. >Bin absolut ratlos, vielleicht kann mir ja einer von Euch weiterhelfen? Lass dir mal temp1 auf eiem LCD oder UART ausgeben. Oder poste mal das vollständige Programm. MFG Falk
Hallo Falk, >>Sobald nun der Mega8 an Diese Stelle im Code kommt wird der Controller >>in 95% der Fälle neugestartet, nur zu 5% wird die Berechnung korrekt >>durchgeführt... >??? >Wie prüfst du das? Mit einem Debugger? Vielleicht wird zu 95% temp1 >kleiner gleich Null. Das Programm liest jede Sekunde über den ADC Die Spannung an einem NTC ein, soll aus der Kanalnummer des ADC Spannung, Wiederstand und Temperatur berechnen und über UART ausgeben. In der T(R)-Rechnung kommt Log(R/R_25°C) vor, daran hakt's. Wenn ich die Log()-Zeile auskommentiere und mir stattdessen das Argument ausgeben lasse klappt alles wunderbar, Argument ist durchwegs positiv im Bereich um 1,2 (keine chance bei R/R_25°C was negatives 'rauszubekommen, siehe code). Sobald ich nun die Log-Zeile mitrechnen lasse bekomme ich quasi immer nur die "Begrüßung" auf dem UART -> Scheinbar ständiger Neustart des Programms >>Bin absolut ratlos, vielleicht kann mir ja einer von Euch weiterhelfen? >Lass dir mal temp1 auf eiem LCD oder UART ausgeben. Oder poste mal das >vollständige Programm. Hier das ganze Programm: $regfile = "m8def.dat" $crystal = 4000000 $baud = 9600 Dim Ad As Word 'Kanalnummer Dim U As Single 'Spannung Dim R As Single 'Widerstand Dim R2 As Integer 'Integer-Widerstand Dim T As Single 'Temperatur Dim Temp1 As Single Dim Temp2 As Single Dim I As Byte 'Zähler im Timer I = 0 S = 0 Config Adc = Single , Prescaler = Auto , Reference = Avcc Start Adc On Timer0 Ontimer0 Config Timer0 = Timer , Prescale = 1024 Enable Timer0 Enable Interrupts Print "Begrüßung" Do Ad = Getadc(0) Loop Ontimer0: Incr I If I >= 32 Then Temp1 = Ad / 1024 U = Temp1 * 5 R = U / 0.000179 R2 = Int(r) Temp1 = R / 10000 'Hier die kritische Zeile !!!!!!! 'Temp2 = Log(temp1) 'Weitere Berechnung von T, momentan inaktiv 'Temp1 = 0.0002569 * Temp2 'Temp2 = Temp1 + 0.003354 'T = 1 / Temp2 'T = T - 273 Print "Ch= " ; Ad ; " - U= " ; U ; " V - R= " ; R2 ; " Ohm - T= " ; Temp1 ; " °C" I = 0 End If Return End
Andre (Gast)
>Hier das ganze Programm:
tststs, was soll dass denn mit dem
Ad = Getadc(0)
in der Endlosschleife aber der Rest im Interrupt? Da kann man sich schön
ins Knie schiessen. Stichwort Atomarer Datenzugriff.
Machs gleich richtig wie die grossen Jungs. Nutze eine Variable um einen
neuen Timerüberlauf an des HAUPTPROGRAMM zu signalisieren. Dort läuft
dann das Programm. Hat viele Vorteile und ist sicher.
Etwa so (ohne Gewähr, bin kein BASCOMER)
$regfile = "m8def.dat"
$crystal = 4000000
$baud = 9600
Dim Ad As Word 'Kanalnummer
Dim U As Single 'Spannung
Dim R As Single 'Widerstand
Dim R2 As Integer 'Integer-Widerstand
Dim T As Single 'Temperatur
Dim Temp1 As Single
Dim Temp2 As Single
Dim I As Byte 'Zähler im Timer
Dim Flag as byte ' Merker für Timerüberlauf
I = 0
S = 0
Config Adc = Single , Prescaler = Auto , Reference = Avcc
Start Adc
On Timer0 Ontimer0
Config Timer0 = Timer , Prescale = 1024
Enable Timer0
Enable Interrupts
Print "Begrüßung"
Do
if flag=1 then
flag = 0
Incr I
If I >= 32 Then
Ad = Getadc(0)
Temp1 = Ad / 1024
U = Temp1 * 5
R = U / 0.000179
R2 = Int(r)
Temp1 = R / 10000
'Hier die kritische Zeile !!!!!!!
'Temp2 = Log(temp1)
'Weitere Berechnung von T, momentan inaktiv
'Temp1 = 0.0002569 * Temp2
'Temp2 = Temp1 + 0.003354
'T = 1 / Temp2
'T = T - 273
Print "Ch= " ; Ad ; " - U= " ; U ; " V - R= " ; R2 ; " Ohm - T= " ;
Temp1 ; " °C"
I = 0
End If
end if
Loop
' Interrupt
Ontimer0:
flag =1
Return
End
MFG
Falk
Wenn ich mir diese Berechnung mal so ansehe Temp1 = Ad / 1024 U = Temp1 * 5 R = U / 0.000179 R2 = Int(r) Temp1 = R / 10000 'Hier die kritische Zeile !!!!!!! 'Temp2 = Log(temp1) Temp1 liegt am Anfang im Bereich 0 bis 1 U kommt daher auf 0 bis 5 In der nächsten Zeile wird U dann durch 0.000179 dividiert um R zu erhalten. Das ist schon mal ziemlich klein. Wird aber dann nochmal durch 10000 dividiert um endlich im log zu landen. Wie du auf einen Wert von 1.2 kommst, kann ich nicht nachvollziehen. Ich würde eher sagen, dass deine Werte so klein werden, dass sie mit der SINGLE Präzission praktisch auf 0 liegen. Und der log von 0 ist nun mal minus unendlich. Was BASCOM in diesem Fall macht weis ich nicht. Aber einen Reset schmeissen, würde mir nicht ungewöhnlich vorkommen.
@ Karl heinz Buchegger: Nein, daran liegt es leider auch nicht, denn: >Wenn ich mir diese Berechnung mal so ansehe >Temp1 = Ad / 1024 >U = Temp1 * 5 >R = U / 0.000179 >R2 = Int(r) >Temp1 = R / 10000 >Wie du auf einen Wert von 1.2 kommst, kann ich nicht >nachvollziehen. Temp1 typisch um 0.4 U damit typisch um 2 R damit typisch um 12000 (!!) (Division durch kleine Zahl) Temp1 damit um 1.2 Log(1.2) scheitert dann, warum auch immer...
Andre wrote: > @ Karl heinz Buchegger: > > Nein, daran liegt es leider auch nicht, denn: > >>Wenn ich mir diese Berechnung mal so ansehe >>Temp1 = Ad / 1024 >>U = Temp1 * 5 >>R = U / 0.000179 >>R2 = Int(r) >>Temp1 = R / 10000 > >>Wie du auf einen Wert von 1.2 kommst, kann ich nicht >>nachvollziehen. > > Temp1 typisch um 0.4 > U damit typisch um 2 > R damit typisch um 12000 (!!) (Division durch kleine Zahl) Ah. Da hast du recht. So weit kann ich mit meinen 10 Fingern nicht zählen :-)
Hallo Falk, >>Hier das ganze Programm: >tststs, was soll dass denn mit dem > >Ad = Getadc(0) > >in der Endlosschleife aber der Rest im Interrupt? Da kann man sich schön >ins Knie schiessen. Stichwort Atomarer Datenzugriff. Hmm, verstehe ich leider nicht ganz, ersten Programm überhaupt für Mikrocontroller und so... g >Machs gleich richtig wie die grossen Jungs. Nutze eine Variable um einen >neuen Timerüberlauf an des HAUPTPROGRAMM zu signalisieren. Dort läuft >dann das Programm. Hat viele Vorteile und ist sicher. >Etwa so (ohne Gewähr, bin kein BASCOMER) Tatsächlich! So funktioniert es wie es soll! Danke!!! Aber wieso genau gings denn vorher nicht? Irgend ein Timing-Problem wenn in der Interrupt-Routine noch gerechnet wird und schon ein neuer Interrupt ausgelöst wird? dauert die Log()-Berechnung und die anderen Berechnungen länger als 65ms (4 MHz 1024 Prescale 256 Timer)? Na ja, danke nochmals jedenfalls! Andre
@ Andre (Gast) >>in der Endlosschleife aber der Rest im Interrupt? Da kann man sich schön >>ins Knie schiessen. Stichwort Atomarer Datenzugriff. >Hmm, verstehe ich leider nicht ganz, ersten Programm überhaupt für >Mikrocontroller und so... *g* Aha. Das Problem is, dass der Interrupt JEDERZEIT auftreten kann. Aber das Abspeichern von Ad = Getadc(0) Dauert MINDESTENS zwei Takte, weil der AVR ein 8 Bit Prozessor ist und nur 8 Bit in einem Takt kopieren kann. Ad ist aber 16 Bit breit. Dann kann es passieren, dass ein Byte schon kopiert ist, das danere aber nicht. Wenn jetzt z.B. in Ad ine 0x00ff drinsteht, die nächste AD-Wandlung aber 0x0100 ergibt dann kanns knallen. Die CPU kopiert z.B. erst das untere Byte. Dann steht in Ad ein 0x0000. Wenn GENAU jetzt der Interrupt zuschlägt wird temp1 zu 0. Ein weiteres Problem ist der Compiler, egal ob BASCOM oder C. Der kann aus prinzipiellen Gründen nicht immer erkennen, wenn "parallel" aus dem Hauptprogramm und einem Interrupt auf Variablen zugegriffen wird. Dort kann es dann optimieren, was aber fatal ist. Denn dann entstehen zwei Variablen! Aber das ist schon die hohe Schule der Programmierung! >Tatsächlich! So funktioniert es wie es soll! Danke!!! Schön zu hören. >Aber wieso genau gings denn vorher nicht? Irgend ein Timing-Problem wenn >in der Interrupt-Routine noch gerechnet wird und schon ein neuer >Interrupt ausgelöst wird? > dauert die Log()-Berechnung und die anderen > Berechnungen länger als 65ms (4 MHz 1024 Prescale 256 Timer)? Na Vorsicht, du hast auch die UART Ausgabe im interrupt. Sowas macht man eigentlich nicht. Interruts müssen so kurz wie möglich sein, erst recht in BASCOM. Die sollten nur fix ihre Daten in Variablen sichern und dem Hauptprogemm per Flag mitteilen, dass neue Daten anliegen. Das gilt auch für Assembler und C. Aber es ist äusserst unwahrscheinlich, dass die 65 ms zu kurz sind, aber möglich. Das kannst du testen, indem du prüfts, obe am ende des Loop flag=1 ist. Wenn ja ist zwischendurch wieder ein Interrupt aufgetreten. Ich tippe aber eher auf das Problem mit atomarem Zugriff. MfG Falk
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.