'18F4431 32MHz XTL BASE_SLAVE RX_QEI 021222 1031 Define CONFIG1L = 0x00 Define CONFIG1H = 0x06 '8mHz x4 =32 Define CONFIG2L = 0x0c Define CONFIG2H = 0x20 Define CONFIG3L = 0x04 Define CONFIG3H = 0x80 Define CONFIG4L = 0x80 'Set for HVP Define CONFIG4H = 0x00 Define CONFIG5L = 0x0f Define CONFIG5H = 0xc0 Define CONFIG6L = 0x0f Define CONFIG6H = 0xe0 Define CONFIG7L = 0x0f Define CONFIG7H = 0x40 'OSH config Define CLOCK_FREQUENCY = 32 Define SINGLE_DECIMAL_PLACES = 2 Define STRING_MAX_LENGTH = 20 '------------- TARGET SETUP ------------------ Const PR2set = 125 'use this for the live board: gets 5ms per interrupt 'Const PR2set = 2 'use this for fast timing to speed up simulator 'Define SIMULATION_WAITMS_VALUE = 1 'Comment in for SIM out for PIC Define SEROUT_DELAYUS = 1000 ANSEL0 = %00000000 ANSEL1 = %00000000 Disable High Disable Low msg1 = "" '******************************************************* '* * '* GLOBAL VARIABLE DECLARATIONS * '* * '******************************************************* 'Comms 'Dim datasw As Byte 'For setting next in sequence of DATASWITCH Dim buf_fill As Bit 'Message loading Dim buf_done As Bit 'Buffer $ to W 1 = Done 0 = Not 'SHARED COUNTERS AND ARRAYS Dim i As Byte 'Altimeter compass (GPS checking ) Dim b(25) As Byte Dim msg1 As String 'Any msg data will be passed via this string Dim wr_adr As Byte '0xxxxxxx BITS Dim rd_adr As Byte '1xxxxxxx BITS Dim wr_byte As Byte Dim rd_Byte As Byte 'DUMMY = 0 'Receive Buffer Dim buf(50) As Byte 'received message comes to buf Const rxbufsize = 50 'keep this the same as the buffer size Dim rxpsn As Byte 'POSITION of character in UART RX buffer STRING. Dim RXerr As Bit 'Errors in receiving $DATA Dim char_rx As Byte 'Added D as part of serial receive Dim RXIRQchar As Byte 'BASE GPS Dim strtim As String Dim strlat As String Dim strlong As String 'IO Config 'Init LATx flip flops before TRIS regs LATA = LATAinit LATB = LATBinit LATC = LATCinit LATD = LATDinit LATE = LATEinit TRISA = TRISAinit TRISB = TRISBinit TRISC = TRISCinit TRISD = TRISDinit TRISE = TRISEinit 'SET BITS ON/OFF before TRIS! Const LATAinit = %00000000 'ON/OFF Const LATBinit = %00000000 Const LATCinit = %00000000 Const LATDinit = %00000000 Const LATEinit = %00000000 'POSS MCLR RE3 'SET PIN IN/OUT 18F4431 Const TRISAinit = %11000000 '7=OSC, 6=OSC, 2=TEMP SEROUT Const TRISBinit = %00000000 Const TRISCinit = %01000100 '6=1-slave4431_cs, 2=MOSI Const TRISDinit = %00100000 '6=led, 7=led, 5=synch Const TRISEinit = %00000000 '************************ ADDED QEI ********************************** 'QEICON = %00011011 'QEI enabled in 4x Update mode; position TIME is reset on period match (POSCNT = MAXCNT)MOVED TEST& '''QEICON VELM=0 Velocity mode enabled, QERR=0 No over/underflo, UP/DOWN=0 REVERSE, QEIM=110 QEI EN POSCNT=MAXCNT), PDEC=11 1:64 'IPR3.IC2QEIP = 0 '& 1 'high pri intr QEI Interrupt priority bit 'PIE3.IC2QEIE = 0 '& 1 'qei intr enb QEI Interrupt flag enable bit 'PIR3.IC2QEIF = 0 'Has reached the MAXCNT value, INT QEI MODULE Interrupt flag bit 'PIR3.IC3DRIF = 0 'clr in s/w REG file motion feedback filter 'PIE1.RCIE = 0 '0= Disables the EUSART receive interrupt 'CAP2BUFL = 0x00 'CAP2BUFH = 0x00 'CAP3BUFL = 0x9f 'CAP3BUFL = 0x67 'CAP3BUFH = 0x05 'CAP3BUFH = 0x01 '************************************************************************* ''PIC18F4431 Symbol slave4431_cs = PORTC.6 Dim m2s(4) As Byte 'MASTER to SLAVE 4431 4XBYTE ARRAY Dim s2m(46) As Byte 'SLAVE 4431 to MASTER Dim data1 As Byte 'TEST Battery voltage from 4431 [ 1 ] (BATT voltage could be inside a single BYTE) Dim data2 As Byte 'TEST Battery voltage from 4431 [ 2 ] m2s(0) = 6 'TEST numbers, can be used to send DATA to 4431 m2s(1) = 7 m2s(2) = 8 m2s(3) = 9 'TIMERS AND SETTINGS Const T2CONset = %00100010 '16*Prescaler, 5* postscaler, Timer OFF Dim ms20PS As Byte 'prescaler for extended timers Const ms20PSset = 4 '4*5ms = 20msec for other timers 'receive guard timer and individual settings for each sentence Dim ms05_RXguard As Byte 'native 20ms RX guard timer derived from TMR2 irq Const RXguardSet_GNRMC = 61 '5ms * 61 = 300ms to wait for $GNRMC 'Data guard timers for each sentence type and their set times Dim ms20_GNRMCguard As Byte 'GNRMC message guard timer Const GNRMCguardSet = 50 '20ms * 50 = 1 sec to get a good GNRMC sentence Dim ms20_reporttimer As Byte 'simple timer to schedule some Hserout reports ? Const reporttimerSet = 100 '20ms * 200 = update reports every 2 seconds 'FLAGS to indicate updated data Dim prsed_GOOD As Bit 'parser found a good sentence indicated by these flags: Dim prsed_ROBI As Bit 'parser found a REMOTE sentence and updated data Dim prsed_GNRMC As Bit 'parser found a GNRMC sentence and updated data Dim prsed_ERRchan As Byte 'channel that generated the last parse error (when parse_GOOD = 0) '++++++++++++++++++++++++ IAN DIMS from below +++++++++++++++++++++++++++ Dim x As Byte Dim ch As Byte '******************************************************* '* * '* START UP CODE BEGINS HERE * '* * '******************************************************* T1CON.7 = 1 '= enables register Read/Write of timer1 in one 16-Bit operation Symbol yled = PORTD.6 Symbol rled = PORTD.7 Symbol synch = PORTD.5 'START UP LEDS rled = 1 WaitMs 1000 rled = 0 WaitMs 1000 yled = 1 WaitMs 1000 yled = 0 WaitMs 1000 'Set up UART and RX interrupt for immediate use Hseropen 9600 'does a basic config of TX and RX including BAUDCON, SPEN, CREN, TXEN etc. RCSTA.CREN = 0 'not ready to receive yet INTCON = 0 'kill any interrupts WaitMs 60 'Set up timer 2 for 10ms interrupt period T2CON = T2CONset 'set up the timer PR2 = PR2set ms20PS = ms20PSset 'set the 20ms prescaler ms20_GNRMCguard = 0 'clear the guard timers PIR1.TMR2IF = 0 'init TIMER2 interrupt PIE1.TMR2IE = 1 T2CON.TMR2ON = 1 'start TIMER 2 'fire up the UART Enable High prsed_GNRMC = 0 'init new data flags (compiler may do this automatically) 'INITIALIZE SPI Call init_spi() 'initialise spi -here SSPEN=1 sets the pin directions for SPI ms20_reporttimer = 0 'force reports on entry to main loop ''******************************************************* ''* * ''* Main loop BEGINS * ''* * ''******************************************************* 'Dim qei As Word 'Dim qeilb As Byte 'Dim qeihb As Byte main_loop: '/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\ s2m(2) = buf(0) s2m(3) = buf(1) s2m(4) = buf(2) s2m(5) = buf(3) s2m(6) = buf(4) s2m(7) = buf(5) s2m(8) = buf(6) s2m(9) = buf(7) s2m(10) = buf(8) s2m(11) = buf(9) s2m(12) = buf(10) s2m(13) = buf(11) s2m(14) = buf(12) s2m(14) = buf(13) s2m(15) = buf(14) s2m(16) = buf(14) s2m(17) = buf(15) s2m(18) = buf(16) s2m(19) = buf(17) s2m(20) = buf(18) s2m(21) = buf(19) s2m(22) = buf(20) s2m(23) = buf(21) s2m(24) = buf(22) s2m(25) = buf(23) s2m(26) = buf(24) s2m(27) = buf(25) s2m(28) = buf(26) s2m(29) = buf(27) s2m(30) = buf(28) s2m(31) = buf(29) s2m(32) = buf(28) s2m(33) = buf(29) s2m(34) = buf(30) s2m(35) = buf(31) s2m(36) = buf(32) s2m(37) = buf(33) s2m(38) = buf(34) s2m(39) = buf(35) s2m(40) = buf(36) s2m(41) = buf(37) s2m(42) = buf(38) s2m(43) = buf(39) s2m(44) = buf(40) s2m(46) = buf(41) s2m(46) = buf(42) s2m(47) = buf(43) s2m(48) = buf(44) s2m(49) = buf(45) s2m(50) = buf(46) '***************************** ADDED SSPBUF *************************************** yled = synch Toggle rled 's2m(0) = CAP2BUFL 'TEST 1001 qei.LB = CAP2BUFL 'TEST moving these 2x around& 's2m(1) = CAP2BUFH 'TEST 1001 & qei.HB = CAP2BUFH s2m(0) = 1 'NEW& s2m(1) = 1 'TRANSMIT GPS Serout PORTB.4, 9600, "TEST IN LOOP ", "m2s(0) ", " ", #m2s(0), ",", "m2s(1)", " ", #m2s(1), " ", "NMEA ", m2s(2), m2s(3), m2s(4), m2s(5), s2m(6), s2m(7), s2m(8), s2m(9), s2m(10), s2m(11), s2m(12), s2m(13), s2m(14), s2m(15), s2m(16), s2m(17), s2m(18), s2m(19), s2m(20), CrLf WaitMs 100 SSPBUF = s2m(0) While slave4431_cs = 1 'Waiting till CS goes ON =0 Wend While Not SSPSTAT.BF Wend SSPBUF = s2m(1) While slave4431_cs = 1 'Waiting till CS goes ON =0 Wend While Not SSPSTAT.BF Wend '****************************************************** SSPBUF = s2m(2) While slave4431_cs = 1 'Waiting till CS goes ON =0 Wend While Not SSPSTAT.BF Wend SSPBUF = s2m(3) While slave4431_cs = 1 'Waiting till CS goes ON =0 Wend While Not SSPSTAT.BF Wend '***************************************************** 'Endif 'RECEIVED SENTENCE: If buf_done = 1 Then 'If got A sentence.. Gosub parse 'parse the received sentence then.. Gosub IRQinitBuf Gosub process_parsed_data 'then process received sentence (types out any new parsed sentence strings) Else If ms05_RXguard = 0 Then 'else nothing yet. check timeout, change channels if timed out Gosub IRQinitBuf Endif Endif 'SCHEDULE COMPASS AND ALTIMETER REPORTS 'Output these once every time the report timer times out If ms20_reporttimer = 0 Then ms20_reporttimer = reporttimerSet 'reset the timer Endif Goto main_loop End '******************************************************* '* * '* Functions BEGIN * '* * '******************************************************* '---------------------- RX/TMR2 INTERRUPT SERVICE ---------------------- 'Captures one sentence from '$' to 'W' in buf. 'Sentences must fit entirely in buf from $ to W 'Re-inits buf on any error and when any $ is received, even if in middle of sentence 'Stops UART and sets buf_done when 'W' is received. 'Sentence in progress will be discarded, buffer reset and UART re-enabled when: 'Any UART error occurs 'A new '$' in the middle of a reception is found 'The buffer overflows before a 'W' is received. Non-fatal, it will just begin looking for the next 'sentence. err will be set when this happens so that main knows about it. 'Returns buf_done=1 and buffer loaded with $,data,W on successful receipt of a complete sentence. 'Requires: 'rxBufSize defined as the size of buf in bytes. Declare the buffer like this: 'Const rxBufSize = 50 'Dim buf(50) As Byte 'Valid buf index range is 0 to rxBufSize-1. After $, index points to last character stored 'Expects: 'Call IRQinitBuf with PIE1.RCIE = 0 to set up for next sentence On High Interrupt Save System If PIE1.RCIE = 1 Then 'overrun error If RCSTA.OERR = 1 Then RCSTA.CREN = 0 'disable UART RXIRQchar = RCREG '1 'clear UART RX registers RXIRQchar = RCREG '2 RCSTA.CREN = 1 'reenable UART Gosub IRQinitBuf 're-init buffer, discard bad sentence Goto RXIRQdone 'done, wait for next character Endif 'OERR 'framing error If RCSTA.FERR = 1 Then RXIRQchar = RCREG 'Read char to clear RCIF and FERR Gosub IRQinitBuf 'Re-init buffer, discard bad sentence Goto RXIRQdone 'wait for next Endif 'FERR 'No UART errors, process character If PIR1.RCIF = 1 Then RXIRQchar = RCREG 'read the received char, clears RCIF 'Look for $, start/restart filling buf when found If RXIRQchar = "$" Then 'Start (re)filling buf on any $ Gosub IRQinitBuf 'init buffer, index and flags buf(rxpsn) = RXIRQchar 'store $ buf_fill = 1 'start storing the sentence Goto RXIRQdone 'done with this character Endif 'char was $ 'no UART errors and character was not $ 'If $ was found previously, process character looking for W and no buffer overflow. 'If haven't found $ yet, just ignore character. If buf_fill = 1 Then 'if filling buffer, see if there is room in buf If rxpsn >= (rxbufsize - 1) Then 'last char was at end of buf - buffer overflow so.. Gosub IRQinitBuf 'restart buffer, discard sentence RXerr = 1 'let main know that the buffer overflowed and is restarting Goto RXIRQdone 'done, resume looking for next $ Endif 'buffer overflow rxpsn = rxpsn + 1 'else, there's room in buf so bump index and store character, might be W buf(rxpsn) = RXIRQchar If RXIRQchar = "W" Then 'if end of sentence.. RCSTA.CREN = 0 'shut down UART PIE1.RCIE = 0 buf_done = 1 'flag buf full Goto RXIRQdone 'and bye! Endif 'RXIRQchar was W Endif 'if buf_fill = 1 Endif 'RCIF=1 Endif 'RCIE=1 'Exit point for each RXinterrupt. Process timers RXIRQdone: If PIE1.TMR2IE Then 'Means = 1 If PIR1.TMR2IF Then 'eans =1 PIR1.TMR2IF = 0 'clear timer flag If ms05_RXguard <> 0 Then 'count this down to 0 and stop ms05_RXguard = ms05_RXguard - 1 Endif ms20PS = ms20PS - 1 'dec 100ms prescaler If ms20PS = 0 Then 'if PS has run out ms20PS = ms20PSset 'reset it and then.. If ms20_GNRMCguard <> 0 Then 'dec each of the sentence guards to 0 and stop ms20_GNRMCguard = ms20_GNRMCguard - 1 Endif If ms20_reporttimer <> 0 Then 'altimeter and compass reports ms20_reporttimer = ms20_reporttimer - 1 Endif Endif '100ms prescaler = 0 Endif 'TMR2IF Endif 'TMR2IE Resume '--------------- 'PARSE UTILITIES 'Show any parsed string with flag set 'Do any other processing here process_parsed_data: If prsed_GNRMC = 1 Then Serout PORTB.4, 9600, "TEST IN PARSED ", strtim, " ", strlat, " ", "N", " ", strlong, "W", " ", #s2m(0), " ", #s2m(1), " ", CrLf prsed_GNRMC = 0 'and clear flag to indicate that new data has been "processed" Endif If prsed_GOOD = 0 Then 'parse tried but string was unknown, corrupt or wrong length 'Hserout "Parse fail", CrLf 'chan: ", #prsed_ERRchan, CrLf& Endif Return '-------------------- PARSE UTILITIES ------------------------------------- 'These extract characters from the raw RX buffer array to OSH string types 'AddStr: Appends k characters from RX buf at BufIX To passed String at StrIX 'Appends 0 at end of result to keep it a string. Proc AddStr(ByRef str As String, ByRef StrIX As Byte, BufIX As Byte, k As Byte) Dim ChCount As Byte For ChCount = 1 To k str(StrIX) = buf(BufIX) StrIX = StrIX + 1 BufIX = BufIX + 1 Next ChCount str(StrIX) = 0 End Proc 'AddChar: adds passed character to passed string at 'passed StrIx. Terminates result with 0 to keep it a string Proc AddChar(ByRef str As String, ByRef StrIX As Byte, ch As Byte) str(StrIX) = ch StrIX = StrIX + 1 str(StrIX) = 0 End Proc '---------- MatchBuf --------------- 'Compares passed string character by character to 'RX buf starting at the passed index BufIX 'Comparison length is determined by passed string 'Sets the value of the global variable MatchBuf to: '0 if no match '1 if the buffer matches the passed string Function MatchBuf(str As String, BufIX As Byte) As Bit Dim argS As Byte 'local variables Dim argB As Byte Dim StrIX As Byte StrIX = 0 'start at first ch of passed string MatchLoop: argS = str(StrIX) 'get str char If argS = 0 Then 'if it is 0 then end of passed string and.. MatchBuf = 1 '.. all chars so far were equal, return 1 Exit Else argB = buf(BufIX) 'else not end of string, get buf char and compare If argS <> argB Then MatchBuf = 0 'no match, return 0 Exit Endif Endif StrIX = StrIX + 1 'else, not at end of string and no mismatch BufIX = BufIX + 1 'bump indexes and do next Goto MatchLoop End Function '--------------- PARSE COMPLETE SENTENCE IN BUFFER ------------------------- 'parse: extracts the main values from GPS,REMOTE and COMPDEG sentences in RXbuf 'into named value messages using the parse utilities above. 'Flags: 'returns prsed_GOOD if it found A good sentence 'if bad, prsed_ERRchan has datasw value of the bad sentence 'Returns prsed_GNRMC, prsed_REMOTE, prsed_COMPDEG flag to indicate new data 'posted to respective string(s). 'Loads respective guard timers to indicate data good fora while 'Expects: rxpsn = index in buffer of the termininating 'W' char (one less than number of chars): Const ixGNRMC_W = 44 parse: Dim tempIX As Byte 'used as index for building/adding to strings tempIX = 0 'string building begins at 0 for any prsed_GOOD = 0 'parse isn't good yet.. If MatchBuf("GNRMC", 1) = 1 Then 'Process $GNRMC sentence If rxpsn <> ixGNRMC_W Then 'check terminating W index for correct sentence length Goto parse_done 'received sentence not correct length, quit parse Endif Call AddStr(strtim, tempIX, 7, 2) 'copy 2 hours characters from buf(7) to strtim. tempIX is updated to next char Call AddChar(strtim, tempIX, 58) 'add ':' to strtim Call AddStr(strtim, tempIX, 9, 2) 'add 2 mins chars from buf(9) to strtim Call AddChar(strtim, tempIX, 58) 'add ':' Call AddStr(strtim, tempIX, 11, 2) 'add 2 secs char from buf(11) to strtim tempIX = 0 Call AddStr(strlat, tempIX, 19, 10) 'copy 10 chars from buf(19) to strlat tempIX = 0 Call AddStr(strlong, tempIX, 33, 8) 'copy 8 chars from buf(33) to strlong prsed_GNRMC = 1 'flag that GNRMC data has been updated ms20_GNRMCguard = GNRMCguardSet 'set guard timer to indicate valid data (for awhile) prsed_GOOD = 1 'flag that parsing was successful Goto parse_done 'bye! Endif '$GNRMC parse_done: Return '------------- UART SETUP UTILITIES ----------------- 'Stops UART, selects channel indicated by datasw (0-2) 'Inits RX buffer then restarts UART and enables RX interrupt 'Sets RX guard timer to time to wait for specific channel 'Expects: 'GIE is enabled 'port directions and basic TX/RX '-------------------- INIT SENTENCE BUFFER ------------------ 'Sets up index and flags for next sentence. Overwrites 'old buffer data 'May be used by main (non-interrupt code) when PIR1.RCIE = 0 IRQinitBuf: rxpsn = 0 'init index buf_fill = 0 'stop filling until $ buf_done = 0 'not done filling buf RXerr = 0 'no error ms05_RXguard = RXguardSet_GNRMC 'set guard timer RCSTA.CREN = 1 RXIRQchar = RCREG RXIRQchar = RCREG PIE1.RCIE = 1 Return '******************************************************* '* * '* START UP SPI ROUTINE * '* * '******************************************************* Proc init_spi() 'PIC 18F4431 '4431 TRISC.6 = 1 '4431_CS=1 TRISD.3 = 1 'SCK from MASTER ******INPUT***** TRISD.1 = 0 'MISO ****** OUTPUT ******* TRISD.2 = 1 'MOSI ****** INPUT ******* 'MODE 0,0 SSPSTAT.SMP = 0 'Input data sampled at middle of data output time ** not about clock generation ** SSPSTAT.CKE = 0 '0 Output data changes on clock transition from active to idle ** AS ABOVE ** SSPSTAT.5 = 0 'I2C only SSPSTAT.4 = 0 'I2C only SSPSTAT.3 = 0 'I2C only SSPSTAT.2 = 0 'I2C only SSPSTAT.1 = 0 'I2C only SSPCON = 0 'RESET THE CONTROL REGISTER **************************************ADDED SSPCON.WCOL = 0 'Collision detect SSPCON.SSPOV = 0 'Overflow SSPCON.SSPEN = 1 'Configure SCK,SD0,SDI,/SS ** HAS TO BE 1. To reset or reconfigure SPI mode, clear the SSPEN bit, 'reinitialize the sspcon registers And Then set the SSPEN Bit from the datasheet !!!!!!!!!!!!!!!! SSPCON.CKP = 1 '1 = Idle state for clock is a high level SSPCON.SSPM3 = 0 '0100 = SPI SLAVE mode, clock = FOSC/64 SSPCON.SSPM2 = 1 SSPCON.SSPM1 = 0 'SLAVE MODE SSPCON.SSPM0 = 0 End Proc