PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Flankenwechsel erkennen, aber wie?



karstenl
24.06.2011, 18:05
Hallo, zusammen!

Ich habe da nur ein "ganz kleines" Problem.

Wie kann ich in BASCOM einen Flankenwechsel LOW>HIGH oder HIGH>LOW erkennen und auswerten?

Der Hintergrund: Ich möchte erkennen ob ein Schalter (KEIN TASTER!) betätigt wurde und daraufhin einen kurzen Impuls ausgeben.

Hat jemand eine Idee?

Che Guevara
24.06.2011, 18:35
Hallo,

dafür gibts 2 Möglichkeiten:
1. mittels Polling, d.h. du fragst die ganze Zeit ab, ob sich der Zustand des Pins geänder hat
2. mittels Interrupt, dieser tritt auf, wenn der Flankenwechsel stattfindet! (Config INTX)

Die 2. Lösung ist meist die bessere, da dadurch das restliche Programm unbeeinflusst weiterlaufen kann!

Gruß
Chris

lokirobotics
24.06.2011, 23:47
Würd ich auch per Interrupt machen. Musst halt bei jedem Auslösen den Interrupt neu konfigurieren (von steigende auf fallende Flanke und dann wieder zurück).

karstenl
25.06.2011, 08:10
Ich danke Euch!

Die Idee per Interrupt hatte ich ja eigentlich auch schon.
Ich muß wohl meine Aufgabe etwas präzisieren!

Ich möchte einen Atmega8 verwenden und muß 4 Schalter abfragen. Also kommt Int nicht in Frage!

Mit einer LOGO! von SIE(ne)MENS wäre es ja kein Problem, aber ich will es anders und preiswerter schaffen!

Helft Ihr mir?

Danke und Grüße

Karsten

wkrug
25.06.2011, 08:52
Es bestünde noch die Möglichkeit die schalter per Pin Change Interrupt abzufragen.
Aber nicht alle ATMEL Controller stellen den zur Verfügung.
Bei jedem Zustandswechsel an einem der beteiligten Pins wird dabei ein Interrupt ausgelöst.
Ob von L->H oder von H->L musst Du allerdings per Software rauskriegen.

Bei einigen Controllern laufen mehrere Pins auf einen Interrupt Vektor.
Das bedeutet, Du musst auch konkret den Pin per Software rauskriegen, der das Interrupt Ereignis ausgelöst hat.

Abe ansonsten wäre Pin Change sicher eine gute Lösung.

Richard
25.06.2011, 09:04
Ich danke Euch!

Die Idee per Interrupt hatte ich ja eigentlich auch schon.
Ich muß wohl meine Aufgabe etwas präzisieren!

Ich möchte einen Atmega8 verwenden und muß 4 Schalter abfragen. Also kommt Int nicht in Frage!

Mit einer LOGO! von SIE(ne)MENS wäre es ja kein Problem, aber ich will es anders und preiswerter schaffen!

Helft Ihr mir?

Danke und Grüße

Karsten

Du fragst einfach kontinuierlich einen kompletten Port ab, speicherst den Wert in einer Variable und vergleichst auf Änderung. Je nachdem welches Bit sich geändert hat, kannst Du den Schalter zu ordnen. Damit der Prozessor auch noch etwas anderes machen kann, lässt Du diese Abfrage in einem Timer IRQ z.B. alle 50 ms ablaufen. ODER Du nimmst einen AVR bei dem alle Pin's IRQ fähig sind, das ist noch eleganter. PIC Prozessoren konnten das schon vor über 10 Jahren....

Gruß Richhard

wkrug
25.06.2011, 09:33
ODER Du nimmst einen AVR bei dem alle Pin's IRQ fähig sind, das ist noch eleganter.
Also wieder Pin Change Interrupts. Es kommt halt auf die Latenz Zeiten an, die in seinem Programm noch akzeptabel sind.
Wenn karstenl ewig lange Wait Schleifen in seinem Hauptprogramm hat wirds schwierig mit dem pollen.
Ausserdem muss er ja noch den Puls erzeugen. Wenn dieser auch in der Interrupt Routine erzeugt werden soll würde das nur mit Wait Schleifen gehen und das wäre in einer Interrupt Routine fatal.

