Forum: Mikrocontroller und Digitale Elektronik Logik Fehler


von Klaus (Gast)


Lesenswert?

Hallo ich hab da mal ein ganz interessantes Problem und zwar nach dem
ich ein program geschrieben habe das nicht funktioniert hat habe ich
ein test Programm geschrieben das folgendes venomehn hat.

Hier erst mal der Code:

.include "4433.inc"

.def temp1 = r16
.def temp2 = r17
.org 0x000
         rjmp main
.org INT0addr
         rjmp inttest

main:
         ldi temp1, RAMEND
         out SPL, temp1

    ldi temp1, $F0
    out DDRD, temp1
    ldi temp1, $0F
    out DDRB, temp1

         ldi temp1, 0b00000010
         out MCUCR, temp1

         ldi temp1, 0b01000000
         out GIMSK, temp1
         sei
    ldi temp1,$00
    ldi temp2,$00
    out PORTB,temp2
    out PORTD,temp1
loop:
    in temp1, PIND
    andi temp1, $01
    cpi temp1, $00
    breq weiter
    rjmp loop
weiter:
    ldi temp1,$a0
    ldi temp2,$0a
    out PORTB,temp2
    out PORTD,temp1
    rjmp loop

inttest:
    ldi temp1,$F0
    ldi temp2,$01
    out PORTB,temp2
                out PORTD,temp1
         reti

Die Pins 2 u. 4 sind als Eingänge wie im I/O Tutorial aufgebaut (also
bei Betätigung auf masse).
Wenn jetzt der Taster S1 der an pin2 angeschlossen ist betätigt wird
dann wird in portB $0A
und in portD $A0 geladen so weit so gut aber wenn ich S2 der mit pin4
verbunden ist und somit den interupt auslöst betätige dann wird aus mir
unerklerlichen gründen in portB $0A
und in portD $A0 oder eben in portB wird $01 und in portD $F0 geladen.
Eigentlich sollte ja nur in portB $01 und in porD $F0 geladen werden.
Woran kann das liegen das der falsche wert geladen wird hat irgend
jemand eine Ahnung ?

PS: noch ne kleine frage wenn ich in der loop schleife statt rjmp nur
jmp verwende was laut datenblat ein Sprung zur absoluten Adresse ist
was für mich bedeutet das ich nicht mehr zurück springen kann und das
ist in diesem fall ja auch nicht nötig nur dann funktioniert das
Programm auch nicht nur mit rjmp aber rjmp speichert eine Adresse auf
dem stack und dann müsste doch eigentlich bei einer endlos schleife der
stack über laufen oder nicht bitte klärt mich mal darüber auf DANKE im
voraus Klaus

PPS: Ich drücke nie beide Taster gleichzeitig

von Andi (Gast)


Lesenswert?

Hi!

Du benutzt in der INT0-Routine die gleichen Register wie im Main-Prog.
(Temp1 (r16) und Temp2 (r17)).
Dadurch verändert die INT0-Routine den Registerinhalt von r16 und r17
des Main-Progs.
Desweiteren soltest Du im INT0 das Statusregister sichern und vor RETI
wieder rücksichern damit die Operationen im Main-Prog nicht verfälscht
werden.
Am einfachsten machst Du das mit

 .def StReg=r0
 in StReg,SREG   ;Statusregister sichern
 ....
 Code
 ....
 out SREG,StReg  ;Statusregister zurückschreiben
 reti

Natürlich ist darauf zu achten, das StReg (r0) für nichts anderes
benutzt wird.

In der INT0-Routine solltest Du entweder Register verwenden, die
überall woanders nicht verwendet werden oder Du setzt vorher den Inhalt
von Temp1 und Temp2 auf den Stapel mit

 .def StReg=r0
 in StReg,SREG
 push Temp1      ;Temp1 (r16) auf den Stapel setzen
 push Temp2      ;Temp2 (r17) auf den Stapel setzen
 ....
 Code
 ....
 pop Temp2       ;Temp2 (r17) vom Stapel holen
 pop Temp1       ;Temp1 (r16) vom Stapel holen
 out SREG,StReg
 reti

Noch ein Vorschlag zwecks logik!
Wenn Du in Deiner loop nicht auf = (breq) sondern <> (brne) prüfst,
kannst Dir den rjmp sparen und das Ergebnis ist das gleiche das bei
Übereinstimmung die Schleife verlassen wird:

loop:
    in temp1, PIND
    andi temp1, $01
    cpi temp1, $00
    brne loop

Eine kürzere Variante gibs noch mit SBIC (Skip if Bit in I/O is
clear):

loop:
    sbic pind,0      ;Ist Pin0 an PortD gelöscht (GND)?
    rjmp loop        ;Wenn nicht, dann zurück zu loop
weiter:              ;Ansonsten gehts hier weiter (Marke nicht
erforderlich)

Gruß
Andi

von Klaus (Gast)


Lesenswert?

Hi und danke Andi

Wie schon gesagt ist das nur ein Test Programm und daher war ich mit
der Sicherung der Register etwas schlampig nur glaub ich das du mich
falsch verstanden hast ich bekomme nicht im Hauptprogramm die falschen
Werte sondern in der INT0 Routine also wenn der INT0 ausgelöst wird
schreibt er die Daten des Haubtprogramms in die Register.

Hast du auch eine Antwort auf die rjmo u. jmp Frage?

Aber die Programmabkürzungs Tips sind gute Tips Danke

Klaus

von Markus_8051 (Gast)


Lesenswert?

Ich habe keine Ahnung, was das für ein µC ist, den Du da programmierst.
Aber von dem was ich so programmiere würde ich sagen, daß sowohl JMP
als auch RJMP nichts auf dem Stack ablegen. Der Unterschied ist, wie Du
schon sagtest: JMP springt eine direkte Adresse an, bei RJMP wird die
Sprungadresse relativ zum aktuellen Programmzähler codiert gespeichert.
Dadurch verbraucht ein RJMP Befehl weniger Speicher, kann dafür keine so
großen Sprünge machen. (Im wahrsten Sinne des Wortes). Als Programmierer
merkt man da eigentlich wenig von. Ich würde mir angewöhnen RJMP zu
benutzen. Wenn die Adresse außerhalb des zu erreichenden Bereiches
liegt, sollte der Assembler einen Fehler anzeigen.
K.A. wie bei Deinem µC dann der Befehl aussieht, der eine
Rücksprungadresse auf den Stack legt. Beim 8051 wäre das CALL, bei 6502
JSR.

Hoffe das trifft in etwa auf Deinen µC zu,

Markus_8051

von Andi (Gast)


Lesenswert?

@Klaus:
Dann sei mal nicht so schlampig und mach das mal mit dem sichern des
Statusregisters und der Register Temp1 und Temp2 bzw. benutze erst mal
andere (reservierte) Register in der INT0-Routine z. B. r18 und r19.
Denn nur wenn man in der Software für korekte Programierung sorgt
steigen die Chancen der korekten Funktion erheblich.
Vielleicht klapps ja dann mit der Funktion die es machen soll.
Wie mein Vorredner schon sagte, RJMP ist ein Sprungbefehl und kein
Call-Befehl (Unterprogrammaufruf).
Mit RJMP spart man sich gegenüber JMP 1 Word da die relative
Sprungadresse im RJMP-Befehl mit 12 Bit enthalten ist.
Man kann relativ vom aktuellen PC von -2047 bis +2047 springen.

Gruß
Andi

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.