; ----------------------------------------------------------------------------- ; Title: GPS Real Time Clock using a GPS NEO-6M module. ; ; Author: Rob Jansen, Copyright (c) 2021..2021 all rights reserved. ; ; Description: Shows the GPS time and GPS date on an SSD1306 with IIC interface. ; ; Sources: ; include 16f1825 ; This program uses the internal oscillator at 1 MHz. pragma target clock 1_000_000 ; oscillator frequency pragma target OSC INTOSC_NOCLKOUT ; Internal Clock pragma target PLLEN DISABLED ; PLL off pragma target WDT DISABLED ; No Watchdog pragma target PWRTE ENABLED ; Power up timer enabled pragma target BROWNOUT DISABLED ; No brownout reset pragma target FCMEN DISABLED ; No clock monitoring pragma target IESO DISABLED ; int/ext osc. switch pragma target LVP ENABLED ; Low voltage programming pragma target MCLR EXTERNAL ; Reset external ; Set the internal clock frequency to 1 MHz. OSCCON_IRCF = 0b1011 ; Set 1 MHz OSCCON_SCS = 0b00 ; Clock determined by OSCCON_IRCF OSCCON_SPLLEN = FALSE ; Software PLL off ; Enable weak pull up for all ports. WPUA = 0b0011_1111 WPUC = 0b0011_1111 OPTION_REG_WPUEN = FALSE enable_digital_io() ; Give the hardware some time to stabilize. _usec_delay(100_000) ; Before including the GPS library, select a serial interface. You can select from ; serial_software, serial_hardware or serial_hw_int_cts. ; Here we use serial_hw_int_cts. alias pin_RX_direction is pin_RX_RC5_direction ; Pin 5 of 14 pin DIP to TX of GPS Module alias pin_TX_direction is pin_TX_RC4_direction ; Pin 6 of 14 pin DIP. Not used. const serial_hw_baudrate = 9600 const SERIAL_XMTBUFSIZE = 5 ; No need for a big transmit buffer const SERIAL_RCVBUFSIZE = 5 ; No need for a big receive buffer include serial_hw_int_cts serial_hw_init ; Now we can include the GPS library. include gps_neo_6m include print ; Define the IIC pins for the SSD1306. alias ssd1306_sck is pin_C0 -- Pin 10 for 14 pin DIP alias ssd1306_sck_direction is pin_C0_direction alias ssd1306_sdo is pin_C1 -- Pin 9 for 14 pin DIP. alias ssd1306_sdo_direction is pin_C1_direction ; Select 100 kHz IIC bus speed because of the 1 MHz clock. const word _i2c_bus_speed = 1 ; Font libraries. include glcd_6x8_font include glcd_font glcd_font_use(FONT_6X8) ; We will use text mode only so no cache required. const SSD1306_TEXT_ONLY = TRUE ; Now we can include SSD1306 GLCD library include glcd_ssd1306 ; Constants. const word TIMER_1_RELOAD = 34_286 ; Gives a 1 second interrupt ; Variables. var byte clock_hours, clock_minutes, clock_seconds var byte clock_date, clock_month, clock_year var byte hours, minutes, seconds var byte date, month, year var bit time_request, date_request, initialize_ssd1306 ; Procedures. ; Print a decimal value always with leading zero's. procedure print_decimal(byte in value) is if (value < 10) then glcd = "0" end if print_byte_dec(glcd, value) end procedure ; Timer 1 interrupt procedure. This interrupt occurs once every second. ; Since we print from the interrupt routine, all printing has to ; be done by this routine including intialization of the ssd1306. procedure timer_1_interrupt() is pragma interrupt if PIR1_TMR1IF then TMR1 = TIMER_1_RELOAD ; Adjust the time, that is add one second. if clock_seconds >= 59 then clock_seconds = 0 if clock_minutes >= 59 then clock_minutes = 0 if clock_hours >= 23 then clock_hours = 0 else clock_hours = clock_hours + 1 ; Synchronize with the GPS date every hour. date_request = TRUE end if else clock_minutes = clock_minutes + 1 ; Synchronize with the GPS clock every minute. time_request = TRUE end if else clock_seconds = clock_seconds + 1 end if ; Update the display, first intialize if not yet done. if initialize_ssd1306 then ; Initialization of the ssd1306 will also initialize the IIC. ssd1306_init() ssd1306_clear_screen() ssd1306_goto(22,0) print_string(glcd,"JAL GPS Clock") ssd1306_goto(18,1) print_string(glcd,"Using a NEO-6M") initialize_ssd1306 = FALSE end if ; Update the time and the date on the display. ssd1306_goto(33,4) print_decimal(clock_hours) glcd = ":" print_decimal(clock_minutes) glcd = ":" print_decimal(clock_seconds) ssd1306_goto(25,6) print_word_dec(glcd,word(clock_year) + 2000) glcd = "-" print_decimal(clock_month) glcd = "-" print_decimal(clock_date) PIR1_TMR1IF = FALSE end if end procedure ; Convert BDC to binary. Copied from rtc_common.jal function bcd2bin(byte in bcd) return byte is var byte t ; intermediate value t = (bcd >> 1) & 0b0111_1000 ; tens * 8 return (bcd - t + (t >> 2)) ; bcd - tens*8 + tens*2 end function ; The main program starts here. ; We use timer 1 to update the SSD1306 every second using the following ; settings: ; -) Fosc/4 divided by 8 = 1.000.000 / 4 / 8 = 31.250 Hz ; -) Timer value 65.536 - 31.250 = 34.286 ; This gives an interrupt time for timer 1 of 1 second. T1CON_TMR1ON = FALSE ; Timer 1 off T1CON_TMR1CS = 0b00 ; Clock soure Fosc/4 T1CON_T1CKPS = 0b11 ; Prescale is 8 TMR1 = TIMER_1_RELOAD ; Gives a 1 second interrupt PIE1_TMR1IE = TRUE ; Enable Timer 1 interrupt PIR1_TMR1IF = FALSE ; Clear Timer 1 interrupt flag INTCON_PEIE = TRUE ; Enable peripheral interrupts INTCON_GIE = TRUE ; Enable global interrupts T1CON_TMR1ON = TRUE ; Start Timer 1 ; Force the request for a new GPS Time and Date. time_request = TRUE date_request = TRUE ; Initialize the SSD1306 once in the interrupt routine. initialize_ssd1306 = TRUE ; Reset the clock and the date. clock_hours = 0 clock_minutes = 0 clock_seconds = 0 clock_year = 0 clock_month = 0 clock_date = 0 forever loop if time_request then if gps_neo_6m_get_time(hours, minutes, seconds) then ; To prevent data corruption when copying data for the interrupt ; routine, temporary stop the timer. T1CON_TMR1ON = FALSE ; Data is BCD, convert to binary, also make the hours UTC + 1, ; wrap when GPS time becomes higher than 23. clock_hours = ((bcd2bin(hours) + 1) % 24) clock_minutes = bcd2bin(minutes) clock_seconds = bcd2bin(seconds) time_request = FALSE T1CON_TMR1ON = TRUE end if end if if date_request then if gps_neo_6m_get_date(date, month, year) then ; To prevent data corruption when copying data for the interrupt ; routine, temporary stop the timer. T1CON_TMR1ON = FALSE ; Data is BCD, convert to binary. clock_date = bcd2bin(date) clock_month = bcd2bin(month) clock_year = bcd2bin(year) date_request = FALSE T1CON_TMR1ON = TRUE end if end if end loop