;********************************************************** ;* KW_NW_Ausgabe.asm ;********************************************************** ;* Microchip Technology Incorporated ;* Mai 2003 ;* Olivia Mutschler, Werner Mayer, BMW AG ;* Assembled with MPASM V3.20 and MPLINK v3.20 ;********************************************************** list p=16f628 ; Include file, change directory if needed include "p16f628.inc" W_TEMP EQU H'0020' ; Zwischenspeicher W_Register für Interruptroutine STATUS_TEMP EQU H'0021' ; Zwischenspeicher STATUS_Register für Interruptroutine COUNTER_KW EQU H'0022' ; Zähler Zahnflanke Kurbelwelle BIT_COUNTER_A EQU H'0023' ; Schiebezähler zum Auslesen der EEPROM BITS für NW Werte Auslass BIT_COUNTER_E EQU H'0024' ; '' Einlass VAR_1 EQU H'0025' ; Berechnungs-Zwischenspeicher COUNTER_NW_A EQU H'0026' ; NW-Zähler Bits von 0.. 239 Auslass COUNTER_NW_E EQU H'0027' ; '' Einlass COMMAND EQU H'0028' ; Letztes gültiges Kommando vio RS232 DATA_COUNTER EQU H'0029' ; Anzahl der bereits gelesenen Datenbyte DATA_T1SETP_LO EQU H'002A' ; Sollwertvorgabe via RS232 T1 Reload Wert LO Byte DATA_T1SETP_HI EQU H'002B' ; Sollwertvorgabe via RS232 T1 Reload Wert Hi Byte DATA_N_LO EQU H'002C' ; Drehzahlwertvorgabe via RS232 Lo Byte DATA_N_HI EQU H'002D' ; Drehzahlwertvorgabe via RS232 Hi Byte DATA_NWA EQU H'002E' ; Nockenwelle Auslass Offsetvorgabe via RS232 DATA_NWE EQU H'002F' ; Nockenwelle Einlass Offsetvorgabe via RS232 TEMP EQU H'0030' ; Receiver_Wert VAR2 EQU H'0031' ; Berechnungszwischenspeicher 2 TEMP_DATA_T1LO EQU H'0032' ; Zwischenspeicher für 1. Receiver Wert T1Lo um Timer gleichzeitig mit neuem gültigen Lo und Hi Byte zu laden. TEMP1 EQU H'0033' START_DATA_NWA EQU D'03' ; Grundstellung = 3 = +90° nach 1. Zahn KW (Wertebereich 0-36; 0= -9° nach 1. Zahn KW, 1 Schritt=3°) START_DATA_NWE EQU D'33' ; Grundstellung = 33 = +90° nach 1. Zahn KW (Wertebereich 0-36) 0=+81° nach 1. Zahn KW, 1 Schritt=3°) START_DATA_N_LO EQU D'40' ; Drehzahl N=40 RPM Grundstellung START_DATA_N_HI EQU D'00' ; START_DATA_T1SETP_LO EQU D'219' ; Grundstellung ist 64 RPM (65536-62500 Dez.= 219 Lo, 11 Hi) START_DATA_T1SETP_HI EQU D'11' Reset_Vector code 0x000 goto Start Interrupt_Vector code 0x004 goto Interrupt ;***************** PROGRAMM START ************************** code 0x010 Start ; ***** RAM BANK 1 aktivieren und initialisieren ***** MOVLW B'00100000' ; BANK 1 aktivieren MOVWF STATUS MOVLW B'00100001' ; RCIE (RS232 Receiver Interrupt) und TIMER 1 Interrupt aktivieren MOVWF PIE1 MOVLW B'11000111' ; PortB Pins 3,4,5 als Ausgänge schalten MOVWF TRISB BCF OPTION_REG,7 ; Pullup's Port B einschalten. MOVLW B'00000100' ; Asynchron, Transmit off, High Baudrate MOVWF TXSTA MOVLW 0x81 ; 9.6kBaud MOVWF SPBRG MOVLW B'00000000' ; ***** RAM BANK 0 aktivieren und initialisieren ***** MOVWF STATUS CALL DEF_WERTE ; Defaultwerte setzen MOVLW 0 MOVWF DATA_COUNTER MOVWF COMMAND MOVLW B'10010000' ;Receiver RS232 on, Countinious Recieve, Asynchron, 8 Bit. MOVWF RCSTA MOVLW B'00000000' ;Timer 1 Status Register initialisieren. Kein Prescaler. fosc/4. Timer 1 an. MOVWF T1CON MOVLW B'11000000' MOVWF INTCON ; GLOBAL INTERRUPT ON LOOP_MAIN GOTO LOOP_MAIN ; ****************************DEFAULT-WERTE***************************** DEF_WERTE MOVLW START_DATA_NWA ;Default Wert für DATA_NWA vergeben. MOVWF DATA_NWA MOVLW START_DATA_NWE ;Default Wert für DATA_NWE vergeben. MOVWF DATA_NWE MOVLW START_DATA_N_LO ;Default Wert für DATA_N_LO vergeben. MOVWF DATA_N_LO MOVLW START_DATA_N_HI ;Default Wert für DATA_N_HI vergeben. MOVWF DATA_N_HI MOVLW START_DATA_T1SETP_LO ;s.o. MOVWF DATA_T1SETP_LO MOVWF TMR1L ;Timer1 Lo vorladen MOVLW START_DATA_T1SETP_HI ;s.o. MOVWF DATA_T1SETP_HI MOVWF TMR1H ;Timer1 Hi vorladen CALL CALC_NWE_POSITION ;Unterprogramm zur Berechnung der Zeiger Werte COUNTER_NW_x, BIT_COUNTER_x CALL CALC_NWA_POSITION ;'' MOVLW 0x77 ; Startwert MOVWF COUNTER_KW ; 119 Kurbelwellenzähne, Counter zählt runter BCF PORTB,3 ; Kubelwellensignal beginnt mit 1 RETURN ;********************** INTERRUPT ROUTINE ************************ Interrupt MOVWF W_TEMP ; Retten von STATUS und W-Register im RAM SWAPF STATUS, W BCF STATUS, RP0 MOVWF STATUS_TEMP MOVLW B'00000000' ; BANK 0 aktivieren MOVWF STATUS BCF T1CON,TMR1ON MOVF DATA_T1SETP_LO,0 MOVWF TMR1L ;Timer1 Lo vorladen MOVF DATA_T1SETP_HI,0 MOVWF TMR1H ;Timer1 Hi vorladen BSF T1CON,TMR1ON ;**************************************** ; ***********Abfrage ob Timer1 interrupt, Receiver interrupt******* BTFSS PIR1,5 ; RCIF-Flag testen GOTO TIMER1_INT ;BCF PIR1,5 ;BCF RCSTA,4 MOVF RCREG,0 MOVWF TEMP ; Register Receiver auslesen und in Temp speichern MOVF COMMAND,0 ANDLW 0xFF BTFSS STATUS,2 GOTO LOOP40 ; Erwartet Datenbyte MOVF TEMP,0 ; Befehl empfangen und im COMMAND-Register ablegen MOVWF COMMAND GOTO INT_END LOOP40 MOVF COMMAND,0 ; Datenbyte zuordnen SUBLW 0x01 BTFSS STATUS,2 ; prüfen ob COMMAND=1 GOTO LOOP41 ; COMMAND!=1 MOVF DATA_COUNTER,0 ; COMMAND=1 SUBLW 0x00 BTFSS STATUS,2 ; prüfen ob DATA_COUNTER=0 GOTO LOOP50 ; DATA_COUNTER!=0 MOVF TEMP,0 ; DATA_COUNTER=0 MOVWF TEMP_DATA_T1LO ; TEMP-WERT nach TEMP_DATA_T1LO schreiben GOTO INT_END LOOP50 BSF PORTB,4 MOVF DATA_COUNTER,0 SUBLW 0x01 BTFSS STATUS,2 ; prüfen ob DATA_COUNTER=1 GOTO LOOP51 ; DATA_COUNTER!=1 MOVF TEMP,0 ; DATA_COUNTER=1 MOVWF DATA_T1SETP_HI ; TEMP-WERT nach DATA_T1SETP_HI schreiben MOVF TEMP_DATA_T1LO,0 ; LO WERT DARF JETZT ERST AKTUALISIERT WERDEN !!! MOVWF DATA_T1SETP_LO GOTO INT_END LOOP51 MOVF DATA_COUNTER,0 SUBLW 0x02 BTFSS STATUS,2 ; prüfen ob DATA_COUNTER=2 GOTO LOOP52 ; DATA_COUNTER!=2 MOVF TEMP,0 ; DATA_COUNTER=2 MOVWF DATA_N_LO ; TEMP-WERT nach DATA_N_LO schreiben GOTO INT_END LOOP52 MOVF DATA_COUNTER,0 SUBLW 0x03 BTFSS STATUS,2 ; prüfen ob DATA_COUNTER=3 GOTO LOOP53 ; DATA_COUNTER!=3 MOVF TEMP,0 ; DATA_COUNTER=3 MOVWF DATA_N_HI ; TEMP-WERT nach DATA_N_HI schreiben MOVLW 0 ; alle Bytes empfangen MOVWF COMMAND ; COMMAND=0 setzen MOVWF DATA_COUNTER ; DATA_COUNTER=0 GOTO INT_END LOOP53 ; Fehler!!! Mehr als 4 Bytes MOVLW 0 MOVWF COMMAND ; COMMAND=0 setzen MOVWF DATA_COUNTER ; DATA_COUNTER=0 GOTO INT_END LOOP41 BCF PORTB,3 ; COMMAND=2,3 oder FF MOVF COMMAND,0 SUBLW 0x02 BTFSS STATUS,2 ; prüfen ob COMMAND=2 GOTO LOOP42 ; COMMAND!=2 MOVF TEMP,0 ; COMMAND=2, Wert nach DATA_NWE kopieren MOVWF DATA_NWE ; TEMP-WERT nach DATA_NWE schreiben CALL CALC_NWE_POSITION MOVLW 0 ; alle Bytes empfangen MOVWF COMMAND ; COMMAND=0 setzen MOVWF DATA_COUNTER ; DATA_COUNTER=0 GOTO INT_END LOOP42 ; COMMAND=3 oder FF MOVF COMMAND,0 SUBLW 0x03 BTFSS STATUS,2 ; prüfen ob COMMAND=3 GOTO LOOP43 ; COMMAND!=3 MOVF TEMP,0 ; COMMAND=3 MOVWF DATA_NWA ; TEMP-WERT nach DATA_NWA schreiben CALL CALC_NWA_POSITION MOVLW 0 ; alle Bytes empfangen MOVWF COMMAND ; COMMAND=0 setzen MOVWF DATA_COUNTER ; DATA_COUNTER=0 GOTO INT_END LOOP43 ; COMMAND=FF oder ? MOVF COMMAND,0 SUBLW 0xFF BTFSS STATUS,2 ; prüfen ob COMMAND=FF GOTO LOOP44 ; COMMAND!=FF CALL DEF_WERTE LOOP44 MOVLW 0 MOVWF COMMAND ; COMMAND=0 seten MOVWF DATA_COUNTER ; DATA_COUNTER=0 setzen GOTO INT_END ;*********************NW-Einlass-Interruptroutine **************** TIMER1_INT MOVF COUNTER_NW_E, 0 ; Berechnet aus COUNTER_NW EEPROM-ADR CALL CALC_EE_ADR CALL READ_EEPROM ANDWF BIT_COUNTER_E, 0 BTFSC STATUS, 2 GOTO LOOP10 BSF PORTB, 5 GOTO LOOP11 LOOP10 BCF PORTB,5 LOOP11 INCF COUNTER_NW_E, 0 ; Zähler Nockenwelle erhöhen MOVWF COUNTER_NW_E SUBLW 0xF0 ; 240 abziehen BTFSC STATUS, 2 ; Ist Zähler auf 239? CLRF COUNTER_NW_E ; Ja, Zähler zurücksetzten ; BIT_COUNTER verschieben: BCF STATUS, 0 ; CARRY-Bit löschen LOOP12 RLF BIT_COUNTER_E, 1 ; 1 um eins weiter nach links schieben BTFSC STATUS, 0 ; Carry Flag? GOTO LOOP12 ; ja, dann nochmal ;*********************NW-Auslass-Interruptroutine ****************** MOVF COUNTER_NW_A, 0 ; Berechnet aus COUNTER_NW EEPROM-ADR CALL CALC_EE_ADR CALL READ_EEPROM ANDWF BIT_COUNTER_A, 0 BTFSC STATUS, 2 GOTO LOOP20 BSF PORTB, 4 GOTO LOOP21 LOOP20 BCF PORTB,4 LOOP21 INCF COUNTER_NW_A, 0 ; Zähler Nockenwelle erhöhen MOVWF COUNTER_NW_A SUBLW 0xF0 ; 240 abziehen BTFSC STATUS, 2 ; Ist Zähler auf 239? CLRF COUNTER_NW_A ; Ja, Zähler zurücksetzten ; BIT_COUNTER verschieben: BCF STATUS, 0 ; CARRY-Bit löschen LOOP22 RLF BIT_COUNTER_A, 1 ; 1 um eins weiter nach links schieben BTFSC STATUS, 0 ; Carry Flag? GOTO LOOP22 ; ja, dann nochmal ;********************** Kurbelwelleninterruptroutine ************ MOVLW 1 ; Test auf COUNTER_KW=1 SUBWF COUNTER_KW, 0 BTFSC STATUS, 2 GOTO LOOP2 ; falls ja, Sprung zu LOOP2 MOVLW 2 ; Test auf COUNTER_KW=2 SUBWF COUNTER_KW, 0 BTFSC STATUS, 2 GOTO LOOP2 ; falls ja, Sprung zu LOOP2 MOVLW 3 ; Test auf COUNTER_KW=3 SUBWF COUNTER_KW, 0 BTFSC STATUS, 2 GOTO LOOP2 ; falls ja, Sprung zu LOOP2 MOVLW 4 ; Test auf COUNTER_KW=4 SUBWF COUNTER_KW, 0 BTFSC STATUS, 2 GOTO LOOP2 ; falls ja, Sprung zu LOOP2 BTFSC PORTB,3 ; RB4 wird getoggelt: GOTO LOOP1 BSF PORTB,3 GOTO LOOP2 LOOP1 BCF PORTB,3 LOOP2 DECF COUNTER_KW, 1 ; Abfrage: COUNTER_KW=0 BTFSS STATUS, 2 GOTO INT_END MOVLW 0x77 ; Falls ja, neu laden MOVWF COUNTER_KW ; 119 Kurbelwellenzähne GOTO INT_END INT_END SWAPF STATUS_TEMP, W ; Register zurückschreiben MOVWF STATUS SWAPF W_TEMP, F SWAPF W_TEMP, W BCF PIR1,TMR1IF ; löschen von TMR2IF RETFIE ; Interruptende ;************************************************** ; Unterprogramm zur Berechnung der EEPROM Adresse ; Im WREG: Counter_NW_A oder E ; Im WREG: Ergebnis CALC_EE_ADR ANDLW 0xF8 MOVWF VAR_1 BCF STATUS, 0 RRF VAR_1, 1 RRF VAR_1, 1 RRF VAR_1, 1 MOVF VAR_1,0 RETURN ;*************************************************** ; Unterprogramm zum Auslesen vom EEPROM ; im WREG ist die Adresse ; Ergebnis auch im WREG READ_EEPROM BSF STATUS, RP0 ; Wechsel auf Bank 1 MOVWF EEADR ; Adresse in das EEADR-Register kopieren BSF EECON1, RD ; Lesevorgan starten MOVF EEDATA, 0 ; Inhalt des EEDATA in das W-Reg kopieren BCF STATUS, RP0 RETURN ;*************************************************** ; Unterprogramm zur Berechung der Nockenwellenposition Einlass NW ABSOLUT ; Input Wert: DATA_NWE (0..36) ; Ausgabe Wert: COUNTER_NW_E, BIT_COUTNER_E CALC_NWE_POSITION MOVF DATA_NWE,0 ;DATA_NWE in das W-Register laden MOVWF COUNTER_NW_E ;Umrechung nicht notwendig, da Wertebereich gleich (0.. max. 239) ANDLW 0x07 ;BIT_COUNTER_E berechnen, dazu sind die untersten 3 Bit notwendig. MOVWF VAR2 ;Wert zwischenspeichern in VAR2 MOVLW B'00000001' ;Bit Counter auf Bit 1 setzen MOVWF BIT_COUNTER_E BCF STATUS,0 ;Carry Flag löschen RRF BIT_COUNTER_E,1 INT_END0 RLF BIT_COUNTER_E,1 DECFSZ VAR2,1 ;Decrementiert VAR2 bis 0, überspringt folge Befehl GOTO INT_END0 RETURN ;*************************************************** ; Unterprogramm zur Berechung der Nockenwellenposition Auslass NW ABSOLUT ; Input Wert: DATA_NWA (0..36) ; Ausgabe Wert: COUNTER_NW_A, BIT_COUTNER_A CALC_NWA_POSITION MOVF DATA_NWA,0 ;DATA_NWA in das W-Register laden ADDLW 30 ;Umrechnung Wertebereich: 20*3=90°KW als Offset zwischen Tabelle 1. Position ung Auslass 0 Position = 81°KW MOVWF COUNTER_NW_A ;Umrechung nicht notwendig, da Wertebereich gleich (0.. max. 239) ANDLW 0x07 ;BIT_COUNTER_A berechnen, dazu sind die untersten 3 Bit notwendig. MOVWF VAR2 ;Wert zwischenspeichern in VAR2 MOVLW B'00000001' ;Bit Counter auf Bit 1 setzen MOVWF BIT_COUNTER_A BCF STATUS,0 ;Carry löschen RRF BIT_COUNTER_A,1 INT_END1 RLF BIT_COUNTER_A,1 DECFSZ VAR2,1 ;Decrementiert VAR2 bis 0, überspringt folge Befehl GOTO INT_END1 RETURN org H'2100' ; Adresse des EEPROM ; 240 Bit Werte für 3-Zahn Synchro de 0x00,0x00,0x00,0x00,0x7f de 0xff,0xc0 de 0x00,0x00,0x00,0x00,0x07 de 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x80 de 0x03 de 0xff,0xff,0xff,0xff,0xff,0xf8 de 0x00,0x00,0x00 end