Forum: Mikrocontroller und Digitale Elektronik Taster als Schalter


von roman (Gast)


Lesenswert?

Ich versuche nun schon seit 2 Tagen einen einfachen Taster als Schalter
zu benutzen. Ich habe einen ATmega8 und benutze Bascom.
LEDs blinken usw. habe ich alles schon hinbekommen nur halt das mit dem
Taster nicht.
Kann mir mal bitte jemand den Code sagen? Ich weiss das ich entprellen
muss, blos verstehe ich das nicht so ganz in Bascom.

Wenn ich den Taster an Pind.2 drücke soll die LED an portd.7 angehen,
wenn ich nochmal den Taster drücke soll sie wieder ausgehen.

Damke schonmal.

von Mr_Boertsch (Gast)


Lesenswert?

Was hast du denn bis jetzt programmiert?

von roman (Gast)


Lesenswert?

Ich habe es nun alleine hinbekommen! Hänge aber beim nächsten problem.
Möchte nun mit 2 Tastern 2 Verschiedene "Programme" Starten und
stopen können.

Hier mal mein 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


Loop
End

If T1 = 1 Then
Gosub Prg1

End If

If T2 = 1 Then
Gosub Prg2

End If

An:
Toggle T1

Aus:
Toggle T2


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

von Mr_Boertsch (Gast)


Lesenswert?

wo liegt denn das problem?

Also ich meine wenn du einfach deine Bits abfragst und dann das
jeweilige programm aufrufst. Geht das nicht?

von roman (Gast)


Lesenswert?

Ne das funktioniert so nicht.
Egal welchen Taster ich drücke, es läuft immer nur Programm1 ab. Es
wiederholt sich auch nicht, sondern läuft nur 1x ! :(

von Peter Dannegger (Gast)


Lesenswert?

Dein Problem dürfte sein, daß, sobald ein Programm läuft, ja nicht mehr
die Loop mit den Debounces ausgeführt wird. Du mußt also sehr lange
drücken.

Als Lösung wüßte ich daher nur, das Entprellen und gedrückt erkennen in
einem Timerinterrupt quasi im Hintergrund ausführen zu lassen.
In der Codesammlung ist dazu ein Beispiel in C oder Assembler für bis
zu 8 Tasten, d.h. der Code ist der gleiche, egal ob eine Taste oder 8.


Ich kenn mich mit Basic nicht aus, aber geht Dein Programm nicht von
"An:" über "Aus:" direkt rein in "Prg1:" ?


Und ist nicht das "If T1 = 1 Then" nach dem "Do...Loop"
unerreichbarer Code ?


Peter

von roman (Gast)


Lesenswert?

Hallo Peter,

ich bin leider noch so ziemlich am Anfang was Uc angeht, deswegen
verstehe ich nicht so ganz was du da geschreiben hast.

Gibts hier jemand der auch mit Bascom codet und mir sagen kann wo der
Fehler liegt?

mfg
roman

von Dirk (Gast)


Lesenswert?

Hi,

der Code ist nicht richtig aufgebaut nach deinen Anforderungen. Peter
hat schon recht mit den tasten in einen Timer abzufragen.

Aber fuer Anfaenger sollte das Polling der Tasten einfacher sein.


An:
Toggle T1

-- hier fehlt ein return

die Hauptschleife sollte dann so aufgebaut sein:

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

prg1:
.......
return

prg2:
......
return

Gruß,
Dirk

von Togger (Gast)


Lesenswert?

Hi Roman,
programmiere schon lange in Bascom.
"Debounce" ist schon lange her, hatte aber nie Erfolg damit, daher
weg damit.
Ich mache es immer wie folgt:


1) Wichtig ist die Deklaration z.b:

Const Pressed = 0     ' kommt später
Config Portd = Input  ' Port D ist Eingang
Btn_up Alias Pind.0   ' Portd.0 gibt Mist ;-) WICHTIG !!!!!

2) Abfragen, ob Taste gedrückt

If Btn_up = Pressed Then

3) ein bischen warten zum Entprellen

  Waitms 200
' Vielleicht geht auch weniger als 200, vielleicht auch ein
Debounce!

