/***********************************************************************
* Project: "Lichtwecker"
* Homepage: http://www.kuspbv.de/projects/electronics/wul.html
* Version: 1.1
* State: stable
*
* Author: Michael Kammer
*
**** Pin Layout *******************************************************
* _________
* 5V -| |- Ground
* RADIO_ON_BTN -| |- LIGHT_SWITCH_BTN
* RADIO_OFF_BTN -| PIC |- DISPLAY_SWITCH_BTN
* ALARM_DETECTION -| 16F- |- TRIAC_GATE
* ALARM_OFF_OC -| 688 |- Comparator
* RADIO_OFF_OC -| |- Comparator
* RADIO_ON_OC -|_______|- DISPLAY_RELAY
*
**** License **********************************************************
*
* Copyright (C) 2009-2013 Michael Kammer
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
**********************************************************************/
#define __16f688
#include "pic16f688.h"
static unsigned int at 0x2007 __CONFIG =
_CP_OFF &
_WDT_ON &
_BOD_ON &
_PWRTE_ON &
_INTRC_OSC_NOCLKOUT &
_MCLRE_OFF &
_IESO_OFF &
_FCMEN_OFF;
#define RADIO_ON_BTN RA5
#define RADIO_OFF_BTN RA4
#define ALARM_DETECTION RA3
#define ALARM_OFF_OC RC5
#define RADIO_OFF_OC RC4
#define RADIO_ON_OC RC3
#define DISPLAY_RELAY RC2
#define TRIAC_GATE RA2
#define DISPLAY_SWITCH_BTN RA1
#define LIGHT_SWITCH_BTN RA0
#define clrwdt() do { \
_asm \
CLRWDT \
_endasm; \
} while (0)
#define sleep() do { \
_asm \
SLEEP \
_endasm; \
} while (0)
#define eewrite(D,A) do { \
EEIF = 0; \
EEADR = A; \
EEDATA = D; \
_asm \
CLRWDT \
BCF EECON1, 3 \
BSF EECON1, 2 \
CLRWDT \
MOVLW 0x55 \
MOVWF EECON2 \
MOVLW 0xAA \
MOVWF EECON2 \
BSF EECON1, 1 \
_endasm; \
while (!EEIF) clrwdt(); \
EEIF = 0; \
} while (0)
#define eeread(V,A) do { \
EEADR = A; \
_asm \
BSF EECON1, 0 \
_endasm; \
V = EEDATA; \
} while (0)
#define await_zerocross() do { \
oldC2OUT = CMCON0; \
while (CMCON0 == oldC2OUT) clrwdt(); \
} while (0)
#define alarm_off() do { \
ALARM_OFF_OC = 1; \
while (!ALARM_DETECTION) clrwdt(); \
ALARM_OFF_OC = 0; \
} while (0)
void main() {
// Variables
static enum {m_man, m_waking, m_gotosleep, m_wokeup, m_wa, m_wb} mode;
static unsigned char i, ticks, secs, rsecs, rmins, ticksH, ticksL;
static unsigned char radio, alarmActive, diag, csecs;
static signed char dimmLevel;
// PIC init
clrwdt();
OPTION_REG = 0x07; // 0000 1111
TRISA = 0x3B; // 0011 1011
TRISC = 0x03; // 0000 0011
WPUA = 0x33; // 0011 0011
ANSEL = 0x30; // 0011 0000
CMCON0 = 0x05; // 0000 0101
T1CON = 0x00; // 0000 0000
clrwdt();
// Port init
TRIAC_GATE = 0;
DISPLAY_RELAY = 0;
RADIO_ON_OC = 0;
RADIO_OFF_OC = 1;
ALARM_OFF_OC = 0;
radio = 0;
dimmLevel = -100;
alarmActive = 0;
/* Okay, this is the plan
*
* 1) Init timer ( 1/4 )
* 2) Start timer when C2OUT goes low
* 3) Stop timer when C2OUT goes low again
* 4) Timer counter now holds 90 degrees of sinus wave (1/4)
*/
clrwdt();
T1CON = 0x00; // 0000 0000
T1IF = 0;
TMR1L = 0;
TMR1H = 0;
while (C2OUT == 0) clrwdt();
while (C2OUT == 1) clrwdt();
// C2OUT gone low
T1CON = 0x21; // 0010 0001
while (C2OUT == 0) clrwdt();
while (C2OUT == 1) clrwdt();
// C2OUT gone low again
T1CON = 0x00; // 0000 0000
ticksH = 0xFF - TMR1H;
ticksL = 0xFF - TMR1L;
// Diagmode?
if (!DISPLAY_SWITCH_BTN) {
diag = 1;
csecs = 1;
clrwdt();
i = 13;
T1CON = 0x31; // 0011 0001
while (i) {
i--;
TMR1L = 0;
TMR1H = 0;
T1IF = 0;
while (!T1IF) clrwdt();
DISPLAY_RELAY++;
}
T1CON = 0x00; // 0000 0000
} else {
diag = 0;
csecs = 41;
}
// Welcome sequence
mode = m_wa;
DISPLAY_RELAY = 1;
i = 0;
while (1) {
clrwdt();
// Alarm
if (!ALARM_DETECTION) {
if (diag) {
ALARM_OFF_OC = 1;
i = 20;
T1CON = 0x31; // 0011 0001
while (i) {
if (ALARM_DETECTION) i--;
TMR1L = 0;
TMR1H = 0;
T1IF = 0;
while (T1IF == 0) clrwdt();
DISPLAY_RELAY++;
}
T1CON = 0x00; // 0000 0000
ALARM_OFF_OC = 0;
} else alarm_off();
if (alarmActive) {
// Start wake up mode
secs = 0;
dimmLevel = -22;
mode = m_waking;
}
}
clrwdt();
// Console
if (!DISPLAY_SWITCH_BTN) {
while (!DISPLAY_SWITCH_BTN) {
while (!DISPLAY_SWITCH_BTN) {
sleep();
if (!RADIO_ON_BTN) {
// Activate alarm
alarmActive = 1;
i = 7;
T1CON = 0x31; // 0011 0001
while (i) {
i--;
TMR1L = 0;
TMR1H = 0;
T1IF = 0;
while (T1IF == 0) clrwdt();
DISPLAY_RELAY++;
}
T1CON = 0x00; // 0000 0000
}
if (!RADIO_OFF_BTN) {
// Deactivate alarm
alarmActive = 0;
i = 3;
T1CON = 0x31; // 0011 0001
while (i) {
i--;
TMR1L = 0;
TMR1H = 0;
T1IF = 0;
while (T1IF == 0) clrwdt();
DISPLAY_RELAY++;
}
T1CON = 0x00; // 0000 0000
}
}
}
DISPLAY_RELAY++;
}
if (!LIGHT_SWITCH_BTN) {
if (mode == m_wokeup) RADIO_OFF_OC = 1;
mode = m_man;
while (!LIGHT_SWITCH_BTN) {
while (!LIGHT_SWITCH_BTN) {
sleep();
if (!RADIO_OFF_BTN) {
// Dimm down
mode = m_gotosleep;
if (dimmLevel > 22) dimmLevel = 22;
secs = 0;
}
if (!RADIO_ON_BTN) {
// Dimm up
mode = m_waking;
if (dimmLevel < -22) dimmLevel = -22;
secs = 0;
}
}
}
if (mode == m_man) {
if (dimmLevel != 100) {
if (dimmLevel < -22) dimmLevel = -22; // Inital on
dimmLevel += 11;
if (dimmLevel >= 22) dimmLevel = 100; // Instant on
} else dimmLevel = -100;
}
}
if (!RADIO_ON_BTN && !radio) {
RADIO_ON_OC = 1;
radio = 1;
rsecs = 0;
rmins = 0;
if (mode == m_waking || mode == m_wokeup) {
mode = m_man;
dimmLevel = 100;
}
}
if (!RADIO_OFF_BTN) {
RADIO_OFF_OC = 1;
radio = 0;
if (mode == m_wokeup) {
mode = m_man;
dimmLevel = -100;
}
}
// Mode selection
if (mode == m_wb) {
if (ticks & 1) {
dimmLevel--;
if (dimmLevel > 22) dimmLevel = 22;
}
if (dimmLevel < -22) {
dimmLevel = -100;
mode = m_man;
}
}
if (mode == m_wa) {
if (ticks & 1) {
dimmLevel++;
if (dimmLevel < -22) dimmLevel = -22;
}
if (dimmLevel > 22) mode = m_wb;
}
if (mode == m_waking) {
if (secs == csecs) {
secs = 0;
dimmLevel++;
if (dimmLevel == 0) {
// Switch on display
DISPLAY_RELAY = 0;
}
if (dimmLevel == 11) {
// Switch on radio
RADIO_ON_OC = 1;
radio = 1;
}
if (dimmLevel == 23) {
// We're done
mode = m_wokeup;
dimmLevel = 100;
}
}
}
if (mode == m_gotosleep) {
if (secs == csecs) {
secs = 0;
dimmLevel--;
if (dimmLevel == 0) {
// Switch off display
DISPLAY_RELAY = 1;
}
if (dimmLevel == -11) {
// Switch off radio
RADIO_OFF_OC=1;
}
if (dimmLevel == -23) {
// We're done
mode = m_man;
dimmLevel = -100;
}
}
}
// Dimmer loop
if (dimmLevel > 22) {
TRIAC_GATE = 1;
while (!C2OUT) clrwdt();
while (C2OUT) clrwdt();
} else {
if (dimmLevel < -22) {
TRIAC_GATE = 0;
while (!C2OUT) clrwdt();
while (C2OUT) clrwdt();
} else {
T1CON = 0x00; // 0000 0000
TMR1L = ticksL;
TMR1H = ticksH;
T1IF = 0;
// phase shift
if (!DISPLAY_RELAY) TMR1H += 5;
TMR1H += (dimmLevel >> 1);
if (TMR1L < 127) if ( !(dimmLevel & 1) ) TMR1L = 0;
while (!C2OUT) clrwdt();
while (C2OUT) clrwdt();
// C2OUT gone low
T1CON = 0x01; // 0000 0001
while (!T1IF) clrwdt();
// Lowest values of sinus
TRIAC_GATE = 1;
T1CON = 0x00; // 0000 0000
TMR1L = ticksL;
TMR1H = ticksH;
T1IF = 0;
// phase shift
if (!DISPLAY_RELAY) TMR1H -= 9; else TMR1H -= 7;
TMR1H += (dimmLevel >> 1);
if (TMR1L < 127) if ( !(dimmLevel & 1) ) TMR1L = 0;
while (!C2OUT) clrwdt();
TRIAC_GATE = 0;
// C2OUT gone high
T1CON = 0x01; // 0000 0001
while (!T1IF) clrwdt();
// Highes values of sinus
TRIAC_GATE = 1;
clrwdt();
clrwdt();
clrwdt();
TRIAC_GATE = 0;
}
// Timer
ticks++;
if (ticks == 50) {
ticks = 0;
secs++;
rsecs++;
if (secs == 60) secs=0;
if (rsecs == 60) {
rsecs = 0;
rmins++;
if (rmins == 50) radio = 0;
}
}
}
// Tidy up
RADIO_ON_OC = 0;
RADIO_OFF_OC = 0;
}
}