PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Anfängerfrage, Taster als Schalter



hardstyleroxx
28.09.2005, 20:30
Hey,

mein myAVR Board ist da und ich finde es bis jetzt echt serh gut, gab noch keine Probleme.
Habe schon ein paar lauflichter und solche spielereien gebastelt und hänge nun bei der Funktion einen Taster als Schalter zu benutzen.
Ich möchte das wenn ich den Taster an Pind.2 drücke das eine Programm läuft und wenn ich den Taster an Pind.3 drücke das andere. Am besten wäre es dann noch das wenn ich beide taster gleichzeitig drücke kein programm mehr läuft.



$regfile = "m8def.dat" ' Prozessortyp ATmega8
$crystal = 3686400 ' Taktrate

Ddrd = &B11100000 ' PD5-PD7 auf Ausgang
Portd = &B00001100 ' alle LEDs off, PullUP von PinD2 & 3 An


Do ' Beginn Mainloop

If Pind.2 = 0 Then ' Wenn Taster 1 gedrückt..

Portd.5 = 1
Waitms 100
Portd.5 = 0
Portd.6 = 1
Waitms 100
Portd.6 = 0
Portd.7 = 1
Waitms 100
Portd.7 = 0
Portd.6 = 1
Waitms 100
Portd.6 = 0
Portd.5 = 1
Waitms 100
Else ' sonst...
Portd.5 = 0
Portd.6 = 0
Portd.7 = 0

End If


If Pind.3 = 0 Then ' wenn Taster 2 gedrückt...
Portd.5 = 1
Portd.7 = 1
Waitms 300
Portd.5 = 0
Portd.7 = 0
Portd.6 = 1
Waitms 300
Portd.6 = 0
Else ' sonst...
Portd.5 = 0
Portd.6 = 0
Portd.7 = 0

End If

Loop ' Ende Mainloop
End ' Programmende
'----------------------------------------------------------

Xtreme
28.09.2005, 21:04
Lagere die zwei unterschiedlichen Routinen in Unterroutinen aus. Also mit sub, gosub usw. Dann wirds übersichtlicher!

hardstyleroxx
28.09.2005, 21:17
Könntest du mir das bitte mal an einem Beispiel erklären? Verstehe das nämlich nicht so ganz und die Bascom hilfe verwirrt mich gerade nur ...
Und wie mache ich das denn nun mit der Taster als Schalter Funktion? Ich muss ja irgentwie den zustand vom taster speichern.

28.09.2005, 21:31
Do
If Pind.2 = 0 Then Gosub Test
Loop

Test:
Portd.5 = 1
Waitms 100
Portd.5 = 0
Portd.6 = 1
Waitms 100
und so weiter

Return



:D

Marco78
28.09.2005, 21:31
$Crystal usw...

Dim T1 as Bit
Dim T2 as Bit

Do

If Pind.2 = 0 then toggle T1
If Pind.3 = 0 then toggle T2
If T1 = 1 then Gosub Taster1
If T2 = 1 then Gosub Taster2

Loop

Taster1:
'hier das Programm für Taster1
Return

Taster2:
'hier das Program für Taster2
Return


Da in den Unterprogrammen selbst schon Wartezeiten eingebaut sind ist das entprellen der Taster nicht notwendig.
Aber die Unterprograme laufen voll durch. Durch drücken eines Tasters wird das Programm nicht abgebrochen!
Um beide als Reset zu verwenden müsste man die Schaltung etwas umbauen. (Und das Progamm anpassen)

Mit GOSUB wird in ein Unterprogramm gesprungen. Mit RETURN geht es wieder dahin zurück von wo aus gesprungen wurde.

TOGGLE schaltet den Zustand um. 0 wird 1, 1 wird 0.

Das Programm ist so noch nicht perfekt. Es wird immer ein Unterprogramm ausgeführt, bis man zufällig zu der Zeit einen Taster drückt, wenn sie abgefragt werden.
Aber da ich deinen gewünschten Ablauf nicht kenne, kann ich es nicht ändern.

hardstyleroxx
29.09.2005, 18:04
Irgentwie bin ich gerade zu dumm. Sitze hier nun 2 Stunden und bekomme es einfach nicht hin eine LED an und aus zu tooglen mitm Taster.
Wäre sehr nett wenn jemand mal gucken kann was in meinem Code falsch ist oder wie es einfacher geht.



$regfile = M8def.dat
$crystal = 3686400


Ddrd = &B10000000 ' PD7 auf Ausgang
Portd = &B00000100 ' PullUP von PinD2 An

Dim T1 As Bit

Do ' Beginn Mainloop


If Pind.2 = 0 Then ' Wenn Taster1 gedrückt, dann..
Waitms 200 ' 200ms warten
If Pind.2 = 0 Then Toggle T1 ' Wenn taster1 immer noch gedrückt, dann Toogle T1


If T1 = 1 Gosub An ' wenn T1 = 1, gehe zum Unterprogramm An
Else Gosub Aus ' sonst gehe zum Unterprogramm Aus
End If
Loop

An:
Portd.7 = 1
Return

