Having realised that I was indulging in some horrible premature optimisation, I stopped trying to make this circuit work using a three-bit output and cracked on with a 4-bit version. The circuit just took a few minutes to build on top of the flashing LED circuit:
I added extra LEDs on RA0-4, and added a push-to-close switch on RB0/INT. I also added a capacitor across the input to even out any voltage fluctuations, and included a diode to save me from my own stupidity – I’ve already zapped more than one IC by getting the polarity wrong.
In the code, I stripped out the delay stuff, and started by just turning all the LEDs on, which was pretty simple:
movlw 0x0F movwf PORTA
I also had to add some more setup stuff:
bsf STATUS,5 ; Switch to Bank 1 bsf OPTION_REG, INTEDG ; Set RB0 to generate an interrupt on a rising edge bcf INTCON, INTF ; clear interrupt flag bsf INTCON, INTE ; mask for external interrupts bsf INTCON, GIE ; enable interrupts movlw 0x01 ; Port B to input movwf TRISB
Then I turned the bulk of the old program into a sleep routine:
; Turn the LED off start movlw 0x00 ; Turn the LED on by first putting movwf PORTA ; it into the w register and then on the port sleep END ; directive 'end of program'
And added some code to the interrupt handling routine:
; isr btfss PORTB, 0 ; Only run if RB0 is high goto end_isr ; If it's not high, branch to the end btfss PORTA, 0 ; Invert Port A - if bit 0 of Port A is set, movlw 0x0F ; skip the instruction that makes it high, btfsc PORTA, 0 ; and vice-versa movlw 0x00 movwf PORTA ; Put the selected value into PORTA bcf PORTB, 0 ; Clear PORTB now that we're done with it. ; I don't know if this works or if it's necessary
This nearly works. As in, when I press the button, the LEDs do all light up. And then pressing it again turns them off. However, they also come on by themselves and flash very quickly, and then turn off. I assume this is because of some other interrupt being called, and that my starting btfss doesn’t sufficiently differentiate between interrupts caused by RB0 going high, and other sorts of interrupts.
Or, it might be because the pin is not tied to ground when the pin is open, and floating voltage is enough to trigger the interrupt.
More fiddling needed.
Useful things found while doing this: