Forum: Mikrocontroller und Digitale Elektronik Ampelschaltung funktioniert nicht


von Sven M. (Gast)


Lesenswert?

Hallo leute ich habe ein Problem undzwar programmier ich mir gerade ne 
einfache ampelschaltung für nen attiny13
mein code is volgender:
1
.include "tn13def.inc" ;Definitionsdatei für den Prozessor typ
2
.def temp1 = r18
3
.def temp2 = r19
4
.ifndef XTAL
5
.equ XTAL = 1000000
6
.endif
7
ldi r16,(1<<PB2)|(1<<PB1)|(1<<PB0)|(1<<PB3)|(0<<PB4)|(0<<PB5)
8
ldi r17,(1<<PB5)|(1<<PB4)
9
out DDRB,r16
10
out PORTB,r17
11
12
main:
13
  sbis PINB,4
14
    rjmp greensof
15
  sbis PINB,5
16
    rjmp green
17
  rjmp red
18
19
rjmp main ;Sprung zur marke "ende" -> endlosschleife
20
21
delay5s:                               ; 5ms Pause
22
; ============================= 
23
;   Warteschleifen-Generator 
24
;     5000000 Zyklen:
25
; ----------------------------- 
26
; warte 4999995 Zyklen:
27
          ldi  R17, $21
28
WGLOOP0:  ldi  R18, $D6
29
WGLOOP1:  ldi  R19, $EB
30
WGLOOP2:  dec  R19
31
          brne WGLOOP2
32
          dec  R18
33
          brne WGLOOP1
34
          dec  R17
35
          brne WGLOOP0
36
; ----------------------------- 
37
; warte 3 Zyklen:
38
          ldi  R17, $01
39
WGLOOP3:  dec  R17
40
          brne WGLOOP3
41
; ----------------------------- 
42
; warte 2 Zyklen:
43
          nop
44
          nop
45
; ============================= 
46
ret
47
                    ; wieder zurück
48
49
delay10s: 
50
; ============================= 
51
;   Warteschleifen-Generator 
52
;     10000000 Zyklen:
53
; ----------------------------- 
54
; warte 9999990 Zyklen:
55
          ldi  R17, $42
56
WGLOOP01:  ldi  R18, $D6
57
WGLOOP11:  ldi  R19, $EB
58
WGLOOP21:  dec  R19
59
          brne WGLOOP21
60
          dec  R18
61
          brne WGLOOP11
62
          dec  R17
63
          brne WGLOOP01
64
; ----------------------------- 
65
; warte 9 Zyklen:
66
          ldi  R17, $03
67
WGLOOP31:  dec  R17
68
          brne WGLOOP31
69
; ----------------------------- 
70
; warte 1 Zyklus:
71
          nop
72
; ============================= 
73
ret     ;wieder zurück
74
75
76
green:
77
rcall delay5s
78
ldi r17,(1<<PB0)|(0<<PB1)|(0<<PB2)
79
out PORTB,r17
80
rcall delay10s
81
ldi r17,(0<<PB0)|(1<<PB1)|(1<<PB2)
82
out PORTB,r17
83
rcall delay5s
84
ret
85
86
red:
87
ldi r17,(0<<PB0)|(1<<PB1)|(1<<PB2)
88
out PORTB,r17
89
ret
90
91
greensof:
92
ldi r17,(1<<PB0)|(0<<PB1)
93
out PORTB,r17
94
ret

so normal soll die ampel immer rot sein wenn kiener der ports gegen gnd 
liegt aber die ampel schaltet immer zeischen grün und rot hin und her 
und es ist ihr egal ob ich einen der ports an gnd lege oder nicht.

wo habe ich den fehler gemacht?

von holger (Gast)


Lesenswert?

>  rjmp red

>red:
>ldi r17,(0<<PB0)|(1<<PB1)|(1<<PB2)
>out PORTB,r17
>ret

Wie wäre es mit einem rcall red?

von Sven M. (Gast)


Lesenswert?

habe jetzt aus rjamp rcall gemacht aber sie springt noch immer hin und 
her und wenn ich Port 4 an gnd halte den leuchtet keine lede mehr danach 
wiederum beide dann nur grün und denn wieder hin und her

von holger (Gast)


Lesenswert?

>habe jetzt aus rjamp rcall gemacht aber sie springt noch immer hin und
>her

Ja, du hast noch mehr rjmps mit einem ret beendet;) Der arme Stack.

von Sven M. (Gast)


Lesenswert?

1
.include "tn13def.inc" ;Definitionsdatei für den Prozessor typ
2
.def temp1 = r18
3
.def temp2 = r19
4
.ifndef XTAL
5
.equ XTAL = 1000000
6
.endif
7
ldi r16,(1<<PB2)|(1<<PB1)|(1<<PB0)|(1<<PB3)|(0<<PB4)|(0<<PB5)
8
ldi r17,(1<<PB5)|(1<<PB4)
9
out DDRB,r16
10
out PORTB,r17
11
12
main:
13
  sbis PINB,4
14
    rcall greensof
15
  sbis PINB,5
16
    rcall green
17
  rcall red
