avr asm rollen einsteigerhilfe

Gast #976507
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
Gast #976552
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
Gast #976711
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.
#976806
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.
Gast #976925
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren