Forum: Mikrocontroller und Digitale Elektronik IF-Abfrage in ASM für mehrere Ausgänge


von Gray (Gast)


Lesenswert?

Hi,

ich versuche mich seit kurzem im programmieren eines Attiny2313 und 
möchte folgendes:

Wenn an PortD 5 & 6 jeweils der Wert auf 0 steht, so soll PortD 5 auf 1 
gesetzt werden.

In PHP würde ich es so machen:
if($PortD[5] == 0 && $PortD[6] == 0){
     $PortD[5] = 1;
}

Ich hoffe ihr wisst was ich machen möchte, das ganze würde ich gerne in 
ASM hinbekommen, thx für eure Hilfe.

von Karl H. (kbuchegg)


Lesenswert?

Gray wrote:
>
> Ich hoffe ihr wisst was ich machen möchte, das ganze würde ich gerne in
> ASM hinbekommen, thx für eure Hilfe.

Den Port abfragen.
Mit einem AND alle anderen Bits wegmaskieren (definiert auf 0 setzen).
Wenn das Ergebnis 0 ist, dann sind Bit 5 und Bit 6 definitiv auf 0.

In Assembler ist das eigentlich eine übliche Vorgehensweise mittels
AND und OR Bits gezielt zu löschen, bzw. gezielt zu setzen.

http://www.mikrocontroller.net/articles/AVR-Tutorial:_Logik

von df311 (Gast)


Lesenswert?

mir wäre jetzt nicht bekannt, dass man mit avr's i/o-pins bidirektional 
nutzen kann, also von daher dürfte das ganze schon schwieriger werden.
1
andi temp, 0xC0
2
tst temp
3
brne _skip
4
ldi temp, 0x10
5
out temp, PORTD
6
_skip:
7
; weiter im programm

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

sbic PinD, 5
rjmp Nix
sbic PinD, 6
rjmp Nix
sbi  DDRD, 5
sbi  PortD, 5
rjmp zurück (oder 'ret' bei Unterprogramm)

Nix:
cbi  DDRD, 5
cbi  PortD, 5
rjmp zurück (oder 'ret' bei Unterprogramm)


Nebenbei bemerkt, ist es problematisch, einen Portpin zu setzen, den man 
auch als Eingang abfragt. Aber vielleicht muß das ja bei Dir so sein.

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

>mir wäre jetzt nicht bekannt, dass man mit avr's i/o-pins bidirektional
>nutzen kann

Na aber sicher doch. Schon immer! Es gibt nur einige Ausnahmen bei AVRs, 
bei denen es einige Portpins gibt, die nur als Eingang oder nur als 
Ausgang fungieren.

von Stefan E. (sternst)


Lesenswert?

@ df311:
1
andi temp, 0xC0
2
tst temp
3
brne _skip
4
ldi temp, 0x10
5
out temp, PORTD
6
_skip:
7
; weiter im programm

Wieso 0xC0? Bit 5 und 6 sind 0x60.
Wozu das tst? andi setzt doch schon das Z-Flag.
Wieso 0x01? Bit 5 ist 0x20.

@  Travel Rec.:
So wie er seinen PHP-Code geschrieben hat, will er Bit 5 abhängig vom 
aktuellen Output an Bit 5 und 6 setzen. Und von einem "sonst Bit 5 auf 
0" steht da auch nichts.

Mein Vorschlag:
1
IN   Reg, PORTD
2
ANDI Reg, 0x60
3
IN   Reg, SREG
4
SBRS Reg, 1
5
SBI  PORTD, 5

von Karl H. (kbuchegg)


Lesenswert?

Stefan Ernst wrote:

>
1
> IN   Reg, PORTD
2
> ANDI Reg, 0x60
3
> IN   Reg, SREG
4
> SBRS Reg, 1
5
> SBI  PORTD, 5
6
>


He, he.
Mit dem IN REG, SREG dürftest du dem OP eine harte Nuss
zu knacken gegeben haben. :-)

Für den OP: Es geht auch so
1
        IN   Reg, PORTD
2
        ANDI Reg, 0x60
3
        BRNE NOSET
4
        SBI  PORTD, 5
5
NOSET:

von Michael Wilhelm (Gast)


Lesenswert?

@ Karl-Heinz

IN   Reg, PORTD

Ich bin zwar kein asm-Spezi, aber ich würde:

IN   Reg, PIND

schreiben.

MW

von Stefan E. (sternst)


Lesenswert?

Ups, mein Code enthält einen Fehler:
SBRS -> SBRC

von Karl H. (kbuchegg)


Lesenswert?

Michael Wilhelm wrote:
> @ Karl-Heinz
>
> IN   Reg, PORTD
>
> Ich bin zwar kein asm-Spezi, aber ich würde:
>
> IN   Reg, PIND
>
> schreiben.

Das kommt drauf an, was er erreichen will (und das geht aus
dem Eröffnungsposting so nicht klar hervor).

  IN  Reg, PORTD

kann durchaus Sinn machen, wenn er zb den zuvor am einem
Port ausgegebenen Wert haben möchte. Oder wenn es darum geht
Pull-Up Widerstände zu- oder wegzuschalten.

von wjunky (Gast)


Lesenswert?

Hallo alle zusammen.

AVRs können für gewöhnlich
in Reg, SREG
da das SREG sich als normales IOReg misshandeln lässt. Verbraucht nur 
unnötig mehr cycles als die vordefinierten, hardware-implementieren 
branches.

@Gray: was genau willst du?
wenn du
in Reg, PORTD machst holst du dir den wert, den du dort 
hineingeschrieben hast. PORTx ist eine Speicherstelle, die nur von 
deinem Programm verändert wird. Sie kann also als Variable missbraucht 
werden, wird aber nicht von außen geändert.
Wenn du wissen willst, ob der Pin high oder low ist musst du PINx 
auslesen.
PINx liefert dir in Abhängigkeit von DDRx entweder den Wert der außen 
anliegt (DDRxn auf input) oder den das bit im PORTx (DDRxn auf output).
Sollte es dennoch Probleme geben, dann schau mal nach, ob der Pin nicht 
überschrieben wird (Doku => alternate Portfunctions). Eine Reihe von 
Devices sind in der Lage die Werte in DDR und PORT zu überlagern. DDR 
und PORT geben zwar immer den Wert zurück der in sie hineingeschrieben 
wurde (von deinem Programm), aber der eigentliche Wert am PIN kann vom 
erwarteten Ergebnis abweichen, wenn beispielsweise das TWI die PINs 
gerade kontrolliert.

Schreib mal etwas genauer, was du machen willst, dann können wir dir 
auch detaillierter helfen...

von Stefan E. (sternst)


Lesenswert?

wjunky wrote:

> Verbraucht nur
> unnötig mehr cycles als die vordefinierten, hardware-implementieren
> branches.

Ja, meine Variante braucht genau 1 Cycle mehr.
Ich bevorzuge trotzdem die Skip-Befehle (vorausgesetzt es muss wirklich 
nur ein Befehl übersprungen werden), weil ich finde, dass es der 
Übersichtlichkeit dient, wenn man Sprungmarken einspart. (Ist aber wohl 
eher persönliche Geschmackssache)

> PINx liefert dir in Abhängigkeit von DDRx entweder den Wert der außen
> anliegt (DDRxn auf input) oder den das bit im PORTx (DDRxn auf output).

Nein, PINx liefert immer den Wert "von außen". Der sollte bei 
DDRx=output allerdings mit PORTx übereinstimmen. Wenn er mal nicht 
übereinstimmt, lebt der Port sicher nicht mehr lange. ;-)

von Gray (Gast)


Lesenswert?

THX@ALL

Ui, hätte ja nicht gedacht das mein erstes Projekt doch so kompliziert 
sein könnte.

Ich möchte insgesamt folgendes:

Ich habe 2 Taster und 4 Ausgänge

Wenn Taster 1 gedrück wird soll Ausgang 1 kurz einen Impuls bekommen und 
Ausgang 2 dauerhaft an bleiben

bis

Tatser 2 gedrückt wird, jetzt gibt es an Ausgang 3 einen Impuls und 
Ausgang 4 wird dauerhaft eingeschaltl dafür aber wieder Ausgang 2 aus.

