Nerds only: This is what the program looks like, without the variable/constant declarations and the
low level I/O subroutines.
This has a diagnostic buzzer, which the downloadable version won't have.
'PicBasic Pro, 16F877 40-pin
'Maps switches to predefined led/relays
'We need 12 Pins for Stomp switches
'3 Pins for other switches (program, bank up, bank down)
'12 pins for relay/led
'Each footswitch is mapped to a "Patch" of relay on/off data
'There are 2 banks of patches, a "Bank" switch toggles between them
'A "Memory" button switches programming mode on and off
'A "Momentary" button switches momentary mode on and off
'In Momentary mode, if you hold down a foot switch for more than a second
'it changes patch instantly, but reverts to the previous patch when
'you release the footswitch.
'--------------------------------------begin main program--------------------------------------
'Convention: subroutines can only go 4 deep, the complier doesn't check.
'so subroutines which call other subroutines have a postfix number
' = number of nesting levels.
'sub means it doesn't GOSUB anything
'sub2 GOSUBs sub, sub3 GOSUBs sub2, sub4 GOSUBS sub3
'GOSUB sub, call stack = 1.
'GOSUB sub2, call stack = 2.
'GOSUB sub3, call stack = 3.
'GOSUB sub4, call stack = 4.
'GOSUB sub5 wraps the call stack around itself. This is very bad
GOSUB init3
WHILE TRUE
GOSUB process_memory3 'programming mode
IF memory_held_mh = TRUE THEN
'memory button still on
GOSUB program_selected_button3 'Deep nesting, so move it up
ENDIF
GOSUB process_buttons3 'patch selection
GOSUB process_momentary2 'special mode switch
GOSUB process_bank2 'toggle bank of patches
WEND
'--------------------------------------end main program--------------------------------------
process_memory3: 'programming mode
GOSUB memory_held 'a latching switch, no debouncing
IF memory_held_mh = TRUE THEN
buzz_pause = 1
GOSUB buzz
'memory button on
GOSUB wait_for_relay_or_memory_off2 'select button to program
IF memory_held_mh = TRUE THEN
'memory button still on
READ low_addr_bh, low_data_sl
READ high_addr_bh, high_data_sl
GOSUB switch_leds2 'use existing program setting
'GOSUB program_selected_button3 'Deep nesting, so move it up
ENDIF
ENDIF
RETURN
process_buttons3: 'patch selection, non-latching toggle
GOSUB button_held
IF button_held_bh <> NOPRESS THEN
READ low_addr_bh, low_data_sl
READ high_addr_bh, high_data_sl
GOSUB switch_leds2
PAUSE 90
ENDIF
RETURN
process_momentary2:
GOSUB momentary_held
'toggle active bank
IF momentary_held_mh THEN 'a latching switch
momentary_flag = MOMENTARY_OFF
ELSE
momentary_flag = MOMENTARY_ON
ENDIF
RETURN
process_bank2:
GOSUB bank_held
'toggle active bank
IF bank_held_bh THEN 'a latching switch
'read new bank data
IF active_bank = BANK_0 THEN
active_bank = BANK_1
ELSE
active_bank = BANK_0
ENDIF
'switch to new bank immediately
'may not be desirable
'plus, what if no footswitch has been pressed?
'if you want to go from bk0:patch2 to bk1:patch3
'you have to go via bk1:patch2
buzz_pause = 2
GOSUB buzz
PAUSE 50
ENDIF
RETURN
program_selected_button3:
' Input: button_held_bh is the button to program
' We change the button_array, and the EEPROM data.
' There is a high byte and a low byte
'get existing data
READ low_addr_bh, low_data_psb 'we edit this, then WRITE it
READ high_addr_bh, high_data_psb 'we edit this, then WRITE it
'remember the address of the button to program
low_addr_psb = low_addr_bh
high_addr_psb = high_addr_bh
GOSUB wait_for_relay_or_memory_off2
buzz_pause = 1
GOSUB buzz
pause 500
GOSUB buzz
'wait for button press and toggle corresponding bit
'turning off the memory button exits loop
WHILE memory_held_mh
button_byte = button_held_bh
'Make a mask with one bit set and shift the set bit left
'to correspond with the footswitch position.
'Then use XOR to toggle the bit
mask_psb = %00000001
'We have to change either the high byte or the low byte
'We toggle the bit which corresponds to the button pressed
IF button_byte > 7 THEN ' high byte
button_byte = button_byte - 8' button 8 is bit 0 on the high byte
IF button_byte <> 0 THEN 'first button mean zero shift left, so do nothing
mask_psb = mask_psb << button_byte
ENDIF
high_data_psb = high_data_psb ^ mask_psb 'XOR toggle button_array bit if button hit
ELSE 'low byte
IF button_byte <> 0 THEN
mask_psb = mask_psb << button_byte
ENDIF
low_data_psb = low_data_psb ^ mask_psb 'XOR toggle button_array bit if button hit
ENDIF
high_data_sl = high_data_psb
low_data_sl = low_data_psb
GOSUB switch_leds2 'use existing program setting
PAUSE 30'debounce
GOSUB wait_for_relay_or_memory_off2
WEND
'You can only WRITE a limited number of times,
'so do it when editing is finished
WRITE low_addr_psb, low_data_psb
WRITE high_addr_psb, high_data_psb
buzz_pause = 3
GOSUB buzz
RETURN
init3:
'-------Hardware essentials-------
DEFINE OSC 4'4MHz
'PIC16F87x series devices will come up in analog mode.
'You must set them to digital if that is how you intend to use them:
ADCON0 = ADCON_DIGITAL 'A register
ADCON1 = ADCON_DIGITAL 'seems to affect the D register
'Just leave unused pins as low outputs
TRISA = %00000000 'output for 8 relays
TRISB = %11111111 'input for 8 footswitches
TRISC = %11110000 '4 input for footswitches, 4 relays
TRISD = %11110000 '4 inputs for special switches
TRISE = %00000000 'relays
INTCON = DISABLE_INTERRUPTS
'-------Default Programming-------
'Set defaults once only.
READ NUM_RELAYS_TIMES_4, loop_byte
IF loop_byte <> PROGRAMMED THEN
'first time we apply power
'It doesn't matter if this doesn't alway work
'Set default switch info for the user to change
'We start with button n as a on switch for relay n
'Button 2 has high byte %000000000, low byte %000000100
'Button 9 has high byte %000000010, low byte %000000000
'low bytes, both banks
mask_psb = %00000001
FOR loop_byte = 0 TO 7
WRITE loop_byte, mask_psb 'bank0
WRITE loop_byte + NUM_RELAYS_TIMES_2, mask_psb 'bank1
mask_psb = mask_psb << 1
WRITE loop_byte + NUM_RELAYS, %000000000 'bank0
WRITE loop_byte + NUM_RELAYS_TIMES_3, %000000000 'bank1
NEXT loop_byte
'high bytes, both banks
mask_psb = %00000001
FOR loop_byte = 8 TO 11
WRITE loop_byte, mask_psb 'bank0
WRITE loop_byte + NUM_RELAYS_TIMES_2, mask_psb 'bank1
mask_psb = mask_psb << 1
WRITE loop_byte + NUM_RELAYS, %000000000 'bank0
WRITE loop_byte + NUM_RELAYS_TIMES_3, %000000000 'bank1
NEXT loop_byte
WRITE NUM_RELAYS_TIMES_4, PROGRAMMED 'never do this again
ENDIF
'Read user programmed patches
'-------set toggle switch initial states-------
active_bank = BANK_0
'-------hardware test-------
GOSUB all_on2
PAUSE 500
GOSUB all_off2
PAUSE 500
buzz_pause = 3
GOSUB buzz
RETURN
switch_leds2:
' switch to a preprogrammed led/relay selection
' Input: low_data_sl, high_data_sl
buzz_pause = 6
GOSUB buzz
mask_sl = %00000001 'start with rightmost bit
FOR relay_roo = 0 TO 7 '8 bits to consider,
led_sl = low_data_sl & mask_sl 'look at one bit
IF led_sl = 0 THEN
on_off_roo = GET_IT_OFF
ELSE
on_off_roo = GET_IT_ON 'bit set = relay on
ENDIF
GOSUB relay_on_off
mask_sl = mask_sl << 1 'next bit to the left
NEXT relay_roo
mask_sl = %00000001 'start with rightmost bit
FOR relay_roo = 8 TO 11 'only 4 bits used on the high bit
led_sl = high_data_sl & mask_sl 'look at one bit
IF led_sl = 0 THEN
on_off_roo = GET_IT_OFF
ELSE
on_off_roo = GET_IT_ON
ENDIF
GOSUB relay_on_off
mask_sl = mask_sl << 1 'next bit to the left
NEXT relay_roo
RETURN
all_on2:
FOR relay_roo = FIRST_BUTTON TO LAST_BUTTON
on_off_roo = GET_IT_ON
GOSUB relay_on_off
NEXT relay_roo
RETURN
all_off2:
FOR relay_roo = FIRST_BUTTON TO LAST_BUTTON
on_off_roo = GET_IT_OFF
GOSUB relay_on_off
NEXT relay_roo
RETURN
wait_for_relay_or_memory_off2:
'Wait until a relay_button is pressed, or the memory switch is released
'Output: button_held_bh and memory_held_mh
memory_held_mh = TRUE
button_held_bh = NOPRESS
WHILE (memory_held_mh = TRUE) AND (button_held_bh = NOPRESS)
GOSUB button_held
GOSUB memory_held
WEND
'either memory_held_mh = FALSE or a button pressed
RETURN