; ====================================== SIMPLE.ASM
; FULLZOOT, enhanced to remove hardware components:
; 1) replace external network w/ internal pullups
; 2) invert MIDI signal and remove PNP output isolator
; MIDI OUT pin = PORTA.3
; CPU configuration
processor 16f84
include
__config _HS_OSC & _WDT_OFF & _PWRTE_ON
; ---------------------------------- Macros
; Note: One-line macros speed code changes during experiments
; with inverted/noninverted MIDI OUT hardware
MidiIdle macro ; set MIDI OUT pin to 'idle' (High)
bsf PORTA,0x03
endm
MidiData macro ; set MIDI OUT pin to 'data' (Low)
bcf PORTA, 0x03
endm
; ---------------------------------- Variables
j equ 0x0C ; timing loop variable (sendmidi)
temp equ 0x0D ; timing loop variable (sendmidi:)
xmit equ 0x0E ; for passing byte to SENDMIDI
note equ 0x0F ; pass note value to on/off routines
rowIs equ 0x10 ; state of buttons in current row
delta equ 0x11 ; map out which button(s) changed
row0Was equ 0x20 ; vars contain saved state of buttons
row1Was equ 0x21 ; ...in each row of the instrument
row2Was equ 0x22
row3Was equ 0x23
row4Was equ 0x24
row5Was equ 0x25
row6Was equ 0x26
row7Was equ 0x27
note0 equ 0x30 ; vars to pass active row's notes
note1 equ 0x31 ; ...to 'parse' subroutine
note2 equ 0x32
note3 equ 0x33
note4 equ 0x34
note5 equ 0x35
note6 equ 0x36
note7 equ 0x37
; ---------------------------------- Program
org 0x000 ; start at address 0
start
movlw b'00000000' ; PORTA is outputs (MIDI OUT)
tris PORTA
movlw b'11111111' ; teach PORTB to be inputs
tris PORTB ; SET at initialization
movwf PORTB ; set inputs HIGH (unpressed)
movwf row0Was ; set all rows to "all up"
movwf row1Was
movwf row2Was
movwf row3Was
movwf row4Was
movwf row5Was
movwf row6Was
movwf row7Was
movlw b'00000000' ; Enable port b pullup resistors
option
MidiIdle ; begin w/ MIDI OUT at Idle state
movlw D'192' ; MIDI Change Program on 0...
movwf xmit
call sendmidi
movlw D'23' ; ...to Bandoneon
movwf xmit
call sendmidi
row0:
bcf PORTA,2 ; set selectors = 000
bcf PORTA,1
bcf PORTA,0
nop ; steady...
movf PORTB,w ; get current state of buttons
movwf rowIs ; ... and set it aside
xorwf row0Was,w ; itIs XOR itWas:
btfsc STATUS,2 ; if zero flag == 1 (true(!)),
goto row1 ; no change, so try next row
movwf delta ; 1 == bit(s) that changed
movf rowIs,w ; Remember itWas = itIs
movwf row0Was ; Save state for next time
call setRow0 ; pass correct notes to parse
call parse ; read notes and turn on/off
row1:
bcf PORTA,2 ; set selectors = 001
bcf PORTA,1
bsf PORTA,0
nop ; steady...
movf PORTB,w ; get current state of buttons
movwf rowIs ; ... and set it aside
xorwf row1Was,w ; itIs XOR itWas:
btfsc STATUS,2 ; if zero flag == 1 (true(!))
goto row2 ; no change, so try next row
movwf delta ; 1 == bit(s) that changed
movf rowIs,w ; Remember itWas = itIs
movwf row1Was ; Save state for next time
call setRow1 ; pass correct notes to parse
call parse ; read notes and turn on/off
row2:
bcf PORTA,2 ; set selectors = 010
bsf PORTA,1
bcf PORTA,0
nop ; steady...
movf PORTB,w ; get current state of buttons
movwf rowIs ; ... and set it aside
xorwf row2Was,w ; itIs XOR itWas:
btfsc STATUS,2 ; if zero flag == 1 (true(!))
goto row3 ; no change, so try next row
movwf delta ; 1 == bit(s) that changed
movf rowIs,w ; Remember itWas = itIs
movwf row2Was ; Save state for next time
call setRow2 ; pass correct notes to parse
call parse ; read notes and turn on/off
row3:
bcf PORTA,2 ; set selectors = 011
bsf PORTA,1
bsf PORTA,0
nop ; steady...
movf PORTB,w ; get current state of buttons
movwf rowIs ; ... and set it aside
xorwf row3Was,w ; itIs XOR itWas:
btfsc STATUS,2 ; if zero flag == 1 (true(!))
goto row4 ; no change, so try next row
movwf delta ; 1 == bit(s) that changed
movf rowIs,w ; Remember itWas = itIs
movwf row3Was ; Save state for next time
call setRow3 ; pass correct notes to parse
call parse ; read notes and turn on/off
row4:
bsf PORTA,2 ; set selectors = 100
bcf PORTA,1
bcf PORTA,0
nop ; steady...
movf PORTB,w ; get current state of buttons
movwf rowIs ; ... and set it aside
xorwf row4Was,w ; itIs XOR itWas:
btfsc STATUS,2 ; if zero flag == 1 (true(!))
goto row5 ; no change, so try next row
movwf delta ; 1 == bit(s) that changed
movf rowIs,w ; Remember itWas = itIs
movwf row4Was ; Save state for next time
call setRow4 ; pass correct notes to parse
call parse ; read notes and turn on/off
row5:
bsf PORTA,2 ; set selectors = 101
bcf PORTA,1
bsf PORTA,0
nop ; steady...
movf PORTB,w ; get current state of buttons
movwf rowIs ; ... and set it aside
xorwf row5Was,w ; itIs XOR itWas:
btfsc STATUS,2 ; if zero flag == 1 (true(!))
goto row6 ; no change, so try next row
movwf delta ; 1 == bit(s) that changed
movf rowIs,w ; Remember itWas = itIs
movwf row5Was ; Save state for next time
call setRow5 ; pass correct notes to parse
call parse ; read notes and turn on/off
row6:
bsf PORTA,2 ; set selectors = 110
bsf PORTA,1
bcf PORTA,0
nop ; steady...
movf PORTB,w ; get current state of buttons
movwf rowIs ; ... and set it aside
xorwf row6Was,w ; itIs XOR itWas:
btfsc STATUS,2 ; if zero flag == 1 (true(!))
goto row7 ; no change, so try next row
movwf delta ; 1 == bit(s) that changed
movf rowIs,w ; Remember itWas = itIs
movwf row6Was ; Save state for next time
call setRow6 ; pass correct notes to parse
call parse ; read notes and turn on/off
row7:
bsf PORTA,2 ; set selectors = 111
bsf PORTA,1
bsf PORTA,0
nop ; steady...
movf PORTB,w ; get current state of buttons
movwf rowIs ; ... and set it aside
xorwf row7Was,w ; itIs XOR itWas:
btfsc STATUS,2 ; if zero flag == 1 (true(!))
goto row0 ; no change here, so start over
movwf delta ; 1 == bit(s) that changed
movf rowIs,w ; Remember itWas = itIs
movwf row7Was ; Save state for next time
call setRow7 ; pass correct notes to parse
call parse ; read notes and turn on/off
goto row0 ; bottom of main polling loop
; ---------------------------------------------
; Read delta map to identify "todo" buttons.
; If button is PRESSED, turn appropriate note On.
; If RELEASED, turn appropriate note Off.
; Notes for buttons 0-7 passed in note0-note7.
parse:
btfss delta,0 ; if delta.0==0...
goto bit1 ; ... try the next bit
movf note0,w
movwf note
btfss rowIs,0 ; skip if NOT pressed
call noteOn
btfsc rowIs,0 ; skip if PRESSED
call noteOff
bit1: btfss delta,1 ; if delta.1==0...
goto bit2 ; ... try the next bit
movf note1,w
movwf note
btfss rowIs,1 ; skip if NOT pressed
call noteOn
btfsc rowIs,1 ; skip if PRESSED
call noteOff
bit2: btfss delta,2 ; if delta.2==0...
goto bit3 ; ... try the next bit
movf note2,w
movwf note
btfss rowIs,2 ; skip if NOT pressed
call noteOn
btfsc rowIs,2 ; skip if PRESSED
call noteOff
bit3: btfss delta,3 ; if delta.3==0...
goto bit4 ; ... try the next bit
movf note3,w
movwf note
btfss rowIs,3 ; skip if NOT pressed
call noteOn
btfsc rowIs,3 ; skip if PRESSED
call noteOff
bit4: btfss delta,4 ; if delta.4==0...
goto bit5 ; ... try the next bit
movf note4,w
movwf note
btfss rowIs,4 ; skip if NOT pressed
call noteOn
btfsc rowIs,4 ; skip if PRESSED
call noteOff
bit5: btfss delta,5 ; if delta.5==0...
goto bit6 ; ... try the next bit
movf note5,w
movwf note
btfss rowIs,5 ; skip if NOT pressed
call noteOn
btfsc rowIs,5 ; skip if PRESSED
call noteOff
bit6: btfss delta,6 ; if delta.6==0...
goto bit7 ; ... try the next bit
movf note6,w
movwf note
btfss rowIs,6 ; skip if NOT pressed
call noteOn
btfsc rowIs,6 ; skip if PRESSED
call noteOff
bit7: btfss delta,7 ; if delta.7==0...
goto eoBits ; ... try the next bit
movf note7,w
movwf note
btfss rowIs,7 ; skip if NOT pressed
call noteOn
btfsc rowIs,7 ; skip if PRESSED
call noteOff
eoBits: return
; --------------------------------------------------
; note value arrives in file register "note"
noteOn:
movlw 0x90 ; note on, channel 1
movwf xmit
call sendmidi
movf note,w ; note value to xmit
movwf xmit
call sendmidi
movlw 0x40 ; velocity 64 (medium)
movwf xmit
call sendmidi
return
; ---------------------------------------------------
; note value arrives in file register "note"
noteOff:
movlw 0x80 ; note off, channel 1
movwf xmit
call sendmidi
movf note,w ; move note value to xmit
movwf xmit
call sendmidi
movlw 0x40 ; velocity
movwf xmit
call sendmidi
return
; --------------------------------------------------
; sendmidi transmits one midi byte on RA3.
; W/ 10mhz xtal, 80 instructions per midi bit.
; Byte to be sent is passed in register xmit.
sendmidi:
startb: MidiData ; begin start bit
movlw D'24' ; delay 73 clocks: 2+(23*3 + 1*2)
movwf temp ; |
loop1: decfsz temp,f ; |
goto loop1 ; end delay
movlw D'8' ; counter to cycle through 8 bits...
movwf j ; ...is in j
sendloop: ; burns 5 cycles before setting bit
rrf xmit,f
btfsc STATUS, C
goto send1
send0: nop
MidiData
goto endloop
send1: MidiIdle
nop
nop
endloop: ;
movlw D'23' ;delay 70 instructions 2+(22*3 + 1*2)
movwf temp ; |
loop2: decfsz temp,f ; |
goto loop2 ; end delay
decfsz j,f
goto sendloop
stopb:
nop
nop
nop
nop
nop
MidiIdle
movlw D'26' ; delay 79 clocks: 2+(25*3 + 1*2)
movwf temp ; |
loop3: decfsz temp,f ; |
goto loop3 ; end delay
return
; ---------------------------------------------
; Called if row0 is detected to have changed.
; Sets note0-note7 to pass to parse subroutine.
; ---------------------------------------------
setRow0: ; Notes for row 0
movlw D'80'
movwf note0
movlw D'82'
movwf note1
movlw D'84'
movwf note2
movlw D'86'
movwf note3
movlw D'88'
movwf note4
movlw D'90'
movwf note5
movlw D'92'
movwf note6
movlw D'94'
movwf note7
return
setRow1: ; Notes for row 1
movlw D'75'
movwf note0
movlw D'77'
movwf note1
movlw D'79'
movwf note2
movlw D'81'
movwf note3
movlw D'83'
movwf note4
movlw D'85'
movwf note5
movlw D'87'
movwf note6
movlw D'89'
movwf note7
return
setRow2: ; Notes for row 2
movlw D'68'
movwf note0
movlw D'70'
movwf note1
movlw D'72'
movwf note2
movlw D'74'
movwf note3
movlw D'76'
movwf note4
movlw D'78'
movwf note5
movlw D'80'
movwf note6
movlw D'82'
movwf note7
return
setRow3: ; Notes for row 3
movlw D'63'
movwf note0
movlw D'65'
movwf note1
movlw D'67'
movwf note2
movlw D'69'
movwf note3
movlw D'71'
movwf note4
movlw D'73'
movwf note5
movlw D'75'
movwf note6
movlw D'77'
movwf note7
return
setRow4: ; Notes for row 4
movlw D'56'
movwf note0
movlw D'58'
movwf note1
movlw D'60'
movwf note2
movlw D'62'
movwf note3
movlw D'64'
movwf note4
movlw D'66'
movwf note5
movlw D'68'
movwf note6
movlw D'70'
movwf note7
return
setRow5: ; Notes for row 5
movlw D'51'
movwf note0
movlw D'53'
movwf note1
movlw D'55'
movwf note2
movlw D'57'
movwf note3
movlw D'59'
movwf note4
movlw D'61'
movwf note5
movlw D'63'
movwf note6
movlw D'65'
movwf note7
return
setRow6: ; Notes for row 6
movlw D'44'
movwf note0
movlw D'46'
movwf note1
movlw D'48'
movwf note2
movlw D'50'
movwf note3
movlw D'52'
movwf note4
movlw D'54'
movwf note5
movlw D'56'
movwf note6
movlw D'58'
movwf note7
return
setRow7: ; Notes for row 7
movlw D'39'
movwf note0
movlw D'41'
movwf note1
movlw D'43'
movwf note2
movlw D'45'
movwf note3
movlw D'47'
movwf note4
movlw D'49'
movwf note5
movlw D'51'
movwf note6
movlw D'53'
movwf note7
return
; ---------------------------------------------
end