; ============================================================================== ; Title: Tea Light ; ; Author: Rob Jansen, Copyright (c) 2017..2017, all rights reserved. ; ; Revision: ; 2017-09-30 : Initial version ; ; Compiler: 2.4q6 ; ; ; Description: Simulate a electronic Tea Light (Candle) with a LED. This program ; uses the hardware PWM of the chip. ; ; Sources: For the random generator, see: ; http://en.wikipedia.org/wiki/Linear_feedback_shift_register ; ;=============================================================================== include 12f615 ; target PICmicro ; Use internal clock and internal reset. Pragma target OSC INTOSC_NOCLKOUT ; Internal Clock Pragma target PWRTE Enabled ; Power up timer Pragma target MCLR Internal ; Reset internal Pragma target WDT Disabled ; No watchdog Pragma target IOSCFS F4MHZ ; Set internal oscillator to 4 MHz Pragma target clock 4_000_000 ; oscillator frequency 4 MHz enable_digital_io() ; make all pins digital I/O ; The LED is directly controller by the hardware PWM output so this is always ; pin CCP1 (P1A) which is pin 5. pin_CCP1_direction = output ; Set the port to Output ; Enable weak pull up for all ports since some inputs are not connected WPU = 0b0011_0111 ; Weak pull-up enabled only for all pins OPTION_REG_NGPPU = FALSE ; Enable Weak Pull-Up ; ================== Constant and variable declarations ======================= ; Specify the values for the minimum and maximum brightness of the LED ; and the value to increase or decrease it. The increase and decrease values ; are different as to create a better candle effect. Const Byte MIN_BRIGHT = 50 Const Byte MAX_BRIGHT = 245 Const Byte UP_BRIGHT = 5 ; Increase to MAX_BRIGHT must be < 255 Const Byte DOWN_BRIGHT = 20 ; Decrease from MIN_BRIGHT must be > 0 ; 16 bit shift register used to generate a random bit with initial value ; See http://en.wikipedia.org/wiki/Linear_feedback_shift_register Var Word Random_Shift_Word = 0xACE1 ; Intialize with Seed for Random Generator ; Initial value for the Duty Cycle var byte Duty_Cycle = 128 ; ========================= Functions and Procedures ========================== Function Give_Random_Word Return Word is ; Generate a new random number using a Linear Feedback Shift Register (LFSR). Var Word Value ; Use Fibonacci LSFR x16 + x14 + x13 + x11 + 1 Value = (Random_Shift_Word ^ (Random_Shift_Word >> 2) ^ (Random_Shift_Word >> 3) ^ (Random_Shift_Word >> 5)) & 0x0001 Random_Shift_Word = (Random_Shift_Word >> 1) | (Value << 15) Return Random_Shift_Word End Function ; Give_Random_Word ; ========================= Main program starts here ========================== ; Register PR2 holds the PWM Timer Period using the following formula: ; PWM Period = (PR2 + 1) * 4 * Tosc * Timer2 prescale value ; where Tosc = 1/Fosc and Fosc = 4.000.000 Hz ; Setting the prescaler at 10 gives (devide by 4): ; (255 + 1) * 4 * 1/4.000.000 * 16 = 4,1 ms Period Cycle (about 244 Hz) ; Set correct Timer 2 values which is used to generate the PWM Period T2CON_TMR2ON = FALSE ; Timer 2 off T2CON_TOUTPS = 0b0000 ; Postscaler is 1:1 T2CON_T2CKPS = 0b10 ; Prescaler divide by 16 PR2 = 255 ; Set CCP1CON to single output PWM Mode CCP1CON_P1M = 0b00 ; Set CCP1CON to have P1A active high in PWM Mode CCP1CON_CCP1M = 0b1100 ; The Pulse Width uses the value in CCPR1L and two LSB's in DC1B to get 10 bit ; resolution. We ignore these two LSB's since their significance is small ; (10 bits are needed since it runs 4 times as fast, see formula below) ; The Pulse Width becomes: CCPR1L+DC1B * * Tosc * Timer2 prescale value ; So set the initial value of the Duty cycle in CCPR1L CCPR1L = Duty_Cycle ; Start Timer 2 (and so PWM) T2CON_TMR2ON = TRUE Forever Loop If (Give_Random_Word > 0x2FFF) Then ; Above half of the Random Word so brightness should go up. Duty_Cycle = Duty_Cycle + UP_BRIGHT ; Top maximum value if value becomes too high. If (Duty_Cycle > MAX_BRIGHT) Then Duty_Cycle = MAX_BRIGHT End If Else ; Below half of the Random Word so brightness should go down. Duty_Cycle = Duty_Cycle - DOWN_BRIGHT ; Top minimum value if value becomes too low. If (Duty_Cycle < MIN_BRIGHT) Then Duty_Cycle = MIN_BRIGHT End If End If ; Give_Random_Word ; Set new Duty Cycle CCPR1L = Duty_Cycle ; Wait some time to get a candle effect _usec_delay(3000) End Loop