Stairs Light Timer

A general-purpose 5s to 21m timer programmable with a single button

by Stefano Purchiaroni

This timer uses a PIC12F683 microcontroller to handle the timing, as well the setting operations. The user can adjust the time using a single button, adding steps of 5 seconds (short click), or resetting the time to 5 seconds (long click). Two Led show the timer state and feedback the user about setting being applied through the button.

The circuit is designed to lay into a small plastic box. Due to the Relays size, it shall be disposed horizontally, connecting its terminals to the board using wires. A hole on the button side, as another large one for the external connections shall be realised. A wall adapter shall supply 12 volts power to the circuit.

The schematic is simple: the microcontroller drives the relays and a state signalling Led through a transistor, and uses another Led to gives feedbacks in front of the button actions.

 

 

As all the functions are managed with a single button, both short and long pressions are handled:

Action on the button (P1)

Operation

Led (D1)

Short

Increase time of 5s

One blink

Long

Reset time to 5s

Three blinks

 

The timer can be programmed in the 5s – 21m range, since the variable where the number of 5 seconds units is stored is an unsigned short (8 bit). Its contents is stored in EEPROM to remember its value also when the circuit is not powered.


 

 

The circuit may be implemented on any proto-board. For a cleaner realisation, a Pcb layout is supplied.

Click to have a fullres mirrored image for Pcb realisation, using your preferred method.

The microcontroller must be programmed using the Hex file available clicking here.

Hereafter a 3D view of the mounted timer:

 
In addition, here the prototype. Notice the horizontal position of the Relay, to fit it in the box:

The source code is supplied in the next pages.


 

/***********************************************************************************
 
     General purpose timer
    
     It needs:
     - One button to program the delay
     - One regulator to feed the PIC (78L05)
     - One led grounded via a 180 ohm resistor
     - One npn transistor with base seried to 2K7 resistor, to activate a rel่
     - One 100nF ceramic capacitor on Vdd as noise protection
    
     Abstract:
     - When the input contact is grounded, the time count begins and the output is set
     - At time expiration, the output is unset and the count stops
     - If the input is stroked during count, the count restarts adding extra time
     - Each short pression on program button increases delay of +5 seconds (led: 1 blink)
     - A long pression on program button reset delay time to 5 seconds (led: 3 blinks)
     - The time delay is stored in flash
 
     MCU:             PIC12F683
     Oscillator:      Internal, 4.000 MHz
     Compilator:      mikroC v8.2.0.0
 
     Author: stefano.purchiaroni@email.it
             www.purchiaroni.com
    
     Changes log:
     - 26.02.2016 : Creation of the program
    
***********************************************************************************/
 
// Pin usage
#define PrgPin  F1               // Input from the programming button
#define OnPin   F2               // Input from the external "ON" button
#define OutPin  F5               // Output to the transistor base, to drive a rel่
#define LedPin  F4               // Output to a led
 
// Constants
#define CycDly  10               // Milliseconds between cycles
#define LongButton 200           // Number of cycle to consider a long pression
 
// On buttons level when pressed
#define ButOn   0
 
// Initial EEPROM address to add to byte offset for store/retrieve operations
#define EEPROM_OFFSET 10
 
// Variables
unsigned short tic = 5;          // [ Volatile ] Time increment (seconds)
unsigned short tim;              // [ Flash    ] Programmed number of tic
unsigned short curprg;           // [ Volatile ] Current Prog Button state
unsigned short curon;            // [ Volatile ] Current On Button state
unsigned short prvprg = 0;       // [ Volatile ] Previous Prog Button state
unsigned short prvon;            // [ Volatile ] Previous On Button state
int            n = 0;            // [ Volatile ] Number of remaining 10ms cycles with output set
int            b = 0;            // [ Volatile ] Duration (cycles) of pressed state of Prog button
 
void Blink(int n) {
// Blink the led n times
int i;
  for (i=1;i<=n;i++) {
    GPIO.LedPin = 1;
    Delay_ms(150);
    GPIO.LedPin = 0;
    Delay_ms(150);
  }
}
 
void StoreByte(unsigned short b, unsigned int offs) {
// Write a byte on EEprom
  EEPROM_Write(EEPROM_OFFSET + offs, b);
  Delay_ms(25);
}
 
unsigned short RetrieveByte(unsigned int offs) {
// Read a byte from EEprom
unsigned short b;
  b = EEPROM_Read(EEPROM_OFFSET + offs);
  Delay_ms(25);
  return b;
}
 
void main() {
int i;
 
  ANSEL  = 0;              // Configure AN pins as digital
  CMCON0  = 7;             // Turn off the comparators
  TRISIO = 0xFF;           // Start with all pin as input
 
  // Set the output pins direction
  TRISIO.OutPin = 0;       // To transistor driving rel่
  TRISIO.LedPin = 0;       // Led
 
  // Set internal pull-up resistors on the input pin
  OPTION_REG.F7 = 0;       // Enable pull-up
  WPU.OnPin = 1;
  WPU.PrgPin = 1;
 
  // Init the output pins value
  GPIO.OutPin = 0;
  GPIO.LedPin = 0;
 
  // Bonjour
  Blink(3);
 
  // Retrieve tim value from flash
  tim = RetrieveByte(0);
  if (tim == 0xFF) tim = 1; // First reading
 
  // Main loop
  do {
 
    // Manage "ON" external button event, starting the countdown
    if (Button(&GPIO, 2, 1, ButOn)) { // "ON" button pressed
      n = tim * tic * 100;            // (Re)initialize the number of 10 ms cycles to wait
    }
 
    if (n == 0) {                     // We are out of countdown
      GPIO.LedPin = 0;                // Led off
      GPIO.OutPin = 0;                // Output off
     
      // Get programming button new state
      curprg = Button(&GPIO, 1, 1, ButOn);
 
      // Detect long pression
      if (b==LongButton) {            // Long pression detected
        tim = 1;                      // Reset time delay duration
        StoreByte(tim,0);             // Store new value in flash
        Blink(2);                     // Announce reset
      }
 
      // Detect short pression
      if ((prvprg) && (!curprg) && (b<LongButton)) {
        tim++;                        // Increase time delay (number of tic)
        Blink(1);                     // Signal the change via one blink
        StoreByte(tim,0);             // Store new value in flash
      }
 
      // Count pression time cycle
      if (curprg) b++;                // Count pressed state cycles
      else        b=0;                // At release, reset pressed state cycles counter
     
      prvprg = curprg; // Save button state
    }
    else {                            // We are in countdown
      GPIO.LedPin = 1;                // Led on
      GPIO.OutPin = 1;                // Output on
      n--;                            // Decrement cycles count
    }
 
    Delay_ms(CycDly);                 // Fit 10ms per cycle
 
  } while(1);                         // endless loop
}