18
19
rjmp main ;Sprung zur marke "ende" -> endlosschleife
20
21
delay5s:                               ; 5ms Pause
22
; ============================= 
23
;   Warteschleifen-Generator 
24
;     5000000 Zyklen:
25
; ----------------------------- 
26
; warte 4999995 Zyklen:
27
          ldi  R17, $21
28
WGLOOP0:  ldi  R18, $D6
29
WGLOOP1:  ldi  R19, $EB
30
WGLOOP2:  dec  R19
31
          brne WGLOOP2
32
          dec  R18
33
          brne WGLOOP1
34
          dec  R17
35
          brne WGLOOP0
36
; ----------------------------- 
37
; warte 3 Zyklen:
38
          ldi  R17, $01
39
WGLOOP3:  dec  R17
40
          brne WGLOOP3
41
; ----------------------------- 
42
; warte 2 Zyklen:
43
          nop
44
          nop
45
; ============================= 
46
ret
47
48
delay10s: 
49
; ============================= 
50
;   Warteschleifen-Generator 
51
;     10000000 Zyklen:
52
; ----------------------------- 
53
; warte 9999990 Zyklen:
54
          ldi  R17, $42
55
WGLOOP01:  ldi  R18, $D6
56
WGLOOP11:  ldi  R19, $EB
57
WGLOOP21:  dec  R19
58
          brne WGLOOP21
59
          dec  R18
60
          brne WGLOOP11
61
          dec  R17
62
          brne WGLOOP01
63
; ----------------------------- 
64
; warte 9 Zyklen:
65
          ldi  R17, $03
66
WGLOOP31:  dec  R17
67
          brne WGLOOP31
68
; ----------------------------- 
69
; warte 1 Zyklus:
70
          nop
71
; ============================= 
72
ret
73
74
green:
75
rcall delay5s
76
ldi r17,(1<<PB0)|(0<<PB1)|(0<<PB2)
77
out PORTB,r17
78
rcall delay10s
79
ldi r17,(0<<PB0)|(1<<PB1)|(1<<PB2)
80
out PORTB,r17
81
rcall delay5s
82
ret
83
84
red:
85
ldi r17,(0<<PB0)|(1<<PB1)|(1<<PB2)
86
out PORTB,r17
87
ret
88
89
greensof:
90
ldi r17,(1<<PB0)|(0<<PB1)
91
out PORTB,r17
92
ret

wo ist da denn der fehler?

ich stehe voll aufen schlauch

von Karl H. (kbuchegg)


Lesenswert?

Hmm

Der Tiny13 ist doch ein älterer Tiny.
Bei denen wurde doch der Stackpointer noch nicht automatisch 
initialisiert.

Schaden kann es auf keinen Fall, wenn man dem Stackpointer erst mal 
etwas vernünftiges zuweist.
1
.include "tn13def.inc" ;Definitionsdatei für den Prozessor typ
2
.def temp1 = r18
3
.def temp2 = r19
4
.ifndef XTAL
5
.equ XTAL = 1000000
6
.endif
7
8
       ldi r16, low(RAMEND)
9
       out SPL,r16
10
11
       ldi r16,(1<<PB2)|(1<<PB1)|(1<<PB0)|(1<<PB3)|(0<<PB4)|(0<<PB5)
12
       ldi r17,(1<<PB5)|(1<<PB4)
13
       out DDRB,r16
14
       out PORTB,r17
15
16
       ....


Wenn ich noch einen Vorschlag machen darf:
Sortiere deinen Code um. Die Delay Funktionen müssen da nicht mitten im 
Code stehen. Wenn du diese Blöcke ans Programmende verschiebst, dann 
hast du Hauptschleife und die einzelnen Unterprogramme physisch näher 
beieinander und man muss nicht dauernd rauf/runter scrollen um sich 
anzusehen, was wann passieren soll. Zumal deine nicht existente 
Codeformatierung die Sache auch nicht gerade leichter zu lesen und zu 
verstehen macht.
1
.include "tn13def.inc" ;Definitionsdatei für den Prozessor typ
2
.def temp1 = r18
3
.def temp2 = r19
4
.ifndef XTAL
5
.equ XTAL = 1000000
6
.endif
7
8
9
       ldi r16, low(RAMEND)
10
       out SPL,r16
11
12
       ldi r16,(1<<PB2)|(1<<PB1)|(1<<PB0)|(1<<PB3)|(0<<PB4)|(0<<PB5)
13
       ldi r17,(1<<PB5)|(1<<PB4)
14
       out DDRB,r16
15
       out PORTB,r17
16
17
main:
18
  sbis PINB,4
19
    rcall greensof
20
  sbis PINB,5
21
    rcall green
22
  rcall red