4) Aktion auslösen z.b. led togglen

  Toggle LED
end if

So geht es, viel Glück!

lg Ralf

von Hannes L. (hannes)


Lesenswert?

Und so vertrödelt der MC wieder seine Rechenzeit in Zeitschleifen,
anstatt sich in dieser Zeit anderen Aufgaben zu widmen...

Ist es denn so schlimm, in einem Timer-Interrupt alle 4...20ms den Port
einzulesen, den Wert mit dem vorhergehenden zu vergleichen und
Änderungen zu übernehmen (nachdem sie 2mal oder besser 4mal
hintereinander stabil aufgetreten sind)?

Es ist schon schlimm genug, dass immer wieder mit Warteschleifen
programmiert wird, aber noch schlimmer ist, dass das Programmieren von
(ellenlangen) Warteschleifen immer wieder als "gutes Beispiel"
angepriesen wird.

...

von Togger (Gast)


Lesenswert?

@Hannes,
viele Wege führen nach Rom!
Sorry, aber meine Interruptroutinen haben was Besseres zu tun, als
Taster abzufragen, kannst natürlich gerne so machen.
Denke mal, dass in ner Schleife für Anfänger so einfacher geht.
Warum sich noch Ärger mit nem Interrupt einhandeln?
"Debounce" wird auch warten, bis der Portpin sich nicht mehr ändert.
Hätte auch besser gefunden, wenn ein konkretes Beispiel beigefügt
hättest, damit Roman damit was anfangen kann.
Und wenn du meinst, daß der MC seine Zeit vertrödelt, wenn er auf
Eingaben wartet, dann ist mir das rätselhaft.
Es gibt z.b. Messaufgaben, die erst dann gestartet werden sollen, wenn
eine Taste gedrückt wurde.
Sehe auch wenig Sinn, wenn in einer komplexen Schleife trotzdem alle
4ms die Interruptroutine nach Tasteneingaben abfragt.
Wie gesagt: kannst natürlich gerne so machen, Hauptsache es funzt.

Ich hatte dieses Forum mal so Verstanden, dass man sich bei konkreten
Problemen Anregungen einholen kann, über die man natürlich auch
diskutieren kann.
Leider driften oft die Themen ab oder es wird Haarspalterei betrieben.
Schau dir mal einige Threads an, dann weisst was ich meine.

Schönes Wochenende
lg Ralf :-)

von Hannes L. (hannes)


Lesenswert?

@Ralf:
> Sorry, aber meine Interruptroutinen haben was Besseres zu tun, als
> Taster abzufragen, kannst natürlich gerne so machen.

Das wird nicht in einem eigens für die Taster reserviertem Interrupt
gemacht, sondern in einem Timer-Interrupt der weitere Aufgaben der
Programmsteuerung hat (Blinken, Verzögerungen, LCD-Synchronisierung
usw...) und in fast jedem Programm sowiso benötigt wird. Die Abfrage
und Entprellung von bis zu 8 Tastern benötigt ganze 12 Takte in der ISR
und stellt dem Hauptprogramm (oder welchem Task auch immer) für jede
Taster ein (entprelltes) Zustandsbit zur Verfügung und zusätzlich ein
Flag (je Taster), das anzeigt, dass ein Taster erneut betätigt wurde
und dieser Tastendruck noch nicht abgearbeitet wurde. Und das alles
ohne Warteschleifen, bequemer geht es nicht...

> Denke mal, dass in ner Schleife für Anfänger so einfacher geht.

Ja, wenn man dem "Anfänger" auch dazusagt, dass man es so nicht
machen sollte. Denn wer sich einmal an das Verheizen von
Prozessortakten gewöhnt hat, kommt nur schwer wieder von diesem
Programmierstil weg. Es gibt genügend Beispiele hier im Forum, wo ein
(übertakteter) Mega128 mit BASCOM seine (wenige) Arbeit nicht schafft.

> Hätte auch besser gefunden, wenn ein konkretes Beispiel beigefügt
> hättest, damit Roman damit was anfangen kann.

