My Garage under attack from LEDs.
PHASE II PROGRAM.
After assembling the 16F877 circuit board, I needed a program for it. PIC Assembly Language is the only way I know to program a PIC so far, so off we go...
The NMEA Sentence RMC sent by the GPS unit is of the format:
<1> UTC time of position fix, hhmmss
<2> Status, A = Valid position, V = NAV receiver warning
<3> Latitude, ddmm.mmmm format (leading zeros will be transmitted)
<4> Latitude hemisphere, N or S
<5> Longitude, dddmm.mmmm format (leading zeros will be transmitted)
<6> Longitude hemisphere, E or W
<7> Speed over ground, 000.0 to 999.9 knots (leading zeros will be transmitted)
<8> Course over ground, 000.0 to 359.9 degrees, true (leading zeros will be transmitted)
<9> UTC date of position fix, ddmmyy format
<10> Magnetic variation, 000.0 to 180.0 degrees (leading zeros will be transmitted)
<11> Magnetic variation direction, E or W (westerly variation adds to true course)
Of primary Interest to me are <1> the time and <9> the
date. These are both UTC. Western NY is 4 hours behind UTC during
Daylight Saving Time, and 5 hours behind the rest of the year.
Copied and pasted from Hyperterm, a $GPRMC sentence looks exactly as follows:
The PIC will need to gather the time "135919" and the date "160302" from the string, and can discard the rest. Checking the STATUS to be certain the GPS is receiving correctly isn't a bad idea either. The year is expressed as "02" to represent 2002.
Daylight Saving Time begins in NY at 2 a.m. on the first Sunday of April. Time returns to standard time at 2 a.m. on the last Sunday of October. This created the need to learn a bit, since the data from the GPS unit does NOT indicate what day of the week it is.
Daylight Saving Time START for the project will be on April 7, 2002 at 2 AM local time; 7 AM UTC. The first Daylight Saving Time END for the project will be October 27, 2002 at 2 AM Local Time; 6 AM UTC.
Converting from date to day of week is fairly easy to accomplish using Zeller's Formula. Re-arranged a bit and simplified to work for all dates in years between 2000 and 2099, with years expressed in 2-digit format, it is as follows (in BASIC type format for easy readability):
IF MONTH < 3 THEN MONTH1=MONTH+12 : YEAR=YEAR-1
DAY = ( INT((13*MONTH1+3)/5) + DAY + YEAR + INT(YEAR/4) +1) MOD 7
Sunday is day 0…
This was not a terrible thing to implement on a PIC. Practicality arrived AFTER I had written and tested code to do so: The Zeller code took about 150 bytes of program and about 200 clock cycles to process, including the divide routines.
A table with the day of the first Sunday in April and the last Sunday in October for 100 years only requires 200 bytes to implement, and fit into half that with small creativity: I had the assembler stuff the start date into the upper 3 bits of the byte, since values will only run 1 to 7; the DST end dates fit into the lower 5 bits since they run from 24 to 31. Compression of 2:1 for such a small bit of thinking was impressive enough that further efforts to compress the table of data seemed silly.
A table has the further advantage of being simple to check, compared to a long routine which could contain errors that go unnoticed. I entered in the table and had my Zeller routine check it for me; it checked ok. Then I deleted the Zeller code. I also had a friend double-check the data, just to be certain.
Interrupt-driven routine grabs serial input to a buffer.
process buffer, see if we are on Daylight Saving Time using table.
Update Clock display.
One Pulse Per Second from GPS set to 500 mS and used to run colon in clock.
Non-interrupt program: Twiddle Thumbs. :-)
Turn on a LED on
the circuit board once a second and reset it on the leading edge of the 1 PPS
Useful as a "Heartbeat" to know the CPU is working.
Eventually this will use ADC to
monitor backup battery voltage.
During power failure, as battery voltage sags, use PWM to reduce display duty cycle
To prolong display time.
of the NMEA sentence wouldn't hurt, in case of communication errors.
PAGE 7 VICTORY!
OLDVAN MAIN PAGE