www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Ampelschaltung funktioniert nicht


Autor: Sven M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo leute ich habe ein Problem undzwar programmier ich mir gerade ne 
einfache ampelschaltung für nen attiny13
mein code is volgender:
.include "tn13def.inc" ;Definitionsdatei für den Prozessor typ
.def temp1 = r18
.def temp2 = r19
.ifndef XTAL
.equ XTAL = 1000000
.endif
ldi r16,(1<<PB2)|(1<<PB1)|(1<<PB0)|(1<<PB3)|(0<<PB4)|(0<<PB5)
ldi r17,(1<<PB5)|(1<<PB4)
out DDRB,r16
out PORTB,r17

main:
  sbis PINB,4
    rjmp greensof
  sbis PINB,5
    rjmp green
  rjmp red

rjmp main ;Sprung zur marke "ende" -> endlosschleife

delay5s:                               ; 5ms Pause
; ============================= 
;   Warteschleifen-Generator 
;     5000000 Zyklen:
; ----------------------------- 
; warte 4999995 Zyklen:
          ldi  R17, $21
WGLOOP0:  ldi  R18, $D6
WGLOOP1:  ldi  R19, $EB
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
                    ; wieder zurück

delay10s: 
; ============================= 
;   Warteschleifen-Generator 
;     10000000 Zyklen:
; ----------------------------- 
; warte 9999990 Zyklen:
          ldi  R17, $42
WGLOOP01:  ldi  R18, $D6
WGLOOP11:  ldi  R19, $EB
WGLOOP21:  dec  R19
          brne WGLOOP21
          dec  R18
          brne WGLOOP11
          dec  R17
          brne WGLOOP01
; ----------------------------- 
; warte 9 Zyklen:
          ldi  R17, $03
WGLOOP31:  dec  R17
          brne WGLOOP31
; ----------------------------- 
; warte 1 Zyklus:
          nop
; ============================= 
ret     ;wieder zurück


green:
rcall delay5s
ldi r17,(1<<PB0)|(0<<PB1)|(0<<PB2)
out PORTB,r17
rcall delay10s
ldi r17,(0<<PB0)|(1<<PB1)|(1<<PB2)
out PORTB,r17
rcall delay5s
ret

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

greensof:
ldi r17,(1<<PB0)|(0<<PB1)
out PORTB,r17
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?

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>  rjmp red

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

Wie wäre es mit einem rcall red?

Autor: Sven M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Sven M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
.include "tn13def.inc" ;Definitionsdatei für den Prozessor typ
.def temp1 = r18
.def temp2 = r19
.ifndef XTAL
.equ XTAL = 1000000
.endif
ldi r16,(1<<PB2)|(1<<PB1)|(1<<PB0)|(1<<PB3)|(0<<PB4)|(0<<PB5)
ldi r17,(1<<PB5)|(1<<PB4)
out DDRB,r16
out PORTB,r17

main:
  sbis PINB,4
    rcall greensof
  sbis PINB,5
    rcall green
  rcall red

rjmp main ;Sprung zur marke "ende" -> endlosschleife

delay5s:                               ; 5ms Pause
; ============================= 
;   Warteschleifen-Generator 
;     5000000 Zyklen:
; ----------------------------- 
; warte 4999995 Zyklen:
          ldi  R17, $21
WGLOOP0:  ldi  R18, $D6
WGLOOP1:  ldi  R19, $EB
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

delay10s: 
; ============================= 
;   Warteschleifen-Generator 
;     10000000 Zyklen:
; ----------------------------- 
; warte 9999990 Zyklen:
          ldi  R17, $42
WGLOOP01:  ldi  R18, $D6
WGLOOP11:  ldi  R19, $EB
WGLOOP21:  dec  R19
          brne WGLOOP21
          dec  R18
          brne WGLOOP11
          dec  R17
          brne WGLOOP01
; ----------------------------- 
; warte 9 Zyklen:
          ldi  R17, $03
WGLOOP31:  dec  R17
          brne WGLOOP31
; ----------------------------- 
; warte 1 Zyklus:
          nop
; ============================= 
ret

green:
rcall delay5s
ldi r17,(1<<PB0)|(0<<PB1)|(0<<PB2)
out PORTB,r17
rcall delay10s
ldi r17,(0<<PB0)|(1<<PB1)|(1<<PB2)
out PORTB,r17
rcall delay5s
ret

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

greensof:
ldi r17,(1<<PB0)|(0<<PB1)
out PORTB,r17
ret

wo ist da denn der fehler?

ich stehe voll aufen schlauch

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.
.include "tn13def.inc" ;Definitionsdatei für den Prozessor typ
.def temp1 = r18
.def temp2 = r19
.ifndef XTAL
.equ XTAL = 1000000
.endif

       ldi r16, low(RAMEND)
       out SPL,r16

       ldi r16,(1<<PB2)|(1<<PB1)|(1<<PB0)|(1<<PB3)|(0<<PB4)|(0<<PB5)
       ldi r17,(1<<PB5)|(1<<PB4)
       out DDRB,r16
       out PORTB,r17

       ....


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.
.include "tn13def.inc" ;Definitionsdatei für den Prozessor typ
.def temp1 = r18
.def temp2 = r19
.ifndef XTAL
.equ XTAL = 1000000
.endif


       ldi r16, low(RAMEND)
       out SPL,r16

       ldi r16,(1<<PB2)|(1<<PB1)|(1<<PB0)|(1<<PB3)|(0<<PB4)|(0<<PB5)
       ldi r17,(1<<PB5)|(1<<PB4)
       out DDRB,r16
       out PORTB,r17

main:
  sbis PINB,4
    rcall greensof
  sbis PINB,5
    rcall green
  rcall red

rjmp main ;Sprung zur marke "ende" -> endlosschleife

green:
rcall delay5s
ldi r17,(1<<PB0)|(0<<PB1)|(0<<PB2)
out PORTB,r17
rcall delay10s
ldi r17,(0<<PB0)|(1<<PB1)|(1<<PB2)
out PORTB,r17
rcall delay5s
ret

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

greensof:
ldi r17,(1<<PB0)|(0<<PB1)
out PORTB,r17
ret

delay5s:                               ; 5ms Pause
; ============================= 
;   Warteschleifen-Generator 
;     5000000 Zyklen:
; ----------------------------- 
; warte 4999995 Zyklen:
          ldi  R17, $21
WGLOOP0:  ldi  R18, $D6
WGLOOP1:  ldi  R19, $EB
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

delay10s: 
; ============================= 
;   Warteschleifen-Generator 
;     10000000 Zyklen:
; ----------------------------- 
; warte 9999990 Zyklen:
          ldi  R17, $42
WGLOOP01:  ldi  R18, $D6
WGLOOP11:  ldi  R19, $EB
WGLOOP21:  dec  R19
          brne WGLOOP21
          dec  R18
          brne WGLOOP11
          dec  R17
          brne WGLOOP01
; ----------------------------- 
; warte 9 Zyklen:
          ldi  R17, $03
WGLOOP31:  dec  R17
          brne WGLOOP31
; ----------------------------- 
; warte 1 Zyklus:
          nop
; ============================= 
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 :-)
          ....
delay10s:
          rcall delay5s
          rcall delay5s
          ret

Autor: otto der erste (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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).

Autor: Ben ___ (burning_silicon)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Ben ___ (burning_silicon)
Datum:

Bewertung
0 lesenswert
nicht 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!**

