Forum: Mikrocontroller und Digitale Elektronik erstes Programm, Binärzähler. Frage (Mega8)


von Jochen (Gast)


Lesenswert?

Hallo,

ich habe einen Atmel Mega 8 und auch das myAVR USB Starterset.
Leider funktioniert mein Programm nicht wie gewünscht.
Ich habe den Port D (2) als Eingang eingestellt und an einen Taster 
angeschlossen. Der Taster liegt auf der Masse. Dann habe ich den Pullup 
aktiviert. Jetzt liegt der Eingang immer auf 0, wenn der Taster gedrückt 
wird.
Mein kleines Programm soll am Ausgang B0, B1 und B2 binär zählen. Immer 
dann eine Stufe weiter, wenn der Taster gedrückt wird.
Leider hat es nicht den gewünschten Effekt, zu zählen. Stattdessen liegt 
am Ausgang irgendwas an und nach jedem Tastendruck leuchtet eine andere 
Kombination von Leds, aber nicht so wie ich das gerne hätte. Was habe 
ich falsch gemacht:

        cbi DDRD, 2
  sbi PORTD, 2
  sbi DDRB,0
  sbi DDRB,1
  sbi DDRB,2
;----------------------------------------------------------------------- 
-
mainloop:
ldi r16, 0b00000000
st:

in r17, PIND
sbrc r17,2
rjmp st
inc r16
out PORTB, r16
rjmp st


Liebe Grüße
Jochen

von fubu1000 (Gast)


Lesenswert?

 hallo,
so sollte es gehen glaub ich.



  ldi r16, 0xFB
  out DDRD, r16
  ldi r16, 0x07
  out DDRB, r16
;----------------------------------------------------------------------- 
-
mainloop:
ldi r16, 0x00

st:

in r17, PIND
sbrc r17, 2
rjmp st
inc r16
out PORTB, r16
rjmp st




gruss fubu

von fubu1000 (Gast)


Lesenswert?

hallo,
ui da fällt mir ein du solltest die taster entprellen!!

also:

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  ldi r16, 0xFB
  out DDRD, r16
  ldi r16, 0x07
  out DDRB, r16
;----------------------------------------------------------------------- 
-
mainloop:
ldi r16, 0x00

st:

in r20, PIND
sbrc r20, 2
rjmp st
inc r16
out PORTB, r16
rcall tastenwait
rjmp st


tastenwait:   ;wartet ne halbe sek falls takt 1MHZ

              ; warte 499995 Zyklen:
          ldi  R17, $0F
WGLOOP0:  ldi  R18, $37
WGLOOP1:  ldi  R19, $C9
WGLOOP2:  dec  R19
          brne WGLOOP2
          dec  R18
          brne WGLOOP1
          dec  R17
          brne WGLOOP0
; -----------------------------
; warte 3 Zyklen:
          ldi  R17, $01
WGLOOP3:  dec  R17
          brne WGLOOP3
; -----------------------------
; warte 2 Zyklen:
          nop
          nop
; =============================

ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 
;


gruss fubu

von Hannes L. (hannes)


Lesenswert?

Jochen, Dein Programm zählt hoch, solange der Taster gedrückt ist.

Wenn Du Tastendrücke zählen willst, nützt Dir das nichts, da musst Du 
dann zählen, wenn der Übergang von unbetätigt auf betätigt erfolgt, also 
bei der entsprechenden Flanke (Pegelwechsel) am Eingang. Das genügt aber 
noch nicht, denn (mechanische) Taster prellen, was zur Folge hat, dass 
jeder Tastendruck mehrmals gezählt wird.

Du brauchst also eine Kombination aus Entprellung und Flankenerkennung. 
Nachdem Du fubus Vorschlag analysiert und verstanden hast, solltest Du 
Dir mal Alternativen ansehen. Recht gut erklärt wird das z.B. hier:
http://www.mikrocontroller.net/articles/AVR-Tutorial:_Tasten

Vermutlich werden da aber schon ein paar Dinge vorausgesetzt, die Du Dir 
noch nicht erarbeitet hast, weshalb es besser ist, wenn Du hier 
beginnst:
http://www.mikrocontroller.net/articles/AVR-Tutorial

