2. Einführung/Assembler Programmierung Es soll eine einfache Einführung in die Fuktionsweise des PIC16F84A gegeben werden. Anhand eines Beispielprogramms werden einige grundlegende Assemblerbefehle besprochen. Empfohlene Literatur: PIC16F84A.pdf (Das Datenblatt des Prozessors) Mid-Range_MCU_Family_Reference_Manual.pdf 2.1 Einführung 2.1.1 Übersicht Der PIC16F84A ist ein Mikrocontroller, der eine CPU, Programm- und Datenspeicher und I/O-Ports auf einem Chip vereint. Die CPU kennt 35 Assemblerbefehle. Features: • 13 Ein- /Ausgänge (I/Os) • einen integrierten 8-Bit Timer / Zähler • Verschiedene Interrupts • einen RAM mit 68 Byte freier Kapazität • integrierter EEPROM (nicht flüchtiger Speicher) • Programmspeicher mit 1024 Worten (bis zu 10.000 mal beschreibbar) • Taktfrequenz bis 5MHz 2-1 2.1.2 Blockschaltbild des Prozessors 13 Program Counter Data Bus 8 EEPROM Data Memory FLASH Program Memory 8 Level Stack (13-bit) 1K x 14 Program Bus 14 RAM File Registers EEDATA 68 x 8 7 RAM Addr EEPROM Data Memory 64 x 8 EEADR Addr Mux Instruction Register 7 Direct Addr 5 TMR0 Indirect Addr FSR reg RA4/T0CKI STATUS reg 8 MUX Power-up Timer Instruction Decode & Control Timing Generation Oscillator Start-up Timer 8 ALU Power-on Reset Watchdog Timer I/O Ports RA3:RA0 W reg RB7:RB1 RB0/INT OSC2/CLKOUT OSC1/CLKIN MCLR VDD, VSS Die PIC Prozessoren besitzen eine Harvard-Architektur, das bedeutet dass Programmund Datenspeicher getrennt sind: Es gibt einen Flash-Program-Memory in den das Programm des Prozessors geladen wird (man spricht hier vom „Flashen“). Dieser Flash Speicher kann bis zu 1024 Befehle speichern; sie bleiben auch nach dem Entfernen der Betriebsspannung gespeichert. Im RAM stehen 88 jeweils ein Byte breite Register zur Verfügung. Ein Teil davon (die SFR Special Function Register) wird verwendet um die Ein- und Ausgänge, den Timer, Interrups und andere "on-chip" Funktionen zu steuern. Die restlichen Register (68 Stück) sind vom Anwender frei verwendbar, in ihnen lassen sich also Variablen und Flaggen abspeichern (GPR = General Purpose Register). Des weiteren verfügt der PIC über einen EEPROM, in dem Werte nicht-flüchtig abgespeichert werden können. Das heisst die Daten bleiben - im Gegensatz zu den im RAM gespeicherten – auch nach dem Entfernen der Betriebsspannung erhalten. 2-2 2.1.3 Register (RAM) File Address File Address 00h Indirect addr. (1) Indirect addr. (1) 80h 01h TMR0 OPTION_REG 81h 02h PCL PCL 82h 03h STATUS STATUS 83h 04h FSR FSR 84h 05h PORTA TRISA 85h 06h PORTB TRISB 86h 07h — — 87h 08h EEDATA EECON1 88h 09h EEADR EECON2(1) 89h 0Ah PCLATH PCLATH 8Ah 0Bh INTCON INTCON 8Bh 8Ch 0Ch 68 General Purpose Registers (SRAM) Mapped (accesses) in Bank 0 4Fh 50h 7Fh CFh D0h Bank 0 FFh Bank 1 Unimplemented data memory location, read as ’0’. Note 1: Not a physical register. Der Datenspeicher ist in zwei Bänke aufgeteilt. Die Umschaltung zwischen den Bänken erfolgt durch Bit 5 im STATUS -Register (STATUS, RP0): RP0 = 0: Bank 0 RP0 = 1: Bank 1 Wie zu erkennen ist, werden alle Speicherplätze bis 0x0B von den SFR verwendet. Das erste freie Register, das zum Abspeichern von Daten verwendet werden darf liegt bei 0x0C. Eine wichtige Ausnahme vom Speicherbereich ist das W (working) Register. Es liegt nicht im RAM sondern gehört zu der ALU. Die ALU speichert darin z.B. Rechenergebnisse ab. 2-3 2.1.4 Befehlssatz Parameter Beschreibung f (file) Ein Register d (destination) Ergebnis speichern in d = 0 → w (working register) d = 1 → f (file, ein Register) k Konstante b (bit) Position eines einzelnen Bits innerhalb eines Registers 2-4 2.1.5 Ein-/Ausgänge Der PIC16F84A besitzt insgesamt 13 I/O Ports: PORTA (5 Bit) und PORTB (8 Bit) welche über die Register PORTA und PORTB angesteuert bzw. ausgelesen werden können. Sie können über die TRIS-Register (TRISA, TRISB) individuell als Einbzw. Ausgänge geschaltet werden. Wird ein TRIS-Bit geöscht, so wird der entsprechende Pin ein Ausgang, wird das Bit gesetzt ein Eingang. Merke: Tris-Bit gelöscht: Tris-Bit gesetzt: 0 = 0utput 1 = 1nput 2.1.6 Timer0 Der Timer0 (TMR0) ist wahlweise ein vom Prozessortakt abhängiger 8-Bit Timer oder ein Zähler. Dies kann im Option-Register durch Bit 5 ( OPTION_REG, T0CS) festgelegt werden; Man schaltet damit eigentlich nur die Taktquelle des Zählers um. T0CS gelöscht: Zähler incrementiert mit Prozessortakt T0CS gesetzt: Zähler zählt Impulse an PORTA,4 Das Register TMR0, in dem gezählt wird, kann beschrieben und gelesen werden. Zur Verringerung der Zählfrequenz kann dem Zähler ein Prescaler vorgeschaltet werden. Dieser ist alternativ beim Watchdog-Timer oder TMR0 einsetzbar. Die Zuweisung erfolgt durch das Bit 3 des Option-Register (OPTION_REG, PSA). PSA gelöscht: Prescaler wird TMR0 zugeordnet PSA gesetzt: Prescaler wird dem Watchdog-Timer zugeordnet Der Wert des Prescalers (Teilungsfaktor) wird durch die Bits 2-0 im OptionRegister bestimmt (siehe Datenblatt Kap. 2.3.2.). Sobald der Timer von 0xFF nach 0x00 überläuft, wird Bit 2 (T0IF) im INTCONRegister (INTCON, T0IF) gesetzt und ein Interrupt ausgelöst, sofern dieser aktiviert ist. 2-5 2.2 Assembler Programmierung Im Folgenden werden einige wenige Assembler-Befehle (Mnemonics) aus dem Befehlssatz des PIC16F84a besprochen. Weitere Mnemonics werden wir in den folgenden Übungen behandeln. Für eine ausführliche Beschreibung aller Befehle siehe PIC16F84A-Datenblatt Kapitel 7.1. 2.2.1 Byte-bezogene Mnemonics Mnemonic Argument Beschreibung verändert in STATUS clrf f löscht das Register f Z movwf f kopiert Inhalt von W nach f none movf f, d kopiert Inhalt von f nach W (d=0) oder nach f (d=1) Z rlf f, d rotiert f nach links durch Carry, Ergebnis in W (d=0) oder f (d=1) C rrf f, d rotiert f nach rechts durch Carry, Ergebnis in W (d=0) oder f (d=1) C Zur Beschreibung der Parameter siehe 2.1.4 2.2.2 Bit-bezogene Mnemonics Mnemonic Argument Beschreibung verändert in STATUS bsf f, b setzt das Bit b in f none bcf f, b löscht das Bit b in f none btfss f, b überspringt den nächsten Befehl, none wenn in f das Bit b gesetzt ist btfsc f, b überspringt den nächsten Befehl, none wenn in f das Bit b gelöscht ist Zur Beschreibung der Parameter siehe 2.1.4 2.2.3 Literal- und Steuerungs-Mnemonics Mnemonic Argument Beschreibung verändert in STATUS movlw k lädt den Wert k in W none goto k setzt das Programm an Stelle k fort none call k ruft das Unterprogramm k auf none return - rückkehr vom Unterprogramm none Zur Beschreibung der Parameter siehe 2.1.4 2-6 2.2.4 Beispiele Beispiel 1: In das Register 0x0C soll der Wert 1 movlw 1 geschrieben werden. Da der Datenbus keinen Zugriff auf den movwf 0x0C Programmspeicher hat ist dies nur über den Umweg über das Arbeistsregister möglich. Beispiel 2: Das Register 0x0E soll auf den Wert des Registers 0x0D gesetzt werden: movf 0x0D, W movwf 0x0C Beispiel 3: Der Inhalt des Registers 0x0C soll mit zwei multipliziert werden und im selben Register gespeichert werden rlf 0x0C, f Beispiel 4: Eine Einfache Schleife loop incf PORTA,f goto loop ... Beispiel 5: Aufruf eines Unterprogramms call Sub ... Sub ... ... return Beispiel 6: Der dritte Pin des Port A (PORTA, 3) soll als Ausgang geschaltet werden, und auf 1 gesetzt werden bsf bcf bcf bsf STATUS, RP0 ;Umschalten auf Bank1 ;(dort liegt das TrisA Register) TRISA, 3 ;Tris-Bit löschen, damit der ;Pin als Ausgang geschaltet wird STATUS, RP0 ;Umschalten auf Bank0 (dort liegt ;das PortA Register) PORTA, 3 ;Port auf High setzen 2-7 2.3 Vollständiger Befehlssatz Es folgt eine Aufstellung des kompletten Befehlssatzes des PIC16F84A. Für eine ausführliche Beschreibung der einzelnen Befehle siehe PIC16F84A-Datenblatt Kapitel 7.1. 2.3.1 Wichtige Flaggen im Status-Register Pos. Name Funktion 0 C (Carry) Überlauf des 8ten Bits 1 DC (Digit Carry) Überlauf des 4ten Bits 2 Z (Zero) Ergebnis ist 0 2.3.2 Speicherbefehle Mnemonic Parameter Beschreibung Status-Flags CLRW - Clear w Z CLRF f Clear f Z MOVLW k Move Literal to w - MOVWF f Move w to f - MOVF f,d Move f to d Z BCF f,b Bit Clear f<b> - BSF f,b Bit Set f<b> - Zur Beschreibung der Parameter siehe 2.1.4. 2-8 2.3.3 Arithmetische- und Logische Befehle Mnemonic Parameter Beschreibung Status-Flags ADDLW k Add literal k to w C,DC,Z SUBLW k Subtract w from literal k C,DC,Z ANDLW k AND literal k with w Z IORLW k Inclusive OR literal k with w Z XORLW k Exclusive OR literal k with w Z ADDWF f,d Add w to f C,DC,Z SUBWF f,d Subtract w from f C,DC,Z ANDWF f,d AND w with f Z IORWF f,d Inclusive OR w with f Z XORWF f,d Exclusive OR w with f Z INCF f,d Increment f Z DECF f,d Decrement f Z COMF f,d Complement f Z RLF f,d Rotate left f C RRF f,d Rotate right f C SWAPF f,d Swap nibbles in f - Beispiel: Zum Register 0x10 soll der Wert 5 movlw 5 addiert werden: addwf 0x10, f Der Wert des Registers 0x11 soll um incf 0x11, w 1 erhöht werden und das Ergebnis in movwf 0x12 Beispiel: 0x12 gespeichert werden: 2-9 2.3.4 Sprungbefehle, Labels, Stack Mnemonic Parameter Beschreibung GOTO k Go to address k CALL k Call subroutine at adress k RETURN - Return from subroutine RETLW k Return from subroutine with literal k in w RETFIE - Return from interrupt An jeder Stelle im Assembler-Quellcode können sogenannte Labels gesetzt werden, die bei der Assemblierung in die Adressen des jeweils nächsten Befehls aufgelöst werden. Labels stehen üblicherweise an erster Position in einer Befehlszeile, alle anderen Ausdrücke nach einem white space (Tab/Leerzeichen). Beispiel: Einfache Schleife loop incf PORTA,f goto loop Ebenfalls nützlich ist der $-Operator, der stets die Adresse des aktuellen Befehls repräsentiert. Beispiel: Einfache Schleife mit incf $-Operator goto $-1 2-10 PORTA,f Beispiel: Aufruf eines ... Unterprogrammes call Sub ... Sub ... ... return Beim Aufruf eines Unterprogramms wird der aktuelle Wert des Programmzählers automatisch auf dem Stack abgelegt. Bei einem Rücksprung aus dem Unterprogramm wird der oberste Eintrag des Stacks zurück in den Programmzähler geschrieben, so daß die Ausführung an der richtigen Stelle fortgesetzt wird. Der Stack des PIC16F84A ist 8 Ebenen tief, es sind daher nur 8 Unterprogrammebenen möglich. Vorsicht: Bei mehr als 8 aufeinanderfolgenden CALL-Anweisungen wird der erste Eintrag im Stack ohne Warnung des Assemblers überschrieben! 2-11 2.3.5 Bedingte Verzweigungen Mnemonic Parameter Beschreibung DECFSZ f,d Decrement f, skip if zero INCFSZ f,d Increment f, skip if zero BTFSC f,b Bit test f<b>, skip if clear BTFSS f,b Bit test f<b>, skip if set Trifft ein Test zu, so wird die nächste Anweisung übersprungen! Beispiel: Bedingte Ausführung einer Anweisung AL = AL + 5; if( STATUS<C>==1 ) AH = AH + 1; movlw 5 addwf AL,f btfsc STATUS,C incf AH,f Beispiel: Bedingte Ausführung eines Anweisungsblocks if( A==B ) { Block_1 } else movf A,w subwf B,w btfss STATUS,Z goto Block_2 Block_1 ... { ... Block_2 goto } Block_2 ... ... Block_2_END 2-12 Block_2_END Beispiel: Schleife for( i=10; i>0; i-- ) { ... } [ äquivalent zu ] i=10; do { movlw 0x0A movwf i loop ... ... i--; } while( i>0 ); 2-13 decfsz i,f goto loop 2.3.6 Sonstige Befehle Mnemonic Parameter Beschreibung NOP - No operation SLEEP - Standby-Modus CLRWDT - Clear Watchdog Timer 2.3.7 Zahlenformate Basis Syntax Dezimal Hexadezimal Oktal Binär d'122' h'7A' o'172' b'1111010' 'z' D'122' H'7A' O'172' B'1111010' A'z' .'122' 0x7A 172o 1111010b .122 PiKdev 122d 7Ah 2-14 ACII 2.4 Metabefehle Neben den Assembler-Befehlen existieren noch zahlreiche Metabefehle, die vom Assembler vor der eigentlichen Code-Generierung bearbeitet werden. Nützliche Metabefehle sind z.B: Befehl Funktion processor processor Stellt den verwendeten Prozessor ein. include "file" (Wie in C.) Fügt an dieser Stelle die Datei file ein. include <file> "file“ : Sucht file im Projektordner. #include "file" <file> : Sucht file im Include-Pfad. #include <file> #define name [string] (Wie in C.) Definiert name := string. #undefine name (Wie in C.) Definition aufheben. org addr Der folgende Code wird ab Adresse addr im Programmspeicher abgelegt. (Wichtig z.B. für Interruptroutinen!) name equ addr Der Adresse addr wird das Label name zugeordnet (z.B. zur Definition von Variablen). cblock addr label_1, label_2 label_3 ... endc Definiert fortlaufende Labels ab Adresse addr banksel addr Generiert automatisch den nötigen Code zur Auswahl der Speicherbank in der die Adresse addr liegt. end Muß am Ende eines Programms stehen. (z.B. zur Definition von Variablenblöcken). 2-15