;*********************************************************************************************************
;*********************************************************************************************************
;** **
;** **
;** Guitar Amp MIDI Decoder **
;** With 16F628 PIC Micro **
;** **
;** By **
;** **
;** Jon Wilder **
;** **
;** **
;*********************************************************************************************************
;*********************************************************************************************************
;** **
;** Processor Config **
;** **
;** **
;*********************************************************************************************************
;*********************************************************************************************************
processor 16F628
include <P16F628.INC>
__CONFIG 0x3D22 ;disable cp, dcp, lvp, boden, wdt & enable mclre, pwrt, hs osc
; external clock speed = 20MHz
;*********************************************************************************************************
;*********************************************************************************************************
;** **
;** Port Initialization **
;** **
;** **
;*********************************************************************************************************
;*********************************************************************************************************
org 0x00 ;start at address 0
clrf PORTA ;initialize Port A register
clrf PORTB ;initialize Port B register
bsf STATUS,RP0 ;switch to Bank 1
bcf STATUS,RP1 ;switch to Bank 1
movlw B'00000001'
movwf TRISA ;set up RA0 as input for "learn" button, RA1-RA4 as outputs
movlw B'00000110' ;set up RB0, RB3-7 as outputs
movwf TRISB ;configure RB1 and RB2 as USART RX/TX
bcf STATUS,RP0 ;switch to Bank 0
bcf STATUS,RP1 ;switch to Bank 0
movlw 0x07 ;disable on board
movwf CMCON ;comparator
;*********************************************************************************************************
;*********************************************************************************************************
;** **
;** USART Initialization **
;** **
;** **
;*********************************************************************************************************
;*********************************************************************************************************
bsf STATUS,RP0 ;switch to Bank 1
bcf STATUS,RP1 ;switch to Bank 1
movlw 0x09 ;set Baud Rate Generator up for
movwf SPBRG ;31,250 baud with 20MHz crystal
bcf TXSTA,SYNC ;enable asynchronous serial comm mode
bcf STATUS,RP0 ;switch to Bank 0
bcf STATUS,RP1 ;switch to Bank 0
bsf RCSTA,SPEN ;serial port enable
bsf RCSTA,CREN ;continuous receive enable
;*********************************************************************************************************
;*********************************************************************************************************
;** **
;** RAM Locations **
;** **
;** **
;*********************************************************************************************************
;*********************************************************************************************************
cblock 0x20
MIDI_PC_RAM
MIDI_CC_RAM
MIDI_PC
MIDI_CC
MIDI_TEMP
EEPROM_ADDR
EEPROM_DATA
LOOP1
LOOP2
endc
;*********************************************************************************************************
;*********************************************************************************************************
;** **
;** Program Start **
;** **
;** **
;*********************************************************************************************************
;*********************************************************************************************************
Main call Init
btfss PORTA,0 ;check if learn button is pressed
call Debounce ;if pressed, call Debounce subroutine
btfss PORTA,0 ;check again after Debounce subroutine
call Learn_CH ;if button pressed, call Learn MIDI Channel subroutine
call Load_RAM ;if button not pressed, call Load RAM subroutine
Byte1 call receivemidi ;call MIDI receive subroutine
Status_Detect btfss MIDI_TEMP,7 ;check bit 7 in MIDI_TEMP set
goto Byte1 ;if not set, clear data and wait for next byte
goto PC_Detect ;if bit 7 set, detect MIDI channel
PC_Detect clrw ;clear W
movf MIDI_TEMP,W ;move new byte in MIDI_TEMP into W
xorwf MIDI_PC_RAM,W ;xor with byte in MIDI_PC_RAM
btfss STATUS,Z ;check zero flag
goto CC_Detect ;if zero flag not set, proceed to test for CC message
goto PC_Data ;if zero flag set, proceed to receive PC data value
CC_Detect clrw ;clear W
movf MIDI_TEMP,W ;copy byte in MIDI_TEMP into W
xorwf MIDI_CC_RAM,W ;xor with byte in MIDI_CC_RAM
btfss STATUS,Z ;check zero flag
goto Byte1 ;if zero flag not set, clear registers and wait for next byte
goto CC_Cont ;if zero flag set, proceed to detect CC number
CC_Cont call receivemidi ;call MIDI receive subroutine
Cont_Detect xorlw 0x50 ;xor with 0x50 (Controller 80)
btfss STATUS,Z ;check zero flag
goto Byte1 ;if zero flag not set, clear registers and wait for next byte
goto CC_Data ;if zero flag set, proceed to read CC data value
Byte3 call receivemidi ;call MIDI receive subroutine
btfss MIDI_TEMP,6 ;check bit 6 set in data value
goto Green_On ;if bit 6 not set, proceed to Green_On
goto Red_On ;if bit 6 set, proceed to Red_On
Green_On bsf PORTB,3 ;turn Green LED on
bcf PORTB,0 ;turn Red LED off
goto MIDI_Status ;go back and wait for next byte
Red_On bsf PORTB,0 ;turn Red LED on
bcf PORTB,3 ;turn Green LED off
goto MIDI_Status ;go back and wait for next byte
PC_Data goto MIDI_Status ;if PC message, go back and wait for next byte (to be continued)
;*********************************************************************************************************
;*********************************************************************************************************
;** **
;** Subroutines **
;** **
;** **
;*********************************************************************************************************
;*********************************************************************************************************
;initialize all registers
Init clrf MIDI_PC_RAM ;initialize all registers
clrf MIDI_CC_RAM
clrf MIDI_PC
clrf MIDI_CC
clrf MIDI_TEMP
clrf EEPROM_ADDR
clrf EEPROM_DATA
clrf LOOP1
clrf LOOP2
clrw
return
;*********************************************************************************************************
;*********************************************************************************************************
;waste some time in nested delay loops to give switch contacts time to stabilize
Debounce movlw 0xFF
movwf LOOP1
movwf LOOP2
Loop1 decfsz LOOP1
goto Loop1
Loop2 decfsz LOOP2
goto Loop1
return
;*********************************************************************************************************
;*********************************************************************************************************
;load data in EEPROM into RAM
Load_RAM bsf STATUS,RP0 ;switch to bank 1
movlw 0x65 ;address EEPROM location 0x65
movwf EEADR
bsf EECON1,RD ;read EEPROM, place data at location 0x65 in EEDATA
movf EEDATA,W ;move data in EEDATA to W
bcf STATUS,RP0 ;switch to Bank 0
movwf MIDI_CC_RAM ;move contents of W into MIDI CC RAM
bsf STATUS,RP0 ;switch to Bank 1
movlw 0x66 ;address EEPROM location 0x66
movwf EEADR
bsf EECON1,RD ;read EEPROM, place data at location 0x66 in EEDATA
movf EEDATA,W ;move contents of EEDATA into W
bcf STATUS,RP0 ;switch to Bank 0
movwf MIDI_PC_RAM ;move contents of W into MIDI PC RAM
return
;*********************************************************************************************************
;*********************************************************************************************************
;receive MIDI
receivemidi clrw
clrf MIDI_TEMP
rcvmidi btfss PORTA,0 ;check if learn button is pressed
call Debounce ;if pressed, call Debounce subroutine
btfss PORTA,0 ;check again after Debounce subroutine
call Learn_PC ;if button still pressed, call MIDI PC Learn subroutine
nop ;if button not pressed, proceed to receive MIDI byte
btfss PIR1,RCIF ;wait for receive flag to set
goto rcvmidi ;if not set, go back and wait for receive flag to set
movf RCREG,W ;if set, move received data into W
movwf MIDI_TEMP ;copy received data into MIDI_TEMP
return ;return
Learn_RCV btfss PIR1,RCIF ;wait for receive flag to set
goto Learn_RCV ;if not set, go back and wait for receive flag to set
movf RCREG,W ;if set, move received data into W
movwf MIDI_TEMP ;copy received data into MIDI_TEMP
return ;return
;*********************************************************************************************************
;*********************************************************************************************************
;MIDI channel learn subroutine
Learn_CH bsf PORTB,3 ;turn on "Learn" LED
call Init ;call initialize all registers subroutine
MIDI_RCV call Learn_RCV ;call MIDI channel receive subroutine
;make sure it's a status byte
MIDI_CH_RCV btfss MIDI_TEMP,7 ;check bit 7 in MIDI_TEMP set
goto MIDI_RCV ;if not set, clear data and wait for next byte
goto CHK_PC ;if bit 7 set, detect MIDI channel
;make sure it's either a PC or a CC message. If not...get rid of it and wait for next byte
CHK_PC movf MIDI_TEMP,W ;move original received byte into W
andlw 0xF0 ;mask low nibble
xorlw 0xC0 ;compare to value 0xC0 (Program Change)
btfss STATUS,Z ;check for zero
goto CHK_CC ;if not zero, proceed to check for Control Change message
goto STORE ;if zero, proceed to store MIDI channel
CHK_CC movf MIDI_TEMP,W ;move original received byte into W
andlw 0xF0 ;mask low nibble
xorlw 0xB0 ;compare to value 0xB0 (Control Change)
btfss STATUS,Z ;check for zero
goto Learn_CH ;if not zero, clear data and wait for next byte
goto STORE ;if zero, proceed to store MIDI channel
;add detected channel to 0xB0 and 0xC0 to set up status compare constants for use in normal program
STORE clrw
movf MIDI_TEMP,W ;place original received byte in MIDI_TEMP in W
andlw 0x0F ;mask high nibble
movwf MIDI_TEMP ;move result into MIDI_TEMP
clrw
movlw 0xB0 ;write value 0xB0 in W
addwf MIDI_TEMP,W ;add byte in MIDI_TEMP to 0xB0 to set CC Detect Constant
movwf MIDI_CC_RAM ;move new CC constant into MIDI_CC_RAM
clrw
movlw 0xC0 ;write value 0xC0 in W
addwf MIDI_TEMP,W ;add byte in MIDI_TEMP to 0xC0 to set PC Detect Constant
movwf MIDI_PC_RAM ;move new PC constant into MIDI_PC_RAM
;address data EEPROM
clrw ;clear w
PROM_ADDR1 movlw 0x65 ;write EEPROM address to W
bsf STATUS,RP0 ;change to Bank 1
movwf EEADR ;move byte in W to EEPROM Address register
bcf STATUS,RP0 ;change to Bank 0
;place data in data EEPROM buffer register
clrw
PROM_DATA1 movf MIDI_CC_RAM,W ;move contents of MIDI_CC_RAM into W
bsf STATUS,RP0 ;change to Bank 1
movwf EEDATA ;move contents of W into EEPROM Data register
bcf STATUS,RP0 ;change to Bank 0
;initiate write to EEPROM and verify write
call EEPROM_WRT ;call EEPROM Write subroutine
movlw 0x65 ;write EEPROM write verify address to W
call WRT_VRFY ;call EEPROM Write Verify subroutine
;address data EEPROM
clrw ;clear w
PROM_ADDR2 movlw 0x66 ;write EEPROM address to W
bsf STATUS,RP0 ;change to Bank 1
movwf EEADR ;move byte in W to EEPROM Address register
bcf STATUS,RP0 ;change to Bank 0
;place data in data EEPROM buffer register
clrw
PROM_DATA2 movf MIDI_PC_RAM,W ;move contents of MIDI_PC_RAM into W
bsf STATUS,RP0 ;change to Bank 1
movwf EEDATA ;move contents of W into EEPROM Data register
bcf STATUS,RP0 ;change to Bank 0
;initiate write to EEPROM and verify write
call EEPROM_WRT ;call EEPROM Write subroutine
movlw 0x66 ;write EEPROM write verify address to W
call WRT_VRFY ;call EEPROM Write Verify subroutine
return ;return to main program
;*********************************************************************************************************
;*********************************************************************************************************
;EEPROM Write
EEPROM_WRT bsf EECON1, WREN ;enable data EEPROM Write
bcf INTCON, GIE ;disable all interrupts
movlw 0x55 ;write 0x55 to W
movwf EECON2 ;copy W into EEPROM Control register
movlw 0xAA ;write 0xAA to W
movwf EECON2 ;copy W into EEPROM Control register
bsf EECON1, WR ;write contents of EEDATA to Data EEPROM register address in EEADR
bcf STATUS,RP0 ;change to Bank 0
return
;*********************************************************************************************************
;*********************************************************************************************************
;EEPROM write verify
WRT_VRFY bsf STATUS,RP0 ;change to Bank 1
movwf EEADR ;write EEPROM address in W to EEADR
bsf EECON1, RD ;read data at address in EEADR
movf EEDATA, W ;copy data at address in EEADR to W
subwf EEDATA, W ;subtract data in EEDATA with data in W
bcf STATUS,RP0 ;change to Bank 0
btfss STATUS,Z ;test for zero
call WRT_ERR ;call Write Error subroutine
call WRT_OK ;call Write OK subroutine
return ;return
;*********************************************************************************************************
;*********************************************************************************************************
;write error indicator
WRT_ERR bsf PORTB,0 ;illuminate red led to indicate write error
goto PWR_DWN ;lock out processor
;*********************************************************************************************************
;*********************************************************************************************************
;write ok indication
WRT_OK bcf PORTB,3 ;flash green LED to indicate successful write
call Loop1
bsf PORTB,3
call Loop1
bcf PORTB,3
call Loop1
bsf PORTB,3
call Loop1
bcf PORTB,3
call Loop1
bsf PORTB,3
call Loop1
bcf PORTB,3
return
;*********************************************************************************************************
;*********************************************************************************************************
;Error Lock Out
PWR_DWN goto PWR_DWN ;must power cycle to resume normal program
;*********************************************************************************************************
;*********************************************************************************************************
Learn_PC bsf PORTB,3
movf PORTB,W
movwf MIDI_TEMP
RCV_PC call Learn_RCV
;*********************************************************************************************************
;*********************************************************************************************************
End