23
24
rjmp main ;Sprung zur marke "ende" -> endlosschleife
25
26
green:
27
rcall delay5s
28
ldi r17,(1<<PB0)|(0<<PB1)|(0<<PB2)
29
out PORTB,r17
30
rcall delay10s
31
ldi r17,(0<<PB0)|(1<<PB1)|(1<<PB2)
32
out PORTB,r17
33
rcall delay5s
34
ret
35
36
red:
37
ldi r17,(0<<PB0)|(1<<PB1)|(1<<PB2)
38
out PORTB,r17
39
ret
40
41
greensof:
42
ldi r17,(1<<PB0)|(0<<PB1)
43
out PORTB,r17
44
ret
45
46
delay5s:                               ; 5ms Pause
47
; ============================= 
48
;   Warteschleifen-Generator 
49
;     5000000 Zyklen:
50
; ----------------------------- 
51
; warte 4999995 Zyklen:
52
          ldi  R17, $21
53
WGLOOP0:  ldi  R18, $D6
54
WGLOOP1:  ldi  R19, $EB
55
WGLOOP2:  dec  R19
56
          brne WGLOOP2
57
          dec  R18
58
          brne WGLOOP1
59
          dec  R17
60
          brne WGLOOP0
61
; ----------------------------- 
62
; warte 3 Zyklen:
63
          ldi  R17, $01
64
WGLOOP3:  dec  R17
65
          brne WGLOOP3
66
; ----------------------------- 
67
; warte 2 Zyklen:
68
          nop
69
          nop
70
; ============================= 
71
ret
72
73
delay10s: 
74
; ============================= 
75
;   Warteschleifen-Generator 
76
;     10000000 Zyklen:
77
; ----------------------------- 
78
; warte 9999990 Zyklen:
79
          ldi  R17, $42
80
WGLOOP01:  ldi  R18, $D6
81
WGLOOP11:  ldi  R19, $EB
82
WGLOOP21:  dec  R19
83
          brne WGLOOP21
84
          dec  R18
85
          brne WGLOOP11
86
          dec  R17
87
          brne WGLOOP01
88
; ----------------------------- 
89
; warte 9 Zyklen:
90
          ldi  R17, $03
91
WGLOOP31:  dec  R17
92
          brne WGLOOP31
93
; ----------------------------- 
94
; warte 1 Zyklus:
95
          nop
96
; ============================= 
97
ret

funktional ist das völlig gleichwertig, aber arbeitstechnisch ist es 
viel einfacher damit zu arbeiten. Und warum die delay10s nicht einfach 
aus 2 Aufrufen von delay5s besteht, weiß auch nur der Programmierer :-)
1
          ....
2
delay10s:
3
          rcall delay5s
4
          rcall delay5s
5
          ret

von otto der erste (Gast)


Lesenswert?

Karl heinz Buchegger schrieb:
> Und warum die delay10s nicht einfach
> aus 2 Aufrufen von delay5s besteht, weiß auch nur der Programmierer :-)

Es ist eben einfacher, blind und gedankenlos sowas 
http://www.home.unix-ag.org/tjabo/avr/AVRdelayloop.html zu bedienen, als 
auch nur kurzzeitig sein Kopf einzusetzen (siehe auch oben: mehr als 
einmal rjump vs. ret).

von Ben _. (burning_silicon)


Lesenswert?

worüber ihr euch aufregt... ist es nicht egal womit man 5 bzw. 10 
sekunden rechenzeit vernichtet, wenn der flash groß genug ist? sorry 
aber ich hasse es wenn man immer über den programmierstil anderer 
herziehen muß. solange wie's funktioniert ist doch gut. als tip kann man 
sowas ja anmerken, aber doch nicht bitte gleich als grundfalsch oder 
bescheuert hinstellen.

von Karl H. (kbuchegg)


Lesenswert?

Ben _ schrieb:
> worüber ihr euch aufregt... ist es nicht egal womit man 5 bzw. 10
> sekunden rechenzeit vernichtet, wenn der flash groß genug ist?

Wenn der Programmierer den Überblick verliert, ist es nicht mehr egal

> sorry
> aber ich hasse es wenn man immer über den programmierstil anderer
> herziehen muß. solange wie's funktioniert ist doch gut.

"Funktioniert" ist nicht alles

> als tip kann man
> sowas ja anmerken

genau so hab ich es auch gemeint.
Oder was ist an der Einleitung des Abschnitts nicht zu verstehen:

<Zitat>
Wenn ich noch einen Vorschlag machen darf:
</Zitat>

> , aber doch nicht bitte gleich als grundfalsch oder
> bescheuert hinstellen.

Hat niemand gemacht.

von Ben _. (burning_silicon)


Lesenswert?

also die antwort von unserem lieben gast otto fand ich schon ziemlich 
grenzwertig. "auch nur kurzzeitig seinen kopf einzusetzen" hat für mich 
nichts mit dem "problem" zu tun wie man am besten die funktion 
aufsplittet oder auch nicht.

und wenn der programmierer in seinem eigenen programm den überblick 
verliert macht er mehr als das verkehrt und merkts hoffentlich. meiner 
meinung nach eignet sich jeder einen programmierstil an, mit dem er 
selber halt am besten klarkommt. die einhaltung bestimmter formen halte 
ich nur dann für wichtig wenn andere mit dem quellcode klarkommen 
müssen, etwa wenn ein programm von mehrere programmierern geschrieben 
wird.

ich z.b. würde meine funktion für sowas variabel gestalten wenn ich 
mehrere zeitintervalle brauche, etwa