Autor: oldmax (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Sven M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Skua (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Sven M. (Gast)
Datum:

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

Autor: Sven M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
soo hier jetzt mal der überarbeitete code:
.include "tn13def.inc" ;Definitionsdatei für den Prozessor typ

.def temp1 = r18
.def temp2 = r19

.ifndef XTAL
  .equ XTAL = 1000000
.endif00


ldi r16, low(RAMEND)
       out SPL,r16

ldi r16,0b00000111
  out DDRB,r16

ldi r17,0b00011000
  out PORTB,r17

main:
  sbis PINB,3
    rcall green
  sbis PINB,4
    rcall greensof
  rcall red
rjmp main ;Sprung zur marke "ende" -> endlosschleife

green:
  rcall delay5s

  ldi r17,(1<<PB0)|(0<<PB1)|(0<<PB2)
    out PORTB,r17

  rcall delay10s

        ldi r17,(0<<PB0)|(1<<PB1)|(1<<PB2)
                out PORTB,r17

        rcall delay5s

  ret

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

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

delay10s: 
; ============================= 
;   Warteschleifen-Generator 
;     10000000 Zyklen:
; ----------------------------- 
; warte 9999990 Zyklen:
           ldi  R20, $42
WGLOOP01:  ldi  R21, $D6
WGLOOP11:  ldi  R22, $EB
WGLOOP21:  dec  R22
            brne WGLOOP21
           dec  R21
            brne WGLOOP11
           dec  R20
            brne WGLOOP01
; ----------------------------- 
; warte 9 Zyklen:
           ldi  R20, $03
WGLOOP31:  dec  R20
            brne WGLOOP31
; ----------------------------- 
; warte 1 Zyklus:
           nop
; ============================= 
ret

delay5s:                               ; 5ms Pause
; ============================= 
;   Warteschleifen-Generator 
;     5000000 Zyklen:
; ----------------------------- 
; warte 4999995 Zyklen:
          ldi  R23, $21
WGLOOP0:  ldi  R24, $D6
WGLOOP1:  ldi  R25, $EB
WGLOOP2:  dec  R25
           brne WGLOOP2
          dec  R24
           brne WGLOOP1
          dec  R23
           brne WGLOOP0
; ----------------------------- 
; warte 3 Zyklen:
          ldi  R23, $01
WGLOOP3:  dec  R23
           brne WGLOOP3
; ----------------------------- 
; warte 2 Zyklen:
          nop
          nop
; ============================= 
ret

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Sven M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Sven M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Sven M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
soo wenn ich jetzt nicht wieder irgend was verpasst habe XD
sollte es so schon gut aussehen:
.include "tn13def.inc" ;Definitionsdatei für den Prozessor typ

.def temp1 = r18
.def temp2 = r19

.ifndef XTAL
  .equ XTAL = 1000000
.endif


ldi r16, low(RAMEND)
       out SPL,r16

ldi r16,(1<<PB0)|(1<<PB1)|(1<<PB2)|(0<<PB3)|(0<<PB4)
  out DDRB,r16

ldi r17,(0<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)
  out PORTB,r17

main:
  sbis PINB,3
    rcall green
  sbis PINB,4
    rcall greensof
  rcall red
rjmp main ;Sprung zur marke "ende" -> endlosschleife

green:
  rcall delay5s

  ldi r17,(1<<PB0)|(0<<PB1)|(0<<PB2)|(1<<PB3)|(1<<PB4)
    out PORTB,r17

  rcall delay10s

  ret

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

greensof:
  ldi r19,(1<<PB0)|(0<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)
    out PORTB,r17
  ret

delay10s: 
; ============================= 
;   Warteschleifen-Generator 
;     10000000 Zyklen:
; ----------------------------- 
; warte 9999990 Zyklen:
           ldi  R20, $42
WGLOOP01:  ldi  R21, $D6
WGLOOP11:  ldi  R22, $EB
WGLOOP21:  dec  R22
            brne WGLOOP21
           dec  R21
            brne WGLOOP11
           dec  R20
            brne WGLOOP01
; ----------------------------- 
; warte 9 Zyklen:
           ldi  R20, $03
WGLOOP31:  dec  R20
            brne WGLOOP31
; ----------------------------- 
; warte 1 Zyklus:
           nop
; ============================= 
ret

delay5s:                               ; 5ms Pause
; ============================= 
;   Warteschleifen-Generator 
;     5000000 Zyklen:
; ----------------------------- 
; warte 4999995 Zyklen:
          ldi  R23, $21
WGLOOP0:  ldi  R24, $D6
WGLOOP1:  ldi  R25, $EB
WGLOOP2:  dec  R25
           brne WGLOOP2
          dec  R24
           brne WGLOOP1
          dec  R23
           brne WGLOOP0
; ----------------------------- 
; warte 3 Zyklen:
          ldi  R23, $01
WGLOOP3:  dec  R23
           brne WGLOOP3
; ----------------------------- 
; warte 2 Zyklen:
          nop
          nop
; ============================= 
ret

Autor: Sven M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was fällt dir hier auf
red:
  ldi r18,(0<<PB0)|(1<<PB1)|(1<<PB2)|(1<<PB3)|(1<<PB4)
      ***
    out PORTB,r17
              ***

Autor: Erich (Gast)
Datum:

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

Autor: Spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Sven M. (Gast)
Datum:

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

Autor: Erich (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Sven M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Sven M. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

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

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl heinz Buchegger schrieb:
> Programm?

Und benutze den Dateianhang.


Peter

Autor: Sven M. (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
hier das programm ;)

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Martin Vogel (oldmax)
Datum:

Bewertung
0 lesenswert
nicht 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.
Ampel_LED:  .Byte 1    ; Bit 0 = Rot
; Bit 1 = Gelb
; Bit 2 = Grün
; 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.
Phase1:  .Byte 1    ; nur Bit 2 setzen, alle anderen auf 0
Phase2:  .Byte 1    ; nur Bit 1 setzen, alle anderen auf 0
Phase3:  .Byte 1    ; nur Bit 0 setzen, alle anderen auf 0
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
Init_Ampel_LED:
LDI Reg_a, 0b00000100  ; Grün
   STS Phase1, Reg_a  
LDI Reg_a, 0b00000010  ; Gelb
STS Phase2, Reg_a
LDI Reg_a, 0b00000001  ; Rot
STS Phase3, Reg_a
LDI Reg_a, 0b00000011  ; Gelb und Rot
STS Phase4, Reg_a
CLR Reg_a                  
STS Phase_Cnt, Reg_a     ; Phasenzähler auf 0 setzen
RCALL Set_Ampel_Status (0)  ; Ampel in Grundstellung anzeigen
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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.