Forum: Mikrocontroller und Digitale Elektronik avr asm rollen einsteigerhilfe


von Markus (Gast)


Lesenswert?

Hallo!

Ich bin gerade dabei mir assembler für avrs anzueignen. dazu wollte ich 
ein wenig mit den leds des stk500 spielen.
Ich würde die leds gerne von aussen nach innen rotieren lassen, aber von 
beiden seite, ungefähr so:

x------x         x = led an
-x----x-         - = led aus
--x--x--
---xx---
---xx---
--x--x--
-x----x-
x------x

dabei bin ich auf folgende zwei probleme gestossen:
1. Wie rotiere ich nur ein bit durch ein register? (wenn ich rol oder 
ror aufrufe, gehen alle leds nacheinander an)
2. Wie lasse ich nur die unteren bzw oberen 4 Bit des registers 
rotieren(ich muss ja unten nach links schieben und die oberen rechts)

hier meine interrupt routine:
schieben_leds:
  push   temp;temp speichern

  clr  mili ;milisekunden zähler zurücksetzen

  mov   temp, leds;register leds in temp laden
  ror   temp;temp nach recht schieben
  mov   leds, temp;geschobenes temp zurück in leds laden
  out   PORTB, leds;ausgabe des led registers

  pop   temp;temp laden

von Sigint 112 (sigint)


Lesenswert?

Hallo Markus,
  sowas machst du am einfachsten mit Tabellen in denen du die Bitmuster 
ablegst. Schiebeoperationen sind dafür zu umständlich.

Gruß,
  SIGINT

