Changed the Makefile for gmake.
[kokare.git] / kokare.c
index 18379e9..f7033d8 100644 (file)
--- a/kokare.c
+++ b/kokare.c
@@ -1,15 +1,17 @@
 #include <avr/io.h>
 #include <avr/interrupt.h>
+#include <avr/eeprom.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,
@@ -34,36 +36,58 @@ uint8_t dsp[2] = {0, 0};
 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;
@@ -112,10 +136,10 @@ unsigned char bindisp(unsigned char num)
     return(ret);
 }
 
-void display(char num)
+void display(char num, char d0, char d1)
 {
-    dsp[0] = font[(num / 10) % 10];
-    dsp[1] = font[num % 10];
+    dsp[0] = font[(num / 10) % 10] | (d0?SEGP:0);
+    dsp[1] = font[num % 10] | (d1?SEGP:0);
 }
 
 void disphex(unsigned char num)
@@ -126,54 +150,60 @@ void disphex(unsigned char num)
 
 unsigned long getticks(void)
 {
-    return(TCNT1 + (((unsigned long)oticks) << 16));
+    uint16_t v;
+    unsigned long r;
+    
+    cli();
+    v = TCNT1;
+    r = v + (((unsigned long)oticks) << 16);
+    if((TIFR1 & 0x01) && !(v & 0x8000))
+       r += 0x10000;
+    sei();
+    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;
        }
     }
 }
@@ -184,22 +214,178 @@ void calcavg(void)
        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(t / (A * C * ln(2)))
+     * Where:
+     *  t = The measured time (s)
+     *  R = The resistance of the thermistor (Ohm)
+     *  C = The capacitance of the capacitor (F)
+     *  T = The temperature (K)
+     *  A, B are the thermistor-specific constants
+     *
+     * In the following code:
+     *  a = ttimea as float
+     *  C = 1e-6 / (A * C * ln(2))
+     *  ra = a * C
+     *  l = ln(ra)
+     *  t = B / l
+     * Note, temperature is in Kelvin
+     */
+#define C 10.819112      /* A is 0.1333469 */
+#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, rstate, delta;
+    unsigned long utime;
     
-    cur = 0;
+    state = 1;
+    cur = eeprom_read_byte(0);
+    if(cur < 0)
+       cur = 0;
+    if(cur > 100)
+       cur = 100;
+    run = 0;
+    rstate = 0;
+    utime = getticks();
     init();
     sei();
-    display(0);
+    if(cur < 100)
+       display(cur, 0, 0);
+    else
+       dsp[0] = dsp[1] = SEGG;
+
     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, 0, run);
+               } else {
+                   dsp[0] = SEGG;
+                   dsp[1] = SEGG | (run?SEGP:0);
+               }
+           }
+           if(pval != 0)
+               state = 1;
+           if(sstate == 2) {
+               sstate = 0;
+               if(stime > 10)
+                   state = 2;
+               else
+                   run = !run;
+           }
+       } else if(state == 1) {
+           /* Temp setting */
+           if(pval != 0) {
+               cur += pval;
+               pval = 0;
+               if(cur < 0)
+                   cur = 0;
+               if(cur > 100)
+                   cur = 100;
+               utime = mnow;
+           }
+           if(mnow - utime > 2000000) {
+               state = 0;
+               eeprom_write_byte(0, cur);
+           }
+           if(sstate == 2) {
+               run = !run;
+               sstate = 0;
+           }
+           if(cur < 100) {
+               display(cur, 0, run);
+           } else {
+               dsp[0] = SEGG;
+               dsp[1] = SEGG | (run?SEGP:0);
+           }
+       } else if(state == 2) {
+           /* Display raw temp time reading */
+           if(ttimea < 20000) {
+               display((ttimea / 100) % 100, 1, ttimea >= 10000);
+           } else {
+               display(ttimea / 1000, 0, 0);
+           }
+           if(sstate == 2) {
+               state = 0;
+               sstate = 0;
+           }
+       }
+       /*
+        * Set Triac to match temperature
+        */
+       if(run) {
+           delta = cur - (tempk - 273);
+           if(rstate == 0) {
+               if(delta > 0) {
+                   tron = 1;
+                   if(delta > 8) {
+                       /* For some reason, the Triac currently doesn't
+                        * trigger on one of the AC half-cycles below 0.7
+                        * ms. */
+                       trdelay = 7;
+                   } else {
+                       trdelay = 75 - (delta * 5);
+                   }
+               } else {
+                   tron = 0;
+                   rstate = 1;
+               }
+           } else if(rstate == 1) {
+               tron = 0;
+               if(delta >= 2)
+                   rstate = 0;
+           }
+       } else {
+           tron = 0;
+       }
+#endif
        /*
          dsp[0] = bindisp((ttimea & 0xff00) >> 8);
          dsp[1] = bindisp(ttimea & 0x00ff);
@@ -207,6 +393,10 @@ int main(void)
        /*
          disphex((ttimea & 0xff000) >> 12);
        */
+#if 0
+       /*
+         Temp display
+       */
        if(ttimea < 20000) {
            display((ttimea / 100) % 100);
            dsp[0] |= SEGP;
@@ -215,8 +405,45 @@ int main(void)
        } 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) {
@@ -233,12 +460,16 @@ int main(void)
        } else {
            display(cur);
        }
-       */
+       if(PINB & 4)
+           dsp[1] |= SEGP;
+#endif
     }
 }
 
 ISR(SIG_INTERRUPT0)
 {
+    ztime = 0;
+    zok = 1;
 }
 
 ISR(SIG_INTERRUPT1)
@@ -256,30 +487,52 @@ ISR(SIG_INTERRUPT1)
     }
 }
 
+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 {
@@ -293,7 +546,7 @@ ISR(SIG_PIN_CHANGE0)
            pstate = 0;
        }
     } else {
-       if((PINB & 2) && (PINB & 4))
+       if((PINB & 2) && (PINB & 1))
            pstate = 0;
     }
 }