Das ganze ist für die Eisenbahnanlage, da ich nur weichen habe die keine 
Rückmeldung und auch keine Endabschaltung haben, hab ich mir das so 
vorgestellt, das beim einschalten alles auf eine "Startposition" 
gebracht5 wird (deshalb die Abfrage anch den Pin 5 & 6).

Wenn ich Tatser 1 drücke geht die Weiche per Impuls nach links und LED 1 
leuchtet und wenn ich Tatser 2 drücke geht die Weiche nach rechts und 
LED 2 leuchtet.

Mag zwar sein das man das einfacher lösen kann mit FlipFlops oder so, 
aber ich brauch halt was praktisches um das proggen der kleinen Dinger 
zu lernen ;)

von wjunky (Gast)


Lesenswert?

Hiho!

@Stefan: stimmt schon, wenn der AVR schon raucht, kann PIN schonmal was 
anderes anzeigen :D

@Gray
Das kannst du sogar mit nur einem Taster realisieren :-)

Aber zu deinem Aufbau:
Die Taster-Pins solltest du gegen GND mit Pull-ups betreiben (DDR clear 
und PORT set). Die LED solltest du gegen VCC (mit Widerstand) betreiben. 
Du ziehst dann einfach den PIN auf GND (DDR und PORT clear). Das ist 
schonender für den AVR.

Dann kannst du dir überlegen, ob du mit Timern oder mit Schleifen bzw. 
mit Interrupts oder mit Polling arbeitest. Für Anfänger sind Schleifen 
und Polling erstmal einfacher. Zum Programmieren lernen, kannst du dich 
dann später noch mit Timer-Interrupts, externen Interrupts und 
Sleepmodes beschäftigen.

Um bei dem ganzen nicht total den Überblick zu verlieren, würde ich den 
aktuellen Zustand einfach in einem Register speichern und dann einfach 
damit arbeiten. Dann schreibst du dir eine Methode, die abhängig vom 
aktuellen Zustand einfach die Port-Register richtig setzt. Das hat auch 
den Vorteil, dass du nur diese Methode ändern musst, wenn du die 
Pinbelegung änderst.

Ich will jetzt nicht zu viel Hilfe geben, da du selber basteln willst. 
Wenn du nochmal hängst, kannst du dich ja noch mal melden.

von Hannes L. (hannes)


Angehängte Dateien:

Lesenswert?

Da Du in jeder Weichenstellung eine LED dauerhaft einschalten willst und 
einen Impuls für die Weichenspule erzeugen willst, reicht es nicht, mit 
kombinatorischer Logik zu arbeiten, da muss sequentielle Logik her. Und 
da Du beim Kauf Deines Tiny2313 die Timer bereits mit bezahlt hast, wäre 
es Unfug, sie (zumindest einen davon) nicht zu benutzen. Und weil der 
Tiny2313 genug I/O-Pins für 2 Weichen hat, wäre es Verschwendung, das 
Programm für nur eine Weiche auszulegen. Und damit Deine Weichen nicht 
bei jedem Rad-Schiene-Funken von alleine schalten, sollte man die 
Tasteneingänge auch ordentlich entprellen. Damit Du Dir nicht erst 
irgendwelchen Blödsinn mit Bitparaden (sowas wie 0b00110101) angewöhnst, 
habe ich die Bits "getauft" und nenne sie beim Namen.

Im Anhang findest Du einen Programm-Quelltext, den Du mit Hilfe der 
enthaltenen Kommentare, des Datenblattes des Tiny2313, der Hilfe (F1) 
des AVR-Studios und des Simulators des AVR-Studios analysieren kannst, 
um die Funktion zu verstehen.

Du kannst natürlich auch einfach die Hexdatei erzeugen und in Deine AVRs 
brennen und Dich freuen, dass es funktioniert, aber dabei lernst Du 
nicht wirklich was...

...

von df311 (Gast)


Lesenswert?

ups, die fehler bei den hex-zahlen oben tun mir leid - ich sollte nicht 
zwischen zwei vorlesungen zuviel nachdenken ;-)

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.