von Steven (. (ovular) Benutzerseite


Lesenswert?

http://www.mikrocontroller.net/articles/AVR-Tutorial:_Mehrfachverzweigung#Sprungtabelle

Nur noch ein Zähler, der von 0-7 oder 8 zählen kann und fertig

Ach ja in den Zweigen schreibst du einfach was wie:
1
zweig_3:    ldi temp2, 0b001000100  rjmp ende_vergleich
2
zweig_4:    ldi temp2, 0b.....

MfG Steven

von Markus (Gast)


Lesenswert?

das funktioniert nicht...

ich denke mal ich mach auch irgendwas falsch

.include "m16def.inc"

.def leds = r16
.def temp = r17
.def mili = r18
.def sek  = r19
.def status = r20
.def temp2 = r21
.equ minimum = 3
.equ maximum = 7

.org 0x00
  rjmp main
.org OVF0addr
  rjmp schieben

main:
  ldi     temp, LOW(RAMEND)  ; Stackpointer initialisieren
  out     SPL, temp
  ldi     temp, HIGH(RAMEND)
  out     SPH, temp
  ldi   leds, 0xFF       ; lade Arbeitsregister r16 mit der Konstanten 
0xFF
  out   DDRB, leds       ; Inhalt von r16 ins IO-Register DDRB ausgeben
  ldi   leds, 0xfe ; 0b11111100 in r16 laden
  out   PORTB, leds      ; r16 ins IO-Register PORTB ausgeben
  ldi     temp, 1 << CS02
    out     TCCR0, temp
  ldi     temp, 1 << TOIE0
    out     TIMSK, temp
  sei
  rjmp   loop
schieben:
   push    temp               ; temp 1 sichern

    in      temp,sreg          ; SREG sichern
    push    temp
  inc   mili
  ldi   temp, 0x0F
  cp    mili, temp

  breq   schieben_leds

  rjmp  end_tim_ovf0
schieben_leds:
  push   temp

  clr    mili
  subi    temp,minimum                 ; Nullpunkt verschieben
    cpi     temp,(maximum-minimum+1)     ; Index auf Maximum prüfen
    brsh    end_tim_ovf0                ; Index zu gross -> Fehler
    ldi     ZL,low(Mustertabelle)       ; Tabellenzeiger laden, 16 Bit
    ldi     ZH,high(Mustertabelle)
    add     ZL,temp                      ; Index addieren, 16 Bit
    ldi     temp,0
    adc     ZH,temp
    ijmp

  out   PORTB, leds     ; aktualisieren

  pop   temp
end_tim_ovf0:
  pop     temp
    out     sreg,temp         ; sreg wieder herstellen
    pop     temp
  reti
Mustertabelle:
    rjmp    m0
    rjmp    m1
    rjmp    m2
    rjmp    m3
m0:
  ldi  leds, 0b10000001
  ret
m1:
  ldi  leds, 0b01000010
  ret
m2:
  ldi  leds, 0b00100100
  ret
m3:
  ldi  leds, 0b00011000
  ret
loop:
  rjmp   loop           ; Sprung zur Marke "ende" -> Endlosschleife

von Steven (. (ovular) Benutzerseite


Lesenswert?

Ja man veröffentlicht sowas als Anhang!

Wo ist da jetzt der Unterschied?

von Markus (Gast)


Lesenswert?

wie meinen unterschied?
es passiert rein garnichts...

von Steven (. (ovular) Benutzerseite


Lesenswert?

Ja nur 2,3 Befehle reichen halt auch nicht. Das ist mir schon klar.
Aber du hast das doch ganz gut hinbekommen. So in der Art meinte ich es.

Ich hab meine Sammlung leider nicht da, aber ich kann dir ja morgen früh 
mal ein Beispiel von mir geben, wenn du willst.

von Markus (Gast)


Lesenswert?

ja aber es passiert gar nichts...

das mit dem beispiel wäre nett.
in c würde ich mir jetzt einen char array anlegen und den durchgehen. 
ist sowas auch in assembler möglich?

von Falk B. (falk)


Lesenswert?


von Markus (Gast)


Lesenswert?

also... das mit der sprungtabelle funktioniert jetzt so weit.
aber das programm springt immer nur in m2. warum?

von spess53 (Gast)


Lesenswert?

Hi

>in c würde ich mir jetzt einen char array anlegen und den durchgehen.

In Assembler(und binär):

Leds:   .db 0b10000001,0b01000010
        .db 0b00100100,0b00011000
        .db 0b00011000,0b00100100
        .db 0b01000010,0b10000001

Zugriff mit:
        ldi ZL,Low(leds<<1)
        ldi ZH,High(leds<<1)
        add ZL,Offset  ;Offset: in Register rxy
        adc ZH,NULL    ;NULL: Register mit 0 geladen
        lpm ry,Z

Das Register Offset musst du in deinem Programm errechnen.

Wenn du Z nicht weiter brauchst:
        ldi ZL,Low(leds<<1)
        ldi ZH,High(leds<<1)
        lpm tyx,Z+
    Jetzt sollte Enderkennung kommen

MfG Spess


PS@ Falk: Das ist aber nur die halbe Wahrheit.

von Markus (Gast)


Lesenswert?

danke

von Herr M. (herrmueller)


Lesenswert?

Das geht auch ohne Tabelle:

M2:
  ldi Hilf,$01
  ldi Hilf2,$80
  ldi temp,8      ; 8mal

M1:  ldi Muster,$00
  or Muster,Hilf
  or Muster,Hilf2
  com Muster      ; für STK500 invertieren
  out PortB, Muster
  rcall delay05s
  lsr Hilf2
  lsl Hilf
  dec temp
  brne M1
  rjmp M2


Hilf2 wird nach rechts geschoben und Hilf nach links und die Bits 
jeweils mit "oder" in Muster gesetzt.

von Steven (. (ovular) Benutzerseite


Angehängte Dateien:

Lesenswert?

>ja aber es passiert gar nichts
geh mir nicht auf dem Keks!!! Das ginge, wenn du wüsstest was ich meine!

Im Anhang ein Programm mit einer Tabelle, das 2 LEDs zeigt, die in einen 
dunklen Raum gehen, dann aber Angst bekommen und zurückrennen.

MfG Steven

von Kachel - Heinz (Gast)


Lesenswert?

Cool, aber echt umständlich...

IJMP und ICALL sind verdammt starke und auch sehr nützliche Befehle, 
aber für diesen Zweck einfach Unfug (zuviel Overhead).

Es ist je nach Zählerstand ein anderes Bitmuster an den Port auszugeben. 
Dies erreicht man am einfachsten mittels LPM über den Z-Pointer. Das 
Verfahren wurde bereits von Spess53 beschrieben, weshalb ich mir jetzt 
ein weiteres Beispiel spare.

KH

von Steven (. (ovular) Benutzerseite


Lesenswert?

Ok scheint einfacher zu sein. Werd ich beim nächsten Mal 
berücksichtigen.
Danke!

MfG Steven

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.