'rfkey_51_1
'jleblanc 5.1.06
'This version is built for the ITP show and doesn't involve targeted
'message sending.
'Also memory is expanded up to past 25 messages
'for my keyboard connector:
'red to ground
'white to power
'black to A0
'yellow to A
'********************************************************************
'*Setup OSC, LCD and Keyboard pins
'********************************************************************
DEFINE OSC 20
'include modedefs.bas for shiftin and out modes used in the RF code
INCLUDE "modedefs.bas"
'SETUP LCD
'This setup will tell PBP a 2-line LCD is connected in 4-bit
'mode with the data bus on the top 4 bits of PORTB, Register
'Select on PORTB.1, and Enable on PORTB.0.
'Data Bits go like: D7>B.7, D6>B.6, D5>B.5, D4>B.4
DEFINE LCD_DREG PORTB
' Set starting Data bit (0 or 4) if 4-bit bus
DEFINE LCD_DBIT 4
' Set LCD Register Select port
DEFINE LCD_RSREG PORTB
' Set LCD Register Select bit
DEFINE LCD_RSBIT 1
' Set LCD Enable port
DEFINE LCD_EREG PORTB
' Set LCD Enable bit
DEFINE LCD_EBIT 0
' Set LCD bus size (4 or 8 bits)
DEFINE LCD_BITS 4
' Set number of lines on LCD
DEFINE LCD_LINES 2
' Set command delay time in us
DEFINE LCD_COMMANDUS 2000
' Set data delay time in us
DEFINE LCD_DATAUS 50
'Setup KeyBoard System
'The keyboard runs off PORTA so this sets it to all digital
ADCON1 = %10000110
KeyData VAR PORTA.0
KeyClk VAR PORTA.1
'Setup RF
'pin definitions for comm w/ Sparkfun MiRF v01
RF_CE VAR PORTD.7 'yellow
RF_CS VAR PORTD.3 'dark green
RF_DR VAR PORTD.2 'blue
'channel 1 PIN definitions
RF_CLK1 VAR PORTD.1 'black
RF_DATA_In VAR PORTD.0 'light blue
RF_DATA_Out VAR PORTD.0
'I/O + Control PINS
switch VAR portc.4
receiveLED VAR portc.3
sendLED VAR portc.2
'********************************************************************
'*Variables
'********************************************************************
'GENERAL VARIABLES
i VAR BYTE
counter VAR BYTE
'KEYBOARD VARIABLES
'Variables used to interface with keyboard
Keypress VAR BYTE'Keyboard value read from keyboard
AscKey VAR BYTE'This is used to send key scan data and subroutine controls to other subroutines
TempReg VAR BYTE'Misc temp register
Temp2Reg VAR BYTE'Misc temp register
ShiftReg VAR BIT'Stores the shift key status. 1=shift 0=no shift
DumpReg VAR BIT'Temp reg for dumping keypress values after a releasecommand
'RF VARIABLES
' THIS IS THE ADDRESS FOR THE MiRF v01
WhichAddress1 VAR BYTE 'Channel 1
WhichAddress2 VAR BYTE 'Channel 2
'constants for RF configuration modes
CONRFRX VAR BYTE
CONRFTX VAR BYTE
'indicates state of current RF configuration - TX is 0, RX is 1
RFCurrentState VAR BIT
'hold data for RF message
RFDataArrayIN VAR BYTE[19]
RFDataArrayOUT VAR BYTE[19]
'hold data for RF configuration
RFConfigArray VAR BYTE[16]
'variables for each received or sent message
msgFromID VAR BYTE
msgToID VAR BYTE
'ID variables
'**me is a key variable because it is the identifier for a given
'unit. Each unit will have its own me ID, and when a unit writes out
'it will either write to a specific other unit (using 1,2,3) or to all
'units using A
me VAR BYTE 'ID that should be set to a unique number for each board
friend VAR BYTE
'******SET AS UNIQUE FOR EACH UNIT
me = 1 'ID that should be set to a unique number for each board
friend = 2
'Line Number Variable: Tells us what line on the LCD a line goes/comes from
line_number VAR BYTE
line_number=0
'LCD VARIABLES
'For the LCD the top 2 lines are the lines the keyboard can write to.
'The bottom 2 lines are for incoming messages. Thus cursor max is 31
'Display Array
DisplayArray VAR BYTE[64] '4 lines by 16 bytes
'Other Variables
pos VAR BYTE 'cursor position
MAXpos VAR BYTE 'max cursor position
Bself VAR BYTE
Eself VAR BYTE
Bother VAR BYTE
Eother VAR BYTE
control VAR BYTE 'Not sure what this does
'initialize
Bself=0 : Eself=31 : Bother=32: Eother=63
MAXpos=Eself 'since we start from 0
pos=0
FOR i=0 TO Eother
DisplayArray[i]=" "
NEXT i
'DISPLAY MEMORY VARIABLES
'Each device will save the last 10 messages that came in
'Anytime a message is sent in it gets sent to the rear
'MemoryArray
MemoryArray VAR BYTE[800] '25 x 32byte messages
'initialize
FOR i=0 TO 799
MemoryArray[i]=" "
NEXT
total_mem VAR BYTE 'total number of messages can be stored
total_mem=25
mem_size VAR BYTE 'number of messages in memory
mem_size=0
current_mem VAR BYTE'newest msg place
current_mem=0
display_mem VAR BYTE 'Current msg on display
display_mem=0
nav VAR BIT 'used to navigate the memory
'OUTPUT CONTROL VARIABLES
trigger VAR BIT
trigger=0
OutputArray VAR BYTE[32]
'************************************************************************
'*Bootup
'************************************************************************
'Bootup RF
WhichAddress1 =$BA 'These are things maybe to change????
WhichAddress2 =$BA
'intialize RF module configuration
'constants to define receive/transmit modes at 2402 Mhz frequency
CONRFRX = $05
CONRFTX = $04
RFCurrentState = CONRFRX
GOSUB INITRFCONFIG
msgToID = 0 ' CHANGE THIS TO WHO SHOULD RECIEVE MESSAGE
msgFromID = me ' CHANGE THIS TO ID OF SENDER
'Bootup LCD
LCDOUT $fe, 1 ' Clear screen
LCDOUT "Starting Up" ' Send Startup Message
PAUSE 1000 'Just Pause for a second
LCDOUT $fe, 1 ' Clear screen
'************************************************************************
'*Main Loop
'************************************************************************
Main:
'This code brings the RF into an active state
LOW RF_CS ' bring CS low before turning CE high - only one high at a time!
HIGH RF_CE ' bring CE high to bring RF into active mode
GOSUB ScanKeyboard'Gets key pressed keycode
GOSUB BackSpace 'Handles backspacing
GOSUB ChrtoASCII'Changes keycode into ascii
GOSUB UpdateMSG 'Updates Msg array
GOSUB Renderscreen 'Updates LCD
'For some reason We need this here even though its in scankeyboard
'For the system to work. Not sure why.
IF RF_DR = 1 THEN
INPUT RF_DATA_In 'This makes that pin an Input PIN
GOSUB RECEIVERF
ENDIF
GOTO Main
'************************************************************************
'*Sub Programs
'************************************************************************
'ScanKeyboard: Gets input from the keyboard and on RETURN sends out message via RF
'UpdateMSG: Updates the message Array and cursor position
'Renderscreen: Renders Msg[] array to the LCD screen
'ClockCycle: Used by ScanKeyboard
'ChrtoASCII: Converts keyboard scan codes to ASCII
'BackSpace: Handles backspace key
'RECEIVERF: Handles Incoming RF messages
'LOADARRAYS: THIS IS USED TO PIECE TOGETHER AN INCOMING MESSAGE
'SENDDATA: Sends Data Out via RF
'SETRFCONFIG: Resets RF configuration after a send or recieve
'INITRFCONFIG: Initiali RF configuration
ScanKeyboard:
DumpReg = 0
DumpKeys:'NOTE
AscKey = 0
Keypress = 0
INPUT KeyClk : KeyClk = 1 'Release Clock Line for Com from Keyboard to PIC
GOSUB ClockCycle'Dumps start bit
FOR TempReg = 0 TO 7
GOSUB ClockCycle
IF KeyData = 1 THEN 'Calculates bit value
LOOKUP TempReg,[1,2,4,8,16,32,64,128],Temp2Reg
Keypress = Keypress + Temp2Reg'Adds the bit values together
ENDIF
NEXT TempReg
GOSUB ClockCycle'Dumps parity bit
GOSUB ClockCycle'Dumps stop bit
OUTPUT KeyClk : KeyClk = 0 'Set Clock Line Low and hold Com from Keyboard to PIC
IF Keypress = $F0 THEN'If key release command then go again
DumpReg = 1'Set so that next key will also get dumped
GOTO DumpKeys'Rerun loop
ENDIF
IF Keypress=$58 || Keypress=$12 || Keypress=$59 && DumpReg = 1 THEN'Turn off ShiftReg
ShiftReg = 0'Sets the Shift Reg for Shift
AscKey = 255'Will not print anything on LCD
ENDIF
IF DumpReg = 1 THEN'If this loop was to dump chr then send a 255 to next
DumpReg = 0 '???????
Keypress = 255
ENDIF
IF Keypress=$58 || Keypress=$12 || Keypress=$59 THEN'Turn on ShiftReg
ShiftReg = 1'Sets the Shift Reg for Shift
AscKey = 255'Will not print anything on LCD
ENDIF
'Note we'll use F1 for back ($05) and F2 for forward ($06)
'we'll say nav=1 goes forward and nav=0 goes back
IF Keypress=$06 THEN
display_mem=(display_mem+1)//(mem_size)'no -1
AscKey = 255'Will not print anything on LCD
ENDIF
IF Keypress=$05 THEN
IF display_mem=0 THEN
display_mem=(mem_size-1)
ELSE
display_mem=display_mem-1
ENDIF
AscKey = 255'Will not print anything on LCD
ENDIF
'IF hit return then set trigger for sending message
IF Keypress=$5A THEN
'Load outputarray with current display
FOR i=0 TO 31
OutputArray[i]=DisplayArray[i]
NEXT
'Goto the transmit subroutine
GOSUB Transmit
AscKey = 255'Will not print anything on LCD
ENDIF
RETURN
'Called in RecieveRF
handlenewmsg:
'UP mem_size
IF mem_size<total_mem THEN mem_size=mem_size+1
'Set current pointer
IF mem_size=1 THEN
current_mem=0
ELSE
current_mem=(current_mem+1)//total_mem
ENDIF
'We also are going to want to default display the new message
display_mem=current_mem
'RecieveRF will now do the proper thing with
RETURN
Transmit:
'All Messages goto everyone in this configuration
msgToID ="A"
'Send both lines of the message out via RF
line_number=1
GOSUB SENDDATA ' goto the sendData function
PAUSE 1
line_number=2
GOSUB SENDDATA ' goto the sendData function
PAUSE 1
'Record Outgoing Message in self's Memory
GOSUB handlenewmsg
FOR i=0 TO 31
MemoryArray[i+32*current_mem]=OutputArray[i]
NEXT
'Reset self area of the Display
FOR i=Bself TO Eself
DisplayArray[i]=" "
NEXT
pos=0
RETURN
UpdateMSG:'This will convert the key scan codes to ASCCII
IF AscKey <> 255 THEN
DisplayArray[pos]=Keypress
pos=pos+1
IF pos > MAXpos THEN pos=MAXpos
ENDIF
RETURN
Renderscreen:
'Clear Screen
LCDOUT $fe, 1
'Print first line
FOR i=0 TO 15
LCDOUT DisplayArray[i]
NEXT
'Move to second line
LCDOUT $fe, $C0
FOR i=16 TO 31
LCDOUT DisplayArray[i]
NEXT
'Print Bottom 2 lines
IF mem_size>0 THEN
'Move to third line
LCDOUT $fe, $90
FOR i=0 TO 15
LCDOUT MemoryArray[i+display_mem*32]
NEXT
'Move to fourth line
LCDOUT $fe, $D0
FOR i=16 TO 31
LCDOUT MemoryArray[i+display_mem*32]
NEXT
ELSE
'Move to third line
LCDOUT $fe, $90
FOR i=0 TO 15
LCDOUT " "
NEXT
'Move to fourth line
LCDOUT $fe, $D0
FOR i=16 TO 31
LCDOUT " "
NEXT
ENDIF
RETURN'renderscreen
'NOTE: This function is the ClockCycle listner from the keyboard
'But also has RF listening too. This is because this function loops
'forever until it gets a signal from the keyboard. Thus embedding the
'RF listen code in here ensures that we will not miss a RF incoming signal
ClockCycle:'Waits for the clock to cycle from keyboard
HoldClockLow:
IF RF_DR = 1 THEN
INPUT RF_DATA_In 'This makes that pin an Input PIN
GOSUB RECEIVERF
ENDIF
IF KeyClk = 0 THEN HoldClockLow
HoldClockHi:
IF RF_DR = 1 THEN
INPUT RF_DATA_In 'This makes that pin an Input PIN
GOSUB RECEIVERF
ENDIF
IF KeyClk = 1 THEN HoldClockHi
RETURN
ChrtoASCII:'Converts keycode into ASCII
IF AscKey <> 255 THEN
AscKey = 255
LOOKDOWN Keypress,[69,22,30,38,37,46,54,61,62,70,28,50,33,35,36,43,52,51,67,59,66,75,58,49,68,77,21,45,27,44,60,42,29,34,53,26,41,78,85,93,84,91,76,82,65,73,74],AscKey
IF ShiftReg = 0 THEN
LOOKUP AscKey,["0123456789abcdefghijklmnopqrstuvwxyz -=|{};',./"],Keypress
ELSE
LOOKUP AscKey,[")!@#$%^&*(ABCDEFGHIJKLMNOPQRSTUVWXYZ _+|{}:'<>?"],Keypress
ENDIF
ENDIF
RETURN
BackSpace:
IF Keypress = $66 THEN'Backspace key pressed
IF pos=MAXpos THEN
IF DisplayArray[pos]=" " THEN
pos=pos-1: DisplayArray[pos]=" "
ELSE
DisplayArray[pos]=" "
ENDIF
ELSE
IF pos > 0 THEN
pos=pos-1
DisplayArray[pos]=" "
ENDIF
ENDIF
AscKey = 255 'Don't enable further writing
ENDIF
RETURN
'***************************************************************************
'*RF SUB PROGRAMS
'***************************************************************************
'RECEIVERF
'LOADARRAYS
'RUNDISPLAY
'SENDDATA
'SETRFCONFIG
'INITRFCONFIG
RECEIVERF:
'TAKE IN THE DATA INTO RFDATAARRAYIN
INPUT RF_DATA_In 'Redudant? given we say this in main loop?
'power down RF front-end for current conservation
LOW RF_CE
'clock in data from RF-24G to PIC
FOR i=0 TO 18
'clock should follow data by at least 50nsec
''This basically sends out a clock signal
''SHIFTIN DataPin,ClockPin,Mode,[Var{\Bits}...]
SHIFTIN RF_DATA_In, RF_CLK1, MSBPRE, [RFDataArrayIN[i]\8]
NEXT
'LOAD DISPLAYARRAY
'power up RF front-end again
HIGH RF_CE
' 'Add to the Control Variables
' msgToID = RFDataArrayIN[0] 'the receiver is in msgToID
' msgFromID = RFDataArrayIN[1] 'sender information in msgFromID
'Load DisplayArray
GOSUB LoadDisplayArray
'Print the whole array
GOSUB Renderscreen'RunDisplay
'Here we blink to acknowledge we have received the message
HIGH receiveLED:PAUSE 50:LOW receiveLED:PAUSE 50
HIGH receiveLED:PAUSE 50:LOW receiveLED:PAUSE 50
RETURN 'RECEIVERF
'THIS IS USED TO PIECE TOGETHER AN INCOMING MESSAGE
'NOTE THIS WILL ONLY PICK UP MESSAGES ADRESSED TO IT
'OR TO ALL
'RFDataArrayIN[0] = msgToID
'RFDataArrayIN[1] = msgFromID
'We want to make sure that [0] matches us or is 'A' (65)
LoadDisplayArray:
msgToID = RFDataArrayIN[0] 'the receiver is in msgToID
msgFromID = RFDataArrayIN[1] 'sender information in msgFromID
IF msgToID=me OR msgToID="A" OR msgToID="a" THEN
'First goto handle handlenewmsg, this will update where things
'must point e.g. sets current_mem we only do this once!!!!
IF RFDataArrayIN[2]=1 THEN
GOSUB handlenewmsg
ENDIF
'Note array element [2] is the line number
'Load first Line
IF RFDataArrayIN[2]=1 THEN
'Load first part of array
FOR i=0 TO 15
'DisplayArray[i+32]=RFDataArrayIN[i+3]
MemoryArray[i+32*current_mem]=RFDataArrayIN[i+3]
NEXT
ENDIF
'Load second Line
IF RFDataArrayIN[2]=2 THEN
'Load second part of array
FOR i=0 TO 15
'DisplayArray[i+48]=RFDataArrayIN[i+3]
MemoryArray[i+32*current_mem+16]=RFDataArrayIN[i+3]
NEXT
ENDIF
ENDIF
RETURN'LOADARRAYS
SENDDATA: 'SENDS OUT 19 byte message
'LOAD RFDATAARRAYOUT
'Load the RF data out array with control Items
RFDataArrayOUT[0] = msgToID
RFDataArrayOUT[1] = me'msgFromID
RFDataArrayOUT[2] = line_number 'this is line number 1-3, here just the number of times we've sent
'Load array with correct line number information
IF line_number=1 THEN
'Load first part of array
FOR i=0 TO 15
RFDataArrayOUT[i+3]=OutputArray[i]
NEXT
ENDIF
'Load second Line
IF line_number=2 THEN
'Load second part of array
FOR i=0 TO 15
RFDataArrayOUT[i+3]=OutputArray[i+16]
NEXT
ENDIF
'SEND THE DATA
'set RF to transmit mode...
RFCurrentState = CONRFTX
GOSUB SETRFCONFIG
' for shockburst TX, the sum of RX address, payload, and CRC must be less than 256 bits long
' the chip then tacks on a preamble to this message, and the total msg is 266 bits
OUTPUT RF_DATA_Out 'Makes the pin an Output
'get back into active mode
HIGH RF_CE
'Need pause between CE high and DATA clock out
PAUSEUS 100
'clock out 5 byte RF address of recipient
FOR i = 8 TO 12
'clock out this byte
SHIFTOUT RF_DATA_Out, RF_CLK1, MSBFIRST, [RFConfigArray[i]\8]
NEXT
'clock out 19 bytes of data payload
FOR i = 0 TO 18
'clock out this byte
SHIFTOUT RF_DATA_Out, RF_CLK1, MSBFIRST, [RFDataArrayOUT[i]\8]
NEXT
'start shockburst transmission
LOW RF_CE
PAUSEUS 300
'flash LED to indicate that we transmitted
HIGH sendLED:PAUSE 50:LOW sendLED:PAUSE 50
HIGH sendLED:PAUSE 50:LOW sendLED:PAUSE 50
'afterward, set RF back to its default receive state
RFCurrentState = CONRFRX
GOSUB SETRFCONFIG
RETURN'SENDATA
SETRFCONFIG: ' THIS IS USED TO SWITCH BETWEEN RECIEVE AND TRANSMIT MODES
'during configuration of the transmitter, we need RF_DATA as an output
OUTPUT RF_DATA_Out
'set chip to configure mode (CE low, CS high)
LOW RF_CE
HIGH RF_CS
'pause between CS high and DATA clockout
PAUSEUS 100
'RFCurrentState indicates 2402 Mhz frequency and either RX or TX state
'clock out new configuration data from PIC to RF-24G
SHIFTOUT RF_DATA_Out, RF_CLK1, MSBFIRST, [RFCurrentState\8]
'configuration set on falling edge of CS
LOW RF_CS
LOW RF_CE
'for consistency with the rx, stick this here
INPUT RF_DR
'flash the LED on B6 to indicate that we configured
'high DEBUG_LED1
' pause 250
'low DEBUG_LED1
RETURN'SETRFCONFIG
INITRFCONFIG:
'configuration is a 144 bit word
'must be clocked in MSB first
'bit map
'143:120 - reserved for testing
'119:112 - length of data payload section RX channel 2
'111-104 - length of data payload section RX channel 1
'103:64 - up to 5 byte address for RX channel 2
'63:24 - up to 5 byte address for RX channel 1
'23:18 - number of address bits (both RX channels)
'17 - 8 or 16 bit CRC
'16 - enable on-chip CRCD generation/checking
'15 - enable two channel receive mode
'14 - communication mode (direct or shockburst)
'13 - RF data rate (1Mbps requires 16Mhz crystal)
'12:10 - crystal frequency
'9:8 - RF output power
'7:1 - frequency channel
'0 - RX or TX operation
'setup RFConfigArray with config bytes, see datasheet for default configuration
'this array is backwards so we can clock from MSB to LSB by increasing the index
'Data bits 119-112: Max data width on channel 2 (excluding CRC and adrs)
RFConfigArray[1] = $98 'payloadSize, 19 BYTES (this is 19*8 for bits in hex)
'Data bits 111-104: Max data width on channel 1 (excluding CRC and adrs)
RFConfigArray[2] = $98 'payloadSize, 19 BYTES
'Data bits 103-64: Channel 2 address, 5 bytes (40 bits)
RFConfigArray[3] = WhichAddress2
RFConfigArray[4] = WhichAddress2
RFConfigArray[5] = WhichAddress2
RFConfigArray[6] = WhichAddress2
RFConfigArray[7] = WhichAddress2
'Data bits 63-24: Channel 1 address, 5 bytes (40 bits)
RFConfigArray[8] = WhichAddress1
RFConfigArray[9] = WhichAddress1
RFConfigArray[10] = WhichAddress1
RFConfigArray[11] = WhichAddress1
RFConfigArray[12] = WhichAddress1
'Data bits 23-16: Address width and CRC - 40 bit addr, 16 bit CRC, CRC enabled
RFConfigArray[13] = $A3
'Data bits 15-8: One Channel Receive, Shockburst Enabled, 250 kilobits, etc
RFConfigArray[14] = $4F
'Data bits 7-0: 2402 Mhz frequency, RX enabled/disabled (depending on RFCurrentState)
RFConfigArray[15] = RFCurrentState
'===================================================================
'During configuration of the transmitter, we need RF_DATA as an output
INPUT RF_DR
INPUT RF_DATA_In
OUTPUT RF_DATA_Out
'set chip to configure mode (CE low, CS high)
LOW RF_CE
HIGH RF_CS
'pause between CS high and DATA clockout
PAUSEUS 100
'clock out configuration bytes from PIC to RF-24G
FOR i = 1 TO 15
'set config one byte at a time from MSB to LSB
SHIFTOUT RF_DATA_Out, RF_CLK1, MSBFIRST, [RFConfigArray[i]\8]
NEXT
'configuration is set on the falling edge of CS, bring it low
LOW RF_CS
LOW RF_CE
'flash LED on pin B6 to debug that we configured
HIGH sendLED:PAUSE 250:LOW sendLED:PAUSE 250
HIGH receiveLED:PAUSE 250:LOW receiveLED:PAUSE 250
HIGH sendLED:PAUSE 250:LOW sendLED:PAUSE 250
HIGH receiveLED:PAUSE 250:LOW receiveLED:PAUSE 250
RETURN'INITRFCONFIG
'***************************************************************************
'*END SUB PROGRAMS
'***************************************************************************