Hallo zusammen,
ich bin fleißig dabei mich durch das Tutorial zu arbeiten.
Dabei habe ich ein LED Lauflicht programmiert, was soweit funktioniert.
Folgendes soll der Code machen:
-- 5 LED ansteuern als Lauflicht
-- über einen Taster den Speed einstellen 1-9
-- Anzeige der Speed auf einem 7-Seqment
Folgendes macht der Code:
-- Die 5 LED werden als Lauflicht angezeigt
-- Tastendruck wird erkannt und Speed erhöht (die Zahl des Speed, ist
aber umgekehrt und wird dadurch langsamer. Soll aber im moment egal
sein)
-- Anzeige des Speed als Zahl
Was der Code noch falsch macht:
-- Die Tasten lassen sich nicht entprellen
-- Der Speed kann auch größer werden als 9 (es fehlt/funktioniert nicht
die begrenzung zwischen 1-9)
Ich packe mal den Code rein.
Folgende Fragen hab ich:
-- Warum funktioniert der Code nicht mehr, wenn ich in der Interrupt
Methode mit push das temp Register weg sichere?
-- Was muss ich ändern, das bei einem Tastendruck nur eine
Flanke/Entprellen funktioniert. Wenn ich den Code auskommentiere, dann
erkennt er mir keinen Tastendruck mehr.
-- Was könnte ich noch verbessern an dem Code ( Tips zum nachlesen )
-- Was ist totaler schwachsinn und sollte ich total anders lösen.
Nur keine Scheu zeigen. Haut rein mit der Kritik. Kann das vertragen und
dadurch den Stil verbessern.
Danke an alle.
Grüße
Stephan
1
/*
2
* LED_Lauflicht.asm
3
*
4
* Created: 17.09.2011 22:55:06
5
* Author: stephan
6
*/
7
8
.include "m8def.inc"
9
10
; definiere Register
11
.def zero = r1
12
.def temp = r16 ; Ein Temporäres Register
13
.def temp2 = r26 ; Ein Temporäres Register
14
.def lauflicht = r17 ; Das Register, für das Lauflicht
15
.def SubCount = r18 ; Timer Interrupt zwischen Variable
16
.def key_now = r19 ; Der aktuelle Tasterstatus
17
.def speed = r20 ; Die Geschwindigkeit der Lauflicht
18
.def key_old = r2 ; Der davor Tasterstatus
19
20
; definiere Ports
21
.equ led_port = PORTB ; Der Port, an dem die LED angeschlossen sind
22
.equ led_ddr = DDRB ; Die Datenrichtung der LED
23
24
.equ taster_port = PORTC ; Der Port an dem die Taster angeschlossen sind
25
.equ taster_ddr = DDRC ; Die Datenrichtung der Taster
26
.equ taster_in = PINC ; Eingabe der Taster
27
28
.equ seq_port = PORTD ; Der Port an dem die Anzeige dran ist
29
.equ seq_ddr = DDRD ; Die Datenrichtung der Anzeige
30
31
; definiere Interrupt
32
.org 0x0000
33
rjmp main ; Reset Handler
34
.org OVF0addr
35
rjmp timer0_overflow ; Timer Overflow Handler
36
37
; Der Einstiegspunkt in die Anwendung
38
main:
39
rcall initialize ; Initialisiere
40
rjmp loop ; Springe in den Programmablauf
41
42
; Die Verarbeitungsschleife des µC
43
; ################################
44
loop:
45
; Lauflicht ausgeben
46
rcall ausgabe_led ; Gehe zur Ausgabe des Lauflicht
47
48
rcall ausgabe_speed ; Gibt den Speed auf der 7-Seqment Anzeige aus
49
50
; Tasten auswerten
51
in key_now, taster_in ; Hole Tasten
52
;mov temp2, key_now ; erstmal in temp sichern
53
;eor key_now, key_old ; mit dem vorherigen zustand vergleichen XOR
54
;mov key_old, temp2 ; und den jetzigen Zustand für den nächsten
55
; Schleifendurchlauf als alten Zustand merken
56
;breq loop ; Das Ergebnis des XOR auswerten:
57
;and temp2, key_now
58
;brne loop
59
60
cpi key_now, 0b00111110 ; Taste 1 gedrückt
61
breq geschwindigkeit ; springe zu Methode geschwindigkeit
62
63
rjmp loop
64
65
; Ändert die Geschwindigkeit der Lauflicht
66
; ########################################
67
geschwindigkeit:
68
inc speed ; speed +1
69
ldi temp2, 9
70
cpc speed, temp2
71
brne return
72
ldi speed, 5
73
reti
74
75
; Gibt das LED Lauflicht auf den Ausgang
76
; ######################################
77
ausgabe_led:
78
ldi ZL, LOW(Codes*2) ; die Startadresse der Tabelle in den
79
ldi ZH, HIGH(Codes*2) ; Z-Pointer laden
80
81
mov temp, lauflicht ; die wortweise Adressierung der Tabelle
82
add temp, lauflicht ; berücksichtigen
83
84
add ZL, temp ; und ausgehend vom Tabellenanfang
85
adc ZH, zero ; die Adresse des Code Bytes berechnen
86
87
lpm ; dieses Code Byte in das Register r0 laden
88
89
out led_port, r0 ; und ausgeben
90
91
reti
92
93
; Gibt den Speed als Zahl auf das 7-Sequment
94
; ##########################################
95
ausgabe_speed:
96
ldi ZL, LOW(Codes_Seqment*2) ; die Startadresse der Tabelle in den
97
ldi ZH, HIGH(Codes_Seqment*2) ; Z-Pointer laden
98
99
mov temp2, speed ; die wortweise Adressierung der Tabelle
100
add temp2, speed ; berücksichtigen
101
102
add ZL, temp2 ; und ausgehend vom Tabellenanfang
103
adc ZH, zero ; die Adresse des Code Bytes berechnen
104
105
lpm ; dieses Code Byte in das Register r0 laden
106
107
out seq_port, r0 ; und ausgeben
108
reti
109
110
; Initialisiere den Controller
111
; ###########################
112
initialize:
113
114
; Stackpointer initialisieren
115
ldi temp, HIGH(RAMEND)
116
out SPH, temp
117
ldi temp, LOW(RAMEND)
118
out SPL, temp
119
120
; LED als Ausgang festlegen
121
ldi temp, 0xFF
122
out led_ddr, temp ; Datenrichtung festlegen auf Ausgang
123
ldi temp, 0xFF
124
out led_port, temp ; LED Ausgänge ausschalten
125
126
; Taster als Eingänge festlegen
127
ldi temp, 0x00
128
out taster_ddr, temp ; Datenrichtung festlegen auf Eingang
Einfach mal ein paar Sachen:
'reti' ist für den Rücksprung aus IRQs, für 'normale' subroutinen
solltest du 'ret' nehmen (Ist hier egal, aber besser direkt nicht
angewöhnen).
'cpc' verwendet auch das Carry-Flag, 'cp' wäre hier richtig.
mit 'push temp' sicherst du nicht das SREG, sondern nur temp. push temp,
in temp, SREG und umgedreht vor dem 'reti' würde das machen, aber dann
musst du auch bei 'return:' einfügen.
Mark
HI
>return:> ; hier wird nix gemacht, außer sauber aus einer Methode zurück springen> reti
Eben nicht. Du springst aus deiner Interrupt-Routine dorthin. Wenn du
vorher temp gepusht hast stimmt der Stack nicht mehr -> Nirvana.
Außerdem sicherst du SREG nicht. Wird noch lustige Effekte geben.
MfG Spess
Danke schonmal, für die Tips
Mark L. schrieb:> Einfach mal ein paar Sachen:> 'reti' ist für den Rücksprung aus IRQs, für 'normale' subroutinen> solltest du 'ret' nehmen (Ist hier egal, aber besser direkt nicht> angewöhnen).
Habe ich geändert und merke mir das.
> 'cpc' verwendet auch das Carry-Flag, 'cp' wäre hier richtig.> mit 'push temp' sicherst du nicht das SREG, sondern nur temp. push temp,> in temp, SREG und umgedreht vor dem 'reti' würde das machen, aber dann> musst du auch bei 'return:' einfügen.
Das versuche ich gerade. Lese da aber nochmal den Teil im Tutorial
durch. Hab dann wohl etwas übersehen dabei.
Auch Dir Danke schonmal.
spess53 schrieb:> HI>>>return:>> ; hier wird nix gemacht, außer sauber aus einer Methode zurück springen>> reti>>> Eben nicht. Du springst aus deiner Interrupt-Routine dorthin. Wenn du> vorher temp gepusht hast stimmt der Stack nicht mehr -> Nirvana.> Außerdem sicherst du SREG nicht. Wird noch lustige Effekte geben.
Ich habe das mal so umgeschrieben. Wäre das so dann besser? Bin mir da
nun nicht ganz sicher. In der Return Methode schreibe ich dann SREG und
temp auch wieder zurück.
1
; Der Timer Overflow Interrupt
2
; ############################
3
timer0_overflow:
4
push temp ; Register sichern
5
in temp, SREG
6
7
inc SubCount ; wenn das nicht der 15. Interrupt
8
cp SubCount, speed ; ist, dann passiert nix
9
brne return
10
11
; Überlauf
12
clr SubCount ; SubCount zurücksetzen
13
14
inc lauflicht ; decrementiere lauflicht
15
cpi lauflicht, 6
16
brne return
17
18
ldi lauflicht, 0
19
out SREG, temp
20
pop temp ; Register zurück laden
21
reti
22
23
; allgemeiner Return nach entscheidungen
24
; ######################################
25
return:
26
; hier wird nix gemacht, außer sauber aus einer Methode zurück springen
spess53 schrieb:> Hi>>>Ich habe das mal so umgeschrieben. Wäre das so dann besser?>> Nicht wirklich. Mach es doch einfach so:>>
1
> ....
2
> ldi lauflicht, 0
3
>
4
> return:
5
> out SREG, temp
6
> pop temp ; Register zurück laden
7
> reti
8
>
>> Oder willst du bei jeder Änderung mehrere Stellen umschreiben?>> MfG Spess
Verstehe ich jetzt nicht ganz. Hab mal meine Gedanken in den Code mit
rein geschrieben
1
; Der Timer Overflow Interrupt
2
; ############################
3
timer0_overflow:
4
push temp ; Register sichern
5
in temp, SREG
6
7
inc SubCount ; wenn das nicht der 15. Interrupt
8
cp SubCount, speed ; ist, dann passiert nix
9
brne return <- Hier springe ich doch in return, weil der vergleich nicht gleich war.
10
11
; Überlauf
12
clr SubCount ; SubCount zurücksetzen
13
14
inc lauflicht ; decrementiere lauflicht
15
cpi lauflicht, 6
16
brne return <- Hier springe ich auch zurück, weil der Zähler noch nicht die 6 erreicht hat.
17
18
ldi lauflicht, 0
19
20
<< Hier muss ich doch genauso temp und SREG zurück schreiben, weil wenn die obigen beiden vergleiche ( == ) waren, dann springen die doch nie in return. Spätestens da wäre dann doch der Fehler wieder vorprogrammiert? >>
21
out SREG, temp
22
pop temp ; Register zurück laden
23
reti
24
25
26
; Return Methode, um damit sauber aus einer Interrupt Routine zu springen
HI
Du hast zwei identische Codeteile. Wozu?
Entweder wird (in meiner Variante) zum Label return gesprungen oder der
Code nach
ldi lauflicht, 0
ausgeführt.
MfG Spess
Jetzt verstehe ich gerade garnichts mehr.
Heist das, der führt den Code dann von oben nach unten aus, bis der
irgendwann ein ret oder reti findet, egal ob da eine Sprungmarke wie
return: noch dazwischen steht?
Hi
>Heist das, der führt den Code dann von oben nach unten aus, bis der>irgendwann ein ret oder reti findet, egal ob da eine Sprungmarke wie>return: noch dazwischen steht?
Bingo. Ein Label beeinflusst den Programmablauf nicht.
MfG Spess
spess53 schrieb:> Hi>>>Heist das, der führt den Code dann von oben nach unten aus, bis der>>irgendwann ein ret oder reti findet, egal ob da eine Sprungmarke wie>>return: noch dazwischen steht?>> Bingo. Ein Label beeinflusst den Programmablauf nicht.>> MfG Spess
Okay, dann ist das klar :)
Man man, wenn man aus der OOP Welt zurück in die Basic (Schneider) Welt
versetzt wird, muss man sich da erstmal wieder total umgewöhnen.
Dann danke ich mal, das kann der entscheidende Hinweis sein, das ich den
Programmcode mit anderen Augen ansehe.
Grüße
Stephan
Hi
>Okay, dann ist das klar :)>Man man, wenn man aus der OOP Welt zurück in die Basic (Schneider) Welt>versetzt wird, muss man sich da erstmal wieder total umgewöhnen.
Der umgedrehte Weg hat auch seine Tücken.
MfG Spess