LDI r16,10
RCALL wait
für eine pause von 10 sekunden.

das finde ich aber nicht schlechter oder besser als andere lösungen 
solange sie im gleichen rahmen funktionieren. es finden sich bestimmt 
sogar leute die mich zusammenhauen weil ich "unnötigerweise" ein 
register verwende.

ok wollte auch keine diskussion vom zaun brechen, sondern nur darauf 
aufmerksam machen, daß man sich auf die wirklichen probleme 
konzentrieren sollte als auf kleinigkeiten im programmierstil. also 
**prost!**

von oldmax (Gast)


Lesenswert?

Hi
Auch wenn der Hinweis auf die Zuweisung der Stackadresse schon genannt 
ist, möchte ich sie trotzdem wiederholen. Außerdem schreibst du von 
Portpins, die gegen GND gschaltet werden und dann die Ampel auslösen. 
Ich sehe aber keinen In-Befehl. Irgendwie sollte aber der Controller 
schon mitbekommen, wenn sich in seiner Peripherie etwas ändert, und so 
solltest du schon sagen, das er sich den Pin mal ansehen soll. Ich kenne 
zwar den Attiny13 nicht, denke aber, das es da auch einen In-Befehl 
gibt.
Ansonsten hilft bei der Analyse eines Problemes nur logisch vorzugehen 
und das Verhalten zu durchleuchten. Sicher ist, das er genau das macht, 
was du ihm befohlen hast.....   auch wenn du etwas ganz anderes 
wolltest.
Gruß oldmax

von Karl H. (kbuchegg)


Lesenswert?

oldmax schrieb:

> Ich sehe aber keinen In-Befehl. Irgendwie sollte aber der Controller
> schon mitbekommen, wenn sich in seiner Peripherie etwas ändert, und so
> solltest du schon sagen, das er sich den Pin mal ansehen soll. Ich kenne
> zwar den Attiny13 nicht, denke aber, das es da auch einen In-Befehl
> gibt.

SBIS bzw. SBIC machen das.
Skip If Bit (in I/O Register) ist Set/Clear

So gesehen ist das schon in Ordnung.

Ohne das jetzt simuliert oder getestet zu haben: Ich denke es ist der 
fehlende Stackpointer wodurch alle RET ins Leere gehen.

von Sven M. (Gast)


Lesenswert?

hallo ich bis nochmal undzwar sehe ich es so das doch zu jedem rcall 
oder rjmp ein ret am ende der aufgerufenen funktion kommt oder ist das 
falsch?

von Skua (Gast)


Lesenswert?

Sven M. schrieb:
> hallo ich bis nochmal undzwar sehe ich es so das doch zu jedem rcall
> oder rjmp ein ret am ende der aufgerufenen funktion kommt oder ist das
> falsch?

Nur bei call.
Bei jmp muss auch mit jmp weitergemacht werden.

von Sven M. (Gast)


Lesenswert?

sprich wenn ich in eine funktion springe muss ich auch wieder am ende 
mit z.B. rjmp main aus ihr raus springen?

von Sven M. (Gast)


Lesenswert?

soo hier jetzt mal der überarbeitete code:
1
.include "tn13def.inc" ;Definitionsdatei für den Prozessor typ
2
3
.def temp1 = r18
4
.def temp2 = r19
5
6
.ifndef XTAL
7
  .equ XTAL = 1000000
8
.endif00
9
10
11
ldi r16, low(RAMEND)
12
       out SPL,r16
13
14
ldi r16,0b00000111
15
  out DDRB,r16
16
17
ldi r17,0b00011000
18
  out PORTB,r17
19
20
main:
21
  sbis PINB,3
22
    rcall green
23
  sbis PINB,4
24
    rcall greensof
25
  rcall red
26
rjmp main ;Sprung zur marke "ende" -> endlosschleife
27
28
green:
29
  rcall delay5s
30
31
  ldi r17,(1<<PB0)|(0<<PB1)|(0<<PB2)
32
    out PORTB,r17
33
34
  rcall delay10s
35
36
        ldi r17,(0<<PB0)|(1<<PB1)|(1<<PB2)
37
                out PORTB,r17
38
39
        rcall delay5s
40
41
  ret
42
43
red:
44
  ldi r18,(0<<PB0)|(1<<PB1)|(1<<PB2)
45
    out PORTB,r17
46
  ret
47
48
greensof:
49
  ldi r19,(1<<PB0)|(0<<PB1)|(0<<PB2)
50
    out PORTB,r17
51
  ret
52
53
delay10s: 
54
; ============================= 
55
;   Warteschleifen-Generator 
56
;     10000000 Zyklen:
57
; ----------------------------- 
58
; warte 9999990 Zyklen:
59
           ldi  R20, $42
60
WGLOOP01:  ldi  R21, $D6
61
WGLOOP11:  ldi  R22, $EB
62
WGLOOP21:  dec  R22
63
            brne WGLOOP21
64
           dec  R21
65
            brne WGLOOP11
66
           dec  R20
67
            brne WGLOOP01
68
; ----------------------------- 
69
; warte 9 Zyklen:
70
           ldi  R20, $03
