PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Wait-Anweisung durch Interrupt unterbrechen?



CapSob
03.06.2008, 00:29
Hallo Leute!

Hab folgendes Problem:

Es läuft eine Wait-Anweißung über 3 Sekunden.

Folgendes: Ich hab einen Interrupt auf Low Level. Wenn ich einen Taster drücke, springt er zum Label vom Interrupt.

Das Problem ist, dass wenn das Programm gerade in der "wait 3"-Anweißung drinn ist, ich den Taster so lange drücken kann, wie ich will, er springt nicht zum Label des Interrupts. Ich muss warten, bis die 3 Sek. um sind, dann geht der Interrupt erst.

Gibt es eine Möglichkeit, die wait-Anweißung zu unterbrechen, oder sogar eine Alternative zum wait, dass der Interrupt funktioniert, wenn ich den Taster drücke???

mfg,
René.

for_ro
03.06.2008, 08:26
Du solltest auf jeden Fall überprüfen, ob die Wait 3 Anweisung wirklich notwendig ist oder durch einen Timer ersetzt werden kann.
Außerdem kannst du das unterbrechbar auch so schreiben:
For I = 1 To 30
Waitms 100
Next I

Gruß

Rolf

CapSob
03.06.2008, 08:41
@for_ro:

Danke Rolf für den Tipp mit der for-Schleife! Muss ich gleich mal heute Abend ausprobieren!


Kurze Frage zum Timer:

Mit "enable Timer0" zB aktiviere ich ihn, kann ich ihn auch mit "disable timer0" wieder ausschalten.

Es geht halt darum, dass der timer0 nicht mehr in seinen isr geht, wenn ein bestimmter Programmabschnitt erreicht ist.

Jaecko
03.06.2008, 08:44
jo klar geht das.
Enable/Disable: Timer läuft weiter, nur der Interrupt wird an/abgeschaltet
Start/Stop: Timer selbst wird gestartet/gestoppt

CapSob
03.06.2008, 09:37
ah, gut zu wissen - danke!

CapSob
03.06.2008, 17:55
Hmm... des mit der For-Schleife geht ned...


Config Int0 = Low Level 'Konfiguriere Int0 auf Low Level
Config Int1 = Low Level 'Konfiguriere Int1 auf Low Level

Enable Interrupts 'Interrupts generell einschalten

Enable Int0 'Interrupt 1 einschalten
Enable Int1 'Interrupt 2 einschalten

On Int0 Blinkenl 'Subroutine Blinken Links
On Int1 Blinkenr 'Subroutine Blinken Rechts


....


Dim Gemessenezeit As Integer 'Selbsterklärend...
Dim I As Integer 'Zähler-Variable

Gemessenezeit = 3000 'Testweiße 3 Sekunden
Gemessenezeit = Gemessenezeit / 100 'Für For-Schleife durch 100 teilen


...


Blinkenl:

Relaisl = 1 'Relais Links einschalten
Hebelgedrueckt = 1 'Hebelgedrueckt zurücksetzen

For I = 1 To Gemessenezeit
Waitms 100
Next I

Do
If Blinkerl = 0 Then 'Wenn Blinker Links gedrückt...
nop
Else 'Wenn nicht, Relais Links ausschalten
Relaisl = 0 'Relais ausschalten
Hebelgedrueckt = 0
End If
Loop Until Hebelgedrueckt = 0 'Schleife solange, wie Hebelgedrueckt = 1

Return
Return

Hat da wer noch ne Idee?

Dirk
03.06.2008, 18:39
Hallo CapSob,

Dein Prog hat noch ganz andere Probleme.
Ab "Blinkenl:" ist das ja eine Interrupt-Routine. Die muss mit Return (1x reicht) beendet werden und möglichst kurz sein. Man sollte in einer ISR nur z.B. ein Flag setzen, dass der Taster gedrückt wurde. Dieses Flag fragt man dann im Hauptprogramm ab.
In der ISR darf man nicht verzögern (Wait) oder in einer DO-LOOP-Schleife auf ein anderes Ereignis warten.

Gruß Dirk

for_ro
03.06.2008, 22:11
Hallo CapSob,
die For-Schleife ist ja in einer Interrupt Routine, da kannst du nicht unterbrechen. Erst wenn die beim return angekommen ist, werden andere Interrupts betrachtet.
Da du Config Int0 = Low Level angegeben hast, schätze ich mal, dass das Programm nach Beendigung des ersten Interrupts sofort wieder in die gleiche ISR springt, weil du so schnell gar nicht die Taste loslassen kannst. Warum machst du das, wenn du dann eh 3s warten willst?

Gruß

Rolf

CapSob
03.06.2008, 23:19
@ Dirk:
Ich glaub, ich muss mein Programm ein "bisschen" umschreiben ;)

@ Rolf:
Die 3 Sekunden sind bloß zum testen. Nachher soll dieser Wert variabel sein. Das Programm wird nachher einen zuvor gemessenen Wert aus dem EEPROM abfragen und solange die Schleife laufen lassen.


Melde mich wieder, wenn ich das Programm umgeschrieben habe!

mfg,
René.

CapSob
04.06.2008, 00:22
Ich komm grad echt nicht weiter...

Hab hier mal den kompletten Quellcode. Ich hoffe, mir kann da jemand helfen...


' KOMFORTBLINKERMODUL

' V0.2 - René Brixel - 02.06.2008
'
'
' PB1 Ausgang Relais (High-Active)
' PB2 Ausgang Relais (High-Active)
'
' PD2 Eingang Blinkerhebel (Low-Activ)(INT0)
' PD3 Eingang Blinkerhebel (Low-Activ)(INT1)
' PD7 TimeSet (Low-Activ)


'---------- uC-Konfig ----------

$regfile = "m8def.dat" 'ATMega8
$crystal = 1000000 'Quarz: 1 MHz


'---------- Port-Konfig ----------

Ddrb = &B11111111 'Port B als Ausgang
Portb = &B00000000 'Port C komplett auf 0 setzen

Ddrd = &B00000000 'Port D als Eingang
Portd = &B11111111 'PullUp´s aktivieren


'---------- Interrupts ----------

Config Int0 = Low Level 'Konfiguriere Int0 auf Low Level
Config Int1 = Low Level 'Konfiguriere Int1 auf Low Level

Enable Interrupts 'Interrupts generell einschalten

Enable Int0 'Interrupt 1 einschalten
Enable Int1 'Interrupt 2 einschalten

On Int0 Blinkenl 'Subroutine Blinken Links
On Int1 Blinkenr 'Subroutine Blinken Rechts


'---------- Alias-Konfig ----------

Relaisl Alias Portb.1 'Relais Links; 1 = Aktiv
Relaisr Alias Portb.2 'Relais Rechts; 1 = Aktiv

Blinkerl Alias Pind.2 'Blinker Links; 0 = gedrückt
Blinkerr Alias Pind.3 'Blinker Rechts; 0 = gedrückt

Timeset Alias Pind.7 'Time Set; 0 = Aktiv (Jumper - gebrückt)


'---------- Variablen-Konfig ----------

Dim Hebelgedrueckt As Integer 'Schleifenvariable für blinken

Dim Gemessenezeit As Integer 'Selbsterklärend...
Dim I As Integer 'Zähler-Variable
Dim Richtung As Integer 'Welche Richtung wurde gedrückt? 1 = Links, 2 = Rechts

Richtung = 0

Gemessenezeit = 3000 'Testweiße 3 Sekunden
Gemessenezeit = Gemessenezeit / 100 'Für For-Schleife durch 100 teilen


'---------- Main ----------

Do

If Richtung = 1 Then 'Richtung Links
Relaisl = 1 'Relais Links einschalten
Hebelgedrueckt = 1 'Hebelgedrueckt zurücksetzen

For I = 1 To Gemessenezeit
Waitms 100
Next I

Do
If Blinkerl = 0 Then 'Wenn Blinker Links gedrückt...
nop
Else 'Wenn nicht, Relais Links ausschalten
Relaisl = 0 'Relais ausschalten
Hebelgedrueckt = 0
End If
Loop Until Hebelgedrueckt = 0 'Schleife solange, wie Hebelgedrueckt = 1
Richtung = 0
End If

If Richtung = 2 Then 'Richtung Rechts
Relaisr = 1 'Relais Rechts einschalten
Hebelgedrueckt = 1 'Hebelgedrueckt zurücksetzen

For I = 1 To Gemessenezeit
Waitms 100
Next I

Do
If Blinkerr = 0 Then 'Wenn Blinker Rechts gedrückt...
Nop
Else 'Wenn nicht, Relais Rechts ausschalten
Relaisr = 0 'Relais ausschalten
Hebelgedrueckt = 0
End If
Loop Until Hebelgedrueckt = 0 'Schleife solange, wie Hebelgedrueckt = 1
Richtung = 0
End If

Loop

End


'---------- Blinken Links ----------
Blinkenl:

Richtung = 1

Return


'---------- Blinken Rechts ----------
Blinkenr:

Richtung = 2

Return

peterfido
04.06.2008, 01:05
Ich würde da eine Menge anders Lösen. Was hast Du denn genau vor?

CapSob
04.06.2008, 10:55
eine sogenannte komfortblinkerschaltung fürs auto.

1x blinkerhebel antippen, 3x nachblinken - wie bei den neueren autos...

soll halt keine verzögerung enthalten, sprich, dass wenn er gerade 3x links blinkt, dass ich auch sofort schnell rechts blinken kann (3x)

wenn der hebel gedrückt bleibt (einrastet) dann soll er nach 3x blinken so lange weiterblinken, wie der hebel gedrückt bleibt.

die testweiße "3 sekunden" soll nachher durch einen timer selbst gemessen werden können und als millisekunden ins eeprom geschrieben werden. beim starten, wenn ein jumper gesetzt ist, soll er die zeit messen (zwischen 2x blinkerhebel betätigen). wenn jumper nicht gesetzt, dann soll er direkt das hauptprogramm ausführen.

mfg,
rene.

enterprise30
04.06.2008, 12:18
http://www.jalt.de/Downloads/BS/BS.zip

CapSob
04.06.2008, 17:29
http://www.jalt.de/Downloads/BS/BS.zip

hey, genau das gleiche baue ich sozusagen auch!

bloß, alleine mit dem hex-file kann ich leider nichts anfangen...

vorallem, weil es für den AT90S1200 geschrieben ist. ich benutze aber einen ATMega8.

@enterprise30:
kannst du mir bitte auch den quellcode dazu geben, please? oder tipps, wie ich mein problem löse?

mfg,
René.

enterprise30
04.06.2008, 20:29
Ich dir den Quäääl-code geben?
Nöööööö [-(
Oder doch?
Nein, kann ich nicht! Ist ja nicht mein Projekt.... :mrgreen:
Frag den Typ mal, aber ich ich glaub nicht daß der das macht.
Und wenn, dann müsst er ja grad in Bascom proggen!
Ich würd das Stück für Stück proggen (oder gleich fertig von Ihm kaufen):

Zb. als aller erstes würd ich das nur dreimal-blinken-beim-antippen proggen.
Dann der Blinkerabbruch wenn von linksblinken auf rechtsblinken geschaltet wird.
Also immer erst die einfachsten Funktionen und dann Stück für Stück dazustricken und austesten. Dazwischen immer schön das lauffähige Programm speichern!

Hardwäremäßig musst du auch was schalten: Du brückst ja quasi den Blinkerhebel entweder mit der Hand und/oder zusätzlich mit Deinem µPc wenn die Hand wieder weggeht.
Hast Du dir mal einen Schaltplan von der Blinkerverdrahtung im Auto geholt?
http://mitglied.lycos.de/Autoelektrik/Eic.htm
Ansonsten machst das so wie in dem Schaltplan vom Jalt:
2 Eingänge für den Blinkerhebel, 2 Ausgänge für die Relais.

CapSob
04.06.2008, 23:09
Guten Abend!

Hardwaretechnisch hab ich es "fast" genauso wie der von Jalt. Außer das meine beiden Eingänge auf INT0 + INT1 liegen.

Das mit dem 3x-Blinken klappt ja. Sei es Links oder Rechts.

Das einzige, woran ich gerade hänge ist der Blinkabbruch. Da komme ich nich weiter. :-k


Hardwäremäßig musst du auch was schalten: Du brückst ja quasi den Blinkerhebel entweder mit der Hand und/oder zusätzlich mit Deinem µPc wenn die Hand wieder weggeht.

Das passt ja soweit. Der Blinkerhebel wird ja sozusagen komplett aus der KFZ-Elektronik raus genommen und in die uC-Schaltung als eine Art Doppel-Taster/-Schalter eingesetzt.

Es hängt wirklich nur an dem Blinkerabbruch!!! Hat keiner eine Idee oder einen kleinen Beispiel-Code, mit dem ich es versuchen könnte?

mfg,
René.

peterfido
05.06.2008, 00:22
Vielleicht hilft Dir das weiter: Allerdings frage ich den Blinkerhebel nicht per Interrupt ab. Ich habe es nicht getestet, sollte aber wenn nur kleine Fehler enthalten.



'Komfortblinker

' PB1 Ausgang Relais (High-Active)
' PB2 Ausgang Relais (High-Active)
'
' PD2 Eingang Blinkerhebel (Low-Activ)(INT0)
' PD3 Eingang Blinkerhebel (Low-Activ)(INT1)
' PD7 TimeSet (Low-Activ)


'---------- uC-Konfig ----------


$regfile = "m8def.dat" 'ATMega8
$crystal = 1000000 'Quarz: 1 MHz

$hwstack = 40
$swstack = 40
$framesize = 60



'---------- Port-Konfig ----------

Ddrb = &B11111111 'Port B als Ausgang
Portb = &B00000000 'Port C komplett auf 0 setzen

Ddrd = &B00000000 'Port D als Eingang
Portd = &B11111111 'PullUp´s aktivieren


Ql Alias Portb.1
Qr Alias Portb.2
Il Alias Pind.2
Ir Alias Pind.3
Timeset Alias Pind.7

Dim Richtung As Byte
Dim Eingangalt As Byte
Ila Alias Eingangalt.1
Ira Alias Eingangalt.2
Const Links = 1
Const Rechts = 2

Dim Tickcount As Long
Dim Blinkzeit As Long
Dim Maxzeit As Long
Dim Dum1 As Eram String * 10 'dummy
Dim Emaxzeit As Eram Long


Config Timer0 = Timer , Prescale = 64 '10ms Takt

On Timer0 Timer_irq

Const Timervorgabe = 100


Enable Timer0
Enable Interrupts

Maxzeit = Emaxzeit
If Maxzeit < 1 Then
Maxzeit = 300 '3 sekunden
End If
if Maxzeit > 1200 Then
Maxzeit = 300
End If

Do
If Timeset = 0 Then
Gosub Zeitsetzen
Goto Sprung
End If
Gosub Eingang
Gosub Zeiten

Sprung:

Loop
End



Eingang:
If Il <> Ila Then
Ila = Il
Waitms 50'entprellung
If Ila = 0 Then
If Richtung = Links Then
Richtung = 0
Else
Richtung = Links
Tickcount = 0
Reset Qr
Set Ql
End If
End If
End If

If Ir <> Ira Then
Ira = Ir
Waitms 50'entprellung
If Ira = 0 Then
If Richtung = Rechts Then
Richtung = 0
Else
Richtung = Rechts
Tickcount = 0
Reset Ql
Set Qr
End If
End If
End If

If Richtung = 0 Then
If Il = 1 Then
Reset Ql
End If
If Ir = 1 Then
Reset Qr
End If

End If
Return

Zeiten:
If Richtung > 0 Then
If Tickcount > Maxzeit Then
Richtung = 0
End If
End If


Return

Zeitsetzen:
If Il <> Ila Then
Ila = Il
Waitms 25'entprellung
If Ila = 0 Then
Richtung = Links
Tickcount = 0
Reset Qr
Set Ql
Else
Reset Ql
Maxzeit = Tickcount
Emaxzeit = Maxzeit
Richtung = 0
End If
End If

If Ir <> Ira Then
Ira = Ir
Waitms 25'entprellung
If Ira = 0 Then
Richtung = Rechts
Tickcount = 0
Reset Ql
Set Qr
Else
Reset Qr
Maxzeit = Tickcount
Emaxzeit = Maxzeit
Richtung = 0
End If
End If

Return


Timer_irq:
Timer0 = Timervorgabe
Tickcount = Tickcount + 1
If Tickcount = 2147483647 Then Tickcount = 0 'sollte es eigentlich nie zu kommen

Return



edit: Maxzeitgrenze optimiert.
edit 2: Eingänge entprellt (05.06.08/11:54)

CapSob
05.06.2008, 09:08
Super! Soweit funktionierts!

Bloß noch ein paar kleine Fragen:

- Timer muss doch irgendwo zurückgesetzt werden wenn er , weil zB wenn ich links drücke, schaltet das relais für 3 sek. wenn ich aber dann rechts drücke, zieht es bloß kurz an, dann muss ich nochmal rechts drücken, dann hält er es für 3 sek.

- Dum1 kann ja eigentlich gelöscht werden, oder?

- speichert er den "gemessenen" Wert im EEPROM? Weil die definition von Eram kenn ich leider nicht. WEnn ichs richtig verstehe, fragt er ja das ram nach emaxzeit ab. wenn sie sozusagen nicht gesetzt ist, setzt er sie auf 300. und im label Zeitsetzen: schreib er sie dann ins EEPROM?

Auf jedenfall mal viiieeelen Dank! WEnn mal der Komfortblinker fertig ist, bekommst du peterfido einen von mir geschenkt!!!

mfg,
René.

peterfido
05.06.2008, 11:30
Timer wird zurückgesetzt (Tickcount=0). evtl mal die Eingänge entprellen, da beim 2. Mal in die selbe Richtung abgebrochen wird. Ich habe das gerade mal auf meinem Testboard probiert. Läuft soweit. Dum1 ist dafür da, weil ich irgendwo mal gelesen habe, dass im Fehlerfall die ersten Stellen des EEproms überschrieben wurden. Durch dum1 wird der Wert ab der 11. Stelle im EEprom gescheichert. Ich editier gleich noch mal das Programm und füge eine Entprellung ein.

edit: emaxzeit = maxzeit speichert ins eeprom

edit2: Habe gerade mal ein wenig getestet. Gute Werte zum entprellen sind 50ms.