' File... HAPB_PCSv2.BSP ' Author... Earl Foster ' Date... 04052006 ' Modifed... 01022008 ' {$STAMP BS2px} ' {$PBASIC 2.5} ' HAPB-3 ' Purpose: Obtain high altitude photos of the Earth. HAPB_PCS stands for ' High Altitude Photographic Balloon Primary Computer System. ' $GPGGA, POS_UTC,LAT,LAT_D,LON,LON_D,FIX,SAT,HDOP,ALT,M,GEO_ALT,M,DGPS,DRS,*CC ' POS_UTC - UTC of position. Hours, minutes and seconds. (hhmmss) ' LAT - Latitude (ddmm.ffff) ' LAT_D - Latitude direction. (N = North, S = South) ' LON - Longitude (dddmm.ffff) ' LON_D - Longitude direction (E = East, W = West) ' FIX - GPS quality indication, 0 = fix not available, 1 = Non-differential, ' 2 = Differential, 6 = Estimated ' SAT - Number of Satellites in use, 00 to 12 ' --- HDOP, ALT, GEO_ALT are variable length ' HDOP - Horizontal diluation of precision, 0.5 to 99.9 ' ALT - Antenna height above'below mean sea level, -9999.9 to 99999.9 meters ' M - constant ' GEO_ALT - Geoidal height, -999.9 to 9999.9 meters ' M - constant ' DGPS - Differential GPS data age, null if FIX <> 2 ' DRS - Differential Reference Station ID, null if FIX <> 2 ' *CC - Checksum ' Due to program space limitation only the required parameters are used from the ' GPS string in this program. Variable are reused throughout the program to save ' variable space. ' You will need ReadEEPROM.bsp in order to retrieve the data from memory. ' --- EEPROM I/O Definitions SDA PIN 0 ' I2C serial data line SCL PIN 1 ' I2C serial clock line ' ---Contants Speaker PIN 8 ' Audible alarms Valid_Position PIN 9 ' Satellites acquired indicator Program_Running PIN 5 ' Program Running indicator MemFull PIN 6 ' Visual indicator MaxMemValue CON 4080 ' 272 15-Byte records ' Provides 2.59 hours of data gathering at 34s increments ' ---Constants Kal CON 39915 Camera PIN 12 ' --- GPS Contants GPSpin CON 11 ' GPS serial input N4800 CON 17197 ' GPS baud rate 17197 CST CON 6 ' UTC Central time correction [Change to 6 when on CST] ClrRt CON 11 ' Clear line right of cursor [Remove when combined with HAPB.BSP] DegSym CON 176 ' degrees symbol for report [Remove when combined with HAPB.BSP] MinSym CON 39 ' minutes symbol [Remove when combined with HAPB.BSP] ' --- Variables rct VAR Word ' Reading from RCTIME Temperature VAR Word Buzzer VAR Nib ' --- GPS Variables UTC_HR VAR Byte ' Universal hour field UTC_MN VAR Byte ' Universal minutes field UTC_SC VAR Byte ' Universal seconds field Degrees VAR Byte ' Navigation Degrees Minutes VAR Byte ' Navigation Minutes DMinutes VAR Word ' Navigation Decimal Minutes Altitude VAR Word ' Sea level Height idx VAR Byte ' Index into GPS data in SPRAM Work VAR Word ' Scrap data and numeric conversions fldWidth VAR Nib ' Width of field char VAR Byte ' General purpose byte size variable counter VAR Byte ' Camera servo counter ' --- EEPROM Variables wrdAddr VAR Word ' word address X VAR Word ' General purpose variable ' --- Camera Variables Snap VAR Byte ' Used to determine when to take picture UpDown VAR Byte ' Used to determine ascent/descent of balloon FREQOUT Speaker, 3000, 1000, 1010 Snap = 0 UpDown = 0 ' --- Initialization Setup: GOSUB Seeking_Satellites GOSUB CheckForReset ' Where does wrdAddr start? DEBUG CLS ' ---- Main Program Main: GOSUB CheckCRDRButton IF wrdAddr =< MaxMemValue THEN SERIN GPSpin, N4800, 3000, No_GPS, [WAIT("GPGGA,"), SPSTR 82] ' Setup link to GPS and process after read GOSUB Parse_GPS_Altitude DEBUG HOME, ' Show captured data to screen "Altitude: ", DEC5 Altitude */ $0348, " Feet", ClrRt, CR ' Show Altitude GOSUB Parse_GPS_Time DEBUG "Time: ", DEC2 UTC_HR, ":", DEC2 UTC_MN, ":", DEC2 UTC_SC, CR ' Show Time corrected for Garland, TX GOSUB Parse_GPS_Lat ' Extract Lat data from Scratchpad RAM DEBUG "Latitude: ", DEC2 Degrees,DegSym, " ", DEC2 Minutes,".", DEC4 DMinutes, MinSym, CR GOSUB Parse_GPS_Long ' Extract Long data from Scratchpad RAM DEBUG "Longitude: ", DEC2 Degrees,DegSym, " ", DEC2 Minutes, ".", DEC4 DMinutes, MinSym, ClrRt, CR GOSUB Get_Internal_Capsule_Temp DEBUG ? wrdAddr work = 4094 I2COUT SDA, $A0, work.BYTE1\work.BYTE0, [wrdAddr.BYTE0, wrdAddr.BYTE1] ' Record last good record at 4094 memory slot PAUSE 5 ELSE DEBUG "Memory Full", CR FREQOUT Speaker, 3000, 500, 1000 PAUSE 1000 IF IN6 <> 1 THEN HIGH MemFull ENDIF ENDIF GOSUB TakePicture TOGGLE Program_Running ' Pulse for 2nd STAMP PAUSE 30000 ' Pause 30 sec ' PAUSE 10 ' Used for testing only GOTO Main ' Start over again ' ---- Beginning of Subroutines ' This procedure loops until the a valid position is received ' by the GPRMC "Status" string is obtained. After GPS receives ' an "A" for valid position the indicator light is turned on and ' control is returned to the main program. Seeking_Satellites: DO SERIN GPSpin, N4800, 3000, No_GPS,[WAIT("GPRMC,"), SKIP 7, STR Char\1] ' Get Status DEBUG CLS DEBUG HOME, "Seeking Satellites.",CR PAUSE 100 DEBUG HOME, "Seeking Satellites..", CR PAUSE 100 DEBUG HOME, "Seeking Satellites...", CR PAUSE 100 DEBUG HOME, "Seeking Satellites....", CR PAUSE 100 DEBUG HOME, "Seeking Satellites.....", CR PAUSE 100 LOOP UNTIL Char = "A" OR IN2 = 0 FREQOUT Speaker, 3000, 800, 802 IF Char = "A" THEN HIGH Valid_Position RETURN ' CheckForReset determines if the program has been reset ' properly. If the program restarts due to adnormal operation ' or operator error all of the previous data will be saved. ' This is accomplished by checking a WORD memory slot starting ' at 4092. This memory slot must be equal to 1 or all previous ' data will be over written. This should only occur if the ' program has run for the first time or has been reset by pressing the ' counter reset button for greater then 5 seconds. CheckForReset: 'work = 0 wrdAddr = 4092 I2CIN SDA, $A1, wrdAddr.BYTE1\wrdAddr.BYTE0, [work.BYTE0, work.BYTE1] IF work <> 1 THEN work = 1 I2COUT SDA, $A0, wrdAddr.BYTE1\wrdAddr.BYTE0, [work.BYTE0, work.BYTE1] PAUSE 5 wrdAddr = 0 ELSE work = 0 wrdAddr = 4094 I2CIN SDA, $A1, wrdAddr.BYTE1\wrdAddr.BYTE0, [work.BYTE0, work.BYTE1] PAUSE 5 wrdAddr = work ENDIF RETURN ' Check to see if CRDR button is pressed and if it is pressed for more ' then 5 seconds then reset onboard EEPROM and over write any existing ' data and set wrdAddr to zero. CheckCRDRButton: IF IN2 = 0 THEN ' Is button pressed? x = 0 ' Counter initializations DO PAUSE 1 x = x + 1 ' Increment counter LOOP UNTIL (IN2=1 OR x > 5000) ' Loop here until button is released or > 5 seconds IF x >= 5000 THEN ' If long press then wrdAddr = 4092 work = 0 ' Reset word address DEBUG CLS ' Clear the display I2COUT SDA, $A0, wrdAddr.BYTE1\wrdAddr.BYTE0, [work.BYTE0, work.BYTE1] ' Write 0 PAUSE 5 wrdAddr = 0 FREQOUT Speaker, 3000, 1000, 1002 DEBUG "EEPROM has been reset",CR LOW MemFull ENDIF ENDIF RETURN ' No GPS detected, keep searching until found No_GPS: DEBUG CLS, "No GPS..." PAUSE 2500 GOTO Setup Get_Internal_Capsule_Temp: ' DS1620 temperature sensor code HIGH 13 ' Select the DS1620 SHIFTOUT 15, 14, LSBFIRST, [238] ' Send the "start conversion" command. LOW 13 ' Do the command. HIGH 13 ' Select the DS1620. SHIFTOUT 15, 14, LSBFIRST, [170] ' Send the "get data" command. SHIFTIN 15, 14, LSBPRE, [x] ' Get the raw temperature data (Twice C) LOW 13 ' End the command. GOSUB Write_Word_Data RETURN ' Get the Altitude ' Altitude is a variable length field ' it follows the 8th comma in the GPGGA string ' which has variable length due to HDOP field having a variable field length. ' First Do loop finds the proper index starting point ' for the altitude by knowing that the altitude follows the 8th comma. ' Second Do loop finds the width of the field. Fractional ' meters are not necessary in this project so the loop stops when it finds ' the decimal point. ' Note: fldWidth and Work is used twice to reduce the number of declarations in the program Parse_GPS_Altitude: idx = 0 : fldWidth = 0 DO GET idx, char IF char = "," THEN fldWidth = fldWidth + 1 idx = idx + 1 ELSE idx = idx + 1 ENDIF LOOP UNTIL fldWidth = 8 ' 8th comma found fldWidth = 0 : work = idx ' Reset fldWidth, idx is copied DO GET work, char ' Work is used to continue indexing IF char = "." THEN ' through the string until the period work = work + 1 ' found. As long as there is no period ELSE ' the field width continues to increment fldWidth = fldWidth + 1 work = work + 1 ENDIF LOOP UNTIL char = "." GOSUB String_To_Value Altitude = Work x = Work GOSUB Write_Word_Data RETURN ' Get the Latitude information ' hhmmss,ddmm.ffff,N,dddmm.ffff ' 01234567890123456789012345678 ' numbers above are used for proper index value for fixed fields Parse_GPS_Time: idx = 0 : fldWidth = 2 ' Hours GOSUB String_To_Value Work = Work + CST // 24 UTC_HR = Work x = Work GOSUB Write_Byte_Data idx = 2 : fldWidth = 2 ' Minutes GOSUB String_To_Value UTC_MN = Work x = Work GOSUB Write_Byte_Data idx = 4 : fldWidth = 2 ' Seconds GOSUB String_To_Value UTC_SC = Work x = Work GOSUB Write_Byte_Data RETURN ' Get the latitude ' North and South America are in the Northern Latitude Hemisphere ' therefore it is unnecesary to extract it from the string for ' for this project. Parse_GPS_Lat: idx = 7 : fldWidth = 2 ' Degrees GOSUB String_To_Value Degrees = Work x = Work GOSUB Write_Byte_Data idx = 9 : fldWidth = 2 ' Minutes GOSUB String_To_Value Minutes = Work x = Work GOSUB Write_Byte_Data idx = 12 : fldWidth = 4 ' Decimal Minutes GOSUB String_To_Value DMinutes = Work x = Work GOSUB Write_Word_Data RETURN ' Get the Longitude information ' North and South America are in the Western Longitude Hemisphere ' therefore it is unnecesary to extract it from the string for ' this project Parse_GPS_Long: idx = 19 : fldWidth = 3 ' Degrees GOSUB String_To_Value Degrees = Work x = Work GOSUB Write_Byte_Data idx = 22 : fldWidth = 2 ' Minutes GOSUB String_To_Value Minutes = Work x = Work GOSUB Write_Byte_Data idx = 25 : fldWidth = 4 ' Decimal Minutes GOSUB String_To_Value DMinutes = Work x = Work GOSUB Write_Word_Data RETURN ' Convert string data (nnnn) to numeric value ' idx - location of first digit in data ' fldWidth - width of data field (1 to 5) ' Work - returns numeric value of field String_To_Value: Work = 0 IF (fldWidth = 0) OR (fldWidth > 5) THEN String_To_Value_Done Get_Field_Digit: GET idx, char ' get digit from field Work = Work + (char - "0") ' convert, add into value fldWidth = fldWidth - 1 ' decrement field width IF (fldWidth = 0) THEN String_To_Value_Done Work = Work * 10 ' shift result digits left idx = idx + 1 ' point to next digit GOTO Get_Field_Digit String_To_Value_Done: RETURN ' All parsed information will be stored on external EEPROM ' This procedure is used for WORD size variables ' wrdAddr and x are passed to subroutine Write_Word_Data: I2COUT SDA, $A0, wrdAddr.BYTE1\wrdAddr.BYTE0, [x.BYTE0] PAUSE 5 wrdAddr = wrdAddr + 1 I2COUT SDA, $A0, wrdAddr.BYTE1\wrdAddr.BYTE0, [x.BYTE1] PAUSE 5 wrdAddr = wrdAddr + 1 RETURN ' All parsed information will be stored on external EEPROM ' This procedure is used for BTYE size variables ' wrdAddr and x are passed to subroutine Write_Byte_Data: I2COUT SDA, $A0, wrdAddr.BYTE1\wrdAddr.BYTE0, [x] PAUSE 5 wrdAddr = wrdAddr + 1 RETURN TakePicture: HIGH Camera 'Take picture PAUSE 2000 'Allow camera time to focus and shoot LOW Camera 'Ready for next picture RETURN