#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>
+#include <math.h>
-#define SEGA 128
-#define SEGB 64
-#define SEGC 4
-#define SEGD 16
-#define SEGE 32
-#define SEGF 2
-#define SEGG 1
-#define SEGP 8
+#define SEGA 4
+#define SEGB 2
+#define SEGC 1
+#define SEGD 32
+#define SEGE 64
+#define SEGF 16
+#define SEGG 8
+#define SEGP 128
uint8_t font[16] = {
SEGA | SEGB | SEGC | SEGD | SEGE | SEGF,
char leda = 0;
char ledc = 0;
/* Timer */
-char of = 0;
-int oticks = 0;
+volatile int oticks = 0;
+unsigned long mnow;
/* Pulse counter */
-char pstate = 0;
+volatile char pstate = 0;
char pval = 0;
/* Switch */
-char sstate = 0;
+volatile char sstate = 0;
int stime = 0;
/* Temp sensor */
-char tstate = 0;
-char tlock = 0;
+volatile char tstate = 0;
+volatile char tlock = 0;
unsigned long tstart;
unsigned long ttime;
unsigned long ttimea = 10000;
+char tavgok = 0;
+/* Conversion loop */
+int tempk;
+volatile ktok = 0;
/* Zero-cross detector*/
+volatile char zok = 0;
+volatile char ztime = 0;
/* Triac */
+char trstate = 0;
+char tron = 0;
+volatile char trtime;
+volatile char trdelay = 0;
void init(void)
{
- /* Timer init */
+ /* Timer init
+ * Timer 0 cycles the Triac
+ * Timer 1 is used for global timing
+ * Timer 2 cycles the LED display
+ */
+ OCR0A = 100;
+ TCCR0A = 2;
+ TCCR0B = 1;
+ TIMSK0 = 2;
TCCR1A = 0;
TCCR1B = 1;
TIMSK1 = 1;
+ OCR2A = 16;
+ TCCR2A = 2;
+ TCCR2B = 4;
+ TIMSK2 = 2;
/*
* B0..2 = Pulse sensor
* B3..5 = ISP
* B6..7 = CLK
*/
- DDRB = 0x00;
+ DDRB = 0x38;
PORTB = 0x07;
PCMSK0 = 0x07;
PCICR = 0x01;
dsp[1] = font[num & 0x0f];
}
+/*
+ * This version is used outside interrupts.
+ * It spins until no overflow has happened.
+ */
unsigned long getticks(void)
{
- return(TCNT1 + (((unsigned long)oticks) << 16));
+ uint16_t v;
+ unsigned long r;
+
+ do {
+ v = oticks;
+ r = TCNT1 + (((unsigned long)oticks) << 16);
+ } while(v != oticks);
+ return(r);
+}
+
+/*
+ * This version is used in interrupts
+ */
+unsigned long getticks2(void)
+{
+ uint16_t v;
+ unsigned long r;
+
+ v = TCNT1;
+ r = v + (((unsigned long)oticks) << 16);
+ if((TIFR1 & 0x01) && !(v & 0x8000))
+ return(r + 0x10000);
+ else
+ return(r);
}
void ledcycle(void)
{
- static uint16_t last = 0;
uint8_t c, d, v;
- if(TCNT1 - last > 500) {
- last = TCNT1;
- if(++leda >= 8) {
- leda = 0;
- if(++ledc >= 2)
- ledc = 0;
- }
- if(dsp[ledc] & (1 << leda)) {
- if(leda < 6) {
- c = 1 << leda;
- d = 0;
- } else {
- c = 0;
- d = 0x10 << (leda - 6);
- }
- d |= ledc?0x40:0x80;
+ if(++leda >= 8) {
+ leda = 0;
+ if(++ledc >= 2)
+ ledc = 0;
+ }
+ if(dsp[ledc] & (1 << leda)) {
+ if(leda < 6) {
+ c = 1 << leda;
+ d = 0;
} else {
- c = d = 0;
+ c = 0;
+ d = 0x10 << (leda - 6);
}
- PORTC = c;
- PORTD = (PORTD & 0x0f) | d;
+ d |= ledc?0x40:0x80;
+ } else {
+ c = d = 0;
}
+ PORTC = c;
+ PORTD = (PORTD & 0x0f) | d;
}
void tempcycle(void)
{
- unsigned long now;
-
- now = getticks();
if(tstate == 0) {
if((PIND & 8) && (tlock == 0)) {
+ cli();
PORTD |= 2;
- tstart = now;
+ sei();
+ tstart = mnow;
tstate = 1;
}
} else if(tstate == 1) {
- if(now - tstart > 1000) {
+ if(mnow - tstart > 1000) {
+ cli();
PORTD &= ~2;
+ sei();
tstate = 0;
- tstart = now;
+ tstart = mnow;
}
}
}
tlock = 2;
ttimea = ((ttimea * 15) + ttime) >> 4;
tlock = 0;
+ tavgok = 1;
+ }
+}
+
+void convcycle(void)
+{
+ static char state = 0;
+ static unsigned long last = 0;
+ static float a, ra, l, t;
+
+ /*
+ * Theoretically:
+ * t = RC * ln(2) => R = t / (C * ln(2))
+ * R = A * exp(B / T) => T = B / ln(R / A)
+ * T = B / ln(R / (A * C * ln(2)))
+ * In the following:
+ * a = ttimea as float
+ * C = 1e6 / (A * C * ln(2))
+ * ra = a * C
+ * l = ln(ra)
+ * t = B / l
+ * Note, temperature is in Kelvin
+ */
+#define C 9.792934
+#define B 4020.0
+ if(state == 0) {
+ if((mnow - last > 200000) && tavgok) {
+ a = (float)ttimea;
+ state = 1;
+ tavgok = 0;
+ last = mnow;
+ }
+ } else if(state == 1) {
+ ra = a * C;
+ state = 2;
+ } else if(state == 2) {
+ l = log(ra);
+ state = 3;
+ } else if(state == 3) {
+ t = B / l;
+ state = 4;
+ } else if(state == 4) {
+ tempk = (int)t;
+ ktok = 1;
+ state = 0;
}
}
int main(void)
{
- int cur;
+ int state, cur, run;
+ unsigned long utime;
- cur = 0;
+ state = 0;
+ cur = 100;
+ run = 0;
init();
sei();
display(0);
+
while(1) {
- ledcycle();
+ mnow = getticks();
tempcycle();
calcavg();
+ convcycle();
+#if 1
+ /*
+ * User interface
+ */
+ if(state == 0) {
+ /* Display temperature */
+ if(ktok) {
+ ktok = 0;
+ if((tempk >= 273) && (tempk <= 372)) {
+ display(tempk - 273);
+ } else {
+ dsp[0] = dsp[1] = SEGG;
+ }
+ }
+ if(pval != 0)
+ state = 1;
+ if(sstate == 2) {
+ sstate = 0;
+ if(stime > 10)
+ state = 2;
+ else
+ run = !run;
+ }
+ if(run)
+ dsp[1] |= SEGP;
+ else
+ dsp[1] &= ~SEGP;
+ } else if(state == 1) {
+ /* Temp setting */
+ if(pval != 0) {
+ cur += pval;
+ pval = 0;
+ if(cur < 0)
+ cur = 0;
+ if(cur > 100)
+ cur = 100;
+ if(cur < 100)
+ display(cur);
+ else
+ dsp[0] = dsp[1] = SEGG;
+ utime = mnow;
+ }
+ if(mnow - utime > 1000000)
+ state = 0;
+ if(sstate == 2) {
+ run = !run;
+ sstate = 0;
+ }
+ } else if(state == 2) {
+ /* Display raw temp time reading */
+ if(ttimea < 20000) {
+ display((ttimea / 100) % 100);
+ dsp[0] |= SEGP;
+ if(ttimea >= 10000)
+ dsp[1] |= SEGP;
+ } else {
+ display(ttimea / 1000);
+ }
+ if(sstate == 2) {
+ state = 0;
+ sstate = 0;
+ }
+ }
+ /*
+ * Set Triac to match temperature
+ */
+ if(run) {
+ if(tempk - 273 < cur) {
+ tron = 1;
+ if(cur - (tempk - 273) > 5) {
+ /* For some reason, the Triac currently doesn't
+ * trigger on one of the AC half-cycles below 0.7
+ * ms. */
+ trdelay = 7;
+ } else if(cur - (tempk - 273) >= 3) {
+ trdelay = 20;
+ } else if(cur - (tempk - 273) >= 2) {
+ trdelay = 40;
+ } else {
+ trdelay = 70;
+ }
+ } else {
+ tron = 0;
+ }
+ } else {
+ tron = 0;
+ }
+#endif
/*
dsp[0] = bindisp((ttimea & 0xff00) >> 8);
dsp[1] = bindisp(ttimea & 0x00ff);
/*
disphex((ttimea & 0xff000) >> 12);
*/
+#if 0
+ /*
+ Temp display
+ */
if(ttimea < 20000) {
display((ttimea / 100) % 100);
dsp[0] |= SEGP;
} else {
display(ttimea / 1000);
}
-
+#endif
+#if 0
+ /*
+ * ZVD debug
+ */
+ if(zok) {
+ if(++cur > 99)
+ cur = 0;
+ display(cur);
+ zok = 0;
+ }
+#endif
+#if 0
+ /*
+ Phony Triac control
+ */
+ if(pval != 0) {
+ cur += pval;
+ if(cur < 0)
+ cur = 0;
+ if(cur > 99)
+ cur = 99;
+ display(cur);
+ trdelay = 99 - cur;
+ pval = 0;
+ }
+ if(sstate == 2) {
+ tron = !tron;
+ sstate = 0;
+ }
+ if(tron)
+ dsp[1] |= SEGP;
+ else
+ dsp[1] &= ~SEGP;
+#endif
+#if 0
/*
+ Pulse counter display
+ */
cur += pval;
pval = 0;
if(sstate == 2) {
} else {
display(cur);
}
- */
+ if(PINB & 4)
+ dsp[1] |= SEGP;
+#endif
}
}
ISR(SIG_INTERRUPT0)
{
+ ztime = 0;
+ zok = 1;
}
ISR(SIG_INTERRUPT1)
{
unsigned long now;
- now = getticks();
+ now = getticks2();
if(tstate == 0) {
tstate = 1;
if(tlock != 2)
}
}
+ISR(SIG_OUTPUT_COMPARE0A)
+{
+ if(trstate == 0) {
+ ztime++;
+ if(tron && (ztime >= trdelay)) {
+ PORTD |= 1;
+ trstate = 1;
+ trtime = 0;
+ }
+ } else if(trstate == 1) {
+ trtime++;
+ if(trtime >= 5) {
+ PORTD &= ~1;
+ trstate = 0;
+ }
+ }
+}
+
+ISR(SIG_OUTPUT_COMPARE2A)
+{
+ ledcycle();
+}
+
ISR(SIG_OVERFLOW1)
{
- of = 1;
oticks++;
}
ISR(SIG_PIN_CHANGE0)
{
- if((sstate == 0) & ((PINB & 1) == 0)) {
+ if((sstate == 0) && !(PINB & 4)) {
stime = oticks;
sstate = 1;
}
- if((sstate == 1) & ((PINB & 1) == 1)) {
+ if((sstate == 1) && (PINB & 4)) {
stime = oticks - stime;
sstate = 2;
}
if(pstate == 0) {
if((PINB & 2) == 0) {
pstate = 1;
- } else if((PINB & 4) == 0) {
+ } else if((PINB & 1) == 0) {
pstate = 2;
}
} else if(pstate == 1) {
- if((PINB & 4) == 0) {
+ if((PINB & 1) == 0) {
pval++;
pstate = 3;
} else {
pstate = 0;
}
} else {
- if((PINB & 2) && (PINB & 4))
+ if((PINB & 2) && (PINB & 1))
pstate = 0;
}
}