Aus RN-Wissen.de
Wechseln zu: Navigation, Suche
Balkonkraftwerk Speicher und Wechselrichter Tests und Tutorials

Einführung

Assembler

Die Maschinensprache, auch Assembler oder kurz ASM genannt, ist eine Sprache die nur bestimmter Prozessor versteht. Für einen Menschen ist sie unverständlich, da sie nur aus hexadezimalen (kurz: hex) Zahlen besteht.

Um sich die Sprache verständlicher zu machen wurden den hex Zahlen s.g. Mnemonics aus Buchstaben zugewiesen. Jeder Befehl für ein Prozessor hat somit einen "Namen", der meistens aus einer Abkürzung des Namens in englischer Sprache stammt.

Obwohl sie 200 bis 1000 mal schneller als die meisten Hochsprachen ist, wird sie wegen dem grossen Aufwand bei Erstellung umfangreichen Programmen, selten benutzt. Man findet sie aber oft in fast allen Hochsprachen, in eigebundenen Funktionen, überall dort wo die Hochsprachen zu langsam sind.

ASM eignet sich aber sehr gut für kleine Anwendungen (meistens Steuerungen) mit Mikrokontrollern (kurz: µC), weil nur bei dieser Programmiersprache ein direkter Zusammenhang zwischen einem bit im Programm und einer Spannung am I/O Pin besteht.

Die Aufgabe eines ASM-Programmierers ist, ein Programm zu schreiben, das der bestimmte Prozessor versteht und nach den Wünschen des Programmierers realisiert.

Beispiel für ein PAD

Weil ASM Programme nicht besonders durchschaubar sind, wurde als Hilfsmittel ein Programmablaufdiagramm (kurz: PAD) erfunden. Beim Programmerstellung fängt man damit an ein PAD zu erstellen, das die wichtigsten Programmschritte enthält.

Weiter werden alle Befehle nach dem PAD mit einem üblichen Texteditor in eine Textdatei mit Erweiterung .asm (Quellcode) geschrieben, durch ein Assemblerprogramm (für PICs: MPASM oder GPASM) von dem für Menschen noch verständlichen Code in die Maschinensprache "übersetzt" und als Texdatei mit Erweiterung .hex gespeichert. Diese Datei wird danach in den Programmspeicher des µC übertragen ("gebrannt"). Das Assemblerprogramm MPASM kann kostenlos von der Haupseite des Herstellers von PICs [htpp://www.microchip.com] runtergeladen werden.

Das PDA ist sehr behilflich um sogar nach langer Zeit im Programm ewentuelle Fehler zu finden oder Änderungen vorzunehmen.

Nach dem Eischalten der Betriebspannung des µC, fängt der Prozessor an, sich im Programmspeicher befindliches Programm mit dem Befehl, der an der Adresse 0 steht, auszuführen.

Grundbeschaltung

Der Prozessor von einem PIC kann arbeiten sofort nach dem Eischalten der Versorgungsspannung nur wenn er einen internen Oszillator besitzt (z.B. PIC12F629, PIC16F630, PIC16F628, u.s.w.). Die meisten haben ihn aber nicht (z.B. PIC16F84, PIC16F870, u.s.w.) und brauchen fürs Funktionieren zusätzliche Bauteile (Resistor + Kondensator, Quarz + 2 Kondensatoren oder Keramik-Resonator + 2 Kondensatoren, bzw. Quarzoszillator) die an Pins OSC1/OSC2 angeschlossen werden um notwendigen Prozessortakt zu erzeugen.

Damit ein Programm zuverlässig ausgeführt werden kann, muss die Versorgungspannung störungsfrei sein. Dafür wird ein Keramik-Vielschicht-Kondensator 100 nF möglichts am kürzesten direkt zwischen VDD und VSS Pins geschaltet.

Folgende Skizze zeigt die Grundbeschaltung eines PICs:

            VDD
             +
             |                           .------.
            .-.                          |  ||  |
          R | |                    VDD --+--||--+-- VSS
            | |                          |  ||  |
            '-'                   OSC1 >-|      |--
             |                           | 100n |
             +------> OSC1        OSC2 >-|      |--
             |                           |      |
          C ---                        --| PIC  |--
            ---                          |      |
             |                           '------'
            ===
         VSS = GND
                                                  OSC1
      Quartz oder                                  ^
                                                   |
      Keramik-Resonator               VDD          |
        +----------------> OSC1        +           |
        |  .--.                        |           |Ausgang
        +-||  ||-+-------> OSC2      .---------------.
        |  '--'  |                   |               |
    C1 ---      --- C2               |Quarzoszillator|
       ---      ---                  |               |
        |        |                   '---------------'
       ===      ===                                |
       GND      GND                               ===
                                                  GND

Wahl des PICs

Für die Wahl eines PICs für bestimmte Anwendung wichtig sind:

- Max. Taktfrequenz des Prozessors.

- Grösse des Datenspeichers (für Variablen).

- Grösse des Programmspeichers (für Programm).

- Integrierte Hardware (komparatoren, A/D Wandler, Timer, USART, I²C, SPI, PWM, u.s.w.).

- Freie I/O Pins für externe Hardware (Display, Tasten, u.s.w.).

- Vorhandene Betriebspannung (Netzteil, Akku, Batterie).

In der Praxis wird meistens für die Programmerstellung ein grösserer PIC genommen (wenn möglich pinkompatibler z.B. PIC16F628 für PIC16F84 oder PIC16F630 für PIC12F629) und erst nach der Optimierung des lauffägiges Programms, der tatsächlich nötiger, da seine Parameter am Anfang nur geschätzt werden können. Wenn man viel Programme für verschiedene PICs entwickelt, optimal wäre der grösste PIC16F877 mit 20 MHz max. Taktfrequenz.

Diese Lösung hat auch den Vorteil, dass während der Programmerstellung kurze Hilfsprogramme (z.B. PIC Trainer) in den Programmspeicher kopiert und benutzt werden können, da sie sowohl ein bischen Programmspeicher und RAM als auch 2 freie I/O Pins fürs PIC Miniterminal brauchen.

Programm

Allgemeines

Jedes Program kann man auf klenere Fragmente unterteilen, die auf bestimmter Weise miteinander verknüpft sind und gemeinsam die Aufgabe des Programms erfüllen. Das wichtigste Teil eines Programms ist s.g. Hautprogram (kurz:HP), das eine führende Rolle spielt. Dem HP sind alle andere Programmteile untergeordnet (weiter als Unterprogramm (kurz:UP) genannt) und werden nach Bedarf von ihm aufgerufen um eine bestimmte Aufgabe zu erledigen.

Die Struktur eines Programs ist aber kompliezierter, da ein UP kann auch ein oder mehrere UPs nacheinander aufrufen. Deswegen wird ein Programm von "unten" aufgebaut. Zuerst werden die UP1s erstellt, die ganz einfache Sachen erledigen. Danach kommt das nächste Ebene mit UP2s die schon mehr komplizierten Aufgaben durch ein Aufruf der UP1s erledigen können, u.s.w. Bei Mid-Range PICs (12FXXX und 16FXXX) können maximal bis zu 8 Ebenen benutzt werden.

         .-------------------------------------------.
         |                                           |
         |                    HP                     |
         |                                           |
         '-------------------------------------------'
             |           |           |           |
             |           |           |           |
             V           V           V           V
         .-------.   .-------.   .-------.   .-------.
         |  UP2  |   |  UP2  |   |  UP2  |   |  UP2  |
         '-------'   '-------'   '-------'   '-------'
          |           |             |         |
          |     +-----|-+-----------|-+-------+
          |     |     | |           | |
          |   +-|-----|-|-----------+-|-----------+
          |   | |     | |           | |           |
          | +-|-|-----+-|---------+-|-|---------+ |
          | | | |       |         | | |         | |
          +-|-|-|-----+-|---------|-|-|-------+ | |
          V V V V     V V         V V V       V V V
         .-------.   .-------.   .-------.   .-------.
         |  UP1  |   |  UP1  |   |  UP1  |   |  UP1  |
         '-------'   '-------'   '-------'   '-------'

Jedes UP kann jederzeit aufgerufen werden, je nach dem was gerade eledigt werden muss. Weil das nicht egal ist, welches UP augerufen wird, da jedes nur eine bestimmte Funktion im Programm hat, muss der Programmierer dafür sorgen, dass alles richtig nach PDA, und nicht chaotisch, abläuft.

Einfaches Beispiel für UPs:

Cmd   bcf   RS   ;setze RS=0 für Befehl
      goto  Send ;gehe zu Send
Dat   bsf   RS   ;setze RS=1 für Daten
Send  .......... ;schicke ein Byte ans Display
      return     ;gehe zurück zum Aufrufer

Das UP "Send" ist den UPs "Cmd" und "Dat" untergeordnet, weil von beiden benutzt wird, kann aber selber weder "Cmd" noch "Dat" benutzen.

Der PDA ist sehr eifach zu erstellen, weil dafür nur drei Symbole benötigt sind:

Symbole des PAD

Das "Start/Stopp" Symbol bedeutet, dass das Programm sich im stabilem Zustand befindet und nicht "läuft". Anstatt "Stopp" kann auch "Sleep" agewendet werden, da das Programm in dem Fall auch nicht aktiv ist. Das "Tun" Symbol stellt meistens ein UP mit Reihenfolge von Befehlen dar. Das "Prüfen" bedeutet eine Prüfung bestimmter Bedingung und abhängig davon einen weiteren Lauf des Programs, endweder in der "ja" oder "nein" Richtung.

Das Erstellen von PDA bei ASM Programmen ist sehr wichtig und darf nicht unterschätzt werden. Je stärker ein Programmierer glaubt, dass er das ohne PDA schaft, um so mehr Zeit wird er danach bei Fehlersuche oder Änderunen im Programm verlieren. Für einfache Programme, die gut kommentiert sind, reicht es meistens aus, ein PDA nur "im Kopf" zu erstellen, aber ganz ohne PDA geht es sicher nicht.

Die Programmierung in ASM ist änlich wie bei Hochsprachen, wenn man sich Bibliotheken mit Prozessorspezifischen UPs erstellt. Um ein lauffähiges Programm zu erstellen, braucht man nur benötigte UPs ins Program kopieren und ein geignetes HP, das sie aufruft, schreiben.

Midrange

Kurzübersicht Assembler Befehle

ADDLW Add literal and W
ADDWF Add W and f
ANDLW AND literal with W
ANDWF AND W with f
BCF Bit Clear f
BSF Bit Set f
BTFSC Bit Test f, Skip if Clear
BTFSS Bit Test f, Skip if Set
CALL Call subroutine
CLRF Clear f
CLRW Clear W
CLRWDT Clear Watchdog Timer
COMF Complement f
DECF Decrement f
DECFSZ Decrement f, Skip if 0
GOTO Go to address or label
INCF Increment f
INCFSZ Increment f, Skip if 0
IORLW Inclusive OR literal with W
IORWF Inclusive OR W with f
MOVF Move f
MOVLW Move literal to W
MOVWF Move W to f
NOP No Operation
RETFIE Return from interrupt
RETLW Return with literal in W
RETURN Return from Subroutine
RLF Rotate Left f through Carry
RRF Rotate Right f through Carry
SLEEP Go into standby mode
SUBLW Subtract W from literal
SUBWF Subtract W from f
SWAPF Swap nibbles in f
XORLW Exclusive OR literal with W
XORWF Exclusive OR W with f

Kurzübersicht zum Ausdrucken

Ausführliche Beschreibung zu den Befehlen

Erklärungen zu den Verwendeten Platzhaltern:

  • k stellt einen fest definierten Wert da. z.B. 0x20, d'42' oder b'00101010'
  • W steht für das W-Register.
  • d steht für destination. Im code wird d durch ein w bzw. 0 (der Wert wird in das W-Register gespeichert ) oder f bzw. 1 (der Wert wird in das davor definierte Register gespeichert)
  • R steht für ein Register
  • fett geschrieben Bedeutet, dass es ein Platzhalter ist und im Quellcode durch eine Registeradresse oder einen Wert ersetzt werden muss
  • Schreibmaschinenstil bedeutet, dass es so im Quellcode geschrieben werden kann.
DECF R,d Decrement f, Skip if 0 - Subtrahiert 1 vom Regiser f
Vom Wert des Registers R wird 1 subtrahiert und das Ergebniss entweder in das W-Register (d=W=0) oder in R gespeichert (d=F=1).
DECFSZ R,d Decrement f, Skip if 0 - Subtrahiert 1 vom Regiser f, überspringe wenn 0
Vom Wert des Registers R wird 1 subtrahiert und das Ergebniss entweder in das W-Register (d=W=0) oder in R gespeichert (d=F=1). Der Zusatz SZ steht für skip if zero, d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen.
GOTO Go to address - Gehe zu Adresse/Sprungmarke
Nach dem GOTO Befehl wird das Programm bei der Adresse weiter ausgeführt, die nach dem GOTO-Befehl steht. Diese Adresse wird durch so genannte Sprungmarken definiert, welche, im Gegensatz zu den Befehlen nicht eingerückt in der asm-Datei stehen.
INCF R,d Increment f - Addiere 1 zum Register f
Zum Wert des Registers R wird 1 addiert und das Ergebniss entweder in das W-Register (d=W=0) oder in R gespeichert (d=F=1).
INCFSZ R,d Increment f, Skip if 0 - Addiere 1 zum Regiser f, überspringe wenn 0
Zum Wert des Registers R wird 1 addiert und das Ergebniss entweder in das W-Register (d=W=0) oder in R gespeichert (d=F=1). Der Zusatz SZ steht für skip if zero, d.h. wenn das Ergebnis der Rechnung Null ist, wird der nächste Befehl übersprungen.
IORLW k Inclusive OR literal with W - ???
Es wird bitweise die logische Funktion [math]W\ ior\ k[/math] ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.
Zur Verdeutlichung der Rechenoperation:
1100 1010 ---- ior 1110
IORWF R,d Inclusive OR W with f - ???
Es wird bitweise die logische Funktion [math]W\ ior\ R[/math] ausgeführt und das Ergebniss entweder in das W-Register (d=W=0) oder in R gespeichert (d=F=1). Vergleiche IORLW
MOVF R,d Move f - Bewege f
Das Register R wird in das W-Register (d=W=0) oder wieder in R geschoben (d=F=1). Letzteres mag sinnlos scheinen, ist aber nützlich, da durch den Befehl das Z-Bit im STATUS-Regsiter gesetzt wird, falls R Null ist.
MOVLW k Move literal to W - Bewege Zahl in W-Register
Der festgelegte Wert k wird in das W-Register geschoben.
MOVWF R Move W to f - Bewege W-Register in das Register F
Das W-Register wird in das Register R kopiert.
NOP No Operation - Kein Befehl
Dieser Befehl macht nichts. Er verbraucht nur Zeit, welche sich einfach mit folgender Formel berechnen lässt. [math]t=\frac{4}{f}[/math],wobei [math]f[/math] für die Frequenz des Oszillators steht.
RETFIE Return from interrupt - Kehre zurück aus der Unterbrechung
Mit diesem Befehl wird der Interrupthandler (ISR) beendet und das Programm wird an der Zeile weiter ausgeführt, vor der es durch den Interrupt angehalten wurde. Es werden auch alle Interrupts wieder erlaubt (das GIE bit wird gesetzt). Siehe hierzu auch Interrupt
RETLW k Return with literal in W - Kehre zurück mit Zahl im W-Register
Wurde ein Programmteil mit dem Befehl CALL aufgerufen, dann springt man mit dem Befehl RETLW zurück in die nächste Zeile nach der Zeile aus der das CALL Befehl ausgeführt wurde. Der in k angegebene Wert wird dabei in das W-Register geschrieben. Dieser Befehl wird vor allem für s.g Sprungtabellen (eng: lookup tables) und Computed-Gotos verwendet.
RETURN Return from Subroutine - Kehre zurück zum Übergeordneten Programmteil
Wurde ein Programmteil mit dem Befehl CALL aufgerufen, dann springt man mit dem Befehl RETURN zurück zu der nächsten Zeile nach der Zeile aus der das CALL Befehl ausgeführt wurde.
RLF R,d Rotate Left f through Carry - Verschiebe das Register f mithilfe des Carry-bits nach links
Die Bits im Register R werden nach links verschoben. Dabei wird das Carry bit (STATUS,C) in das Bit 0 des Registers R geschoben. Bit 7 aus dem Register R wird in das Carry bit "geschoben". Das Ergebnis wird entweder in das W-Register (d=W=0) oder in R gespeichert (d=F=1).
Zur Verdeutlichung:
|C| |-Register R-| ;C steht für das Carry-bit, STATUS,C c 7 6 5 4 3 2 1 0 ;vor dem Verschieben 7 6 5 4 3 2 1 0 c ;nach dem Verschieben
RRF R,d Rotate Right f through Carry - Verschiebe das Register f mithilfe des Carry-bits nach rechts
Die Bits im Register R werden nach rechts verschoben. Dabei wird das Carry bit (STATUS,C) in das 7.Bit des Registers R geschoben. Bit 0 aus dem Register R wird in das Carry bit "geschoben". Das Ergebnis wird entweder in das W-Register (d=W=0) oder in R gespeichert (d=F=1).
Zur Verdeutlichung:
|C| |-Register R-| ;C steht für das Carry-bit, STATUS,C C 7 6 5 4 3 2 1 0 ;vor dem Verschieben 0 C 7 6 5 4 3 2 1 ;nach dem Verschieben
SLEEP Go into standby mode - Versetze den Mirokontroller in Bereitschaftsmodus
Der µC wird in den Sleep-Mode versetzt, in dem er weniger Strom verbraucht. Er kann durch einen Reset, einem Watchdog-Timer-Reset oder durch einen Interrupt wieder aufgeweckt werden.
SUBLW k Subtract W from literal - Ziehe W von Zahl ab
Es wird die Rechenoperation [math]k-W[/math] ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register
SUBWF R,d Subtract W from f - Ziehe W von f ab
Es wird die Rechenoperation [math]R-W[/math] ausgeführt und das Ergebniss entweder in das W-Register (d=W=0) oder in R gespeichert (d=F=1). Dieser Befehl beeinflusst das STATUS-Register. Siehe hierzu Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register
Beispiel:
movlw d'20'  ;schreibe 20 in das W-Register movwf Register1  ;bewegt das W-Register in das Register1 movlw d'10'  ;schreibt 10 in das W-Register SUBWF Register1,F ;schreibt Register1(20)-W(10) in Register1
SWAPF R,d Swap nibbles in f - Vertausche die Halbbyte Hälften
Es es werden die ersten 4 bit mit den letzten 4 bit eines Registers vertauscht und entweder in das W-Register (d=W=0) oder in R gespeichert (d=F=1).
Beispiel:
movlw b'00001111' ;schreibe b'00001111' in das W-Register movwf Register1  ;bewegt das W-Register in das Register1 SWAPF Register1,W ;vertauscht die ersten 4 bit mit den letzen  ;4 bit in Register 1 und schreibt es in das W-Register  ;im W-Register steht nun b'11110000'
XORLW k Exclusive OR literal with W
Es wird bitweise die logische Funktion [math]W\ xor\ k[/math] ausgeführt und das Ergebniss in das W-Register gespeichert. Dieser Befehl setzt das Z bit des STATUS-Register, falls W=k und das Ergebnis 0 ist.
Zur Verdeutlichung der Operation:
1100 1010 ---- xor 0110
XORWF R,d Exclusive OR W with f - ???
Es wird bitweise die logische Funktion [math]W\ xor\ R[/math] ausgeführt und das Ergebniss entweder in das W-Register (d=W=0) oder in R gespeichert (d=F=1). Vergleiche XORLW

Überprüfung von Rechenergebnissen mit Hilfe des STATUS-Register

Auswirkungen auf das STATUS-Register bei Subtraktionen
Ergebnis STATUS,C STATUS,Z
positiv 1 0
negativ 0 0
Null 1 1
Auswirkungen auf das STATUS-Register bei Addition
Ergebnis STATUS,C STATUS,Z
positiv 0 0
Überlauf 1 0
Null 1 1

LiFePO4 Speicher Test