Daten im PIC ablegen

Das letzte Experiment mit dem Lautsprecher hat dazu geführt, dass  man für jeden Ton eine eigene Routine schreiben mussten, obwohl sich diese Routinen nur durch den Wert des übergebenen Parameters unterscheiden. Im folgenden werden wir verschiedene Möglichkeiten kennenlernen, wie man solche Daten im PIC ablegen kann und durch geschicktes Adressieren ansprechen kann

1. Tabellen im Programmspeicher.

Eigentlich können Daten aus dem Programmspeicher nicht so ausgelesen werden, dass sie von einem Programm selber verwertet werden können. Allerdings gibt es im PIC-Assembler eine Rückkehr aus einer Prozeduraufruf, dem einen Wert im Work-Register mit an das Hauptprogramm übergeben kann:  retlw wert. 

Nach Rücksprung in die aufrufende Prozedur steht der übergebene Wert im Workregister. Das kann man sich zunutze machen, um Tabellen auch im Programmspeicher abzulegen: Das Hauptprogramm ruft die Prozedur tabelle mit dem offset des Wertes auf, den man auslesen möchte.

main
    movwf  offset     
    call   tabelle
    incf   offset,1
    goto   main

tabelle
    addwf  pc,1  ; addiere den Inhalt von w zum Befehlszähler
    retlw  5a    
    retlw  50       
    retlw  48    ; Sprungziel für offset = 3, Rückkehr mit w =48
    retlw  43
    retlw  40
;   usw
;   usw

Die Manipulation des Befehlszählers hat keinen Einfluss auf den Stack, auf den die Rücksprungsadresse beim Prozeduraufruf gelegt worden war.

 Aufgaben: 

1.  Lege die Frequenzdaten für die c-Dur-Tonleiter in einer Tabelle ab. Hole die Daten nacheinander mit Hilfe der obigen Methode ins Work-Register, so dass der entsprechende Ton dann gespielt werden kann. Sind alle acht Töne gespielt, so soll die Tonleiter wiederholt werden.

2. Auch die Dauer des Tones soll aus einer Tabelle ausgelesen und entsprechend ausgewertet werden.

 

2. Daten in Registern - Indirektes Adressieren

Viele Assembler kennen Befehle für das sogenannte indirekte Adressieren. So bedeutet z.B. der 8086-Assembler-Befehl  mov dl,basis[bx] folgendes. Lade den Inhalt der Adresse Basis+[bx]  ([bx] : Inhalt des Registers bx als offset) ins Register dl. Das ist eine elegante Möglichkeit, um Tabellen aus- bzw. einzulesen. Eine nicht ganz so elegante Art der indirekten Adressierung gibt es auch im PIC. 

So  kann man Konstanten in Registern ablegen, wenn man diese nicht für wichtigere Zwecke benötigt. Fängt eine Tabelle z.B. im Register Tabelle equ 18 an, dann ist eine Adressierung in der Form  movwf tabelle+3 möglich. Anweisungen wie movwf tabelle+offset  (wobei offset selbst ein Register ist) sind im Assembler des PIC nicht vorgesehen. Allerdings hat der PIC zwei Register, die eine indirekte Adressierung möglich machen: fsr_data equ 0 und fsr_adr equ 4. Führt man eine Schreib- oder Leseoperation in dem Register fsr_data durch, so wird diese in dem Register wirksam, dessen Adresse in fsr_adr steht.  Das folgende Programm zeigt, wie man in den Registern eine Tabelle indirekt schreiben und anschließend wieder auslesen kann.

; *********************************************************************indirekt.asm
; Beispielprogramm für indirekten Zugriff auf Datenregister
    list P=16C84
    fsr_data equ 00
    fsr_adr equ 04
    portb equ 06
    offset equ 0c

    verz1 equ 0d
    verz2 equ 0e
    Tabelle = 18     ; Datenadressen in der Tabelle dürfen nicht durch
                     ; sonstige Register überschrieben werden
    org 3ff
    goto start
 
    org 00
    start
    movlw 0          ; 00: alle Bits als Ausgang setzen
    trist portb
 
maien
    call writedata_ind
;   call writedata_dir
noch mal
    movlw 05
    movwf offset 
lies
    decfsz offset,1
    goto weiter        ; falls counter >0 liesdata
    goto noch mal       ; ansonsten fang wieder neu an
weiter
    movf offset,0      ; offset in w laden
    call readdata      ; und damit readdata aufrufen
    xorlw 0ff          ; invertieren des w-Registers
    movwf portb        ; Ausgabe nach Port B
    call verz
    goto lies          ; Schleife wiederholen
 

;*** Beispiel für indirekten schreibenden Zugriff auf die Register
writedata_ind
    movlw tabelle      ; Anfangsadresse der Tabelle nach
    movwf fsr_adr      ; fsr_adr (FSR:FileStackRegister) laden
    movlw 04           ; Zähler laden
    movwf offset
loopw
    movf offset,0      ; Jede Operation auf fsr_data wird in der
    movwf fsr_data     ; Adresse ausgeführt, die in fsr_adr enthalten ist
    incf fsr_adr,1     ; Tabellenadresse erhöhen
    decfsz counter
    goto loopw
    return

;*** Hier werden Daten direkt in die Register geschrieben
writedata_dir
    movlw 081
    movwf tabelle
    movlw 042
    movwf tabelle+1
    movlw 024
    movwf tabelle+2
    movlw 018
    movwf tabelle+3
return

;*** Daten werden durch indirekten Zugriff ausgelesen
readdata
    addlw tabelle-1     ; tabelle-1 um offset erhöhen
    movwf fsr_adr       ; die folgenden Leseopereation wird in dem
    movf fsr_data,0     ; Register ausgeführt, dass in fsr_adr steht
    return
 
verz
; die altbekannte verz-Routine
return
END

Aufgabe:

1. Benutze die Register 10 bis 19 für die Speicherung der Anzeigebytes für die 7-Segment-Anzeige. Dabei sollen diese Register beim Start des Programms nacheinander mit den entsprechenden Daten geladen werden. Im Hauptprogramm sollen ein Zähler vom 9 auf 0 heruntergezählt werden und dabei als offset für die indirekte Adressierung bzgl. der Basisadresse tabelle=100 verwendet werden. Die Werte sollen dann am PortB mit der 7-Segment-Anzeige ausgegeben werden.

 

Zurück