Taster Abrage mit gedrückt halten

Gast #5470995
Lesenswert?

Hallo,
ich wollte einen Zähler programmieren,
der bei gedrückt gehaltenem Taster weiterhochzählt,
jedoch funktioniert das Gedrückthalten nicht richtig.
Den Code habe ich im Laufe des AVR ASM Taster Tutorial
geschrieben.

Vielleicht findet ihr ja meinen Denkfehler:
1
.def  iwr0        = R1
2
.def  iwr1        = R2
3

4
.def  key_state      = R4
5
.def  key_press      = R5
6
.def  key_rep_press    = R6
7
.def  key_rep        = R16
8

9
.def  temp1        = R17
10
.def  temp2        = R18
11
.def  temp3        = R19
12
.def  counter        = R20
13

14
.equ  KEY_PORT      = PORTB
15
.equ  KEY_DDR        = DDRB
16
.equ  KEY_PIN        = PINB
17
.equ  LED          = 1
18
.equ  BTN1        = 0
19
.equ  BTN2        = 1
20
.equ  KEY_REPEAT_START  = 40
21
.equ  KEY_REPEAT_NEXT    = 15
22

23
.equ  PRESCL_1024      = 1<<CS00 | 1<<CS02
24

25
.equ  XTAL        = 8000000
26

27
.org 0x0000
28
    rjmp  init
29

30
.org OVF0addr
31
    rjmp  timer_overflow0
32

33
timer_overflow0:
34
    push  R0
35
    in    R0, SREG
36
    push  R0
37

38
    push  R16
39
    ldi    R16, -( XTAL / 1024 * 10 / 1000 + 1 )
40
    out    TCNT0, R16
41
    pop    R16
42

43
get8key:
44
    in    R0, KEY_PIN
45
    com    R0
46
    eor    R0, key_state
47
    and    iwr0, R0
48
    com    iwr0
49
    and    iwr1, R0
50
    eor    iwr1, iwr0
51
    and    R0, iwr0
52
    and    R0, iwr1
53
    eor    key_state, R0
54
    and    R0, key_state
55
    or    key_press, R0
56
    tst    key_state
57
    breq  get8key_rep
58
    dec    key_rep
59
    brne  get8key_finish
60
    mov    key_rep_press, key_state
61
    ldi    key_rep, KEY_REPEAT_NEXT
62
    rjmp  get8key_finish
63

64
get8key_rep:
65
    ldi    key_rep, KEY_REPEAT_START
66

67
get8key_finish:
68
    pop    R0
69
    out    SREG, R0
70
    pop    R0
71
    reti
72
  
73
.include "lcd-routines.asm"
74

75
init:
76
    ldi    temp1, LOW(RAMEND)
77
    out    SPL, temp1
78
    ldi    temp1, HIGH(RAMEND)
79
    out    SPH, temp1
80

81
    ldi    temp1, 1<<BTN1 | 1<<BTN2
82
    out    KEY_PORT, temp1
83

84
    ldi    temp1, PRESCL_1024
85
    out    TCCR0B, temp1
86
    ldi    temp1, 1<<TOIE0
87
    sts    TIMSK0, temp1
88

89
    rcall  lcd_init
90
    rcall  lcd_clear
91

92
    clr    key_state
93
    clr    key_press
94
    clr    key_rep_press
95
    clr    key_rep
96

97
main:
98
    ldi    counter, 0
99
    rjmp  update_lcd
100

101
loop:  
102
    ; normaler Tastendruck
103
    cli
104
    mov    temp1, key_press
105
    clr    key_press
106
    sei
107
    cpi    temp1, BTN1+1
108
    breq  increment
109
    cpi    temp1, BTN2+1
110
    breq  decrement
111

112
    ; Tastendruck gedrückthalten
113
    cli    
114
    mov    temp1, key_rep_press
115
    clr    key_rep_press
116
    sei
117
    cpi    temp1, BTN1+1
118
    breq  increment
119
    cpi    temp1, BTN2+1
120
    breq  decrement
121

122
    rjmp  loop
123

124
increment:
125
    inc    counter
126
    rjmp  update_lcd
127

128
decrement:
129
    dec    counter
130

131
update_lcd:
132
    mov    temp1, counter
133
    rcall  lcd_clear
134
    rcall  lcd_number
135
    rjmp  loop
136

137
; Left Scroll Display
138
lcd_lscroll:
139
    push  temp1
140
    ldi    temp1, 0b00011000
141
    rcall  lcd_command
142
    rcall  delay5ms
143
    pop    temp1
144
    ret
145

146
; Right Scroll Display
147
lcd_rscroll:
148
    push  temp1
149
    ldi    temp1, 0b00011100
150
    rcall  lcd_command
151
    rcall  delay5ms
152
    pop    temp1
153
    ret
154
; Move Cursor Left
155
lcd_lmove_cursor:
156
    push  temp1
157
    ldi    temp1, 0b00010000
158
    rcall  lcd_command
159
    rcall  delay5ms
160
    pop    temp1
161
    ret
162
; Move Cursor Right
163
lcd_rmove_cursor:
164
    push  temp1
165
    ldi    temp1, 0b00010100
166
    rcall  lcd_command
167
    rcall  delay5ms
168
    pop    temp1
169
    ret
170

171
text:  .db    "Start Counter", 0
Gast #5472021
Lesenswert?

Ich habe jetzt mit Atmel Studio 7 mein Programm gedebuggt,
aber da hat alles so funktioniert wie es soll.
An der Hardware kann es aber eigentlich auch nicht liegen,
weil der normale Tastendruck auch funktioniert,
nur der gehaltene Tastendruck funktioniert nicht.
Gast #5472184
Lesenswert?

Der get8key_rep Abschnitt wird doch nur aufgerufen,
wenn die Zero-Flag durch tst gesetzt wurde im
Status Register, also wenn keine Taste gedrückt wird.

Ich denke das geht schon so, da auch der Debugger im Simulator
aus der Schleife ausbrechen konnte.
#5472664
Lesenswert?

In key_state sind nicht genutzte Pins ständig auf 1 gesetzt. Dadurch ist 
Repeat ständig aktiv und Du bekommst in key_rep_press nie die erwarteten 
Werte. Also musst Du vor "tst key_state" alle nicht genutzten Bits 
maskieren und darfst später auch nur die genutzten Bits in key_rep_press 
übernehmen.
Gast #5472974
Lesenswert?

Wie Mario M. um 15:41 schrieb!

Wenn es nicht anders verstanden wird, hier im Detail für Taster auf B0 
(ziemlich wüst allerdings):
1
...
2
    or    key_press, R0
3
 ldi r24,$01
4
 and key_press,r24
5
    tst    key_state
6
.
7
.
8
.
9
    mov    key_rep_press, key_state
10
 ldi r24,$01
11
 and key_rep_press,r24
12
    ldi    key_rep, KEY_REPEAT_NEXT
13
...

Und die Zeiten sind etwas knapp bemessen.
Gast #5473006
Lesenswert?

Ja, so funktioniert das gut,
aber dann kann ich den Port nicht
für andere Sachen benutzen.

Kann es vielleicht sein, dass auch
Probleme an dem Port auftauchen, weil
der Programmer und der Quartz an den PortB
angeschlossen ist?
Gast #5473120
Lesenswert?

Ich habe meinen Code jetzt mal ein wenig angepasst
an die C-Routine von Peter Dannegger.
Jetzt funktioniert eigentlich alles soweit,
jedoch kommt es ab und zu vor bei normalen Tastendrücken,
dass der nicht erkannt wird.

Hier nochmal mein aktualisierter Code:
1
.def  iwr0        = R1
2
.def  iwr1        = R2
3

4
.def  key_state      = R4
5
.def  key_press      = R5
6
.def  key_rep_press    = R6
7
.def  key_rep        = R16
8

9
.def  temp1        = R17
10
.def  temp2        = R18
11
.def  temp3        = R19
12
.def  counter        = R20
13

14
.equ  KEY_PORT      = PORTB
15
.equ  KEY_DDR        = DDRB
16
.equ  KEY_PIN        = PINB
17
.equ  LED          = 1
18
.equ  KEY0        = 0
19
.equ  KEY1        = 1
20
.equ  ALL_KEYS      = (1<<KEY0 | 1<<KEY1)
21

22
.equ  KEY_REPEAT_MASK    = (1<<KEY0 | 1<<KEY1)
23
.equ  KEY_REPEAT_START  = 50
24
.equ  KEY_REPEAT_NEXT    = 20
25

26
.equ  PRESCL_1024      = (1<<CS00 | 1<<CS02)
27

28
.equ  XTAL        = 8000000
29

30
.org 0x0000
31
    rjmp  init
32

33
.org OVF0addr
34
    rjmp  timer_overflow0
35

36
timer_overflow0:
37
    push  temp1
38
    push  R0
39
    in    R0, SREG
40
    push  R0
41

42
    push  R16
43
    ldi    R16, -( XTAL / 1024 * 10 / 1000 + 1 )
44
    out    TCNT0, R16