Auf dieses Beispiel hat Peter Dannegger (der Urheber dieser Routine)
bereits verwiesen (Codesammlung). Wenn es aber sein muss, dann gibt es
das Beispiel eben hier nochmal. Es ist allerdings in Assembler. Die
folgenden Codezeilen sind Bestandteil der Timer-ISR, die noch andere
Aufgaben hat.

TIM1_COMPA:             ;ISR Timer1-Interrupt (alle 10ms)
 in srsk,sreg               ;SREG sichern (Exklusivregister)
 push xh                    ;benutzte Register
 push xl                    ;sichern
 in xl,ocr1al               ;Weckzeit
 in xh,ocr1ah               ;holen,
 subi xl,low(-tim1zu)       ;Intervall
 sbci xh,high(-tim1zu)      ;dazu,
 out ocr1ah,xh              ;und wieder
 out ocr1al,xl              ;in den Timer
 ;xl und xh können jetzt innerhalb dieser ISR frei benutzt werden
Tastenabfrage:          ;Entprellroutine geklaut bei Peter
Dannegger...
 in xl,tap      ;Tastenport einlesen (gedrückt=L)
 com xl         ;invertieren (gedrückt=H)
 eor xl,tas     ;nur Änderungen werden H
 and tz0,xl     ;Prellzähler unveränderter Tasten löschen (Bit0)
 and tz1,xl     ;Prellzähler unveränderter Tasten löschen (Bit1)
 com tz0        ;L-Bit zählen 0,2,->1, 1,3,->0
 eor tz1,tz0    ;H-Bit zählen 0,2,->tz1 toggeln
 and xl,tz0     ;Änderungen nur dann erhalten, wenn im Prellzähler
 and xl,tz1     ;beide Bits gesetzt sind (Zählerstand 3)
 eor tas,xl     ;erhaltene Änderungen toggeln alten (gültigen)
Tastenstatus
 and xl,tas     ;nur (neu) gedrückte Tastenbits bleiben erhalten
 or tfl,xl      ;und zugehörige Bits setzen (gelöscht wird nach
Abarbeitung)
 ;in "tas" steht jetzt der gültige Tastenzustand,
 ;in "tfl" die Flags der neu gedrückten, noch nicht abgearbeiteten
Tasten...
 ;xl ist jetzt wieder frei für weitere temporäre Zwecke in der ISR
 ;...
 ;Weitere Aufgaben der ISR...
 ;...
tim1_ovf_ende:
 pop xl                     ;benutzte Register
 pop xh                     ;wiederherstellen
 out sreg,srsk              ;SREG wiederherstellen
 reti                       ;fertig...

> Sehe auch wenig Sinn, wenn in einer komplexen Schleife trotzdem
> alle 4ms die Interruptroutine nach Tasteneingaben abfragt.

Ich schon, wobei ich mich nicht an den 4ms festhalte. Ich nutze den
Abstand, der für die restliche Interruptarbeit günstig ist. Wird z.B.
(für Messungen) eine "Uhr" mit Hundertstel Sekunden benötigt, dann
ist der Abstand 10ms. Brauche ich den Timer-Int für eine mehrkanalige
Software-PWM, dann wird der Zeitabstand halt soweit wie möglich
reduziert, so dass zwischen den ISRs noch genügend Zeit für die
Funktionen des Hauptprogramms bleibt, aber eben nicht mehr als nötig.

Es gibt eben (unter anderem) 2 Arten von Programmierstil.
Der eine wartet in einer Warteschleife, wenn eine Aktion nicht sofort
(sondern etwas später) ausgeführt werden soll.
Der andere springt sofort zur Mainloop zurück und schaut nach, ob es
nicht noch andere Arbeit gibt, die man zwischendurch erledigen kann.
Was soll daran falsch sein?

> Ich hatte dieses Forum mal so Verstanden, dass man sich bei
> konkreten
> Problemen Anregungen einholen kann, über die man natürlich auch
> diskutieren kann.
> Leider driften oft die Themen ab oder es wird Haarspalterei
> betrieben.
> Schau dir mal einige Threads an, dann weisst was ich meine.

