' File... HAPB_PCS.BSP ' Author... Earl Foster ' Date... 04052006 ' {$STAMP BS2px} ' {$PBASIC 2.5} ' 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. ' --- 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 SPR PIN 4 ' Second Power Relay ' ---Constants Kal CON 39915 ' --- GPS Contants GPSpin CON 11 ' GPS serial input N4800 CON 17197 ' GPS baud rate 17197 CST CON 7 ' 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 ' --- 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 HIGH SPR Snap = 0 UpDown = 0 ' --- Initialization Setup: GOSUB Seeking_Satellites GOSUB CheckForReset ' Where does wrdAddr start? DEBUG CLS ' ---- Main Program Main: 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 > 3 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 wrdAddr = 0 FREQOUT Speaker, 3000, 1000, 1002 DEBUG "EEPROM has been reset",CR LOW MemFull ELSE IF IN2 = 0 THEN x = 0 DO x = x + 1 LOOP UNTIL (IN2=1 OR x > 1000) ENDIF IF x >= 1000 THEN FREQOUT Speaker, 3000, 1200,1204 GOSUB Display_Captured_Data DEBUG CLS ENDIF ENDIF ENDIF SERIN GPSpin, N4800, 3000, No_GPS, [WAIT("GPGGA,"), SPSTR 82] ' Setup link to GPS and process after read ' Showing captured data will be replaced with storing captured data procedure 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 ' Show Latitude coordinates in degrees and decimal minutes DEBUG "Latitude: ", DEC2 Degrees,DegSym, " ", DEC2 Minutes,".", DEC4 DMinutes, MinSym, CR GOSUB Parse_GPS_Long ' Extract Long data from Scratchpad RAM ' Show Longitude coordinates in degrees and decimal minutes DEBUG "Longitude: ", DEC2 Degrees,DegSym, " ", DEC2 Minutes, ".", DEC4 DMinutes, MinSym, ClrRt, CR GOSUB Get_Internal_Capsule_Temp GOSUB Get_External_Temp DEBUG ? wrdAddr work = 4094 ' End of showing captured data. I2COUT SDA, $A0, work.BYTE1\work.BYTE0, [wrdAddr.BYTE0, wrdAddr.BYTE1] ' Record last good record IF Snap <> 36 THEN GOSUB TakePicture ENDIF TOGGLE Program_Running ' Pulse for 2nd STAMP PAUSE 5000 ' Remove when Altitude is used GOTO Main ' Start over again END ' ---- 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 or been reset by pressing the ' counter reset button for greater then 3 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] wrdAddr = 0 ELSE work = 0 wrdAddr = 4094 I2CIN SDA, $A1, wrdAddr.BYTE1\wrdAddr.BYTE0, [work.BYTE0, work.BYTE1] wrdAddr = work 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_External_Temp: ' AD592 temperature sensor code RCTIME 10, 0, rct ' Time for the volts to rise to 1.3volts LOW 10 ' Discharge capacitor x = (Kal/rct*10 + (Kal//rct*10/rct)) - 273 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 ' Make sure that the last 2 WORDs locations are not ' over written. ' This procedure is used for WORD size variables Write_Word_Data: IF wrdAddr =< 4080 THEN I2COUT SDA, $A0, wrdAddr.BYTE1\wrdAddr.BYTE0, [x.BYTE0, x.BYTE1] wrdAddr = wrdAddr + 2 ELSE DEBUG "Memory Full", CR IF IN6 <> 1 THEN HIGH MemFull ENDIF ENDIF RETURN ' All parsed information will be stored on external EEPROM ' Make sure that the last 2 WORDs locations are not ' over written. ' This procedure is used for BTYE size variables Write_Byte_Data: IF wrdAddr =< 4080 THEN I2COUT SDA, $A0, wrdAddr.BYTE1\wrdAddr.BYTE0, [x] wrdAddr = wrdAddr + 1 ELSE DEBUG "Memory Full", CR IF IN6 <> 1 THEN HIGH MemFull ENDIF ENDIF RETURN ' This procedure can only be accessed through a ' slow double click of the Counter Reset\Display button. ' Once activiated, the program will read the wrdAddr varaible ' and reset the memory location to "0". The information ' will be displayed in the debug window and the program will ' stop until the CRDR is pressed again. Display_Captured_Data: work = wrdAddr wrdAddr = $0 DEBUG CLS DEBUG ? work DO GOSUB Read_Word_Data Altitude = x GOSUB Read_Byte_Data UTC_HR = x GOSUB Read_Byte_Data UTC_MN = x GOSUB Read_Byte_Data UTC_SC = x GOSUB Read_Byte_Data Degrees = x GOSUB Read_Byte_Data Minutes = x GOSUB Read_Word_Data DMinutes = x DEBUG DEC5 Altitude */ $0348, ",", ' Show Altitude DEC2 UTC_HR + CST, ":", DEC2 UTC_MN, ":", DEC2 UTC_SC, ",", ' Show Time corrected for Garland, TX ' Show Latitude coordinates in degrees and decimal minutes DEC2 Degrees, " ", DEC2 Minutes,".", DEC4 DMinutes, "N," ' Show Longitude coordinates in degrees and decimal minutes GOSUB Read_Byte_Data Degrees = x GOSUB Read_Byte_Data Minutes = x GOSUB Read_Word_Data DMinutes = x DEBUG DEC2 Degrees, " ", DEC2 Minutes, ".", DEC4 DMinutes, "W," GOSUB Read_Word_Data Temperature = x / 2 DEBUG DEC3 Temperature, DegSym, "C," GOSUB Read_Word_Data Temperature = x DEBUG DEC3 Temperature, DegSym, "C," DEBUG ? wrdAddr LOOP UNTIL wrdAddr = work OR wrdAddr = 4080 DO LOOP UNTIL (IN2=0) ' Loop here until button is pressed DEBUG CLS ' Clear the screen RETURN Read_Word_Data: IF wrdAddr < 4092 THEN I2CIN SDA, $A1, wrdAddr.BYTE1\wrdAddr.BYTE0, [x.BYTE0, x.BYTE1] wrdAddr = wrdAddr + 2 ENDIF RETURN Read_Byte_Data: IF wrdAddr < 4092 THEN I2CIN SDA, $A1, wrdAddr.BYTE1\wrdAddr.BYTE0, [x] wrdAddr = wrdAddr + 1 ENDIF RETURN ' These procedures will take a picture every 2000 meters until 26000 meters ' is reached. It will then take a picture every program cycle until 36 pictures ' have been taken. After 36 pictures have been taken the procedure will be bypassed ' This is due to the film camera that is used in this project. ' If a digital camera is used then the limit and frequency of pictures ' can be increased for the quality of the jpg image and size of memory used. TakePicture: IF (Altitude/1000) >= updown THEN SELECT Altitude CASE 200 TO 1000 IF snap < 3 THEN GOSUB Snapshot ENDIF CASE 2000 TO 26000 IF Altitude/1000 > updown + 1 AND snap < 17 THEN GOSUB Snapshot ENDIF CASE > 26000 GOSUB Snapshot ENDSELECT ELSEIF (Altitude/1000) < updown AND snap <> 36 THEN GOSUB Snapshot ENDIF RETURN SnapShot: FOR counter = 1 TO 60 ' Rotate Photo Arm Counter Clockwise PULSOUT 12, 1500 ' to take a picture PAUSE 10 NEXT PAUSE 300 ' Pause 1/4 of a second for focusing FOR counter = 1 TO 60 ' Recenter Photo Arm Clockwise PULSOUT 12, 2150 PAUSE 10 NEXT snap = snap + 1 updown = (Altitude/1000) RETURN