Wenn die Latenz keine Rolle spielt würde ich es per Polling in der Hauptroutine machen.
Die alte Bit Kombination wird in einer Byte Variable gespeichert und invertiert ( aus allen 1 wird 0 und umgekehrt ) und mit der neuen Abfrage Exclusiv verodert.
Wenn sich dann ein Bit Verändert hat kriegt man ein Ergebnis das >0 ist raus.
Auf das kann man abfragen und den Puls generieren. Danach wird der aktuelle Zustand wieder in der Hilfsvariable gespeichert und invertiert.
Das ist mit wenigen Programmzeilen zu machen. Allerdings ist die Reaktionszeit zwischen Tastenänderung und Impulsgenerierung dabei von der Durchlaufzeit der Hauptroutine abhängig. Ist dabei ein Schleifendurchlauf ziemlich kurz, dürfte das keine große Rolle spielen.

Che Guevara
25.06.2011, 11:02
Also ich habe soetwas auch mal gemacht, ich musste damals 8 Tasten mittels Interrupt überwachen! Ich habe einfach jede Taste an einen Pin des AVRs gelegt und dann von jedem dieser Pins noch jeweils eine Diode zum Int0. Somit wurde der Int bei allen Tasten ausgelöst und ich konnte im Programm abfragen, welcher der Taster gedrückt wurde! Ist zwar vielleicht ein bisschen umständlich, aber es ist einfach umzusetzen und bei mir hats auch zuverlässig funktioniert!
Das geht allerdings nur, wenn der Taster nur in eine Richtung schaltet! Bei einem Flankenwechsel wirds wohl nicht funktionieren, außer dir reicht jeder 2.

Gruß
Chris

Richard
25.06.2011, 11:08
Also wieder Pin Change Interrupts. Es kommt halt auf die Latenz Zeiten an, die in seinem Programm noch akzeptabel sind.


Na ja, eigentlich meine ich (beim mega 8) zumindest den Timer IRQ und natürlich dort NUR die Auswertung auf Änderung = Schalter betätigt. Den Rest in der Hauptroutine wie es sich gehört.
Ob der Impuls "zu Fuß" oder mit dem Pulsout Befehl erzeugt wird hängt auch von der benötigten Pulslänge ab. Wobei mir nicht wirklich klar ist vie Bascom Pulsout umsetzt, das sollte man sich vielleicht einmal in ASM ansehen.

Andererseits habe ich früher beim PIC die IRQ Fähigkeit aller (fast aller) Pins schätzen gelernt. Damals habe ich allerdings nur in ASM Programmiert, so eine Außenkamera schenkk/neige/Zoom/Focus RS 485 Sticksteuerung war in ganz wenigen Zeilen "erschlagen". Mehr hatte der Prozessor aber auch nicht zu tun.:-)

Gruß Richard

wkrug
25.06.2011, 20:54
zumindest den Timer IRQ und natürlich dort NUR die Auswertung auf Änderung = Schalter betätigt
Dann kann ich's aber auch gleich wieder per Polling machen.


PIC die IRQ Fähigkeit aller (fast aller) Pins schätzen gelernt
Fast alle ATMEL Controller der "neueren" Serien ( ATTINY, ATMEGA ) können Pin Change Interrupts was in etwas das gleiche sein sollte.

Mit Latenzzeiten meinte ich die Zeit, die vom Tastendruck bis zur Impulsausgabe vergeht.
Wenn ich das per Polling mache ist diese Zeit variabel, da ja die Tastenabfrage irgendwo im Hauptprogramm gemacht wird.
Sind dann im Hauptprogramm Operationen die sehr lange dauern, wird durch diese die Impulsausgabe verhindert.

Wenn das eine Rolle spielt kann man das so nicht machen.