71
WGLOOP31:  dec  R20
72
            brne WGLOOP31
73
; ----------------------------- 
74
; warte 1 Zyklus:
75
           nop
76
; ============================= 
77
ret
78
79
delay5s:                               ; 5ms Pause
80
; ============================= 
81
;   Warteschleifen-Generator 
82
;     5000000 Zyklen:
83
; ----------------------------- 
84
; warte 4999995 Zyklen:
85
          ldi  R23, $21
86
WGLOOP0:  ldi  R24, $D6
87
WGLOOP1:  ldi  R25, $EB
88
WGLOOP2:  dec  R25
89
           brne WGLOOP2
90
          dec  R24
91
           brne WGLOOP1
92
          dec  R23
93
           brne WGLOOP0
94
; ----------------------------- 
95
; warte 3 Zyklen:
96
          ldi  R23, $01
97
WGLOOP3:  dec  R23
98
           brne WGLOOP3
99
; ----------------------------- 
100
; warte 2 Zyklen:
101
          nop
102
          nop
103
; ============================= 
104
ret

von Karl H. (kbuchegg)


Lesenswert?

Sven M. schrieb:
> sprich wenn ich in eine funktion springe muss ich auch wieder am ende
> mit z.B. rjmp main aus ihr raus springen?

Genau.

RJMP springt einfach irgendwo hin. Punkt. Mehr gibt es dazu nicht zu 
sagen.

Aber RCALL und RET gehören zusammen.

RCALL springt irgendwo hin UND speichert sich die Adresse von wo 
weggesprungen wurde auf dem Stack ab. Wird dann ein RET ausgeführt, so 
holt sich der RET diese Adresse wieder vom Stack und führt einen Sprung 
dorthin aus. Der RET springt also wieder dorthin zurück, von wo der 
RCALL hergekommen ist.

Allerdings: Der RET weiß nichts von einem RCALL. Er holt sich einfach 
Bytes vom Stack, interpretiert die als Adresse und springt dorthin. Es 
gibt nämlich auch noch andere Möglichkeiten wie man auf dem Stack etwas 
ablegen kann, nicht nur RCALL. Das heißt, man muss dann aufpassen, dass 
dieser Mechanismus nicht durcheinander kommt. Der RET passt da nicht 
darauf auf.

von Peter D. (peda)


Lesenswert?

Zeig dochmal den Schaltplan.

Oder erzähl mal, wo was angeschlossen ist und wo gegen.
Hast Du Widerstände in Reihe zu den LEDs?
Hast Du Pullups an den Tasten?


Der ATtiny13 läuft übrigens mit 1,2MHz und der Stack ist nach dem Reset 
schon richtig gesetzt.


Peter

von Sven M. (Gast)


Lesenswert?

also PB4 Taster gegen GND PB3 andere µC entweder gegen GND oder VCC 
pullups sind doch aktiviert...

LED's:
VCC->R1,5K->LED Rot 2mA->PB0
VCC->R1,5K->LED Grün 2mA->PB1

PB2 Ausgang zu anderem µC

von Karl H. (kbuchegg)


Lesenswert?

Ach.
An den Kopf klatsch.

Du brauchst natürlich die Pullup an den Eingängen.

Nur:

zb Hier
red:
  ldi r18,(0<<PB0)|(1<<PB1)|(1<<PB2)
    out PORTB,r17
  ret

schaltest du dir irrtümlich die Pullups wieder weg.

Damit sind dann die Eingänge offen und alles mögliche kann passieren.

Ein klassischer Fehler, wenn man nicht genau Buch darüber führt, welche 
Portbits welchen Zustand haben MÜSSEN und sich nicht ändern dürfen. Bei 
dir ist es eben PORTB, PB4 und PB3 die 1 sein müssen.

von Peter D. (peda)


Lesenswert?

Sven M. schrieb:
> pullups sind doch aktiviert...

Nö.

Vielleicht zu Anfang mal kurz.
Aber alle nachfolgenden OUT setzen nur PB0,1 oder 2.


Peter

von Sven M. (Gast)


Lesenswert?

mich selber hau

ja is ja klar alle anderen nich gesetzten bits werden denn ja 0 und so 
die pullups wieder deaktiviert -.-

jaa... *guten morgen XD

von Sven M. (Gast)


Lesenswert?

soo wenn ich jetzt nicht wieder irgend was verpasst habe XD
sollte es so schon gut aussehen:
1
.include "tn13def.inc" ;Definitionsdatei für den Prozessor typ
2
3
.def temp1 = r18
4
.def temp2 = r19
5
6
.ifndef XTAL
7
  .equ XTAL = 1000000
8
.endif
9
10
11
ldi r16, low(RAMEND)
12
       out SPL,r16
13
14
ldi r16,(1<<PB0)|(1<<PB1)|(1<<PB2)|(0<<PB3)|(0<<PB4)
15
  out DDRB,r16
16
17
ldi r17,(0<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)
18
  out PORTB,r17
19
20
main:
21
  sbis PINB,3
22
    rcall green
23
  sbis PINB,4
24
    rcall greensof
25
  rcall red
26
rjmp main ;Sprung zur marke "ende" -> endlosschleife
27
28
green:
29
  rcall delay5s
