;=========================================================================== ;PLSDNMEA G4JNT Nov 2006 ; Read Trimble Palisade 10-8F string, generate pseudo NMEA string $GPRMC ;============================================================================ LIST P=16F628 errorlevel 2 INCLUDE "P16F628.INC" __config 0x3F61 ;LV Programming off , OSC XT Mode #define LED PORTB, 3 #define GRXD PORTB, 4 #define TXD PORTB, 6 ;RS232 data out #define RXD PORTB, 7 ;RS232 Data in #define GPSValid Flags, 1 GRXDPol = 1 ;1 = RS232 levels, 0 = TTL Stack0 = 0xA0 ;Gives 96 bytes in page 1, indirect addressed PI180 = d'5729578' ;180/pi * 1e5 org 0x2100 ;============================================= org 0 nop clrw movwf INTCON ;disable interrupts goto StartUp ;jump to main code retfie ;Just in case StartUp clrf PORTA ;Special setup to disable comparator on 'F628 movlw 7 movwf CMCON bsf STATUS,RP0 ;ram page 1 movlw b'00000000' movwf PORTA ; movlw b'10010000' ;B7 = RXD, B4 = GPS Data in movwf PORTB movlw b'00000000' ;Enable pull ups movwf OPTION_REG bcf STATUS , RP0 clrf PORTB ;All low clrf PORTA clrf Flags MainLoop call Palisade movlw "$" call Send232 movlw "G" call Send232 movlw "P" call Send232 movlw "R" call Send232 movlw "M" call Send232 movlw "C" call Send232 movlw "," call Send232 call SendBackTime call CrLf goto MainLoop ;====================================== Palisade movlw Stack0 ;All critical values come in pairs, 10,## movwf FSR bsf LED clrf RxChar clrf LastRxChar PaLoop1 call GetGPSByte movwf RxChar ;Save current byte ; movlw 0x10 ;Then check to see if the previous one was a 10 subwf LastRxChar, w btfsc STATUS, Z goto LastWas10 ;If so, investigate further movf RxChar, W ;If not, update and save latest to memory movwf INDF ;It MAY be a 0x10 which could be data or stuffed movwf LastRxChar ; or a genuine DLE - but is in memory anyway! incf FSR ;Increment pointer, btfss FSR,7 ;Check for overflow in case of nasties, decf FSR ; and if so, force to 0xFF goto PaLoop1 ;Carry on looping ;................... LastWas10 ;Current memory position, and LastChar are both 0x10 movf RxChar, W ;Is the current character also a DLE ? sublw 0x10 btfsc STATUS, Z goto Pair10 ;If so, treat as bit stuffed goto Delimiter ;Otherwise test for delimiter ;............ Pair10 ;Two DLEs appeared together - one was already clrf LastRxChar ; saved and we know it was data so mustn't be goto PaLoop1 ; used on next pass, so set to default value ;......... Delimiter ;DLE followed by another character, not a DLE movf RxChar, W ; is definitely a delimiter movwf INDF ;Save it anyway movwf LastRxChar incf FSR movlw 0x03 subwf RxChar, w btfsc STATUS, Z ;03 is terminator goto DoneField movlw 0x8F ;If it is not Start of field, start again subwf RxChar, W btfss STATUS, Z goto Palisade goto PaLoop1 ;............................... DoneField ;All the 8F field except for bcf LED ; stuffed DLE's are in memory movlw Stack0 + 8 movwf FSR movf INDF, w movwf A2 incf FSR movf INDF, w movwf A1 incf FSR movf INDF, w movwf A0 clrf A3 movlw d'60' movwf B0 call Divide32x8 ;Gives minutes of week in Q0/Q1, Seconds in R0 movf R0, w movwf Seconds movf Q0, w movwf A0 movf Q1, W movwf A1 clrf A2 clrf A3 movlw d'60' movwf B0 call Divide32x8 ;Hours of week in Q0/1, Minutes in R0 movf R0, W movwf Minutes movf Q0, w movwf A0 movf Q1, W movwf A1 clrf A2 clrf A3 movlw d'24' movwf B0 call Divide32x8 ;Day of week in Q0, Hour in R0 movf R0, W movwf Hours movlw Stack0 + d'15' movwf FSR movf INDF, w movwf Day incf FSR movf INDF, w movwf Month incf FSR movf INDF, w movwf YearHi incf FSR movf INDF, w movwf Year ;Lat and Long treated as as radians * 2^32 ;Multiply by 180/pi * 10^5. Approx 1m accuracy clrf B3 movlw (PI180 >> d'16') & 0xFF movwf B2 movlw (PI180 >> d'8') & 0xFF movwf B1 movlw PI180 & 0xFF movwf B0 movlw Stack0 + d'50' ;Point at Latitude mantissa movwf FSR movf INDF, w movwf A3 incf FSR movf INDF, w movwf A2 incf FSR movf INDF, w movwf A1 incf FSR movf INDF, w movwf A0 call Multiply32 ;Radians * 2^32 * 100000 movf Acc5, W ;divide by 2^32 by starting at Acc5 movwf A0 movf Acc6, W movwf A1 movf Acc7, W movwf A2 movf Acc8, w movwf A3 ;Lat in units of deg / 100000 ;B is preserved in multiply routine movlw Stack0 + d'58' ;Point at Longitude mantissa movwf FSR movf INDF, w movwf A3 incf FSR movf INDF, w movwf A2 incf FSR movf INDF, w movwf A1 incf FSR movf INDF, w movwf A0 call Multiply32 ;Radians * 2^32 * 100000 return ;-------------------------------------- BitDelay ;For RS232 4800 Baud link movlw d'39' ; delay = 5.N + 5 = 200us + 8 in routine movwf DelCount HalfBaudDelLoop nop nop decfsz DelCount goto HalfBaudDelLoop return ;--------------------------- Send232 ;Enter with data in W, send it to PC movwf Temp bsf TXD ;start bit call BitDelay ; movlw 8 movwf Counter nop nop SendDatLoop rrf Temp ;bit into C btfsc STATUS , C bcf TXD btfss STATUS , C bsf TXD ;could have 2us jitter depending on 1/0 call BitDelay decfsz Counter goto SendDatLoop ;loop 8 + BitDelay long bcf TXD ;stop bit call BitDelay call BitDelay ;Two stop bits return ;------------------------- GetGPSByte if GRXDPol == 1 ;1 = RS232 levels, 0 = TTL btfss GRXD ;Data inverted for RS232 polarity else btfsc GRXD endif goto GetGPSByte ;Loop waiting for start bit call GPSHalfBitDelay ;Centre of start bit if GRXDPol == 1 btfss GRXD ;Data inverted for RS232 polarity else btfsc GRXD endif goto GetGPSByte ;Glitch movlw 8 movwf Counter clrf Temp ;probably not needed, but good practice InitGPSByteLoop call GPSHalfBitDelay call GPSHalfBitDelay ;200us here nop bcf STATUS , C ;start in known state if GRXDPol == 1 btfss GRXD ;data polarity is inverted for RS232 polarity else btfsc GRXD endif bsf STATUS , C ;Data into Carry rrf Temp ;and then into Temp, LSB first decfsz Counter goto InitGPSByteLoop ;loop is 8 + 2 * HalfBitDelay long call GPSHalfBitDelay ;Parity bit call GPSHalfBitDelay ;We now have the entire stop bit left to use movf Temp , W ; this data, approx 200 clocks return ;Exit with received byte in W and Temp ;----------------------------------------- GPSHalfBitDelay ;4800 = 100us (2 * 100 + 8 overhead = 208) use d'19' movlw 8 ;9600 = 48us use d'8' and 3 nops at end movwf DelCount HalfGPSBaudDelLoop nop nop decfsz DelCount goto HalfGPSBaudDelLoop nop nop nop return ;--------------------------- GetEE ;different from ;F84 EE registers all in bank 1 now bsf STATUS,RP0 ;ram page 1 movwf EEADR bsf EECON1 , RD movf EEDATA , W bcf STATUS , RP0 ;ram page 0 return ;------------------------- StoreEE ;Enter with W = EE data, Whi = EE address bsf STATUS, RP0 movwf EEDATA bcf STATUS, RP0 movf Whi, W bsf STATUS, RP0 movwf EEADR bsf STATUS , RP0 ;All EE registers in Bank 1 bsf EECON1 , WREN ;Enable EEprom writing movlw 0x55 movwf EECON2 movlw 0xAA movwf EECON2 bsf EECON1 , WR bcf STATUS, RP0 ;PIR1 register is in bank 0 EEwaitW btfss PIR1 , EEIF goto EEwaitW bcf PIR1 , EEIF ;has to be cleared manually bsf STATUS, RP0 bcf EECON1 , WR bcf STATUS , RP0 return ;------------------------- CrLf ;Uses less space than storing in string movlw 0x0D call Send232 movlw 0x0A call Send232 return ;-------------------------- SendBackTime ;Send date and time back as decimal on 4800 baud link movf Hours, W movwf A0 clrf A1 clrf A2 call BinToBCD movf BCDLo, w call DebugSend movf Minutes, W movwf A0 clrf A1 clrf A2 call BinToBCD movf BCDLo, w call DebugSend movf Seconds, W movwf A0 clrf A1 clrf A2 call BinToBCD movf BCDLo, w call DebugSend ; movf GPSStatusData, W ; call DebugSend movlw "," call Send232 movlw "A" call Send232 movlw "," call Send232 movlw " " call Send232 movlw "," call Send232 movlw " " call Send232 movlw "," call Send232 movlw " " call Send232 movlw "," call Send232 movlw " " call Send232 movlw "," call Send232 movlw " " call Send232 movlw "," call Send232 movlw " " call Send232 movlw "," call Send232 movf Day, W movwf A0 clrf A1 clrf A2 call BinToBCD movf BCDLo, w call DebugSend movf Month, W movwf A0 clrf A1 clrf A2 call BinToBCD movf BCDLo, w call DebugSend clrf A2 movf YearHi, W movwf A1 movf Year, W movwf A0 call BinToBCD movf BCDLo, w ;Full year call DebugSend ;Packed BCD will appear as decimal movlw "," call Send232 movlw " " call Send232 movlw "," call Send232 movlw " " call Send232 movlw "*" call Send232 return ;---------------------------------- DebugSend ;Send byte as hex on RS232 link movwf SendChar swapf SendChar, w andlw 0x0F movwf Temp2 sublw 9 ;W = 9 - W if -ve (C=0) letter A - F movlw 0 btfss STATUS, C movlw 7 addwf Temp2, w addlw 0x30 call Send232 movf SendChar, w andlw 0x0F movwf Temp2 sublw 9 movlw 0 btfss STATUS, C movlw 7 addwf Temp2, w addlw 0x30 call Send232 return ;-------------------------------- Divide32x8 ;[32bit] A / [8 bit] B = [32 bit] Quotient, movlw d'32' ; remainder in [8 bit] in R0 movwf Counter clrf R0 Divide16Loop bcf STATUS, C rlf A0 rlf A1 rlf A2 rlf A3 rlf R0 movf B0, W subwf R0, W btfsc STATUS, C movwf R0 rlf Q0 rlf Q1 rlf Q2 rlf Q3 decfsz Counter goto Divide16Loop return ;---------------------------------------------------- Multiply32 ;32 bit * 32 bit multiplication, more efficient method Clrf Acc1 ;Input A0/1/2/3 and B0/1/2/3, output Acc1/2/3/4/5/6/7/8 clrf Acc2 ;A destroyed, B kept clrf Acc3 clrf Acc4 clrf Acc5 clrf Acc6 clrf Acc7 clrf Acc8 movlw d'32' ;A and B 24 bit movwf Counter MultLoop bcf STATUS, C rrf A3 rrf A2 ;Working bit into carry rrf A1 rrf A0 ;Effectivley adds shifted version of B btfss STATUS, C ; into Acc depending on working bit of A goto NoMult ; by shifting the accumulator instead of B itself movf B0, W ;get shifted B0 value addwf Acc5 ; and add into accumulator if 1 in btfss STATUS, C ; appropriate bit in Avalue goto MulAdd1 incf Acc6 btfss STATUS, Z goto MulAdd1 incf Acc7 btfss STATUS, Z goto MulAdd1 movlw 1 ;Need more complex addition routine for last Acc as addwf Acc8 ; final Carry has to be preserved for the shift MulAdd1 movf B1, W addwf Acc6 btfss STATUS, C goto MulAdd2 incf Acc7 btfss STATUS, Z goto MulAdd2 movlw 1 addwf Acc8 MulAdd2 movf B2, W addwf Acc7 btfss STATUS, C goto MulAdd3 movlw 1 addwf Acc8 MulAdd3 movf B3, W addwf Acc8 NoMult ;Need to rotate in carry from final addition. C is rrf Acc8 ; already zero if we've jumped in here. rrf Acc7 rrf Acc6 rrf Acc5 rrf Acc4 rrf Acc3 rrf Acc2 rrf Acc1 decfsz Counter goto MultLoop return ;Acc8/7/6/5/4/3/2/1 = A * B ;------------------------------------------------------------------ BinToBCD ;Takes in A2/A1/A0, calculates packed BCD equivalent clrf BCDVi ;Result in BCDVi/Hi/Me/Lo clrf BCDHi ;Also uses BCDCounter, BCDTemp Destroys A clrf BCDMe clrf BCDLo ;Approx 1235 clocks movlw d'24' movwf BCDCounter BcdLoop rlf A0 rlf A1 rlf A2 rlf BCDLo rlf BCDMe rlf BCDHi rlf BCDVi decfsz BCDCounter ;Need a final shift only, so loop count here goto BCDgo goto BCDone ;.......... BCDgo movf BCDVi , W addlw 3 movwf BCDTemp btfsc BCDTemp , 3 movwf BCDVi ;If BCDVi >= 5, add 3 and store back movf BCDVi , W addlw 0x30 movwf BCDTemp btfsc BCDTemp , 7 movwf BCDVi ;Adjust BCDVi if > 80 movf BCDHi , W addlw 3 movwf BCDTemp btfsc BCDTemp , 3 movwf BCDHi movf BCDHi , W addlw 0x30 movwf BCDTemp btfsc BCDTemp , 7 movwf BCDHi movf BCDMe , W ;Repeating for middle then low digits addlw 3 movwf BCDTemp btfsc BCDTemp , 3 movwf BCDMe movf BCDMe , W addlw 0x30 movwf BCDTemp btfsc BCDTemp , 7 movwf BCDMe movf BCDLo , W ; addlw 3 movwf BCDTemp btfsc BCDTemp , 3 movwf BCDLo movf BCDLo , W addlw 0x30 movwf BCDTemp btfsc BCDTemp , 7 movwf BCDLo goto BcdLoop ;........... BCDone return ;============================================================= cblock 0x20 Temp Temp2 Whi DelCount DelCount2 Counter Flags RxChar LastRxChar Seconds Minutes Hours Day Month Year YearHi MinLatLo MinLatHi DegLat MinLongLo MinLongHi DegLong PosCR SendChar GPSStatusData BCDLo BCDMe BCDHi BCDVi BCDTemp BCDCounter A0 ;A, B , Q , R used in maths routines A1 A2 A3 B0 B1 B2 B3 Acc0 Acc1 Acc2 Acc3 Acc4 Acc5 Acc6 Acc7 Acc8 Q0 Q1 Q2 Q3 R0 R1 P0 endc ;:::::::::::::::::::::::::::::::::::::::::::::::::::::::: end