avr asm rollen einsteigerhilfe

Gast #976507
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
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
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?
Gast
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.
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
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

Eine eigene Frage? Dieser Thread ist über 18 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.