;--------------------------------Konfiguration--------------------------------------------- list p=16f877 ;Prozessortyp angeben #include ;Iclude Datei für Controllervariablen einfügen ;Config-Bits __CONFIG _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_ON & _XT_OSC & _CPD_OFF & _LVP_OFF Errorlevel -302 ;BANKSEL-Meldungen abschalten ;------------------------------------------------------------------------------------------ ;-----------------------------------Belegung des PICs (PIC 16F877)------------------------- ; ; ________________ ; MCLR 5V--------1| |40-------Rel 16 RB7 ; RA0 Kanalsw1------2| |39-------Rel 15 RB6 ; RA1 Tast.Up/Kanalsw2------3| |38-------Rel 14 RB5 ; RA2 Tast.Dn/Kanalsw3------4| |37-------Rel 13 RB4 ; RA3 Kanalsw4------5| |36-------Rel 12 RB3 ; RA4 EDIT-sw-------6| |35-------Rel 11 RB2 ; RA5 ChannelNrRead Out-----7| |34-------Rel 10 RB1 ; RE0 BCD-Cathode1------8| PIC16F877 |33-------Rel 9 RB0 ; RE1 BCD-Cathode2------9| |32-------VDD(5V) VDD ; RE2 BCD-Cathode3-----10| |31-------VSS(0V) VSS ; VDD VDD(5V)------11| |30-------Rel 8 RD7 ; VSS VSS(0V)------12| |29-------Rel 7 RD6 ; OSC1 OSC1---------13| |28-------Rel 6 RD5 ; OSC2 OSC2---------14| |27-------Rel 5 RD4 ; RC0 BCD8---------15| |26-------RX(MIDI-IN) RC7 ; RC1 BCD4---------16| |25-------TX(RS-OUT) RC6 ; RC2 BCD2---------17| |24-------LiveModeTaster RC5 ; RC3 BCD1---------18| |23-------Edit/LiveModeOut RC4 ; RD0 Rel1---------19| |22-------Rel 4 RD3 ; RD1 Rel2---------20|________________|21-------Rel 3 RD2 ; ; ; ; Notizen: Bei Subtraktionen ist das Carry-Flag auf 1 wenn es keinen Überlauf gab, ; bei Additionen auf 0, wenn es keinen Überlauf gab! ;------------------------------------------------------------------------------------------ ;-------------------Variablen------------------------ #define Edit Flags,0 ; Name Edit= Flags, 0 #define Sw_Edit PORTA,4 ; Name für Edit-Taster #define Sw_Up PORTA,1 ; Name für preset-Up-Taster loops EQU 0x20 ; Variable loops für Zählschleife preset EQU 0x21 ; Variable für die aktuelle Nummer presetAnz EQU 0x22 ; Hilfsvariable für presetAnzeige Einer EQU 0x23 ; Rechte Ziffer der Anzeige Zehner EQU 0x24 ; Mittlere Ziffer der Anzeige Hunderter EQU 0x25 ; Linke Ziffer der Anzeige loopsEdit EQU 0x26 ; Anzahlvariable im Edit-Modus Flags EQU 0x27 ; Byte mit flags zum abfragen ; Bit 0 = Edit-Taster gedrueckt? ; Bit 1 = Statusbyte oder Datenbyte? ; Bit 2 = EEBYTE1 oder EEBYTE2 ? Channel EQU 0x28 ; Register für Kanalnummer Bytetemp EQU 0x29 ; Temporäre Variable für Empfangene Bytes EEPBYTE1 EQU 0x2A ; Erste EEPROM-Adresse EEPBYTE2 EQU 0x2B ; Zweite EEPROM-Adresse PresPart1 EQU 0x2C ; Preset Part 1 und PresPart2 EQU 0x2D ; Pres.Pt2 aus EEPROM als Relaismaske loops2 EQU 0x2E ; Variable f. aeussere Abfrageschleife StatusResc EQU 0x2F ; Rettungsvariable f. STATUS-Register WResc EQU 0x30 ; Rettungsvariable f. Arbeitsregister preseth EQU 0x31 ; hilfsvariable für preset org 0x00 ; Sprungziel bei reset goto STARTUP ;-------------------------------------------ISR---------------------------------------------------- org 0x04 ; Sprungziel bei Aufruf ISR goto ISR ISR movwf WResc ; Arbeitsregister retten movfw STATUS ; STATUS-Register laden movwf StatusResc ; Und ins Rettungsregister schreiben btfss PIR1, RCIF ; Pruefen ob Interupt durch Receive ausgeloest wurde goto ISREND ; Wenn nein, gehe zu Ende von ISR movfw RCREG ; Empfangsregister auslesen movwf Bytetemp btfss Flags,1 ; Wurde schon ein Statusbyte (Bit1) empfangen? goto EmpfangStatusByte ; Wenn nein gehe zu Empfang Statusbyte goto EmpfangDatenByte ; Wenn ja, gehe zu Empfan Datenbyte EmpfangStatusByte movfw Bytetemp sublw d'192' ; Konstante C (Prog-Change kennung) abzihen ;subwf Channel ; Danach Wird die Kanalnummer abgezogen btfss STATUS,Z ; Ist das Ergebnis = "0" ? goto ISREND ; Wenn nein, beende empfang bsf Flags,1 ; Markiere dass der erste Teil Empfangen wurde goto ISREND ; Beende ISR EmpfangDatenByte bcf Flags, 1 ; Setze Empfangsbytezuordnung wieder zurück, für die ; Nächste Nachricht movfw Bytetemp sublw D'127' ; Ziehe Maximalwert ab btfsc STATUS, Z ; Ist das Ergebnis Null? goto PresetZuweisung ; Wenn ja, gehe zur Zuweisung btfsc STATUS, C ; Ist das Carry-Bit gesetzt? goto PresetZuweisung ; Wenn ja, gehe zur Zuweisung goto ISREND ; Wenn nein, dann Wars wohl nix! PresetZuweisung movfw Bytetemp movwf preset goto ISREND ISREND call RS232Send bcf PIR1, RCIF ; Receive-Interupt-Bit wieder loeschen movfw StatusResc ; Statusregister wieder laden movwf STATUS ; und zurueckschreiben movfw WResc ; Arbeitsregister wieder laden retfie ; Zurückkehren aus Interuptroutine ;------------------------------------Eigentliches Programm------------------------------------- STARTUP BCF CCP1CON, CCP1M3 ; Abschalten der 2 Capture- BCF CCP1CON, CCP1M2 ; Compare-Module BCF CCP1CON, CCP1M1 BCF CCP1CON, CCP1M0 BCF CCP2CON, CCP2M3 BCF CCP2CON, CCP2M2 BCF CCP2CON, CCP2M1 BCF CCP2CON, CCP2M0 BSF STATUS, RP0 ; auf Bank 1 Umschalten MOVLW B'00000110' ; PCFG0-3 aus ; =Analog-Digital-Wandler aus MOVWF ADCON1 ; nach AD-Register schreiben ;---------------------Ports------------------------ MOVLW B'11011111' ; Konfiguration Port A. 6+7 nicht vorhanden MOVWF TRISA ; RA5 Output. RA4-RA0 inputs MOVLW B'00000000' ; Konfiguration Port B MOVWF TRISB ; Port B komplett Outputs (Rel 9-16) MOVLW B'10000000' ; Konfiguration Port C. 7= RX = Input | 6= TX = Output MOVWF TRISC ; 4+5 unbenutzt= Output | 3-0 = BCD-Ausgänge = Outputs MOVLW B'00000000' ; Konfiguration Port D MOVWF TRISD ; PORT D Komplett Outputs (Rel 1-8) MOVLW B'00000000' ; Konfiguration Port E MOVWF TRISE ; RE0-RE2 = Cathode Outs für BCD; 4 muss 0 sein, sonst ; Wären Port E und Port D Paralel Slave Port ;---------------------RS232------------------------ clrf PIE2 ; Interuptarten Rücksetzen bsf PIE1, RCIE ; Receive Interupts Enable movlw D'25' ; Ergibt zusammen mit BRGH='0' 31.250 kbaud/s movwf SPBRG ; und mit SPBRG='25' 2400 baud/s movlw B'00100010' ; Sender Einstellen: 8 Bit-Modus, Transmit Enable movwf TXSTA ; asynchrone mode, Tranmit Shift Register Leer (=1) bcf STATUS, RP0 ; zurück in Bank 0 movlw B'10010000' ; Empfänger Einstellen: Pins RX und TX aktivieren movwf RCSTA ; 8 Bit-Empfang, Continous Receive clrf INTCON ; Interupterlaubnis Ruecksetzen bsf INTCON, GIE ; Interupts generell erlauben (Global Interupt Enable) bsf INTCON, PEIE ; Peripheral Equipment Interupt Enable ;--------------------Ports auf Null---------------- clrf PORTA ; Alle Ausgänge Low clrf PORTB clrf PORTC clrf PORTD clrf PORTE ;-------------------Intro-Animation---------------- movlw d'4' ; Preset wird kurz als zählervariable movwf preset ; missbraucht Intro1 bsf PORTE, 0 ; Segment eins aktiv movlw d'1' ; Wert Ziffer 1 laden call BCD ; BCD-Auswertung movwf PORTC ; 7-Segmentanzeige beschreiben movlw d'254' ; ca 0,5s lang anzeigen call WAIT call WAIT bcf PORTE, 0 bsf PORTE, 1 movlw d'1' call BCD movwf PORTC movlw d'255' call WAIT call WAIT bcf PORTE, 1 bsf PORTE, 2 movlw d'1' call BCD movwf PORTC movlw d'255' call WAIT call WAIT bcf PORTE, 2 incfsz preset,f ; mache die Vorgegebenen Durchgänge goto Intro1 movlw d'8' ; Lade die 8 movwf Einer ; und schreibe sie auf alle ziffern movwf Zehner movwf Hunderter movlw d'255' ; 255 mal die Anzeigeschleife durchlaufen movwf preset ; wird nochmal missbraucht Intro2 call Anzeigeschleife ; rufe die Anzeigeschleife auf decfsz preset, f ; wenn noch nicht null goto Intro2 ; gehe wieder zu Intro2 ;--------------------Ausgangszustand--------------- movlw D'0' movwf preset ; 0 als Grundwert Definieren call RS232Send ;----------------------------MAIN------------------------------------ MAIN call Anzeigeberechnung M2 call Anzeigeschleife btfsc Edit ; Edit-Mode-Bit gesetzt? goto EditModus1 ; gehe zu Edit-Modus1 btfsc Sw_Edit ; Edit-Taster gedrueckt? goto EditModus ; gehe in den Edit-Modus goto MAIN ;-------------------------------------BCD-Tabelle----------------------------------------------- org 0x100 ; tabelle steht ab 100 ; BCD-Zuordnungen für 7-Segment-Anzeige BCD addwf PCL,f ; addiert den Wert aus W mit dem Programmcounter ; Es folgen die Zuordnungen für den Port C in BCD ; retlw kehrt zurück mit dem Wert im Akku ; ACHTUNG! Aufgrund der Portbelegung ist RC3 die 1er-Stelle ; und RC0 die 8er-Stelle! Nach dem ersten Nipple Also ; "Digital, aber von links nach rechts!" LSB links, MSB rechts! retlw B'00000000' ; 0 retlw B'00001000' ; 1 retlw B'00000100' ; 2 retlw B'00001100' ; 3 retlw B'00000010' ; 4 retlw B'00001010' ; 5 retlw B'00000110' ; 6 retlw B'00001110' ; 7 retlw B'00000001' ; 8 retlw B'00001001' ; 9 ;------------------------------------------------------------------------------------------------- ;-------------------------------------Anzeigeberechnung------------------------------------------- Anzeigeberechnung clrf Einer ; Ziffernwerte löschen clrf Zehner clrf Hunderter movfw preset ; Presetnummer in Akku laden movwf presetAnz HunAuswertung movlw d'100' ; Hundert von PresetAnz abziehen subwf presetAnz,f btfss STATUS, C ; Wurde ein Carry-Bit geloescht? goto Unterhundert ; Dann wars weniger als Hundert! incf Hunderter,f ; Addiere Hunderter um 1 goto HunAuswertung ; Und frage weiter ab Unterhundert movlw d'100' ; Addiere wieder Hundert dazu addwf presetAnz,f ZehnerAuswertung movlw D'10' subwf presetAnz,f ; ziehe Zehn ab btfss STATUS, C ; Carry-Bit geloescht? goto UnterZehn ; Dann gehe auch zu den Einern! incf Zehner,f ; erhoehe Zehner um eins goto ZehnerAuswertung ; Und mach weiter mit der Auswertung der Zehnerstelle UnterZehn movlw D'10' addwf presetAnz,f ; Wieder 10 addieren EinerAuswertung movfw presetAnz ; Schreibe den Rest in Einer movwf Einer Return ; Und gehe zurück! ; Das wars mit Anzeigeberechnung ;----------------------------------------------------------------------------------------------- Anzeigeschleife clrf PORTE clrf PORTC A1 bsf PORTE, 0 ; Segment eins aktiv movf Einer, 0 ; Wert Ziffer 1 laden call BCD ; BCD-Auswertung movwf PORTC ; 7-Segmentanzeige beschreiben movlw d'5' ; 5ms lang anzeigen call WAIT ; bcf PORTE, 0 bsf PORTE, 1 movf Zehner, 0 call BCD movwf PORTC movlw d'5' call WAIT bcf PORTE, 1 bsf PORTE, 2 movf Hunderter, 0 call BCD movwf PORTC movlw d'5' call WAIT bcf PORTE, 2 retlw D'0' ; wenn ja, gehe wieder zu M1 ;----------------------------------------------------------------------------------------------- ;------------------------------------Edit-Modus------------------------------------------------- EditModus bsf Edit ; Setze Flags, 0 um Modus zu Kennzeichnen movlw d'20' ; Warte 20ms (Prellen des Tasters Abfangen) call WAIT EditModus1 btfsc Sw_Up ; wurde der Up-Taster gedrückt? goto PresetUp ; dann gehe zu Preset Up btfsc PORTA, 2 ; wurde der Down-Taster gedrückt? goto PresetDown ; dann gehe zu Preset Down btfsc Sw_Edit ; Edit-Switch wieder gedrückt? goto EditEnd ; gehe zu EditEnd ;----------------------------------------------------------------------------------------------- ;------------------------------------Subroutine PresetUp---------------------------------------- PresetUp movlw d'100' ; ca 100 ms warten (entprellen und mehrfachbetätigen verhindern) call WAIT movfw preset ; preset laden movwf preseth ; zum verarbeiten in preseth kopieren incf preseth ; und preseth um eins erhöhen movlw d'127' ; maximalwert laden addwf preseth,f ; und addieren btfsc STATUS,C ; max 127+127, wenn nein, dann wars mehr-> goto M2 ; Überlauf und nicht verwertbar ; dann gehe zur Hauptschleife movfw preseth ; ansonsten preseth laden movwf preset ; und erhoehtes preseth zurueckschreiben goto MAIN ; gehe wieder zu MAIN ;----------------------------------------------------------------------------------------------- ;------------------------------------Subrouine PresetDown--------------------------------------- PresetDown movlw d'100' ; ca 100 ms warten (entprellen und mehrfachbetätigen verhindern) call WAIT movfw preset ; preset laden movwf preseth ; zum verarbeiten in preseth kopieren movlw d'1' ; den Wert eins laden subwf preseth,f ; und preseth um eins vermindern btfss STATUS,C ; ging der Wert unter 0? goto M2 ; Überlauf und nicht verwertbar ; dann gehe zur Hauptschleife movfw preseth ; ansonsten preseth laden movwf preset ; und erhoehtes preseth zurueckschreiben goto MAIN ; gehe wieder zu MAIN ;----------------------------------------------------------------------------------------------- ;------------------------------------Subroutine WarteEdit des Edit-Modes------------------------ AbfrageEdit ;----------------------------------------------------------------------------------------------- ;------------------------------------Routine EditEnd-------------------------------------------- EditEnd movlw d'20' ; erstmal wieder 20ms warten (entprellen) call WAIT goto AbfrageEdit ; Edit beenden oder Speichern? ;----------------------------------------------------------------------------------------------- ;------------------------------------Laden der EEPROM-Bytes------------------------------------- EEPDATAGET movfw preset ; Lade Preset movwf EEPBYTE1 ; Da Preset nie größer 127, ist Byte 1 = preset addlw d'127' ; Addiere 127 dazu movwf EEPBYTE2 ; Das Ergibt dann Byte 2 bcf INTCON, GIE ; deaktiviere Interupts EEPDATAREAD bsf STATUS, RP1 bcf STATUS, RP0 ; EEADR befindet sich in Bank 2 btfss Flags, 2 ; erster oder zweiter durchgang? movfw EEPBYTE1 ; Je nachdem wird EEPBYTE1 oder btfsc Flags, 2 ; EEPBYTE2 als Adresse übergeben movfw EEPBYTE2 movwf EEADR ; schreibe Adresse in EEADR bsf STATUS, RP0 ; EECON1 befindet sich in Bank 3 bcf EECON1, EEPGD ; mitteilen, dass man lesen moechte bsf EECON1, RD ; EEPROM-Zelle auslesen bcf STATUS, RP0 ; EEDATA befindet sich in Bank 2 movfw EEDATA ; ausgelesenes Byte in den Akku laden bcf STATUS, RP1 ; Wieder zurück in Bank 0 gehen btfss Flags, 2 ; erster oder zweiter durchgang? goto ErsterDurchgang ; Wenn erster, gehe zu ErsterDurchgang goto ZweiterDurchgang ; Wenn zweiter, gehe zu ZweiterDurchgang ErsterDurchgang movwf PresPart1 ; schreibe ersten Teil des Presets bsf Flags, 2 ; setze Flags, 2 fuer Durchgangssignalisierung goto EEPDATAREAD ; gehe zurück und lese zweites Byte ZweiterDurchgang movwf PresPart2 ; schreibe zweiten Teil des Presets bcf Flags, 2 ; setze Durchgangszaehler wieder auf 0 bsf INTCON, GIE ; erlaube Interupts wieder retlw d'0' ; und gehe zurueck ;----------------------------------------------------------------------------------------------- ;------------------------------------Schreiben der EEPROM-Bytes--------------------------------- EEPDATAWRITE bcf INTCON, GIE ; Alle Interupts sperren bcf PIR2, EEIF ; Lösche EEPROM - Interuptflag bsf STATUS, RP1 ; In Bank 2 wechseln bcf STATUS, RP0 ; fuer EEADR und EEDATA btfss Flags, 2 ; erster oder zweiter durchgang? movfw EEPBYTE1 ; Je nachdem wird EEPBYTE1 oder btfsc Flags, 2 ; EEPBYTE2 als Adresse übergeben movfw EEPBYTE2 movwf EEADR ; In EEADR schieben btfss Flags, 2 ; erster oder zweiter durchgang? movfw PresPart1 ; Je nachdem wird PresPart1 oder btfsc Flags, 2 ; PresPart2 als Adresse übergeben movfw PresPart2 movwf EEDATA ; Schiebe es in den Schreibpuffer bsf STATUS, RP0 ; wechsle zu Bank 3 fuer EECON1 bcf EECON1, EEPGD ; Datenspeicher als Typ angeben bsf EECON1, WREN ; Schreiben erlauben movlw h'55' ; Diese Befehlsreihenfolge ist movwf EECON2 ; fest vorgegeben und darf auf keinen movlw h'AA' ; Fall verändert werden movwf EECON2 bsf EECON1, WR ; Beginne schreiben bcf STATUS, RP1 ; gehe zurück in Bank 0 bcf STATUS, RP0 TestWriteEnd btfss PIR2, EEIF ; EEPROM fertig mit schreiben? goto TestWriteEnd ; Wenn nein, frage weiter ab btfss Flags, 2 ; erster oder zweiter durchgang? goto FirstWrite ; Wenn erster, gehe zu FirstWrite bcf Flags, 2 ; setze Abfragebit wieder zurück bsf INTCON, GIE ; Interupts wieder zulassen retlw d'0' ; zurueck FirstWrite bsf Flags, 2 ; setze Abfragebit auf 1 goto EEPDATAWRITE ; gehe zurück und schreibe 2ten Teil ;------------------------------------RS232 Sendeprogramm---------------------------------------- RS232Send bsf STATUS, RP0 ; auf Bank eins umschalten Sendwait btfss TXSTA, TRMT ; Abfragen des Transmit Register Status-Bit, wenn gesetzt ist ; Senden moeglich goto Sendwait ; Wenn nicht, gehe zu Sendwait bcf STATUS, RP0 ; gehe wieder auf Bank 0 movfw preset ; Lade preset addlw D'1' ; Addiert eins zum preset dazu movwf TXREG ; Schreibt das Ergebnis (Preset Inkrementiert mit 1) in ; den Sender retlw D'0' ;------------------------------------Warteschleife 1 Millisekunde--------------------------------- WAIT ;movwf loops ; Es wird übergeben wie viele ms es dauern soll movlw d'3' movwf loops W1 movlw D'1'; ; 110mal wird die Schleife durchlaufen um movwf loops2; ; 1ms zu ergeben W2 nop nop nop nop nop nop decfsz loops2, f ; Überprüfung ob 1 ms vorbei goto W2 ; noch nicht? dann nochmal ab W2 decfsz loops, f ; Gesamtzeit vorbei? goto W1 ; noch nicht? dann nochmal ab W1 retlw 0 ; gehe zurück ins Programm mit '0' im Akku END