This is post #4 in a series covering the hardware and software design for my work-in-progress GPS-guided rocket recovery project. The main index to the series of posts is here, and an introduction to the project (a PowerPoint presentation) is here.
This post covers main.c, which has just one function in it, main(), the program that runs on power-up or reset.
INITIALIZATION
main() starts by calling SetupHardware() in hardware.c, which initializes the PIC internal registers. Many of the values used to initialize things are computed from macros based on tweaks.h. OSCCON is set to control the CPU clock frequency, INTCON and PIE are set to enable the global, peripheral, UART, and Timer1 interrupts. SetupHardware() has comments on how Timer1 is used to generate the servo control pulses, which I won’t repeat here, but see my discussion of this in my posting about the ISR.
Next 16-bit timers Timer1 and Timer3 are initialized to run at a rate of 250 kHz (1/32 of the 8 MHz CPU clock) and started.
Then, the I/O ports are setup (direction and weak pullups on Port B), CVRef is setup to produce a reference voltage and an analog comparator is configured for level-conversion of the incoming received GPS data (see the hardware description for details of that) and an ADC is setup to read AN1 for the pressure sensor.
Finally Timer2 (TMR2) and CCP2 are setup to produce the 47 kHz square wave modulation for the camera control IR pulses (again, see the hardware description). Finally, the magnetic compass is initialized, if the compilation switch COMPASS is defined (it isn’t, now).
main() then turns on all 3 LEDs (to indicate that the system is powered up and running), sets the servo to the middle position, initializes the leaky integrator values used to smooth out pressure sensor readings, calls InitGPS() to send GPS commands to set the desired baud rate and mode (38,400 bps, $GPRMC and $GPGGA messages only), and initializes the state machine.
The last thing main() does before entering the main (endless) software loop is:
nextRTC8 = RTC8 + LOOP_PERIOD;
This deserves some explanation, as I use this technique a lot (mostly in stateMachine.c – see next post).
Global 32-bit variable RTC holds a count of real-time-clock (RTC) interrupts since power-up. Macros RTC24, RTC16, and RTC8 (all in globals.h) return the low-order 24, 16, and 8 bits of this count (respectively – note that the C18 compiler supports 24 bit wide variables).
This statement assigns the modulo-256 (8 bit) sum of the lower 8 bits of this count (RTC8) and a constant called LOOP_PERIOD to an 8-bit variable called nextRTC8.
LOOP_PERIOD is defined in tweaks.h as the number of RTC ticks in 40 milliseconds (25 Hz). So nextRTC8 represents the future value RTC8 will have 40 milliseconds from now.
By comparing nextRTC8 to RTC8, we can easily determine whether the 40 milliseconds have expired. Macros YET8(), YET16(), YET24(), YET32() and NOTYET8(), NOTYET16(), NOTYET24() and NOYET32() (all in globals.h) implement this comparison and allow for the possibility that by the time the comparison is made (between nextRTC8 and RTC8), RTC8 might have already moved on to a later value (if the check isn’t performed between each tick of the RTC interrupt).
So, when later in main() we say:
while (NOTYET8(nextRTC8))
we will continue in the while() loop as long as the current time has not yet reached future time “nextRTC8” (40 milliseconds from the time we set the value of nextRTC8).
Of course, nextRTC8 and RTC8 are only 8 bits wide, so the time represented in nextRTC8 had better not be more than 127 RTC ticks in the future (127 mS). If you need to deal with longer time periods than that, you’ll have to use one of the wider versions – RTC16, RTC24, or RTC32.
MAIN LOOP
The main loop of the program starts with while(1) and runs once every 40 milliseconds (25 Hz). All system functions are driven by this loop, except what the interrupt service routine (ISR) does.
A 32-bit variable CycleCount is incremented each time through.

Graph from logged pressure altitude & GPS data. GPS altitude is useless – data is heavily damped, resulting in a lag of 12 seconds or so. But the GPS position data is not too bad.
GPS
Then CheckForNewGPSFix() is called (from nmeaGps.c). Any incoming data from the GPS has been received by the ISR and placed in a small text buffer, NMEAbuffer[]. CheckForNewGPSFix() looks at the text buffer to see if a complete message has been received from the GPS. If so, it parses the message. ($GPGGA or $GPRMC; these are the only two messages that are handled.) Continue reading →