...

von Jochen (Gast)


Lesenswert?

Vielen Dank für die Antworten ich werde mir das sofort ansehen!
Aber wieso zählt es nicht dann hoch, wenn ich einen taster drücke:

Wenn ich ihn drücke, wird das Register r16 erhöht und ausgegeben.
Drücke ich ihn nicht, wird r16 nicht erhöht und das ausgegeben.
Starte ich das Programm, ist r16 gleich null.
Null wird ausgegeben.
Drücke ich ihn, ist r16 gleich 00000001 und wird ausgegeben.
Wenn der Taster jetzt nicht gedrückt wird, bleibt r16 unverändert und 
das vorherige wird ausgegeben, denn die Erhöhung wird übersprungen.
Wird er jetzt gedrückt, wird r16 um eins erhöht usw.

Was ist an diesem Denkstoß falsch?

von Jochen (Gast)


Lesenswert?

Ich habe noch eien Frage.
In dem ersten Link sind Pfeile verwendet.

z.B.

  ldi  temp1, 1<<LED


in dem zweiten Link konnte ich nicht finden, was sie bedeuten.
Könntet ihr mir das sagen?

von Peter D. (peda)


Lesenswert?

Jochen wrote:
> Vielen Dank für die Antworten ich werde mir das sofort ansehen!
> Aber wieso zählt es nicht dann hoch, wenn ich einen taster drücke:

Es zählt hoch, etwa eine Million mal pro Sekunde.

Du bist halt nur zu langsam, das zu sehen.


Peter

von Hannes L. (hannes)


Lesenswert?

Jochen wrote:
> Ich habe noch eien Frage.
> In dem ersten Link sind Pfeile verwendet.
>
> z.B.
>
>   ldi  temp1, 1<<LED

Im Endeffekt: Es wird das Bt mit dem Namen "LED" im Register "temp1" 
gesetzt und alle anderen Bits gelöscht.

Aber eigentlich: Es wird eine "Eins" um "LED" Binärstellen nach links 
geschoben.

Warum?
Schau Dir die Unterschiede der Befehle ldi (sbr, andi, ori, cbr) und 
sbrs (sbrc) an (die F1-Taste im AVR-Studio ist Dein Freund), dann wirst 
Du merken, dass die eine Befehlsgruppe eine Bitmaske (Wert 0..255) 
erfordert, die andere Befehlsgruppe aber die Bitnummer (0..7). Um nun 
mit nur einem symbolischen Namen für das Bit auszukommen, macht man aus 
der Bitnummer die Bitmaske, indem man eine 1 um soviele Stellen nach 
links schiebt, wie die Wertigkeit der Bitnummer ist.

 ldi temp,3               ;setzt Bit 0 und 1, der Wert ist 3
 ldi temp,1<<3            ;setzt Bit 3, der Wert ist 8

 sbrs temp,3              ;überspringt den rjmp, wenn Bit 3 gesetzt ist
 rjmp weg_hier            ;der Else-Zweig der IF-Abfrage...


>
>
> in dem zweiten Link konnte ich nicht finden, was sie bedeuten.

Doch, in irgendeinem Artikel des Tutorials wird das beiläufig 
angesprochen und ausführlich erklärt. Ich kann aber jetzt nicht sagen, 
wo, denn ich lese das Tutorial nicht intensiv (nicht als Wissensquelle), 
denn als ich anfing war es noch sehr dürftig und inzwischen habe ich mir 
das Wissen anderweitig erarbeitet.

> Könntet ihr mir das sagen?

Ich empfehle Dir, das gesamte Tutorial der Reihe nach abzuarbeiten, Du 
hast sogar die richtige Hardware dafür. Da werden sehr viele 
Missverständnisse schon im Vorfeld beseitigt.

Viel Erfolg...

...

von Jochen (Gast)


Lesenswert?

Ok danke für die Antworten.

Ich habe das soweit verstanden.
Nochmal zurück zu 
http://www.mikrocontroller.net/articles/AVR-Tutorial:_Tasten

Ich habe mir den ersten Abschnitt also die Lösung ohne Berücksichtigung 
der Prellung angesehen.

