; PIC2 for Hurdy ; this firmware controls the motor functions of the robot ; by Johannes Taelman, June 2004 ; 20.07.2004 last update ; changed ; * fix motor direction bit typo list p=18f252 ;list directive to define processor #include ;processor specific definitions ;#define simulate 1 ; enable simulation ;#define heartbeat 1 ; enable heatbeats ;****************************************************************************** ;Configuration bits ; The __CONFIG directive defines configuration data within the .ASM file. ; The labels following the directive are defined in the P18F252.INC file. ; The PIC18FXX2 Data Sheet explains the functions of the configuration bits. ; Change the following lines to suit your application. __CONFIG _CONFIG1H, _OSCS_OFF_1H & _HSPLL_OSC_1H __CONFIG _CONFIG2L, _BOR_OFF_2L & _PWRT_OFF_2L __CONFIG _CONFIG2H, _WDT_OFF_2H __CONFIG _CONFIG3H, _CCP2MX_OFF_3H __CONFIG _CONFIG4L, _STVR_OFF_4L & _LVP_OFF_4L & _DEBUG_OFF_4L __CONFIG _CONFIG5L, _CP0_OFF_5L & _CP1_OFF_5L & _CP2_OFF_5L & _CP3_OFF_5L __CONFIG _CONFIG5H, _CPB_OFF_5H & _CPD_OFF_5H __CONFIG _CONFIG6L, _WRT0_OFF_6L & _WRT1_OFF_6L & _WRT2_OFF_6L & _WRT3_OFF_6L __CONFIG _CONFIG6H, _WRTC_OFF_6H & _WRTB_OFF_6H & _WRTD_OFF_6H __CONFIG _CONFIG7L, _EBTR0_OFF_7L & _EBTR1_OFF_7L & _EBTR2_OFF_7L & _EBTR3_OFF_7L __CONFIG _CONFIG7H, _EBTRB_OFF_7H ;---------------------------------------------------------------------------- ;Constants ;SPBRG_VAL EQU 027h ;set baud rate 31250 for 20Mhz clock SPBRG_VAL EQU 04Fh ;set baud rate 31250 for 40Mhz clock TX_BUF_LEN EQU 010h ;length of transmit circular buffer RX_BUF_LEN EQU TX_BUF_LEN ;length of receive circular buffer WAITSTATES EQU 010h ;---------------------------------------------------------------------------- ;Bit Definitions TxBufFull EQU 0 ;bit indicates Tx buffer is full TxBufEmpty EQU 1 ;bit indicates Tx buffer is empty RxBufFull EQU 2 ;bit indicates Rx buffer is full RxBufEmpty EQU 3 ;bit indicates Rx buffer is empty ;ReceivedCR EQU 4 ;bit indicates character received ;---------------------------------------------------------------------------- ;Variables CBLOCK 0x000 WREG_TEMP ;to save WREG during interrupt STATUS_TEMP ;to save STATUS during interrupt BSR_TEMP ;to save BSR during interrupt FSR0H_TEMP ;to save FSR0H during interrupt FSR0L_TEMP ;to save FSR0L during interrupt FSR0H_SHADOW ;to save FSR0H during high interrupt FSR0L_SHADOW ;to save FSR0L during high interrupt MidiInByte ; Rcv'd Byte MidiByte0 ; status MidiByte1 ; data1 MidiByte2 ; data2 MidiCurData ; current data byte index MidiNumData ; expected data bytes MidiTestByte ; for testing only TmpM ; non-ISR scratch TmpT ; non-ISR scratch ErrorLed EnableMotor ENDC CBLOCK 0x40 ; Flags ;byte for indicator flag bits TempData ;temporary data in main routines TempRxData ;temporary data in Rx buffer routines TempTxData ;temporary data in Tx buffer routines TxStartPtrH ;pointer to start of data in Tx buffer TxStartPtrL ;pointer to start of data in Tx buffer TxEndPtrH ;pointer to end of data in Tx buffer TxEndPtrL ;pointer to end of data in Tx buffer RxStartPtrH ;pointer to start of data in Rx buffer RxStartPtrL ;pointer to start of data in Rx buffer RxEndPtrH ;pointer to end of data in Rx buffer RxEndPtrL ;pointer to end of data in Rx buffer TxBuffer:TX_BUF_LEN ;Tx buffer for data to transmit RxBuffer:RX_BUF_LEN ;Rx buffer for received data ENDC ;---------------------------------------------------------------------------- ;This code executes when a reset occurs. ORG 0x0000 ;place code at reset vector ResetVector: bra Main ;go to beginning of program ;---------------------------------------------------------------------------- ;This code executes when a high priority interrupt occurs. ORG 0x0008 HighInt: bra HighIntCode ;go to high priority interrupt routine ;---------------------------------------------------------------------------- ;This code executes when a low priority interrupt occurs. ORG 0x0018 LowInt: movff STATUS,STATUS_TEMP ;save STATUS register movff WREG,WREG_TEMP ;save working register movff BSR,BSR_TEMP ;save BSR register movff FSR0H,FSR0H_TEMP ;save FSR0H register movff FSR0L,FSR0L_TEMP ;save FSR0L register ;test other interrupt flags here btfss PIR1,RCIF ;test for RCIF receive interrupt flag bra LowInt1 ;if RCIF is not set, done with test btfsc PIE1,RCIE ;else test if Rx interrupt enabled bra GetData ;if so, go get received data LowInt1: btfss PIR1,TXIF ;test for TXIF transmit interrupt flag bra LowInt2 ;if TXIF is not set, done with test btfsc PIE1,TXIE ;else test if Tx interrupt is enabled bra PutData ;if so, go transmit data ;can do special error handling here - an unexpected interrupt occurred LowInt2: reset ;error if no valid interrupt so reset ;------------------------------------ ;Read data from the transmit buffer and put into transmit register. PutData: btfss Flags,TxBufEmpty ;check if transmit buffer is empty bra PutDat1 ;if not then go transmit bcf PIE1,TXIE ;else disable Tx interrupt bra EndLowInt PutDat1: rcall GetTxBuffer ;get data from transmit buffer movwf TXREG ;and transmit ;------------------------------------ ;End of low priority interrupt routine restores context. EndLowInt: movff FSR0L_TEMP,FSR0L ;restore FSR0L register movff FSR0H_TEMP,FSR0H ;restore FSR0H register movff BSR_TEMP,BSR ;restore BSR register movff WREG_TEMP,WREG ;restore working register movff STATUS_TEMP,STATUS ;restore STATUS register retfie ;---------------------------------------------------------------------------- ;High priority interrupt routine. HighIntCode: movff FSR0H,FSR0H_SHADOW ;save FSR0H register movff FSR0L,FSR0L_SHADOW ;save FSR0L register ;test other interrupt flags here btfss PIR2,TMR3IF ;test for Timer3 receive interrupt flag bra HighInt1 ;if RCIF is not set, done with test btfsc PIE2,TMR3IE ;else test if Timer3 interrupt enabled bra Timer3ISR ;if so, go get received data ;can do special error handling here - an unexpected interrupt occurred HighInt1: reset ;error if no valid interrupt so reset ;------------------------------------ ;Get received data and write into receive buffer. GetData: ; btg LATA,1; ; toggle LATA:1 = HEARTBEAT btfsc RCSTA,OERR ;if overrun error bra ErrOERR ;then go handle error btfsc RCSTA,FERR ;if framing error bra ErrFERR ;then go handle error btfsc Flags,RxBufFull ;if buffer full bra ErrRxOver ;then go handle error ; btg LATA,1; ; toggle LATA:1 = HEARTBEAT movf RCREG,W ;get received data ; xorlw 0x0d ;compare with ; btfsc STATUS,Z ;check if the same ; bsf Flags,ReceivedCR ;indicate character received ; xorlw 0x0d ;change back to valid data rcall PutRxBuffer ;and put in buffer bra EndLowInt ;error because OERR overrun error bit is set ;can do special error handling here - this code simply clears and continues ErrOERR: bcf RCSTA,CREN ;reset the receiver logic bsf RCSTA,CREN ;enable reception again setf ErrorLed; error LED movlw 0xFA; ; MIDI RT Start rcall PutTxBuffer ;put data in transmit buffer bra EndLowInt ;error because FERR framing error bit is set ;can do special error handling here - this code simply clears and continues ErrFERR: movf RCREG,W ;discard received data that has error bcf RCSTA,CREN ;reset the receiver logic bsf RCSTA,CREN ;enable reception again setf ErrorLed; error LED movlw 0xFB; ; MIDI RT Continue rcall PutTxBuffer ;put data in transmit buffer bra EndLowInt ;error because receive buffer is full ;can do special error handling here - this code checks and discards the data ErrRxOver: movf RCREG,W ;discard received data ; xorlw 0x0d ;but compare with ; btfsc STATUS,Z ;check if the same ; bsf Flags,ReceivedCR ;indicate character received setf ErrorLed; error LED movlw 0xFB; ; MIDI RT Start rcall PutTxBuffer ;put data in transmit buffer bra EndLowInt ;------------------------------------ ;End of high priority interrupt routine restores context. EndHighInt: movff FSR0L_SHADOW,FSR0L ;restore FSR0L register movff FSR0H_SHADOW,FSR0H ;restore FSR0H register retfie FAST ;return and restore context ;---------------------------------------------------------------------------- ;Main routine checks for for reception of a and then calls a routine to ; move the data to transmit back. Main: clrf TRISA ; Config PORTA as all outputs clrf TRISB ; Config PORTB as all outputs clrf TRISC ; Config PORTC as all outputs setf LATA clrf LATB clrf LATC bsf LATC,0 ; Light error LED on powerup ; Wait a second with ALoop and BLoop clrf EnableMotor ; init PWM movlw 0xFF; movwf PR2 movlw 0xFF; clrf CCPR1L movlw 0x0F; movwf CCP1CON movlw 0x04 movwf T2CON setf TmpM BLoop1: movlw 0xff; decfsz WREG; bra $-2; movlw 0xff; decfsz WREG; bra $-2; movlw 0xff; decfsz WREG; bra $-2; movlw 0xff; decfsz WREG; bra $-2; decfsz TmpM; goto BLoop1 bcf LATC,0 ; Been patient enough, dim error LED and start lfsr FSR0 ,0000h lfsr FSR1 ,0000h rcall SetupSerial ;set up serial port and buffers MainLoop: ;do other stuff here #ifdef simulate nop; your chance to schedule midi cmd movff MidiTestByte,WREG; rcall MidiInParser; rcall Timer3ISR #endif call PollMidiIn; bra MainLoop ;go wait for more data ;---------------------------------------------------------------------------- ;Set up serial port and buffers. SetupSerial: movlw 0x80 ;set tris bits for Tx and RX iorwf TRISC,F movlw SPBRG_VAL ;set baud rate movwf SPBRG movlw 0x04 ;no transmission, high baud rate ;0x24 ;enable transmission and high baud rate movwf TXSTA movlw 0x90 ;enable serial port and reception movwf RCSTA clrf Flags ;clear all flags rcall InitTxBuffer ;initialize transmit buffer rcall InitRxBuffer ;initialize receive buffer movlw 0x30 ;enable Tx and Rx interrupts movwf PIE1 movlw 0x00 ;set Rx low and Tx low priority movwf IPR1 bsf RCON,IPEN ;enable interrupt priorities movlw 0xc0 ;enable global high and low ints movwf INTCON return ;---------------------------------------------------------------------------- ;Circular buffer routines. ;---------------------------------------------------------------------------- ;Initialize transmit buffer. InitTxBuffer: movlw HIGH TxBuffer ;take high address of transmit buffer movwf TxStartPtrH ;and place in transmit start pointer movwf TxEndPtrH ;and place in transmit end pointer movlw LOW TxBuffer ;take low address of transmit buffer movwf TxStartPtrL ;and place in transmit start pointer movwf TxEndPtrL ;and place in transmit end pointer bcf Flags,TxBufFull ;indicate Tx buffer is not full bsf Flags,TxBufEmpty ;indicate Tx buffer is empty return ;---------------------------------------------- ;Initialize receive buffer. InitRxBuffer: movlw HIGH RxBuffer ;take high address of receive buffer movwf RxStartPtrH ;and place in receive start pointer movwf RxEndPtrH ;and place in receive end pointer movlw LOW RxBuffer ;take low address of receive buffer movwf RxStartPtrL ;and place in receive start pointer movwf RxEndPtrL ;and place in receive end pointer bcf Flags,RxBufFull ;indicate Rx buffer is not full bsf Flags,RxBufEmpty ;indicate Rx buffer is empty return ;---------------------------------------------------------------------------- ;Add a byte (in WREG) to the end of the transmit buffer. PutTxBuffer: bcf PIE1,TXIE ;disable Tx interrupt to avoid conflict btfsc Flags,TxBufFull ;check if transmit buffer full bra ErrTxBufFull ;go handle error if full movff TxEndPtrH,FSR0H ;put EndPointer into FSR0 movff TxEndPtrL,FSR0L ;put EndPointer into FSR0 movwf POSTINC0 ;copy data to buffer ;test if buffer pointer needs to wrap around to beginning of buffer memory movlw HIGH (TxBuffer+TX_BUF_LEN) ;get last address of buffer cpfseq FSR0H ;and compare with end pointer bra PutTxBuf1 ;skip low bytes if high bytes not equal movlw LOW (TxBuffer+TX_BUF_LEN) ;get last address of buffer cpfseq FSR0L ;and compare with end pointer bra PutTxBuf1 ;go save new pointer if at end lfsr 0,TxBuffer ;point to beginning of buffer if at end PutTxBuf1: movff FSR0H,TxEndPtrH ;save new EndPointer high byte movff FSR0L,TxEndPtrL ;save new EndPointer low byte ;test if buffer is full movf TxStartPtrH,W ;get start pointer cpfseq TxEndPtrH ;and compare with end pointer bra PutTxBuf2 ;skip low bytes if high bytes not equal movf TxStartPtrL,W ;get start pointer cpfseq TxEndPtrL ;and compare with end pointer bra PutTxBuf2 bsf Flags,TxBufFull ;if same then indicate buffer full PutTxBuf2: bcf Flags,TxBufEmpty ;Tx buffer cannot be empty bsf PIE1,TXIE ;enable transmit interrupt return ;error because attempting to store new data and the buffer is full ;can do special error handling here - this code simply ignores the byte ErrTxBufFull: bsf PIE1,TXIE ;enable transmit interrupt return ;no save of data because buffer is full ;---------------------------------------------- ;Add a byte (in WREG) to the end of the receive buffer. PutRxBuffer: btfsc Flags,RxBufFull ;check if receive buffer full bra ErrRxBufFull ;go handle error if full movff RxEndPtrH,FSR0H ;put EndPointer into FSR0 movff RxEndPtrL,FSR0L ;put EndPointer into FSR0 movwf POSTINC0 ;copy data to buffer ;test if buffer pointer needs to wrap around to beginning of buffer memory movlw HIGH (RxBuffer+RX_BUF_LEN) ;get last address of buffer cpfseq FSR0H ;and compare with end pointer bra PutRxBuf1 ;skip low bytes if high bytes not equal movlw LOW (RxBuffer+RX_BUF_LEN) ;get last address of buffer cpfseq FSR0L ;and compare with end pointer bra PutRxBuf1 ;go save new pointer if not at end lfsr 0,RxBuffer ;point to beginning of buffer if at end PutRxBuf1: movff FSR0H,RxEndPtrH ;save new EndPointer high byte movff FSR0L,RxEndPtrL ;save new EndPointer low byte ;test if buffer is full movf RxStartPtrH,W ;get start pointer cpfseq RxEndPtrH ;and compare with end pointer bra PutRxBuf2 ;skip low bytes if high bytes not equal movf RxStartPtrL,W ;get start pointer cpfseq RxEndPtrL ;and compare with end pointer bra PutRxBuf2 bsf Flags,RxBufFull ;if same then indicate buffer full PutRxBuf2: bcf Flags,RxBufEmpty ;Rx buffer cannot be empty return ;error because attempting to store new data and the buffer is full ;can do special error handling here - this code simply ignores the byte ErrRxBufFull: return ;no save of data because buffer is full ;---------------------------------------------- ;Remove and return (in WREG) the byte at the start of the transmit buffer. GetTxBuffer: btfsc Flags,TxBufEmpty ;check if transmit buffer empty bra ErrTxBufEmpty ;go handle error if empty movff TxStartPtrH,FSR0H ;put StartPointer into FSR0 movff TxStartPtrL,FSR0L ;put StartPointer into FSR0 movff POSTINC0,TempTxData ;save data from buffer ;test if buffer pointer needs to wrap around to beginning of buffer memory movlw HIGH (TxBuffer+TX_BUF_LEN) ;get last address of buffer cpfseq FSR0H ;and compare with start pointer bra GetTxBuf1 ;skip low bytes if high bytes not equal movlw LOW (TxBuffer+TX_BUF_LEN) ;get last address of buffer cpfseq FSR0L ;and compare with start pointer bra GetTxBuf1 ;go save new pointer if at end lfsr 0,TxBuffer ;point to beginning of buffer if at end GetTxBuf1: movff FSR0H,TxStartPtrH ;save new StartPointer value movff FSR0L,TxStartPtrL ;save new StartPointer value ;test if buffer is now empty movf TxEndPtrH,W ;get end pointer cpfseq TxStartPtrH ;and compare with start pointer bra GetTxBuf2 ;skip low bytes if high bytes not equal movf TxEndPtrL,W ;get end pointer cpfseq TxStartPtrL ;and compare with start pointer bra GetTxBuf2 bsf Flags,TxBufEmpty ;if same then indicate buffer empty GetTxBuf2: bcf Flags,TxBufFull ;Tx buffer cannot be full movf TempTxData,W ;restore data from buffer return ;error because attempting to read data from an empty buffer ;can do special error handling here - this code simply returns zero ErrTxBufEmpty: retlw 0 ;buffer empty, return zero ;---------------------------------------------- ;Remove and return (in WREG) the byte at the start of the receive buffer. GetRxBuffer: bcf PIE1,RCIE ;disable Rx interrupt to avoid conflict btfsc Flags,RxBufEmpty ;check if receive buffer empty bra ErrRxBufEmpty ;go handle error if empty movff RxStartPtrH,FSR0H ;put StartPointer into FSR0 movff RxStartPtrL,FSR0L ;put StartPointer into FSR0 movff POSTINC0,TempRxData ;save data from buffer ;test if buffer pointer needs to wrap around to beginning of buffer memory movlw HIGH (RxBuffer+RX_BUF_LEN) ;get last address of buffer cpfseq FSR0H ;and compare with start pointer bra GetRxBuf1 ;skip low bytes if high bytes not equal movlw LOW (RxBuffer+RX_BUF_LEN) ;get last address of buffer cpfseq FSR0L ;and compare with start pointer bra GetRxBuf1 ;go save new pointer if at end lfsr 0,RxBuffer ;point to beginning of buffer if at end GetRxBuf1: movff FSR0H,RxStartPtrH ;save new StartPointer value movff FSR0L,RxStartPtrL ;save new StartPointer value ;test if buffer is now empty movf RxEndPtrH,W ;get end pointer cpfseq RxStartPtrH ;and compare with start pointer bra GetRxBuf2 ;skip low bytes if high bytes not equal movf RxEndPtrL,W ;get end pointer cpfseq RxStartPtrL ; and compare with start pointer bra GetRxBuf2 bsf Flags,RxBufEmpty ;if same then indicate buffer empty GetRxBuf2: bcf Flags,RxBufFull ;Rx buffer cannot be full movf TempRxData,W ;restore data from buffer bsf PIE1,RCIE ;enable receive interrupt return ;error because attempting to read data from an empty buffer ;can do special error handling here - this code simply returns zero ErrRxBufEmpty: bsf PIE1,RCIE ;enable receive interrupt retlw 0 ;buffer empty, return zero ;---------------------------------------------------------------------------- ;Move data from receive buffer to transmit buffer to echo the line back. CopyRxToTx: ; bcf Flags,ReceivedCR ;clear received indicator Copy1: btfsc Flags,RxBufEmpty ;check if Rx buffer is empty return ;if so then return rcall GetRxBuffer ;get data from receive buffer ; movwf TempData ;save data rcall PutTxBuffer ;put data in transmit buffer ; movf TempData,W ;restore data ; xorlw 0x0d ;compare with ; bnz Copy1 ;if not the same then move another byte bra Copy1 return ;---------------------------------------------------------------------------- ; Timer3 setup SetupTimer3: movlw 0x01 movwf T3CON ; timer3 on, other bits cleared bsf IPR2,1 ; timer3 = high priority interrupt bsf PIE2,1 ; timer3 interrupt enable return Timer3ISR: bcf PIR2,TMR3IF ; clear interrupt flag movlw 000h ;0x7F; 0xA0 movwf TMR3L ; preset timer setf TMR3H ; preset timer #ifdef heartbeat bsf LATC,0; ; LATC:5 = TIMER ISR HEARTBEAT #endif TISRDone: #ifdef heartbeat bcf LATC,0; ; heatbeat #endif #ifdef simulate return ; OUTSIDE ISR *WARNING* FOR SIMULATION ONLY #endif bra EndHighInt ; resume ;---------------------------------------------------------------------------- ; MIDI Input parser ; ; pseudocode: ; ; MidiInParser: ; if (inByte & 0x80) ; MidiStatus = inByte ; goto MidiInStatus ; else ; goto MidiInData ; return ; ; MidiInStatus: ; Look up # databytes ; 1000xxxx -> 2 (noteOn) ; 1001xxxx -> 2 (noteOff) ; 1010xxxx -> 2 (polyKeyPr) ; 1011xxxx -> 2 (ctrlChange) ; 1100xxxx -> 1 (pgmChg ; 1101xxxx -> 1 (chnlPr) ; 1110xxxx -> 0 (System Common Messages -> ignore) ; 1111xxxx -> 0 (SysEx) ; ; store in MidiNumData ; MidiCurDataBytes=0 ; return ; ; MidiInData: ; If (CurDBytes==0) ; MidiData1=inByte ; If (CurDBytes==1) ; MidiData2=inByte ; CurDBytes++; ; ; If (CurDBytes>MidiNumData) ; If (MidiStatus==NoteOn) ; If (channel = x) ; ... ; ... ; ; If (MidiStatus==NoteOff) ; If (channel = x) ; ... ; ; goto MidiInStatus PollMidiIn: btfsc Flags,RxBufEmpty ;check if Rx buffer is empty return ;if so then return rcall GetRxBuffer ;get data from receive buffer MidiInParser: #ifdef heartbeat btg LATC,3; ; heatbeat #endif movwf MidiInByte; btfss MidiInByte,7; bra MidiInData; ; jump if it wasn't a status byte movwf MidiByte0; MidiInStatus: movlw 0; clrf MidiCurData; btfss MidiByte0,6; bra MidiInStatus2words; btfss MidiByte0,5; movlw 1; movwf MidiNumData; bra MidiInStatusEnd; MidiInStatus2words: movlw 2; movwf MidiNumData; MidiInStatusEnd: return MidiInData: tstfsz MidiCurData; bra MidiInDataM2; bra MidiInDataM1; MidiInDataM2: ; 2nd byte movff MidiInByte,MidiByte2; clrf MidiCurData; bra MidiInAction2Bytes; MidiInDataM1: movff MidiInByte,MidiByte1; incf MidiCurData,1; movf MidiCurData,0; subwf MidiNumData,0; bz MidiInAction1Byte; return; MidiInAction1Byte: return; MidiInAction2Bytes: #ifdef heartbeat btg LATC,2; ; heatbeat #endif movlw 099h; noteOn, ch F subwf MidiByte0,0; bz MidiInNoteOn; movlw 089h; noteOff, ch F subwf MidiByte0,0; bz MidiInNoteOff; movlw 0B9h; cc, ch F subwf MidiByte0,0; bz MidiInCC; return; MidiInNoteOn: ;************** ; lookup timer #, read from table in PM:0Fvv movf MidiByte2,0; bz MidiInNoteOff; ; velocity=0 -> NOTE OFF movf MidiByte1,0; incf WREG dcfsnz WREG bsf LATB,7 dcfsnz WREG bsf LATB,6 ; btfsc EnableMotor,0 ; bsf LATA,0 ; return MidiInNoteOff: ; lookup timer #, read from table in PM:0Fvv movf MidiByte1,0; incf WREG dcfsnz WREG bcf LATB,7 dcfsnz WREG bcf LATB,6 return MidiInCC movlw 0x07; CC Volume subwf MidiByte1,0; bz MidiInCCVolume; movlw 0x42; MotorOnOff subwf MidiByte1,0; bz MidiInCCMotorOnOff; movlw 0x43; MotorDir subwf MidiByte1,0; bz MidiInCCMotorDir; movlw 0x44; MotorAck subwf MidiByte1,0; bz MidiInCCAuxBit2; ; movlw 0x09; EnableMotor ; subwf MidiByte1,0; ; bz MidiInCCEnableMotor; movlw 0x7B; CC NotesOff, ch F subwf MidiByte1,0; bz MidiInCCAllNotesOff; movlw 0x5C; aux bit subwf MidiByte1,0; bz MidiInCCAuxBit; return MidiInCCVolume: movff MidiByte2, TBLPTRL; movlw 0x10; movwf TBLPTRH tblrd* movf TABLAT,0; xorlw 0xFF; movwf CCPR1L; return MidiInCCMotorOnOff: movf MidiByte2,0 bz motorOff bcf LATA,0 return motorOff: bsf LATA,0 return ;MidiInCCEnableMotor: ; movf MidiByte2,0 ; bz motorEOff ; setf EnableMotor ; return ;motorEOff: ; clrf EnableMotor ; return MidiInCCAllNotesOff: bsf LATA,0 ; bsf LATA,2 ; movlw 0x7f; ; decfsz WREG; ; bra $-2; ; bcf LATA,2 return MidiInCCMotorDir: btfss LATA,0 return movf MidiByte2,0 bz motorDirOff bsf LATA,1 return motorDirOff: bcf LATA,1 return MidiInCCAuxBit: movf MidiByte2,0 bz AuxOff bsf LATB,5 return AuxOff: bcf LATB,5 return MidiInCCAuxBit2: movf MidiByte2,0 bz Aux2Off bcf LATA,2 return Aux2Off: bsf LATA,2 return org 0x1000 pwmtab: DB 0x00,0x01,0x02,0x03,0x05,0x06,0x07,0x08; DB 0x0A,0x0B,0x0C,0x0E,0x0F,0x10,0x11,0x13; DB 0x14,0x15,0x17,0x18,0x19,0x1A,0x1C,0x1D; DB 0x1E,0x20,0x21,0x22,0x23,0x25,0x26,0x27; DB 0x28,0x2A,0x2B,0x2C,0x2E,0x2F,0x30,0x31; DB 0x33,0x34,0x35,0x37,0x38,0x39,0x3A,0x3C; DB 0x3D,0x3E,0x40,0x41,0x42,0x43,0x45,0x46; DB 0x47,0x48,0x4A,0x4B,0x4C,0x4E,0x4F,0x50; DB 0x51,0x53,0x54,0x55,0x57,0x58,0x59,0x5A; DB 0x5C,0x5D,0x5E,0x60,0x61,0x62,0x63,0x65; DB 0x66,0x67,0x68,0x6A,0x6B,0x6C,0x6E,0x6F; DB 0x70,0x71,0x73,0x74,0x75,0x77,0x78,0x79; DB 0x7A,0x7C,0x7D,0x7E,0x80,0x84,0x89,0x8E; DB 0x92,0x97,0x9C,0xA0,0xA5,0xAA,0xAF,0xB3; DB 0xB8,0xBD,0xC1,0xC6,0xCB,0xCF,0xD4,0xD9; DB 0xDE,0xE2,0xE7,0xEC,0xF0,0xF5,0xFA,0xFF; END