Wenn die Reaktion schnell erfolgen soll, muss man die Tastenabfrage per Interrupts machen, den Impulsausgang sofort setzen und eventuell einen Timer ( Comparematch Interrupt ) als Abschalter für die Impulsausgabe missbrauchen.

Sagen wir mal eine Taste wurde gedrückt, der zugehörige Interrupt aktiviert und der Impulsausgang gesetzt.
Nun wird der aktuelle Zählerstand des Abschaltetimers ( z.B. Timer 1 ) ausgelesen, der Wert für die gewünschte Impulslänge dazuaddiert und im COMP1x Register abgelegt.
Schlägt nun der Comparematch Interrupt zu wird der Impulsausgang abgeschaltet.

Diese Methode würde sehr kurze Latenzzeiten produzieren und das Hauptprogramm immer nur kurzzeitig stören. Ist aber vom Handling her nicht so ganz einfach und Unproblematisch. Die komplette Tastenabfrage, Impulsgenerierung würde dabei, wie schon gesagt, in Interrupts abgewickelt.

peterfido
25.06.2011, 23:06
Eine Idee:

$regfile = "m8def.dat"
$crystal = 1000000

Config Timer0 = Timer , Prescale = 1024 'längster Impuls (bei 1 MHZ etwa 1/4 Sekunde) für längere Zeit 16 Bit Timer nehmen
On Timer0 Timer_irq
Enable Timer0
Enable Interrupts
Ddrc = &B00001111 'Ausgänge an Port C0-3
Ddrb = 0 'Eingänge an B0-3
Dim Pinb_alt As Byte

Do


Loop
End


Timer_irq:
Dim I As Byte

For I = 0 To 3
If Pinb_alt.i <> Pinb.i Then
Set Portc.i
Else
Reset Portc.i
End If
Next I
Pinb_alt = Pinb
Return

Oder für längeren Impuls:


$regfile = "m8def.dat"
$crystal = 1000000

Const Impulsdauer = 5 '4fache Impulsdauer
Config Timer0 = Timer , Prescale = 1024 'längster Impuls (bei 1 MHZ etwa 1/4 Sekunde) für längere Zeit 16 Bit Timer nehmen
On Timer0 Timer_irq
Enable Timer0
Enable Interrupts
Ddrc = &B00001111 'Ausgänge an Port C0-3
Ddrb = 0 'Eingänge an B0-3
Dim Pinb_alt As Byte
Dim Zeit(4) As Byte
Dim I As Byte

Do
If Zeit(4) >= 1 Then '>=1 erzeugt kleineren Code als >0...

For I = 0 To 3
If Zeit(i) >= 1 Then
Decr Zeit(i)
End If
If Zeit(i) = 0 Then
Reset Portc.i
Else
Set Portc.i
End If

If Pinb_alt.i <> Pinb.i Then
Zeit(i) = Impulsdauer
End If
Next I
Pinb_alt = Pinb
Zeit(4) = 0
End If

Loop
End


Timer_irq:
Incr Zeit(4)
Return

guenter1604
03.07.2011, 20:41
Hallo,

hier mal ein Code für die Interrupts eines Mega88. Da der Change Interrupt nicht zwischen ansteigender und abfallender Flanke unterscheidet, wird einfach der Pegel des Pins im Interrupt abgefragt.


Config Int0 = Change
Config Int1 = Change
On Int0 Int_0
On Int1 Int_1

Int_0: 'A changing Flank was detected from the left Sensor
If Pind.2 = 1 Then 'the rising Flank
'Int0 (PinD.2) ist gerade auf High gesprungen
Else 'the falling Flank
'Int0 (PinD.2) ist gerade auf Low gesprungen
End If
Return

Int_1: 'A changing Flank was detected from the left Sensor
If Pind.3 = 1 Then 'the rising Flank
'Int1 (PinD.3) ist gerade auf High gesprungen
Else 'the falling Flank
'Int1 (PinD.3) ist gerade auf Low gesprungen
End If
Return

Gruß Günter