;registers used ; R0 = byte read from serial port ; R1 = GPS output field number (1-15) ; R2 = GPS field character number ; R3 = timer routine during LCD initialization, minute timer ; R4 = timer routine during LCD initialization, minute timer ; R5 = timer routine during LCD initialization, minute timer ; R6 = character read from serial port ; R7 = temp storage for character while writing to LCD ;register addresses not already defined MCON EQU 0C6h TA EQU 0C7h ;reset interrupt service routine ORG 0000h SJMP start ;GPS interrupt service routine ORG 0023h JMP GPS ;power fail warning interrupt service routine (just wait to die) ORG 002Bh SJMP $ RETI ;-------------------------------------------------------------------------------- ;main routine ORG 0030h start: ;Set memory partition MOV TA, #0AAh ;Timed... MOV TA, #055h ; ...Access ORL MCON, #02h ;Set PAA MOV MCON, #020h ;Set partition to 4KB MOV TA, #0AAh ;Timed... MOV TA, #055h ; ...Access ANL MCON, #0FDh ;Clear PAA ;Move data pointer to first unused RAM location MOV DPTR, #1000h ;Start of data memory iram: MOVX A,@DPTR ;Read what's at the current data memory location CJNE A,#0B7H,used ;If it's not the predefined value B7H, it's used SJMP unused ;If we get here, the location is unused and we're done used: INC DPTR ;If we get here, current position's used, go to next SJMP iram unused: ;Turn on interrupts ORL PCON, #08h ;Enable Power-fail warning SETB PS ;Set serial port interrupt to high priority SETB ES ;Enable serial port interrupt CLR PT0 ;Set external interrupt 0 to low priority CLR EX0 ;Disable external interrupt 0 (pin 3.2) SETB EA ;Turn on interrupts ;Danger, may want to turn on interrupts after ;initialize LCD ;Set up serial port MOV SCON, #01010000b ;Select mode 1 (async, 8N1, baud from timer 1) MOV TH1, #245 ;Baud rate (245 -> 2400 baud) ANL PCON, #07fh ;Baud rate multiplier (set to 1) MOV TMOD, #00100000b ;Set timer 1 for 8-bit auto-reload mode MOV TCON, #01000000b ;Enable timer 1 CLR RI ;Clear serial receive flag CLR TI ;Clear serial transmit flag ;Initialize radiation pulse counter MOV 2BH,#48 ;Count stored in 5 bytes, ones place MOV 2CH,#48 ;tens place MOV 2DH,#48 ;hundreds place MOV 2EH,#48 ;thousands place MOV 2FH,#48 ;ten thousands place ;LCD initialization MOV A,20 ;wait > 15ms ACALL waitms MOV A,#00011000b ACALL wlcd MOV A,5 ;Wait > 4.1ms ACALL waitms MOV A,#00011000b ACALL wlcd MOV A,100 ;Wait > 100us ACALL waitus MOV A,#00011000b ACALL wlcd MOV A,5 ;Wait > 4.1ms ACALL waitms MOV A,#00010000b ;Set 4 bit operation, interface still 8 bit ACALL wlcd MOV A,#00010000b ;Interface 4 bit, set number of lines and font ACALL wlcd MOV A,#01000000b ACALL wlcd MOV A,#00000000b ;Turn display off ACALL wlcd MOV A,#01000000b ACALL wlcd MOV A,#00000000b ;Turn display on ACALL wlcd MOV A,#01100000b ACALL wlcd MOV A,#00000000b ;Clear display ACALL wlcd MOV A,#00001000b ACALL wlcd MOV A,5 ACALL waitms MOV A,#00000000b ;Set entry mode to increment cursor w/o shift ACALL wlcd MOV A,#00110000b ACALL wlcd MOV R1,#1 ;First field MOV R2,#1 ;First character MOV A,#01000000b ;Set LCD address to character position 0 ACALL wlcd MOV A,#00000000b ACALL wlcd ;-------------------------------------------------------------------------------- ;Geiger counter routine ;This routine loops for up to slightly more than ;1 minute counting radiation pulses. If there is ;no GPS receiver the radiation count will be written ;out at this interval. If there is a GPS receiver ;it will cause data to be written every minute restarting ;the following loops before they cause the output. ;This way, data is output about every minute whether ;or not the GPS receiver is attached. Geiger: MOV R3,#200 ;this set of loops gives a slightly > 1 min. integration gloop1: MOV R4,#255 gloop2: MOV R5,#255 gloop3: JNB P3.2,nopul ;check for a pulse ACALL pulse nopul: DJNZ R5,gloop3 DJNZ R4,gloop2 DJNZ R3,gloop1 ACALL wgeig ;if no GPS, write geiger output here MOV R0,#13 ACALL save SJMP Geiger ;Go back and integrate for another minute pulse: INC 2BH ;Increment the pulse counter MOV A,2BH CJNE A,#58,nocarry MOV 2BH,#48 INC 2CH MOV A,2CH CJNE A,#58,nocarry MOV 2CH,#48 INC 2DH MOV A,2DH CJNE A,#58,nocarry MOV 2DH,#48 INC 2EH MOV A,2EH CJNE A,#58,nocarry MOV 2EH,#48 INC 2FH nocarry: JB P3.2,$ ;Wait for geiger-mueller dead time to end RET ;-------------------------------------------------------------------------------- ;LCD update routine LCD: MOV R7,A RR A ANL A,#01111000b ORL A,#00000001b ACALL wlcd MOV A,R7 RL A RL A RL A ANL A,#01111000b ORL A,#00000001b ACALL wlcd MOV A,R7 RET ;-------------------------------------------------------------------------------- ;GPS/data storage routine GPS: MOV R0,SBUF JB RI,good CLR RI CLR TI RETI good: CLR RI CLR TI CJNE R0,#36,chkcom ;If the character is a $, at start so reset field MOV R1,#1 ACALL wgeig ;Output the radiation count and zero counters RETI chkcom: CJNE R0,#44,field1 ;If the character is a comma, we have a new field ACALL comma RETI field1: CJNE R1,#1,field2 ;field 1 is the unused key phrase RETI field2: CJNE R1,#2,field3 ;field 2 is the time ACALL save ;all time bytes get stored hhmm: CJNE R2,#3,mmss ;put a colon between the hour and minute... MOV A,#58 ACALL LCD mmss: CJNE R2,#5,time ;...or put a colon between the minute and second MOV A,#58 ACALL LCD time: MOV A,R0 ;...then/or display the number ACALL LCD INC R2 ;another character done RETI field3: CJNE R1,#3,field4 ;field 3 is the latitude ACALL save ;all latitude bytes get stored CJNE R2,#3,lat ;write degree symbol if the right spot... MOV A,#0DFH ACALL LCD lat: MOV A,R0 ;...then/or display the number... ACALL LCD CJNE R2,#9,didlat ;...plus the minute tick if the right spot MOV A,#39 ACALL LCD didlat: INC R2 ;another character done RETI field4: CJNE R1,#4,field5 ;field 4 is always "N" MOV A,#78 ACALL LCD RETI field5: CJNE R1,#5,field6 ;field 5 is the longitude ACALL save ;all longitude bytes get stored CJNE R2,#4,lon ;write degree symbol if the right spot... MOV A,#0DFH ACALL LCD lon: MOV A,R0 ;...then/or display the number... ACALL LCD CJNE R2,#10,didlon ;...plus the minute tick if the right spot MOV A,#39 ACALL LCD didlon: INC R2 ;another character done RETI field6: CJNE R1,#6,field7 ;field 6 is always "W" MOV A,#87 ACALL LCD RETI field7: CJNE R1,#7,field8 ;field 7 is unused quality number RETI field8: CJNE R1,#8,field9 ;field 8 is the number of satellites ACALL save ;all characters of this field get saved MOV A,R0 ;all characters get written to the LCD too ACALL LCD CJNE R2,#2,didsat ;after second number, write units MOV A,#32 ACALL LCD MOV A,#115 ACALL LCD MOV A,#97 ACALL LCD MOV A,#116 ACALL LCD MOV A,#115 ACALL LCD didsat: INC R2 ;another character done RETI field9: CJNE R1,#9,fielda ;field 9 is the unused hdop RETI fielda: CJNE R1,#10,fieldb ;field 10 is the altitude ACALL save ;all characters of this field get saved ; CJNE R0,#46,chkalt ;we won't write the decimal or digits after it ; MOV A,#109 ;write units ; ACALL LCD ; MOV R2,#18 ;set flag so wont do next character ; RETI ;chkalt: CJNE R2,#18,doalt ;if decimal number, just return ; RETI doalt: MOV A,R0 ;write the number CALL LCD RETI fieldb: CJNE R1,#11,fieldc ;field 11 is the altitude units (always "m") RETI fieldc: CJNE R1,#12,fieldd ;field 12 is the unused geoid altitude RETI fieldd: CJNE R1,#13,fielde ;field 13 is the unused geoid units RETI fielde: CJNE R1,#14,fieldf ;field 14 is the differential age RETI fieldf: CJNE R0,#13,back ;field 15 contains the , output it to memory CALL save RETI back: RETI ;-------------------------------------------------------------------------------- ;Increments the field count and cursor ;position when we get a comma from the GPS comma: INC R1 ;Number of next field MOV R2,#1 ;Set pointer to point at first char of field CJNE R1,#1,char2 ;$GPGGA, unused RET char2: CJNE R1,#2,char3 ;time MOV A,#01000000b ACALL wlcd MOV A,#00000000b ACALL wlcd RET char3: CJNE R1,#3,char4 ;latitude MOV A,#01100000b ACALL wlcd MOV A,#00001000b ACALL wlcd RET char4: CJNE R1,#4,char5 ;N or S MOV A,#01100000b ACALL wlcd MOV A,#01101000b ACALL wlcd RET char5: CJNE R1,#5,char6 ;longitude MOV A,#01001000b ACALL wlcd MOV A,#00000000b ACALL wlcd RET char6: CJNE R1,#6,char7 ;E or W MOV A,#01001000b ACALL wlcd MOV A,#01101000b ACALL wlcd RET char7: CJNE R1,#7,char8 ;quality, unused RET char8: CJNE R1,#8,char9 ;number of satellites MOV A,#01000000b ACALL wlcd MOV A,#01001000b ACALL wlcd RET char9: CJNE R1,#9,chara ;HDOP, unused RET chara: CJNE R1,#10,charb ;altitude MOV A,#01101000b ACALL wlcd MOV A,#00000000b ACALL wlcd ; MOV A,#32 ;1st, clear the field ; ACALL LCD ; ACALL LCD ; ACALL LCD ; ACALL LCD ; ACALL LCD ; MOV A,#01101000b ;move back to the start of the field ; ACALL wlcd ; MOV A,#00000000b ; ACALL wlcd RET charb: CJNE R1,#11,charc ;altitude units ; MOV A,#01101000b ; ACALL wlcd ; MOV A,#00100000b ; ACALL wlcd RET charc: CJNE R1,#12,chard ;geoid height, unused RET chard: CJNE R1,#13,chare ;geoid units, unused RET chare: CJNE R1,#14,charf ;diff GPS age, unused RET charf: CJNE R1,#15,badf RET badf: RET ;-------------------------------------------------------------------------------- ;Writes the radiation count wgeig: MOV A,#01101000b ;set the location on the LCD ACALL wlcd MOV A,#00110000b ACALL wlcd MOV A,2FH ;ten thousands place ACALL LCD MOV R0,2FH ACALL save MOV A,2EH ;thousands place ACALL LCD MOV R0,2EH ACALL save MOV A,2DH ;hundreds place ACALL LCD MOV R0,2DH ACALL save MOV A,2CH ;tens place ACALL LCD MOV R0,2CH ACALL save MOV A,2BH ;ones place ACALL LCD MOV R0,2BH ACALL save MOV A,#0E4H ;mu ACALL LCD MOV A,#82 ;R ACALL LCD MOV A,#47 ;/ ACALL LCD MOV A,#104 ;h ACALL LCD MOV A,#114 ;r ACALL LCD MOV 2BH,#48 ;reset radiation pulse counter MOV 2CH,#48 MOV 2DH,#48 MOV 2EH,#48 MOV 2FH,#48 MOV R3,#200 ;reset integration timeout loop counters MOV R4,#255 MOV R5,#255 RET ;-------------------------------------------------------------------------------- ;Save a byte to memory save: MOV A,R0 MOVX @DPTR,A INC DPTR RET ;-------------------------------------------------------------------------------- ;Millisecond delay routine, waits ACC ms waitms: DEC A ;Note, if A=1, may fail MOV R3,A loopm1: MOV R4,#2 ;2*208 loops approx 1ms loopm2: MOV R5,#208 DJNZ R5,$ DJNZ R4,loopm2 DJNZ R3,loopm1 ;ACC=number of milliseconds to wait RET ;-------------------------------------------------------------------------------- ;Microsecond delay routine, waits ACC us waitus: DEC A ;Note, if A=1, may fail DJNZ ACC,$ ;each loop is 2.4 us (so will get 2.4x time requested) RET ;-------------------------------------------------------------------------------- ;Write byte to LCD wlcd: MOV P0,A ;Initial setup SETB P0.2 ;Take E high CLR P0.2 ;Take E low MOV A,120 ;Wait 120us ACALL waitus RET ;-------------------------------------------------------------------------------- END