Da hast du das Forum richtig verstanden.
Ich sehe meinen Beitrag auch nicht als Flamwar oder Haarspalterei,
sonern als einen Hinweis, dass man vorteilhafter programmieren kann.
Vielleicht auch darauf, dass nicht auf den Beitrag mit der Lösung
reagiert wurde.

...

von roman (Gast)


Lesenswert?

@ Togger
Wenn ichs mit waitms 200 mache blinkt die LED ja so lange bis ich die
taste loslasse, weil ja jede 200ms neu getoggelt wird.

@ Dirk
Ich hab nun die 2 vergessenen Returns hinzugefügt mit dem Ergebnis das
es schon fast funktioniert. Blos muss ich beim Ausschalten den Taster
immer so lange gedrückt halten, bis das ganze Programm einmal
durchgelaufen ist.

von Peter D. (peda)


Lesenswert?

"Blos muss ich beim Ausschalten den Taster immer so lange gedrückt
halten, bis das ganze Programm einmal durchgelaufen ist."


Genau das hatte ich doch schon gesagt.

Interrupts sind gar nicht so schlimm. Und wenn man sie erstmal kapiert
hat, erleichtern sie das Programmieren ungemein.


Peter

von roman (Gast)


Lesenswert?

Wäre denn mal jemand so lieb, meinen Code zu
vervollständigen/Verbessern?
Dann habe ich wenigstens mal ein Konkretes beispiel was ich auch
verstehe.

Danke schonmal.

von aaa (Gast)


Lesenswert?

do
if pind.0=1 and portb.0=0 then
portb.0=1   'LED an
end if

waitms 100

if pind.0=1 and portb.0=1 then
portb.0=0   'LED aus
end if

loop

von Hannes L. (hannes)


Lesenswert?

Und dazu brauchst Du knapp zwei Jahre???

...

von mohi (Gast)


Lesenswert?

Hallo,

hab einen Atmega32-Grundschaltung aufgebaut und an folgenden Ports je 
eine LED angeschlossen:

PD5
PD6
PD7

Zwei Taster habe ich an PD und PD3 angeschloßen.

Nun wollte ich folgenden Code mal ausprobieren, aber es funktioniert 
nicht richtig:
1
$regfile = "m32def.dat"
2
$framesize = 32
3
$swstack = 32
4
$hwstack = 32
5
$crystal = 1000000
6
7
Ddrd = &B11100000
8
Portd = &B00001100
9
10
Declare Sub An
11
Declare Sub Aus
12
Declare Sub Prg1
13
Declare Sub Prg2
14
15
Dim T1 As Bit
16
Dim T2 As Bit
17
18
19
Do
20
21
Debounce Pind.2 , 0 , An , Sub
22
Debounce Pind.3 , 0 , Aus , Sub
23
24
25
Loop
26
End
27
28
If T1 = 1 Then
29
Gosub Prg1
30
31
End If
32
33
If T2 = 1 Then
34
Gosub Prg2
35
36
End If
37
38
An:
39
Toggle T1
40
41
Aus:
42
Toggle T2
43
44
45
Prg1:
46
47
 Portd.5 = 1
48
 Waitms 100
49
 Portd.5 = 0
50
 Portd.6 = 1
51
 Waitms 100
52
 Portd.6 = 0
53
 Portd.7 = 1
54
 Waitms 100
55
 Portd.7 = 0
56
57
 Return
58
59
Prg2:
60
 Portd.5 = 1
61
 Waitms 400
62
 Portd.5 = 0
63
 Portd.6 = 1
64
 Waitms 400
65
 Portd.6 = 0
66
 Portd.7 = 1
67
 Waitms 400
68
 Portd.7 = 0
69
70
 Return


Es leuchten alle drei LEDs auf und wenn ich den Taster an PD2 betätige, 
dann läuft Prg1 einmal durch und die LEDs leuchten wieder.
Daselbe spiel mit dem Taster PD3, da läuft auch Prg:1 einmal durch...

Also eigentlich kein Unterschied bei den Tastern.

Woran könnte das liegen? Oder besser gesagt, was mach ich falsch?

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
Noch kein Account? Hier anmelden.