Jetzt vergleich ich sie mit meiner Lösung.
Inwiefern zählt meine Lösung eine Millionen mal pro Sekunde hoch wenn 
der Taster gedrückt ist, bei der Lösung vom Link dagegen jedoch nur 
exakt einmal pro Tastendruck?

von Hannes L. (hannes)


Lesenswert?

> Inwiefern zählt meine Lösung eine Millionen mal pro Sekunde hoch wenn
> der Taster gedrückt ist

Deine Lösung (kopiert aus erstem Beitrag):
1
;Vorbereitungen:
2
  cbi DDRD, 2
3
  sbi PORTD, 2
4
  sbi DDRB,0
5
  sbi DDRB,1
6
  sbi DDRB,2
7
8
mainloop:             ;irreführede Bezeichnung, da dies nicht Teil der
9
;Schleife ist!!!
10
11
ldi r16, 0b00000000   ;r16 auf 0 setzen
12
13
14
st:                   ;Beginn der Schleife (Rücksprungmarke)
15
16
in r17, PIND          ;Eingangszustand (ganzes Byte) einlesen
17
sbrc r17,2            ;überspringe "rjmp st", wenn Taster gedrückt (L)
18
rjmp st               ;Abbruch, wenn Taster nicht gedrückt
19
20
inc r16               ;Zähler hoch, wenn Taster gedrückt ist, aber auch
21
;in jeder bweiteren "Runde", solange der Taster gedrückt ist...
22
out PORTB, r16        ;Zählerstand anzeigen
23
rjmp st               ;dasselbe nochmal...

Deine Schleife (von st: bis rjmp st) wird voll durchlaufen, solange der 
Taster betätigt ist (L-Pegel) (sie wird verkürzt durchlaufen, wenn der 
Taster unbetätigt ist). Die Schleife ist aber so schnell, dass es Dir 
nicht gelingt, den Taster so kurz zu betätigen, dass ein Tastendruck nur 
einmal gezählt wird.
Um bei jedem Tastendruck nur einen Schritt weiter zu zählen, musst Du 
eine Flankenerkennung bauen, die nur dann um 1 weiterzählt, wenn der 
Taster jetzt betätigt ist, vorher (in der vorhergehenden Runde der 
Schleife) aber unbetätigt war. Dazu muss man sich den vorherigen Zustand 
merken und den neuen Zustand damit vergleichen. Nur bei einem 
Unterschied hat sich der Pegel am Eingang geändert. Jetzt muss noch 
ermittelt werden, ob der Unterschied Auswirkung des Drückens oder des 
Loslassens war, denn man will ja nicht doppelt zählen.

Wenn das alles klappt, dann funktioniert das zwar im Simulator, aber 
noch lange nicht mit einem mechanischen Taster, denn mechanische Taster 
oder Schalter prellen. Sie schalten also nicht einfach ein, sondern 
klappern eine Weile zwischen aus und ein hinundher, worauf der 
Mikrocontroller aufgrund seines enormen Arbeitstempos etliche 
Tastendrücke erkennt.

Dies kann man vermindern, indem man den Taster einfach langsamer 
abfragt. Die einfachste, aber uneffizienteste Variante ist die 
Warteschleife (siehe oben). Effizienter ist es aber, in der Wartezeit 
andere Aufgaben zu erledigen, daher schafft man sich mittels Timer einen 
Teit-Takt von etwa 5..20ms, in dem man die Tasten abfragt und auch noch 
andere Dinge erledigt, wie das Hochzählen der Zeit für eine Uhr.

Im Tutorial findest Du eine Routine, die vereint das Abfragen der Taster 
mit Flankenerkennung und Vierfach-Entprellung. Sie ist genial, aber 
recht komplex, also für den Anfänger etwas schwer verständlich. Such mal 
in der Artikelsammkung nach "entprellung", da gibt es einige Links auf 
weiterführende Diskussion über diese Routine.

...

von Jochen (Gast)


Lesenswert?

Alles klar, ich habe jetzt das ganze durchgearbeitet und es 
funktioniert. Herzlichen Dank!

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.