45
    pop    R16
46

47
get8key:
48
    in    R0, KEY_PIN
49
    com    R0
50
    eor    R0, key_state    ; key changed?
51
    and    iwr0, R0      ; count in iwr0 and iwr1
52
    com    iwr0
53
    and    iwr1, R0
54
    eor    iwr1, iwr0
55
    and    R0, iwr0
56
    and    R0, iwr1
57
    eor    key_state, R0    ;
58
    and    R0, key_state
59
    or    key_press, R0
60
    ldi    temp1, KEY_REPEAT_MASK
61
    and    key_state, temp1
62
    tst    key_state
63
    breq  get8key_rep
64
    dec    key_rep
65
    brne  get8key_finish
66
    mov    key_rep_press, key_state
67
    ldi    key_rep, KEY_REPEAT_NEXT
68
    rjmp  get8key_finish
69

70
get8key_rep:
71
    ldi    key_rep, KEY_REPEAT_START
72

73
get8key_finish:
74
    pop    R0
75
    out    SREG, R0
76
    pop    R0
77
    pop    temp1
78
    reti
79
  
80
.include "lcd-routines.asm"
81

82
init:
83
    ldi    temp1, LOW(RAMEND)
84
    out    SPL, temp1
85
    ldi    temp1, HIGH(RAMEND)
86
    out    SPH, temp1
87

88
    ldi    temp1, ALL_KEYS
89
    com    temp1
90
    out    KEY_DDR, temp1
91

92
    ldi    temp1, ALL_KEYS
93
    out    KEY_PORT, temp1
94

95
    ldi    temp1, PRESCL_1024
96
    out    TCCR0B, temp1
97
    ldi    temp1, 1<<TOIE0
98
    sts    TIMSK0, temp1
99

100
    rcall  lcd_init
101
    rcall  lcd_clear
102

103
    clr    key_state
104
    clr    key_press
105
    clr    key_rep_press
106
    clr    key_rep
107

108
main:
109
    ldi    counter, 0
110
    rjmp  update_lcd
111

112
loop:  
113
    rcall  get_short_key
114
    cpi    temp1, 1<<KEY0
115
    breq  increment
116
    cpi    temp1, 1<<KEY1
117
    breq  decrement
118

119
    rcall  get_long_key
120
    cpi    temp1, 1<<KEY0
121
    breq  increment
122
    cpi    temp1, 1<<KEY1
123
    breq  decrement
124

125
    rjmp  loop
126

127
increment:
128
    inc    counter
129
    rjmp  update_lcd
130

131
decrement:
132
    dec    counter
133

134
update_lcd:
135
    mov    temp1, counter
136
    rcall  lcd_clear
137
    rcall  lcd_number
138
    rjmp  loop
139

140
; normaler Tastendruck
141
get_short_key:
142
    cli
143
    mov    temp1, key_press
144
    clr    key_press
145
    sei
146
    ret
147

148
; Tastendruck gedrückthalten
149
get_long_key:
150
    cli    
151
    mov    temp1, key_rep_press
152
    clr    key_rep_press
153
    sei
154
    ret
155

156
; Left Scroll Display
157
lcd_lscroll:
158
    push  temp1
159
    ldi    temp1, 0b00011000
160
    rcall  lcd_command
161
    rcall  delay5ms
162
    pop    temp1
163
    ret
164

165
; Right Scroll Display
166
lcd_rscroll:
167
    push  temp1
168
    ldi    temp1, 0b00011100
169
    rcall  lcd_command
170
    rcall  delay5ms
171
    pop    temp1
172
    ret
173
; Move Cursor Left
174
lcd_lmove_cursor:
175
    push  temp1
176
    ldi    temp1, 0b00010000
177
    rcall  lcd_command
178
    rcall  delay5ms
179
    pop    temp1
180
    ret
181
; Move Cursor Right
182
lcd_rmove_cursor:
183
    push  temp1
184
    ldi    temp1, 0b00010100
185
    rcall  lcd_command
186
    rcall  delay5ms
187
    pop    temp1
188
    ret
189

190
text:  .db    "Start Counter", 0
#5473188
Lesenswert?

In Peters Routine wird im Interrupt key_state nicht geändert und es 
werden auch nur die repetierenden Bits zurück gegeben:
1
    mov    temp1, key_state
2
    andi   KEY_REPEAT_MASK
3
    breq   get8key_rep
4
    dec    key_rep
5
    brne   get8key_finish
6
    mov    key_rep_press, temp1
7
    ldi    key_rep, KEY_REPEAT_NEXT
8
    rjmp   get8key_finish

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren