In the end I didn't use a 16F84A, but purely because the code space wasn't big enough for what i wanted to do. Also, I never ended up using any special PBP commands, opting to write a subroutine using interrupts that would get the timing perfect. I used an 18F1320 with it's 8Mhz internal clock, but I think 4Mhz would work too.
Here's my code:
Code:
INCLUDE "DT_INTS-18.bas" ' Include base interrupt system
INCLUDE "ReEnterPBP-18.bas"
' Interrupt Aliases
INT0IE var INTCON.4 ' INT0 external interrupt enable bit
INTEDG0 var INTCON2.6 ' INT0 external interrupt edge select bit: 1=Rising Edge 0=Falling Edge
' I/O
kb_clock var PORTB.0 ' Keyboard clock pin
kb_data var PORTB.1 ' Keyboard data pin
' Constants
buffer_size CON 32 ' Keyboard buffer size
' Variables
packet var word bank0 ' Latest packet from the keyboard
packet_index var byte bank0 ' Current bit in keyboard packet
buffer var byte[buffer_size] bank0 ' Keyboard data buffer
buffer_i_index var byte bank0 ' Current buffer possition for inputs
buffer_o_index var byte bank0 ' Current buffer possition for outputs
data_received var byte bank0 ' Latest byte retrieved from the buffer
n var word bank0 ' Temporary variable for loops
temp var word bank0 ' General temporary variable
new_data var bit bank0 ' Flag to indicate there is new data from the keyboard
parity_bit var bit bank0 ' Parity bit used for PIC->keyboard communication
error var bit bank0 ' Flag to indicate an invalid packet
' Initialisation
INPUT kb_clock ' Keyboard Clock Pin = Input
INPUT kb_data ' Keyboard Data Pin = Input
ASM
INT_LIST macro ; IntSource Label Type Reset Flag?
INT_Handler INT0_INT, _int0_handler, PBP, yes
endm
INT_CREATE
ENDASM
INTEDG0=0 ' INT0 Interrupt to Trigger on Falling Edge
@ INT_ENABLE INT0_INT
main:
gosub check_for_new_data
IF new_data=1 then
' Do whatever you want with the byte we just received. It is stored in data_received.
ENDIF
goto main
' Keyboard interrupt handler: Retrieves packet from keyboard
int0_handler:
packet.11=kb_data ' Store bit
packet=packet>>1 ' Rotate the packet so it is ready for the next bit
packet_index=packet_index+1 ' Increment packet bit index
iF packet_index=11 then ' If packet is complete:
gosub check_packet_for_errors ' Check the packet for errors
if error=1 then ' If there was an error:
packet=0 ' Discard the packet
packet_index=0 ' Reset the packet bit index
goto int_exit ' Exit the interrupt
ENDIF
packet_index=0 ' Reset Packet Index
packet=packet>>1 ' Discard the start bit
buffer[buffer_i_index]=packet.byte0 ' Store just the recieved byte
buffer_i_index=buffer_i_index+1 ' Increment buffer input index
if buffer_i_index=buffer_size then buffer_i_index=0 ' If end of buffer has been reached, reset the index
IF buffer_i_index=buffer_o_index THEN ' If the buffer is full:
INT0IE=0 ' Disable Interrupt
OUTPUT kb_clock ' Set the keyboard's clock as output
low kb_clock ' Set the keyboard's clock line low (tell the keyboard to stall)
endif
endif
int_exit:
@ INT_RETURN
' Subroutine to check to see if there is any new data waiting in the keyboard buffer
check_for_new_data:
IF buffer_o_index!=buffer_i_index then ' If the buffer is not empty:
data_received=buffer[buffer_o_index] ' Get the next byte from the buffer
new_data=1 ' Set the new data flag
buffer_o_index=buffer_o_index+1 ' Increment buffer output index
if buffer_o_index=buffer_size then buffer_o_index=0 ' If end of buffer has been reached, reset the index
IF INT0IE=0 THEN ' If the buffer was full, its now got a space, so:
INPUT kb_clock ' Release the keyboard's clock line
INT0IE=1 ' Re-enable the interrupt
ENDIF
else
new_data=0 ' If the buffer is empty, clear the new_data flag
endif
return
' Subroutine to check the incoming packet for errors
check_packet_for_errors:
error=0 ' Reset error flag
parity_bit=1 ' Set parity bit for start of calculation
temp=packet ' Copy the packet to a temp variable so we can play with it
if packet.0=1 then ' Check that start bit = 0
error=1
return
endif
if packet.10=0 then ' Check that stop bit = 1
error=1
return
endif
temp=temp>>1 ' Discard the start bit
for n=0 to 7 ' Calculate what the bit parity should be
if packet.0=1 then toggle parity_bit
temp=temp>>1
next n
if packet.10!=parity_bit then ' Check the parity bit
error=1
return
endif
return
Bookmarks