30
31
  ldi r17,(1<<PB0)|(0<<PB1)|(0<<PB2)|(1<<PB3)|(1<<PB4)
32
    out PORTB,r17
33
34
  rcall delay10s
35
36
  ret
37
38
red:
39
  ldi r18,(0<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)
40
    out PORTB,r17
41
  ret
42
43
greensof:
44
  ldi r19,(1<<PB0)|(0<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)
45
    out PORTB,r17
46
  ret
47
48
delay10s: 
49
; ============================= 
50
;   Warteschleifen-Generator 
51
;     10000000 Zyklen:
52
; ----------------------------- 
53
; warte 9999990 Zyklen:
54
           ldi  R20, $42
55
WGLOOP01:  ldi  R21, $D6
56
WGLOOP11:  ldi  R22, $EB
57
WGLOOP21:  dec  R22
58
            brne WGLOOP21
59
           dec  R21
60
            brne WGLOOP11
61
           dec  R20
62
            brne WGLOOP01
63
; ----------------------------- 
64
; warte 9 Zyklen:
65
           ldi  R20, $03
66
WGLOOP31:  dec  R20
67
            brne WGLOOP31
68
; ----------------------------- 
69
; warte 1 Zyklus:
70
           nop
71
; ============================= 
72
ret
73
74
delay5s:                               ; 5ms Pause
75
; ============================= 
76
;   Warteschleifen-Generator 
77
;     5000000 Zyklen:
78
; ----------------------------- 
79
; warte 4999995 Zyklen:
80
          ldi  R23, $21
81
WGLOOP0:  ldi  R24, $D6
82
WGLOOP1:  ldi  R25, $EB
83
WGLOOP2:  dec  R25
84
           brne WGLOOP2
85
          dec  R24
86
           brne WGLOOP1
87
          dec  R23
88
           brne WGLOOP0
89
; ----------------------------- 
90
; warte 3 Zyklen:
91
          ldi  R23, $01
92
WGLOOP3:  dec  R23
93
           brne WGLOOP3
94
; ----------------------------- 
95
; warte 2 Zyklen:
96
          nop
97
          nop
98
; ============================= 
99
ret

von Sven M. (Gast)


Lesenswert?

also habe das ganze mal aufgespielt wenn ich die schaltung unter strom 
setzte leuchtet erst rot dann dauer grün egal ob ich die pins gegen VCC 
oder GND lege-.- ich finde einfach keinen fehler

von Karl H. (kbuchegg)


Lesenswert?

Was fällt dir hier auf
1
red:
2
  ldi r18,(0<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)
3
      ***
4
    out PORTB,r17
5
              ***

von Erich (Gast)


Lesenswert?

Man könnte sich hier viel Arbeit und Diskussion ersparen durch 
Verwendung eines C-Compilers.

von Spess53 (Gast)


Lesenswert?

Hi

>Man könnte sich hier viel Arbeit und Diskussion ersparen durch
>Verwendung eines C-Compilers.

Stimmt. C korrigiert die Fehler automatisch.

MfG Spess

von Karl H. (kbuchegg)


Lesenswert?

Erich schrieb:
> Man könnte sich hier viel Arbeit und Diskussion ersparen durch
> Verwendung eines C-Compilers.

Würde auch nicht viel ändern.
Sorgfältig arbeiten muss man da wie dort.

Die Art der Fehler ist in C dann eben eine andere.

von Sven M. (Gast)


Lesenswert?

herlich manchmal steht man cht vor ner wand -.- natürlich lese ich das 
falsche register aus

von Erich (Gast)


Lesenswert?

1.)
>Aber RCALL und RET gehören zusammen.

2.)
>>habe jetzt aus rjamp rcall gemacht aber sie springt noch immer hin und
>>her

>Ja, du hast noch mehr rjmps mit einem ret beendet;) Der arme Stack.

3.)
>herlich manchmal steht man cht vor ner wand -.- natürlich lese ich das
>falsche register aus


Das sind z.B. 3 Situationen, die mit einem C Compiler in dieser Art und 
Weise überhaupt nicht passieren können.
Klar, mit den Ports, der Initialisierung, den Masken und Operationen 
muss man sich auch in C auseinandersetzen, sonst wird das nix.

>Sorgfältig arbeiten muss man da wie dort.

Das stimmt.

von spess53 (Gast)


Lesenswert?

Hi

>Das sind z.B. 3 Situationen, die mit einem C Compiler in dieser Art und
>Weise überhaupt nicht passieren können.

Und wenn man Assembler kann, passieren die auch nicht. Du wirst doch 
nicht die Schwierigkeiten eines Anfängers als Arument benutzen. Was 
meinst du, was
ich hier schon für Anfänger-C-Code gesehen habe, der als Gegenargument 
getaugt hätte. Also lass deine Missionierungsversuche.

MfG Spess

von Sven M. (Gast)


Lesenswert?

Natürlich muss ich dazusagen C ist was feines da es eine hochsprache 
ist... ich habe mal mit C für programme angefangen und durfte 
ähnlichkeit zu PHP faststellen daher sind mir manche sachen in C recht 
leicht gefallen... da die sprachen eine gewisse ähnlichkeit haben

