Timing 1wire

hage

Mitglied
12. Sep. 2010
41
0
6
Sprachen
Hallo Forum,
ich habe schon öfter mal im Forum gelesen, melde mich nun aber das erste mal mit einer Frage an Euch.
Ich habe mit Bascom einen Dimmer realisiert, mehr oder weniger standard:
Nullduchgang (alle 20ms) erkennen und Interrupt auslösen
Timer laden und mit Timer Interrupt Triac zünden. Soweit kein Problem.

Die zweite Funktion ist eine Temperaturmessung mit dem DS 1820.
Für sich allein auch kein Problem,
1wreset
1wwrite &HCC
1wwrite &H44
1wreset
1wwrite &HCC
1wwrite &HBE
Ar(1) = 1wread(2)
usw.

Aber:
Wenn ich die beiden Programmteile zusammenfüge gibt es anscheinend ein Timingproblem.
Die Abfrage des DS gibt sehr häufig fehlerhafte Werte aus, weil vermutlich der Interrupt der Dimmerfunktion das auslesen stört.
Wenn ich die Interrupt-Funktion während der Temp.-messung 'dissable', flackert die Lampe weil vermutlich der Zündimpuls fehlt bzw. der Nulldurchgang den Interrupt nicht auslösen kann.
Guter Rat teuer ? Hat jemand eine Idee ?
Kennt jemand die Zeiten / Timing für 1wire - Befehle ?

Viele Grüße
hage
 
Hi,

Hallo Forum,
ich habe schon öfter mal im Forum gelesen, melde mich nun aber das erste mal mit einer Frage an Euch.
denn mal herzlich willkommen :flowers:

Ich habe mit Bascom einen Dimmer realisiert, mehr oder weniger standard:
Nullduchgang (alle 20ms) erkennen und Interrupt auslösen
Timer laden und mit Timer Interrupt Triac zünden. Soweit kein Problem.

Die zweite Funktion ist eine Temperaturmessung mit dem DS 1820.
Für sich allein auch kein Problem,
1wreset
1wwrite &HCC
1wwrite &H44
1wreset
1wwrite &HCC
1wwrite &HBE
Ar(1) = 1wread(2)
usw.

Aber:
Wenn ich die beiden Programmteile zusammenfüge gibt es anscheinend ein Timingproblem.
Die Abfrage des DS gibt sehr häufig fehlerhafte Werte aus, weil vermutlich der Interrupt der Dimmerfunktion das auslesen stört.
Wenn ich die Interrupt-Funktion während der Temp.-messung 'dissable', flackert die Lampe weil vermutlich der Zündimpuls fehlt bzw. der Nulldurchgang den Interrupt nicht auslösen kann.
Guter Rat teuer ? Hat jemand eine Idee ?
Kennt jemand die Zeiten / Timing für 1wire - Befehle ?
Ja ;)

Guckst du hier ...


CodeBox CODE
;            __                  ___________              _________
; Init/Reset |________________/ |____________/ :
; : : : : :
; | |- 15-60us -|- 60-240us -| |
; |- >=480us ------|--------- >=480us ------------|
; |- Master Tx ----|----------- Master Rx --------|
;
;
; ___ _______ <1us _______________________
; Master Tx |___________________________/ |_____/ : : :
; : : : : : : : :
; |- 15us -|- 15us -|- 30us -| |- 15us -|- 15us -|- 30us -|
; |----- 60-120us -----------|- >1us -|----- 60-120us -----------|
; | Slave-Sample^ | | Slave-Sample^ |
; |- Master Write 0-Slot ----| |- Master Write 1-Slot ----|
;
;
; ___ >1us _______ >1us ______________________
; Master Rx |____ ________/////////////// |____ // : : :
; : : : : : : : : : :
; |- 15us ---|--- 45us ------|- >1us -|- 15us ---|--- 45us ------|
; | : ^Master-Sample | | : ^Master-Sample |
; ##### vom Master generiert ##### vom Master generiert
;

; ========== DS18S20 - Commands ==========
; 0xF0 - Search ROM 0x44 - Convert T 0x48 - Copy Scratchpad
; 0x33 - Read ROM 0x4E - Write Scratchpad 0xB8 - Recall EEPROM
; 0x55 - Match ROM 0xBE - Read Scratchpad 0xB4 - Read Power Supply
; 0xCC - Skip ROM 0xEC - Alarm Search


