; ============================================================================== ; Title: Sleep Enough Timer. ; ; Author: Rob Jansen, Copyright (c) 2018..2019, all rights reserved. ; ; Revision: ; 2018-12-21 : Initial version. ; 2019-06-01 : Added low voltage detection. ; 2019-01-09 : Disabled comparator and reference voltage to save power. ; ; Description: This device starts a timer of 8 hours after start-up. When ; this time is passed, a LED will blink. The device uses a ; 32 kHz watch crystal for low power battery use. ; When powered up and the supply voltage is above 3.0 Volts, ; the LED will blink 3 times. A test pin signal is available ; on pin 6 to check if the PIC is running correctly. ; The program operates interrupt driven. ; ; Dependencies: - ; ; ------------------------------ Pragmas --------------------------------------- include 12f615 pragma warn all yes pragma opt variable_reduce no ; Use a 32.768 crystal and internal reset. pragma target OSC LP ; Low Power crystal. pragma target PWRTE Enabled pragma target MCLR Internal pragma target WDT Disabled pragma target BROWNOUT Disabled pragma target clock 32_768 ; Clock watch crystal. ; --------------------------------- Pins --------------------------------------- alias led is pin_GP2 ; Pin 5. LED connected to this pin. pin_GP2_direction = Output alias test_pin is pin_GP1 ; Pin 6. Used to see if the PIC is running. pin_GP1_direction = Output alias dummy_pin is pin_GP0 ; Pin 7. Dummy but initialize. pin_GP0_direction = output dummy_pin = LOW ; -------------------------- Constant declarations ----------------------------- ; Timer 1 is used to create a 1 seconds timing signal. const word TIMER1_RELOAD = 65_536 - 32_768 ; This gives a 1 second timeout. const word TIMEOUT = 28_800 ; 28.800 seconds gives 8 hours. ; Value for detecting when the voltage of the battery gets too low. The higher ; the figure, the lower the supply voltage. const word VOLTAGE_LEVEL = 195 ; This equals a battery volrage of 3.0 Volt const bit LED_ON = TRUE const bit LED_OFF = FALSE ; ------------------------- Variable declarations ------------------------------ var word timeout_counter = 0 var bit led_toggle = FALSE ; ------------------------- Functions and Procedures--------------------------- ; This interrupt routine is called once every second and does all the work. procedure timer1_interrupt is pragma interrupt if PIR1_TMR1IF then TMR1 = TIMER1_RELOAD PIR1_TMR1IF = FALSE led_toggle = !led_toggle if (timeout_counter == TIMEOUT) then ; We are done, blink the LED. led = led_toggle else timeout_counter = timeout_counter + 1 ; Toggle the test pin to see if controller is running. test_pin = led_toggle end if end if end procedure ; Test the supply voltage using the ADC. If the voltage is below 3.0 Volt, the ; function will return TRUE. function low_supply_voltage() return bit is var bit voltage_low ; Disable the comparator reference voltages to save power. VRCON_CMVREN = FALSE VRCON_FVREN = FALSE ; We use Frc. All pins are digital_io. ANSEL = 0b0011_0000 ; Right justified, VDD 0,6 Volt reference ADC enabled. ADCON0 = 0b1001_0101 _usec_delay(1_000) ; Start ADC and give it time to do the conversion. ADCON0_GO = TRUE _usec_delay(1_000) ; Get and check ADC value if ((word(ADRESH * 255) + word(ADRESL)) > VOLTAGE_LEVEL) then voltage_low = TRUE else voltage_low = FALSE end if ; Right justified switch channel off 0.6V (reduces power consumption!) ADCON0 = 0b1000_0000 return voltage_low end function ; ========================= Main program starts here =========================== _usec_delay(100_000) ; Stabilize supply voltage. enable_digital_io() led = LED_OFF if low_supply_voltage() then ; Test if the suppply voltage is OK. asm sleep ; Too low, it all ends here. end if ; Initialize Timer 1 to generate a 1 second interrupt. We use the external ; clock of 32.768 without any prescaling. T1CON_TMR1ON = FALSE ; Timer 1 off T1CON_TMR1GE = FALSE ; Disable gate enable. T1CON_T1OSCEN = TRUE ; LP oscillator is enabled for Timer 1. T1CON_NT1SYNC = TRUE ; Do not synchronize external clock input. T1CON_TMR1CS = FALSE ; Since we use a low clock frequency ... CMCON1_T1ACS = TRUE ; ... we will use Fosc. T1CON_T1CKPS = 0b00 ; Prescaler 1:1 so 32.768 Hz clock. TMR1 = TIMER1_RELOAD PIR1_TMR1IF = FALSE ; Clear Timer 1 interrupt flag. PIE1_TMR1IE = TRUE ; Enable Timer 1 interrupt. T1CON_TMR1ON = TRUE ; Start Timer 1. ; Enable all used interrupt, external and - peripheral - timers. INTCON_PEIE = TRUE ; Enable peripheral interrupt. INTCON_GIE = TRUE ; Globale interrupt enabled. ; Blink the led 3 times at start-up and then do nothing anymore. for 3 loop led = LED_ON _usec_delay(1_000_000) led = LED_OFF _usec_delay(1_000_000) end loop forever loop ; All work is done on interrupt basis ... end loop