von Sven M. (Gast)


Lesenswert?

Heyy ich bins nach langem nochmal :)

undzwar folgendes das mit den rot und grün phasen über PB3 geht aber das 
mit sofort green geht nicht die rote led wird nur etwas schwächer wenn 
ich PB4 an masse anlege

von Karl H. (kbuchegg)


Lesenswert?

Programm?
Man sollte meinen, dass du schön langsam den Hausbrauch kennst :-)

von Peter D. (peda)


Lesenswert?

Karl heinz Buchegger schrieb:
> Programm?

Und benutze den Dateianhang.


Peter

von Sven M. (Gast)


Angehängte Dateien:

Lesenswert?

hier das programm ;)

von Karl H. (kbuchegg)


Lesenswert?

OK.
Den 2.ten Registerfehler hast du gesehen.

Aber: Was denkst du?
Wenn du PB4 drückst, dann geht der rcall nach greensof. Dort wird rot 
ausgschaltet und eine andere ein. Gleich darauf geht es mit einem ret 
wieder zurück zur Aufrufstelle wo gleich danach ein rcall nach rot 
stattfindet wo rot wieder eingeschaltet wird.

Was denkst du, wie lange das in etwa dauert, dass rot abgeschaltet ist?
10µs, 15µs?
Auf jeden Fall viel zu kurz als dass du als Mensch das wahrnehmen 
könntest, dass rot tatsächlich aus ist. Du siehst das als: rot wird im 
Mittel etwas schwächer. Und wenn du dir die andere LED ganz genau 
ansiehst, dann wirst du sehen, dass sie ganz leicht glimmt.

Vergleich doch einfach mal, wodurch sich der Code beim Drücken von PB3 
und beim Drücken von PB4 unterscheidet. In der Subroutine, die nach PB3 
angesprungen wird, sind Wartezeiten drinnen, die dir erlauben, das 
Aufleuchten der entsprechenden LED (und das Abschalten von Rot) auch 
tatsächlich zu sehen. In der Subroutine von PB4 sind diese Wartezeiten 
aber nicht drinnen.

Nachdem das gesagt ist: Du solltest tatsächlich dein Zeitkonzept nochmal 
überdenken. So wie es jetzt ist, ist es nicht sehr flexibel.
Auf der anderen Seite macht man so eine Ampelsteuerung allerdings in der 
Realität ganz anders (mit einer State-Maschine) und ich verstehe schon, 
dass das für dich jetzt erst mal einfach nur eine Übung ist, damit sich 
da etwas an den LEDs tut. Nichts desto trotz musst du dir mehr Sorgfalt 
und mehr Beobachtung auf die Fahnen schreiben. Einfach irgendwas 
hinzuschreiben, ist auf Dauer zu wenig. Wenn deine Programme nicht 
funktionieren, dann musst du sie analysieren. Auch, oder auch ganz 
speziell mit dem Hintergedanken: Moment, wie lange dauert das denn 
eigentlich? Hier und hier schalte ich zwar die LED ein, aber wie gehts 
dann im Programm weiter? Was passiert danach? Welche LED wird denn dann 
ein/aus geschaltet? Wieviel Zeit (Systemtakte) ist denn da ungefähr 
vergangen? Ist das viel Zeit oder ist das wenig Zeit? Kann ich als 
Mensch so kurze Zeitspannen überhaupt sehen?

von Martin V. (oldmax)


Lesenswert?

Hi
Vielleicht noch ein kleiner Tip von mir....
Also, du hast 3 LED Rot, Grün und Gelb.  Nun nimmst du eine Variable und 
spendierst der diese 3 Bits.
1
Ampel_LED:  .Byte 1    ; Bit 0 = Rot
2
; Bit 1 = Gelb
3
; Bit 2 = Grün
4
; Bit 3-7 nicht benutzt
Nun überlegst du, wie viele Ampelphasen es gibt:
1=nur Grün
2=nur Gelb
3=nur Rot
4=Rot und gelb
danach wieder von vorn. Dies kann man nutzen, indem man dieses Muster in 
ein Variablenfeld packt.
1
Phase1:  .Byte 1    ; nur Bit 2 setzen, alle anderen auf 0
2
Phase2:  .Byte 1    ; nur Bit 1 setzen, alle anderen auf 0
3
Phase3:  .Byte 1    ; nur Bit 0 setzen, alle anderen auf 0
4
Phase4:  .Byte 1    ; nur Bit 0 und 1 setzen, alle anderen auf 0
Diese Variablen initialisierst du vor deiner Programmschleife mit den 
Bits der LED
1
Init_Ampel_LED:
2
LDI Reg_a, 0b00000100  ; Grün
3
   STS Phase1, Reg_a  
4
LDI Reg_a, 0b00000010  ; Gelb
5
STS Phase2, Reg_a
6
LDI Reg_a, 0b00000001  ; Rot
7
STS Phase3, Reg_a
8
LDI Reg_a, 0b00000011  ; Gelb und Rot
9
STS Phase4, Reg_a
10
CLR Reg_a                  
11
STS Phase_Cnt, Reg_a     ; Phasenzähler auf 0 setzen
12
RCALL Set_Ampel_Status (0)  ; Ampel in Grundstellung anzeigen
13
RET
Im Programm rufst du nun deine Ampel auf und zählst einfach eine 
Variable von 0 bis 3 in deinen Zeiten. Nennen wir sie mal Phase_Cnt.
Also mal ganz grob:
Progamm:
Stack setzen
LED-Feld Initialisieren (RCall  INIT_Ampel_LED)
Programm Schleife
   Eingänge lesen        (RCall Read_IO)
   Bei Ereignis die Ereignisroutine aufrufen  (RCall  Ampel_Zyklus)

Schleife Ende
[avrasm]
Ampel_Zyklus:
Delay...
LDS  Reg_a, Phase_Cnt
INC   Reg_a    ; nächste Ampelphase
STS  Phase_Cnt, Reg_a
RCALL Set_Ampel_Status (1)
Delay...
LDS   Reg_a, Phase_Cnt
INC   Reg_a    ; nächste Ampelphase
STS   Phase_Cnt, Reg_a
RCALL Set_Ampel_Status (2)
Delay...
LDS   Reg_a, Phase_Cnt
INC   Reg_a    ; nächste Ampelphase
STS   Phase_Cnt, Reg_a
RCALL Set_Ampel_Status (3)
Delay...
CLR   Reg_a
RCALL Set_Ampel_Status (0)
RET

Set_Ampel_Status:
LDI XL,Low(Phase1)  ; 1. Adresse vom Variablenfeld holen
LDI XH,High(Phase1)
LDS Reg_a, Phase_Cnt
ADD XL, Reg_a
CLR Reg_a
ADC XH, Reg_a     ; addressieren
LD Reg_a, X       ; adressiertes Byte holen
RCall Set_Ausgabe ; Aufruf einer Routine für die Ausgabe
                     ; das Bitmuster steht in den Bits 0-2 von Reg_a
RET
[/avsasm]
Ich habe dir mal so in etwa die Routinen aufgeschrieben. Ob du in deinem 
µC die Adressierung über das X-Register durchführen kannst, weiß ich 
nicht, aber ein Atmega 8 arbeitet damit. In der Routine Set_Ausgabe 
holst du dir die Bits und setzt die entsprechenden Portbits. Das ist nun 
nicht mehr so schwer. Der Vorteil dieser Vorgehensweise liegt auf der 
Hand. Die Routinen sind klein und leicht nachvollziehbar. Außerdem 
kannst du nun ohne große Anstrengung deine Ampelsteuerung erweitern. 
Überleg einmal, wie viele Schritte eine Kreuzung bräuchte. Bei  der 
Variablen Ampel_LED setzt du einfach weitere Bits für die andere 
Fahrtrichtung, erweiterst das Variablenfeld Phase und initialisierst 
entsprechend die erweiterten Bits zu den Phasen. Nun endet Phase_Cnt 
nicht mehr bei 4, sondern halt bei 7 oder so. Am Programm brauchst du 
fast nichts mehr ändern. Gerade bei der Anwendung von Assembler ist es 
wichtig, ein Programm in kleine Aufgaben zu packen. Auch solltest du dir 
angewöhnen, von Anfang an auf Delays in Form von Schleifen zu 
verzichten. Lerne mit dem Timer umzugehen und leite Zeitereignisse aus 
dem Timer –Interrupt ab. Im Moment sind die Delays noch nicht kritisch, 
aber wenn du erst mal eine Taste 5 Sek. Festhalten musst, um sicher zu 
sein, das dein Programm auch in dieser Zeit den Eingang gelesen hat, 
wirst du dich fragen, warum. Und es ist nun mal so, das ein Programm in 
einer Schleife zur Zeitenbildung nichts anderes machen kann, es sei 
denn, du arbeitest mit Interrupts auf den Eingängen. Aber auch das ist 
nict unbedingt das gelbe vom Ei…
Nimm meinen Beitrag nicht als Kritik, sondern als einen weiteren Weg, 
Programme zu gestalten. Die Kunst eines Programmierers liegt nun mal im 
Erkennen der Aufgabe und der Lösung, die manchmal gar nicht so 
offensichtlich ist. Es scheint auch etwas aufgebläht, durch die 
Verwendung von Variablen, aber sehr schnell lernt man diese Eigenschaft 
eines Controllers zu schätzen. Angenommen, du möchtest eine 
7-Segmentanzeige mit den Zahlen 0 bis 9 ansteuern, nimm ein 
Variablenfeld Segment_a usw.
Nun ist deine Zahl in irgendeinem Register, also X-Register auf die 
Adresse der ersten Variable setzen, deine Zahl dazuaddiert und die 
dadurch adressierte Variable laden. Da sollte dann das passende 
Binärmuster für die 7-Segmentanzeige für die Ausgabe drin stehen. Einmal 
getestet und es funktioniert immer. Solche Bausteine kannst du dir dann 
in irgendeiner Datei ablegen und bei Bedarf wieder für weitere Projekte 
holen.
Gruß oldmax

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.