Aus meinen Assembler-Routinen.

Danach dauert ein Bit mindestens 60µs. Eher etwas mehr. Plus die Zeit
zwischen den Bits die man beliebig verlängern kann (>1µs). Mann könnte
also die Bits theoretisch mit der Netzfrequenz synchronisieren. Das wird
aber in BASCOM nicht gehen weil du dafür die Befehle zerlegen oder selbst
nachbauen müßtest.

Ein Byte dauert also - sagen wir mal - 8x 62µs => 0,5ms.
Eine Halbwelle dauert beim 230V 10ms.
Wenn du also zB deine 1Wire Befehle mit den Interrupts des Dimmers
synchronisierst dann sollte da was zu machen sein. Zum Beispiel so ...

Du stückelst deine 1Wire-Befehlssequenz in Teile die maximal 5ms dauern.

Ich nehme jetzt mal an du hast einen Dimmer mit Triac (Phasenanschnitt).
Also läuft dein Zündimpuls von 0...10ms auf der Halbwelle. Bei 0ms ist
Vollgas (der Triac bleibt bis zum nächsten Nulldurchgang an) und bei 10ms
ist beinahe 0% weil der Triac kaum noch angeschaltet ist.

Wenn du jetzt unter 5ms Zeit bis zum Zündimpuls hast dann läßt du dein
Teilstück der Befehlssequenz nach dem Zündimpuls laufen und wenn du
über 5ms vom Nulldurchgang bis zum Zündimpuls hast dann läuft deine
Befehlssequenz vom Nulldurchgang an.

Grob verstanden was ich meine ?
So eine Art Mini-Multitasking das von der Netzfrequenz synchronisiert wird.
Du stückelst deinen "Task" Temperaturmessung in einzelne Teile von maximal
5ms Laufzeit die dann ablaufen wenn du grade in der Dimmersequenz mehr als
5ms Luft hast.

Gruß
Dino
 
Hallo hage,
willkommen in diesem freundlichen Forum.

Die Ausführungszeiten der einzelnen 1wire Befehle ist im Millisekunden Bereich:
1wreset 1,5ms
1wwrite 0,6ms
1wread(2) 1ms

Alle zusammen also locker unter 20ms (hast du nicht 2 Nulldurchgänge alle 10ms?)
Ich würde die beiden Arbeiten synchronisieren. Dazu setzt du beim Auftreten des Nulldurchgang Interrupts ein Flag. In der Routine zum Auslesen der Sensoren startest du dann erst, wenn das Flag gesetzt ist. Dann schaffst du alle Befehle, bis der nächste Interrupt eintrifft.

Edit: Etwas zu langsam ...http://www.avr-praxis.de/forum/images/smilies2/bawling.gif

HBA:bawling:
 
Ich würde die beiden Arbeiten synchronisieren. Dazu setzt du beim Auftreten des Nulldurchgang Interrupts ein Flag. In der Routine zum Auslesen der Sensoren startest du dann erst, wenn das Flag gesetzt ist. Dann schaffst du alle Befehle, bis der nächste Interrupt eintrifft.
Was red ich mir denn hier den Mund fusselig (schreib mir die Finger blutig) :p
Sach ich doch das der Kram synchronisiert werden muß :D :rolleyes:

Gruß
Dino
 
Hallo Dino, Hallo Hba,
vielen Dank für die schnelle Antwort!
Ja Ihr habt natürlich recht der Null-Interrupt kommt alle 10 ms.

Die Idee sieht auf dem ersten Blick vielversprechend aus!

Ich hab es mal eben - quick & dirty eingepflegt
Code:
' Hauptschleife
Do

  If T >= 100 Then
    Gosub Tempmes
  End If
...
....
......
Loop
  '##################    Timer1 INT Dimmer      ##########################
 Timer_start:
Portc.5 = 0
Stop Timer1
Timer1 = Hell
Start Timer1
T = T + 1
Return

  '##################    Dimmer Triac zuenden   ##########################
Triac_zuenden:

Stop Timer1
' Pulseout Portc , 0 , 100
Portc.5 = 1
Return



 '##################    SUB Temperaturmessung  ##########################

Tempmes:
 1wreset
 1wwrite &HCC
 1wwrite &H44
 1wreset
 1wwrite &HCC
 1wwrite &HBE
 Ar(1) = 1wread(2)
 Temp_int = Makeint(ar(1) , Ar(2))
 Shift Ar(1) , Right , 1
 Temperatur = Temp_int / 2
 T = 0
Return

Mit 'T' mess ich nur alle 100 x 10ms = 1s den DS aus.
Ergebnis Messwerte teils daneben & Licht flackert.

Steh nun echt auf dem Schlauch....
 
Hallo,

Ich hab es mal eben - quick & dirty eingepflegt
Code:
 '##################    SUB Temperaturmessung  ##########################

Tempmes:
 1wreset
 1wwrite &HCC
 1wwrite &H44
 1wreset
 1wwrite &HCC
 1wwrite &HBE
Mit 'T' mess ich nur alle 100 x 10ms = 1s den DS aus.
Ergebnis Messwerte teils daneben & Licht flackert.

Steh nun echt auf dem Schlauch....
ich habs mal grad auf das entscheidende eingekürzt ;)

Ein 1Wire-Reset dauert mindestens 1ms ! Du machst 2 davon !
Außerdem mußt du nach dem anstoßen der Messung (1wwrite &H44)
eine Sekunde auf das Ergebniss warten !
Also mach da mal mehrere Teile von ...

1.Teil
1wreset

2.Teil
1wwrite &HCC
1wwrite &H44

3..103.Teil
eine Sekunde garnix machen (also 100 Halbwellen Pause)

104.Teil
1wreset

105. Teil
1wwrite &HCC
1wwrite &HBE

Also kannst du zB mit deiner Interrupt-Routine einen Zähler von 1...105
hochzählen. wenn der Zähler auf 1 steht führst duu den ersten Teil aus,
wenn er auf 2 steht den 2ten, ... usw.
Wenn er auf 106 steht dann stellst du ihn wieder auf 1 und führst den
ersten Teil aus.

So etwas nennt man beim Multitasking "Prozess-Scheduler".
Nur das das Ding da wesentlich komplizierter ist. Hier wird das in der
allerkleinsten Version gemacht. Das Ergebnis davon ist das du keine
Wartebefehle benötigst (also keine Prozessorzeit verplemperst) und
trotzdem deine Aufgaben genau in der richtigen Zeit ausführen kannst.

Als Tip: Dafür kann man wunderbar Select-Case verwenden ;)
Case 1
Case 2
Case 104
Case 105
Case 106
die restlichen 100 kannst du dir sparen da ja eine Sekunde nix passieren
soll. Den Befehl kann man in der BASCOM-Referenz genau nachlesen.

Gruß
Dino
 
Nochwas ...
arbeitest du mit 2 Interrupts ?
Einer für den Nulldurchgang erkennen und
einer für den Zündimpuls des Triacs ?

Wenn ja wirst du bei höherer Helligkeit Probleme mit der Temperaturmessung
bekommen weil dir dein Interrupt für den Zündimpuls in die Messung läuft.
Darum meinte ich vorhin das mit den "vor oder hinter dem Zündimpuls".

Stell doch mal bitte das gesamte Programm und nicht nur die Hauptschleife
rein damit man das sehen kann.

Und wie erkennst du den Nulldurchgang ? Mit INT0 oder INT1 ?

EDIT: Nochwas ... ich hab dein 1wread vergessen. Also den Zähler bis 107 laufen
lassen und 106 wird dann das 1wread. Damit müßte jedes Teilstück etwa 1ms dauern.

Gruß
Dino
 
Hallo Dino,
danke für Deine Unterstützung. Ich habe das Programm mal auf das notwendigste gekürzt. Ich nutze übrigens den internen Oszillator. Es hängt
zusätzl. ein uhrenquarz dran um die Soft clock zu nutzen, das ist aber erst
einmal nebensächlich.
Ja, ich arbeite mit beiden Interrupts. Der Nullduchgang gelangt über einen Optokoppler an Int0. Standard Triac Phasenanschnittsteuerung.
Code:
'#############################################################################
'$sim
$regfile = "m8def.dat"
$crystal = 1000000
$hwstack = 32                                                ' default use 32 for the hardware stack
$swstack = 10                                                ' default use 10 for the SW stack
$framesize = 40                                              ' default use 40 for the frame space



Config Lcdbus = 4                                            ' LCD konfigurieren
Config Lcdpin = Pin , Db4 = Portb.3 , Db5 = Portb.2 , Db6 = Portb.1 , Db7 = Portb.0 , E = Portb.4 , Rs = Portb.5
Config Lcd = 16 * 2
Cursor Off
                                                            ' I/O konfigurieren
Config Portc.5 = Output                                      'Dimmer out
Config Portd = Input
Portd = &B11011111                                           ' PORT D alle Pull Up auf EIN
                                                            ' ausser INT0
Config 1wire = Portc.0                                       ' onewire kofigurieren

Config Timer1 = Timer , Prescale = 1                         ' Timer1 für Dimmer
On Timer1 Triac_zuenden                                      'konfigurieren
Enable Timer1

Config Int0 = Rising                                         ' Interrupt für Nulldurchgang
On Int0 Timer_start                                          ' konfigurieren
Enable Int0
Enable Interrupts

Deflcdchar 1 , 6 , 9 , 9 , 6 , 32 , 32 , 32 , 32             ' Grad -zeichen
Deflcdchar 2 , 32 , 32 , 10 , 32 , 4 , 4 , 17 , 14           ' Smilie

Dim Ar(2) As Integer
Dim Temp_int As Integer
Dim Temperatur As Integer
Dim Hell As Word                                             ' Wert fuer Dimmer
Dim T As Word                                                ' Zeitintervall für Temp. Messung

Cls

Hell = 57000                                                 ' Dimmer Licht


' ############################## main ######################################

Do

    Home
    Lcd " moin   "
    Lowerline
    Locate 2 , 1
    Lcd Temperatur ; Chr(1) ; "C  " ; T ; "   "


    Select Case T

     Case 10:

             Home
             Lcd T                                           ' um zu sehen ob die case erreicht wird
             1wreset
     Case 30:
             1wwrite &HCC
             1wwrite &H44

     Case 150:
             1wreset

     Case 170:
             1wwrite &HCC
             1wwrite &HBE
              Ar(1) = 1wread(2)
             Temp_int = Makeint(ar(1) , Ar(2))
             Shift Ar(1) , Right , 1
             Temperatur = Temp_int / 2



     Case 180:
              T = 0

    End Select


    If T > 185 Then T = 0


Loop


 '##################    SUB Temperaturmessung  ##########################

Tempmes:
Disable Interrupts


Enable Interrupts
Return


  '##################    Timer1 INT Dimmer      ##########################
 Timer_start:
Portc.5 = 0
Stop Timer1
Timer1 = Hell
Start Timer1
T = T + 1
Return

  '##################    Dimmer Triac zuenden   ##########################
Triac_zuenden:

Stop Timer1
' Pulseout Portc , 0 , 100
Portc.5 = 1
Return


End

Wie Du siehst habe ich bei case: 10 eine LCD Anzeige eingebaut. So wie ich das im Moment sehe wird die case Select Abfrage gar nicht erreicht. D.h. 'T' wird auch nicht bei case: 180 zurückgesetzt

Edit: das mit case 10 ist unsinn!!! wir sofort wieder mit 'moin' überschrieben! Trotzdem wird 'T' nicht bei case:180 auf '0' gesetzt!

Gruß
hage
 
Hallo hage!

Willkommen, im AVR-Praxis Forum! :ciao:

Ich bin zwar etwas spät dran, aber ich würde es ähnlich machen wie Dino es beschrieben hat.
Einmal das Initialisieren des Sensors....
dann das Auslesen des Sensors....
und dann die Temperaturberechnung durchführen.

Einer dieser drei Abschnitte sollte in den 10ms immer erledigt werden können.


Grüße,
Cassio
 
Hi,

dann wolln wir doch mal ... :D

Ich nutze übrigens den internen Oszillator. Es hängt
zusätzl. ein uhrenquarz dran um die Soft clock zu nutzen, das ist aber erst
einmal nebensächlich.
Ja, ich arbeite mit beiden Interrupts. Der Nullduchgang gelangt über einen Optokoppler an Int0. Standard Triac Phasenanschnittsteuerung.
Softclock bringt zusätzliche Interrupts über einen Timer rein. Das würfelt dir
noch mehr durcheinander. Du wirst die Netzfrequenz- und die Softclock-INTs
nicht synchron bekommen und deine Messung dazwischen platzieren können.
Softclock und Netzfrequenz/Dimmer-Interrupts werden wie bei einer
Schwebung von 2 Tönen durcheinanderlaufen und dir die Messungen
zerbrezeln. Also entweder Dimmer oder Softclock oder du mußt deine
Messung vergessen.

Jetzt aber mal zum Code ...
Code:
'#############################################################################
'$sim
$regfile = "m8def.dat"
$crystal = 1000000
$hwstack = 32                                                ' default use 32 for the hardware stack
$swstack = 10                                                ' default use 10 for the SW stack
$framesize = 40                                              ' default use 40 for the frame space



Config Lcdbus = 4                                            ' LCD konfigurieren
Config Lcdpin = Pin , Db4 = Portb.3 , Db5 = Portb.2 , Db6 = Portb.1 , Db7 = Portb.0 , E = Portb.4 , Rs = Portb.5
Config Lcd = 16 * 2
Cursor Off
                                                            ' I/O konfigurieren
Config Portc.5 = Output                                      'Dimmer out
Config Portd = Input
Portd = &B11011111                                           ' PORT D alle Pull Up auf EIN
                                                            ' ausser INT0
Config 1wire = Portc.0                                       ' onewire kofigurieren

Config Timer1 = Timer , Prescale = 1                         ' Timer1 für Dimmer
On Timer1 Triac_zuenden                                      'konfigurieren
Enable Timer1

Config Int0 = Rising                                         ' Interrupt für Nulldurchgang
On Int0 Timer_start                                          ' konfigurieren
Enable Int0
Enable Interrupts

Deflcdchar 1 , 6 , 9 , 9 , 6 , 32 , 32 , 32 , 32             ' Grad -zeichen
Deflcdchar 2 , 32 , 32 , 10 , 32 , 4 , 4 , 17 , 14           ' Smilie

Dim Ar(2) As Integer
Dim Temp_int As Integer
Dim Temperatur As Integer
Dim Hell As Word                                             ' Wert fuer Dimmer
Dim T As Word                                                ' Zeitintervall für Temp. Messung

Cls

Hell = 57000                                                 ' Dimmer Licht
soweit der Teil vor der Hauptschleife. Sieht auf den ersten Blick OK aus.

Code:
' ############################## main ######################################

Do

    Home
    Lcd " moin   "
    Lowerline
    Locate 2 , 1
    Lcd Temperatur ; Chr(1) ; "C  " ; T ; "   "


    Select Case T

     Case 10:

             Home
             Lcd T                                           ' um zu sehen ob die case erreicht wird
             1wreset
     Case 30:
             1wwrite &HCC
             1wwrite &H44

     Case 150:
             1wreset

     Case 170:
             1wwrite &HCC
             1wwrite &HBE
              Ar(1) = 1wread(2)
             Temp_int = Makeint(ar(1) , Ar(2))
             Shift Ar(1) , Right , 1
             Temperatur = Temp_int / 2



     Case 180:
              T = 0

    End Select


    If T > 185 Then T = 0


Loop
und da ist ein ganz dicker Wurm drin. Die LCD-Routinen sind mächtige
Zeitfresser ! Mach die dahin wo sie mit sicherheit dein Timing nicht
durcheinanderbringen. Erst die wichtigen Sachen (1Wire) und dann dein
Debugging (LCD). NICHT andersrum.

Code:
 '##################    SUB Temperaturmessung  ##########################

Tempmes:
Disable Interrupts


Enable Interrupts
Return
Der nächste Wurm.
Wenn du die Interrupts bei nem Dimmer abschaltest dann zerbrezelt es dir
die Synchronität mit der Netzfrequenz und deine Helligkeitswerte passen
nicht mehr. Alles kommt aus dem Tritt.

Deine Routine für INT0 (Nulldurchgänge)
Code:
  '##################    Timer1 INT Dimmer      ##########################
 Timer_start:
Portc.5 = 0
Stop Timer1
Timer1 = Hell
Start Timer1
T = T + 1
Return

Deine Routine für den Zündimpuls (Timer1)
Code:
  '##################    Dimmer Triac zuenden   ##########################
Triac_zuenden:

Stop Timer1
' Pulseout Portc , 0 , 100
Portc.5 = 1
Return

End

Wie Du siehst habe ich bei case: 10 eine LCD Anzeige eingebaut. So wie ich das im Moment sehe wird die case Select Abfrage gar nicht erreicht. D.h. 'T' wird auch nicht bei case: 180 zurückgesetzt

mach mal folgendes ...

- deine Select-Case für die Messungsteile baust du in eine Subroutine.
- Beim INT0 läßt du einen Zähler um 1 hochzählen (Bytevariable reicht)
- Wenn dein Zündimpuls näher am Nulldurchgang ist (vor dem Sinusscheitel)
dann rufst du die Sub in der ISR des Zündimpulses auf.
- Wenn dein Zündimpuls hinter dem Sinusscheitel ist dann rufst du deine
Messung in der ISR vom INT0 am Schluß auf.
- Nimm mal die Zählerwerte die ich bei meinem Beispiel genommen habe.
Also 1,2,104,105,106,107.

Also nochmal "ASCII-grafisch" ;)

0 = Nulldurchgang (INT0)
Z = Zündimpuls (Timer1)
S = Sinusscheitel (90° oder 50%)
T = Temperaturmessung

0-----ZT--S----------|
0T---------S-----Z----|

Siehst du ungefähr was ich meine ? Die Teile der Temperaturmessung da
hinpacken wo sie am meißten Zeit zur Verfügung haben.

Gruß
Dino
 
Hallo Dino,

vielen Dank, dass waren sehr viele gute Denkanstösse!
Das die LCD Zeit frisst ist schon klar, aber irgendwo musste ich ja eben eine Anzeige hinfriemeln :)
Die Sub Tempmes stammt noch aus vorherigen Versuchen eine Lösung zu finden und wird hier nicht aufgerufen. Wie gesagt das war etwas quick & dirty.
Ich habe die case auf 'case x to y' geändert falls aus irgend einem Grund (Interrupt duch Störung im Netz o.ä. ) mal ein case verschluckt wird.
Damit läuft nun die Temp.-messung und der Dimmer in diesem abgespeckten Programm stabil. Ich werde das ganze nun in das bestehende Progr. mit
Tastaturabfragen und weiterer Steuerung einbinden.
Die Uhr (Soft Clock) war eher ein Gimick und muss nicht sein. Evtl. experemintier ich damit noch mal etwas.

Sehr gut ist die Idee die Temp.messung abhängig vom Zündzeitpunkt zu steuern !!!!:flowers:

Also vielen Dank für die vielen guten Hinweise! Ich wünsch Euch allen einen schönen Abend.
@Dino, ich schließ Dich in mein Nachtgebet ein !

hage
 

Über uns

  • Makerconnect ist ein Forum, welches wir ausschließlich für einen Gedankenaustausch und als Diskussionsplattform für Interessierte bereitstellen, welche sich privat, durch das Studium oder beruflich mit Mikrocontroller- und Kleinstrechnersystemen beschäftigen wollen oder müssen ;-)
  • Dirk
  • Du bist noch kein Mitglied in unserer freundlichen Community? Werde Teil von uns und registriere dich in unserem Forum.
  •  Registriere dich

User Menu

 Kaffeezeit

  • Wir arbeiten hart daran sicherzustellen, dass unser Forum permanent online und schnell erreichbar ist, unsere Forensoftware auf dem aktuellsten Stand ist und der Server regelmäßig gewartet wird. Auch die Themen Datensicherheit und Datenschutz sind uns wichtig und hier sind wir auch ständig aktiv. Alles in allem, sorgen wir uns darum, dass alles Drumherum stimmt :-)

    Dir gefällt das Forum und unsere Arbeit und du möchtest uns unterstützen? Unterstütze uns durch deine Premium-Mitgliedschaft!
    Wir freuen uns auch über eine Spende für unsere Kaffeekasse :-)
    Vielen Dank! :ciao:


     Spende uns! (Paypal)