Aus:
Portd.7 = 0
Return

End

Jahn Kohlhas
29.09.2005, 23:04
hast du es schon mal mit dem befehl: DEBOUNCE versucht?

DEBOUNCE

Action
Debounce a port pin connected to a switch.


Syntax
DEBOUNCE Px.y , state , label [ , SUB]


Remarks

Px.y A port pin like PINB.0 , to examine.
State 0 for jumping when PINx.y is low , 1 for jumping when PINx.y is high
Label The label to GOTO when the specified state is detected
SUB The label to GOSUB when the specified state is detected

hardstyleroxx
30.09.2005, 12:55
Ich bekomme das einfach nicht hin ...

Kann mir mal bitte jemand den ganzen Code sagen, damit die LED an Portd.7 angeht wenn ich den Taster an Pind.2 drücke. Wenn ich nochmal drücke soll sie ausgehen.

Danke schonmal.

hardstyleroxx
30.09.2005, 15:16
Habs schon alleine hinbekommen !

Marco78
05.10.2005, 21:06
Und wir müssen jetzt dumm sterben und werden den fertigen Code nie seh'n :(

Er könnte ja den nächsten helfen, die auch das Problem haben und zufällig mal die Suche benutzt haben. Dann müssen die keinen neuen Beitrag eröffnen.

Ich denke das Hauptproblem in deinem Code war die IF-Abfrage.
Schau dir den Syntax für IF mal in der Hilfe genau an.
Entweder:

IF ... THEN ... ELSE
Else kann auch wegfallen.

Oder:

IF...
THEN...
ELSE ...
END IF

auch hier kann Else entfallen. Das wichtige ist das End If! Unter THEN können auch noch viele weitere Befehle stehen.

IF Pind.1 = 0
THEN A=1
B=X
C="Hallo"

ELSE
Y=0
H="H"

END IF

hardstyleroxx
05.10.2005, 21:33
Sorry hier is der Code:


$regfile = M8def.dat
$crystal = 3638400

Ddrd = &B11100000
Portd = &B00001100

Declare Sub An
Declare Sub Aus
Declare Sub Prg1
Declare Sub Prg2


Dim T1 As Bit
Dim T2 As Bit



Do

Debounce Pind.2 , 0 , An , Sub
Debounce Pind.3 , 0 , Aus , Sub

If T1 = 1 Then
Gosub Prg1
End If

If T2 = 1 Then
Gosub Prg2
End If

Loop
End



An:
Toggle T1
Return

Aus:
Toggle T2
Return

Prg1:

Portd.5 = 1
Waitms 100
Portd.5 = 0
Portd.6 = 1
Waitms 100
Portd.6 = 0
Portd.7 = 1
Waitms 100
Portd.7 = 0

Return


Prg2:
Portd.5 = 1
Waitms 400
Portd.5 = 0
Portd.6 = 1
Waitms 400
Portd.6 = 0
Portd.7 = 1
Waitms 400
Portd.7 = 0

Return

Nun habe ich leider das Problem, dass ich die Programme nicht mehr sauber abschalten kann. Is ja auch logisch, da er das Programm erst ganz abarbeiten möchte bevor er stoppt. Also muss man genau im richtigen moment stoppen. Jemand ne idee wie ich das lösen kann?

Marco78
05.10.2005, 22:15
Einen externen Interrupt verwenden.

Aber wie ich schon gesagt habe, wenn du von der Programmierung noch nicht soviel Ahnung hast und dir ein fertiger Code mehr helfen würde, muss man den genauen Ablauf des Programms kennen.

hardstyleroxx
05.10.2005, 22:53
Der Code ist mein komplettes programm, es geht halt bei mir immoment nur darum die Grundfunktionen kennenzulernen (LED an LED aus, taster usw.)

Die Funktion vom geposteten Code:

Portd.5 & Portd.6 sind LEDs
Pind.2 & Pind.3 sind Taster

Prg1: Leds blinken abwechselnd "Schnell"
Prg2: Leds blinken abwechselnd "Langsam"

Wenn ich Taster1 drücke soll prg1 laufen bis ich den selber Taster nochmal drücke. Das selbe gillt für Taster2 (Blos das dann halt prg2 läuft). Wenn nun prg1 läuft und ich Taster2 drücke soll prg1 aufhören und prg2 anfangen und umgekehrt.

Marco78
06.10.2005, 20:37
Dann musst du INT0 und INT1 verwenden. Den Syntax findest du in der Hilfe zum Thema Interrupt.

Ein INT unterbricht das laufende Programm und führt das Programm in der SUB zun INT aus.
In deinem Fall könnte da das togglen stehen.

Ich glaube du hast mich etwas falsch verstanden. Als ich davon sprach das man den genauen Ablauf des Programmes kennen müsste, meinte ich damit, den Funktionsablauf. Was soll wann pasieren.
Es bringt ja nicht viel, einen fertigen Code zu sehen, der offentsichtlich Fehler beinhaltet und man frage wo der Fehler ist.
Die, die den Fehler suchen sollen, müssen ja ganz genau wissen, was eigentlich passieren sollte.
Und ganz genau heisst auch wirklich ganz genau. Dazu gehört dann ggf. welche Funktionen oder Taster Vorrang haben sollen und vieles mehr.

hardstyleroxx
06.10.2005, 20:42
Es muss aber doch noch eine andere Lösung geben um ein laufendes "programm" zu unterbrechen als int0 und int1. Was ist denn wenn ich z.B an 8 eingängen Taster habe und die sollen alle eine unterbrechende Funktion haben?

Marco78
06.10.2005, 21:14
Das ganze ist kein PC!

Wenn du schreibst waitms 300, dann wartet er auch wirklich 300ms und schaut nicht nebenbei was andere Schalter noch so machen. Der läuft sein Programm Schritt für Schritt von oben bis unten ab und verzeigt auf Anweisung ab und zu mal.

Und selbst der PC (außer Intel's HT im Ansatz) macht das so! Da haben die Steckkarten auch alle einen Interrupt der dann weiteres anfordert.

Bei 8 Tastern könnte man alle Taster zusätzlich mit Dioden von einander entkoppelt auf einen INT legen. Und in der SUB des INT wird dann abgefragt, welcher Taster tatsächlich gedrückt wurde.

Sonst geht es nur, wenn die Taster dauerhaft abgefragt werden. Aber dann ist keine Zeit mehr da um das restliche Programm auszuführen.
Es geht nunmal nur mit Interrupts das Programm zu verlassen.

Aber wenn du sagst, "es muss", musst du ja auch wissen wie :P

hardstyleroxx
07.10.2005, 11:41
ok ich geb mich geschlagen, dann muss ich halt anfangen mit interrupts zu arbeiten.

Klaus_0168
10.10.2005, 14:35
Hi hardstyleroxx,

sorry, aber hier Interrupts zu verwenden ist eine Verschwendung.

Die Funktion die Du haben willst ist die eines RS-Flip-Flop's.
ACHTUNG - In den folgenden Zeilen fehlen mit Sicherheit Semikola u.s.w. es sollte jedoch klar sein, was gemeint ist. 'Merker' ist eine Bitvariable, mit der der Schalterzustand zwischengespeichert wird. Unter Subroutine sind die Zeilen abgelegt, die Du beim Einschalten abarbeiten willst.

If Pind 1.0 = 1 then 'Wenn der Einschalttaster betätigt wird Merker setzen
Merker = 1
If Pind 1.1 = 1 then 'Wenn der Ausschalttaster betätigt wird Merker löschen
Merker = 0

If merker 0 1 then 'Wenn Merker gesetzt ist in Subroutine verzweigen
gosub Subroutine

: Subroutine
hier steht der Code für die Subroutine

End Of Programm

Grüße Klaus

Marco78
10.10.2005, 22:12
If Pind 1.0 = 1
Diese Zeile wird doch aber nur dann abgearbeitet, wenn das Programm grade an dieser Stelle ist.
Wenn das Programm an der Stelle ist wo ein anderer Pin abgefragt wird, wird der erste(zitierte) nicht erkannt.
Somit ist es doch nicht möglich, das eine blinken zu unterbrechen und sofort zum nächsten zu wechseln.

Ich lass mich auch gerne belehren. Bin heute morgen früh aufgestanden und grade erst nach Hause gekommen. Mag sein das ich estwas unkonzentriert gelesen habe.

Klaus_0168
11.10.2005, 00:20
Hi Marco78,

Ich sehe gerade, das ich zwei Zeilen vergessen habe.

Richtig wäre :

: Anfang 'Anfang der Endlosschleife
If Pind 1.0 = 1 then 'Wenn der Einschalttaster betätigt wird -> Merker setzen
Merker = 1
If Pind 1.1 = 1 then 'Wenn der Ausschalttaster betätigt wird -> Merker löschen
Merker = 0

If merker = 1 then 'Wenn Merker gesetzt ist -> in Subroutine verzweigen
gosub Subroutine

Goto Anfang 'Rücksprung zum Anfang

: Subroutine
hier steht der Code für die Subroutine

End Of Programm

Sinn und Zweck des Ganzen ist folgender.
Zwischen ':Anfang' und 'Goto Anfang' ist der Programmcode, der die Abfrage der Taster vornimmt. In diesem Fall ist es eine Endlosschleife, die sehr schnell abgearbeitet wird, bis ...

... die Bitvariable 'Merker' gesetzt ist. Wenn der Merker gesetzt ist wird in die Subroutine verzweigt. In der Subroutine muss jetzt gewährleistet werden, daß diese so schnell wie möglich abgearbeitet wird. Das ist zwingend notwendig, damit die Taster so oft wie möglich abgefragt werden können. Waitbefehle sollten so klein wie möglich gewählt werden. Die Kombination eines kurzen Waitbefehles mit einem Zähler führt zu einem langen Wartezeitraum. Mit dem 'Select Case' - Befehl kann der Zählerstand und damit die abgelaufene Zeit in der Subroutine verwendet werden. Das hat jetzt aber nichts mehr mit dem Tasterproblem zu tun.

Grüße Klaus