Changed the Makefile for gmake.
[kokare.git] / kokare.c
1 #include <avr/io.h>
2 #include <avr/interrupt.h>
3 #include <avr/eeprom.h>
4 #include <inttypes.h>
5 #include <math.h>
6
7 #define SEGA 4
8 #define SEGB 2
9 #define SEGC 1
10 #define SEGD 32
11 #define SEGE 64
12 #define SEGF 16
13 #define SEGG 8
14 #define SEGP 128
15
16 uint8_t font[16] = {
17     SEGA | SEGB | SEGC | SEGD | SEGE | SEGF,
18     SEGB | SEGC,
19     SEGA | SEGB | SEGD | SEGE | SEGG,
20     SEGA | SEGB | SEGC | SEGD | SEGG,
21     SEGB | SEGC | SEGF | SEGG,
22     SEGA | SEGC | SEGD | SEGF | SEGG,
23     SEGA | SEGC | SEGD | SEGE | SEGF | SEGG,
24     SEGA | SEGB | SEGC,
25     SEGA | SEGB | SEGC | SEGD | SEGE | SEGF | SEGG,
26     SEGA | SEGB | SEGC | SEGD | SEGF | SEGG,
27     SEGA | SEGB | SEGC | SEGE | SEGF | SEGG,
28     SEGC | SEGD | SEGE | SEGF | SEGG,
29     SEGA | SEGD | SEGE | SEGF,
30     SEGB | SEGC | SEGD | SEGE | SEGG,
31     SEGA | SEGD | SEGE | SEGF | SEGG,
32     SEGA | SEGE | SEGF | SEGG,
33 };
34 /* LED */
35 uint8_t dsp[2] = {0, 0};
36 char leda = 0;
37 char ledc = 0;
38 /* Timer */
39 volatile int oticks = 0;
40 unsigned long mnow;
41 /* Pulse counter */
42 volatile char pstate = 0;
43 char pval = 0;
44 /* Switch */
45 volatile char sstate = 0;
46 int stime = 0;
47 /* Temp sensor */
48 volatile char tstate = 0;
49 volatile char tlock = 0;
50 unsigned long tstart;
51 unsigned long ttime;
52 unsigned long ttimea = 10000;
53 char tavgok = 0;
54 /* Conversion loop */
55 int tempk;
56 volatile ktok = 0;
57 /* Zero-cross detector*/
58 volatile char zok = 0;
59 volatile char ztime = 0;
60 /* Triac */
61 char trstate = 0;
62 char tron = 0;
63 volatile char trtime;
64 volatile char trdelay = 0;
65
66 void init(void)
67 {
68     /* Timer init
69      * Timer 0 cycles the Triac
70      * Timer 1 is used for global timing
71      * Timer 2 cycles the LED display
72      */
73     OCR0A = 100;
74     TCCR0A = 2;
75     TCCR0B = 1;
76     TIMSK0 = 2;
77     TCCR1A = 0;
78     TCCR1B = 1;
79     TIMSK1 = 1;
80     OCR2A = 16;
81     TCCR2A = 2;
82     TCCR2B = 4;
83     TIMSK2 = 2;
84     
85     /*
86      * B0..2 = Pulse sensor
87      * B3..5 = ISP
88      * B6..7 = CLK
89      */
90     DDRB = 0x38;
91     PORTB = 0x07;
92     PCMSK0 = 0x07;
93     PCICR = 0x01;
94     /*
95      * C0..5 = LEDA0..5
96      * C6 = /RESET
97      * C7 = NC
98      */
99     DDRC = 0x3f;
100     PORTC = 0x00;
101     /*
102      * D0 = Triac
103      * D1 = NTC FET
104      * D2 = ZCD (INT0)
105      * D3 = NTC Op-amp (INT1)
106      * D4..5 = LEDA6..7
107      * D6..7 = LEDC0..1
108      */
109     DDRD = 0xf3;
110     PORTD = 0x00;
111     EICRA = 0x0d;
112     EIMSK = 0x03;
113 }
114
115 unsigned char bindisp(unsigned char num)
116 {
117     unsigned char ret;
118     
119     ret = 0;
120     if(num & 1)
121         ret |= SEGA;
122     if(num & 2)
123         ret |= SEGB;
124     if(num & 4)
125         ret |= SEGC;
126     if(num & 8)
127         ret |= SEGD;
128     if(num & 16)
129         ret |= SEGE;
130     if(num & 32)
131         ret |= SEGF;
132     if(num & 64)
133         ret |= SEGG;
134     if(num & 128)
135         ret |= SEGP;
136     return(ret);
137 }
138
139 void display(char num, char d0, char d1)
140 {
141     dsp[0] = font[(num / 10) % 10] | (d0?SEGP:0);
142     dsp[1] = font[num % 10] | (d1?SEGP:0);
143 }
144
145 void disphex(unsigned char num)
146 {
147     dsp[0] = font[(num & 0xf0) >> 4];
148     dsp[1] = font[num & 0x0f];
149 }
150
151 unsigned long getticks(void)
152 {
153     uint16_t v;
154     unsigned long r;
155     
156     cli();
157     v = TCNT1;
158     r = v + (((unsigned long)oticks) << 16);
159     if((TIFR1 & 0x01) && !(v & 0x8000))
160         r += 0x10000;
161     sei();
162     return(r);
163 }
164
165 void ledcycle(void)
166 {
167     uint8_t c, d, v;
168     
169     if(++leda >= 8) {
170         leda = 0;
171         if(++ledc >= 2)
172             ledc = 0;
173     }
174     if(dsp[ledc] & (1 << leda)) {
175         if(leda < 6) {
176             c = 1 << leda;
177             d = 0;
178         } else {
179             c = 0;
180             d = 0x10 << (leda - 6);
181         }
182         d |= ledc?0x40:0x80;
183     } else {
184         c = d = 0;
185     }
186     PORTC = c;
187     PORTD = (PORTD & 0x0f) | d;
188 }
189
190 void tempcycle(void)
191 {
192     if(tstate == 0) {
193         if((PIND & 8) && (tlock == 0)) {
194             cli();
195             PORTD |= 2;
196             sei();
197             tstart = mnow;
198             tstate = 1;
199         }
200     } else if(tstate == 1) {
201         if(mnow - tstart > 1000) {
202             cli();
203             PORTD &= ~2;
204             sei();
205             tstate = 0;
206             tstart = mnow;
207         }
208     }
209 }
210
211 void calcavg(void)
212 {
213     if(tlock == 1) {
214         tlock = 2;
215         ttimea = ((ttimea * 15) + ttime) >> 4;
216         tlock = 0;
217         tavgok = 1;
218     }
219 }
220
221 void convcycle(void)
222 {
223     static char state = 0;
224     static unsigned long last = 0;
225     static float a, ra, l, t;
226     
227     /*
228      * Theoretically:
229      *  t = RC * ln(2) => R = t / (C * ln(2))
230      *  R = A * exp(B / T) => T = B / ln(R / A)
231      *  T = B / ln(t / (A * C * ln(2)))
232      * Where:
233      *  t = The measured time (s)
234      *  R = The resistance of the thermistor (Ohm)
235      *  C = The capacitance of the capacitor (F)
236      *  T = The temperature (K)
237      *  A, B are the thermistor-specific constants
238      *
239      * In the following code:
240      *  a = ttimea as float
241      *  C = 1e-6 / (A * C * ln(2))
242      *  ra = a * C
243      *  l = ln(ra)
244      *  t = B / l
245      * Note, temperature is in Kelvin
246      */
247 #define C 10.819112      /* A is 0.1333469 */
248 #define B 4020.0
249     if(state == 0) {
250         if((mnow - last > 200000) && tavgok) {
251             a = (float)ttimea;
252             state = 1;
253             tavgok = 0;
254             last = mnow;
255         }
256     } else if(state == 1) {
257         ra = a * C;
258         state = 2;
259     } else if(state == 2) {
260         l = log(ra);
261         state = 3;
262     } else if(state == 3) {
263         t = B / l;
264         state = 4;
265     } else if(state == 4) {
266         tempk = (int)t;
267         ktok = 1;
268         state = 0;
269     }
270 }
271
272 int main(void)
273 {
274     int state, cur, run, rstate, delta;
275     unsigned long utime;
276     
277     state = 1;
278     cur = eeprom_read_byte(0);
279     if(cur < 0)
280         cur = 0;
281     if(cur > 100)
282         cur = 100;
283     run = 0;
284     rstate = 0;
285     utime = getticks();
286     init();
287     sei();
288     if(cur < 100)
289         display(cur, 0, 0);
290     else
291         dsp[0] = dsp[1] = SEGG;
292
293     while(1) {
294         mnow = getticks();
295         tempcycle();
296         calcavg();
297         convcycle();
298
299 #if 1
300         /*
301          * User interface
302          */
303         if(state == 0) {
304             /* Display temperature */
305             if(ktok) {
306                 ktok = 0;
307                 if((tempk >= 273) && (tempk <= 372)) {
308                     display(tempk - 273, 0, run);
309                 } else {
310                     dsp[0] = SEGG;
311                     dsp[1] = SEGG | (run?SEGP:0);
312                 }
313             }
314             if(pval != 0)
315                 state = 1;
316             if(sstate == 2) {
317                 sstate = 0;
318                 if(stime > 10)
319                     state = 2;
320                 else
321                     run = !run;
322             }
323         } else if(state == 1) {
324             /* Temp setting */
325             if(pval != 0) {
326                 cur += pval;
327                 pval = 0;
328                 if(cur < 0)
329                     cur = 0;
330                 if(cur > 100)
331                     cur = 100;
332                 utime = mnow;
333             }
334             if(mnow - utime > 2000000) {
335                 state = 0;
336                 eeprom_write_byte(0, cur);
337             }
338             if(sstate == 2) {
339                 run = !run;
340                 sstate = 0;
341             }
342             if(cur < 100) {
343                 display(cur, 0, run);
344             } else {
345                 dsp[0] = SEGG;
346                 dsp[1] = SEGG | (run?SEGP:0);
347             }
348         } else if(state == 2) {
349             /* Display raw temp time reading */
350             if(ttimea < 20000) {
351                 display((ttimea / 100) % 100, 1, ttimea >= 10000);
352             } else {
353                 display(ttimea / 1000, 0, 0);
354             }
355             if(sstate == 2) {
356                 state = 0;
357                 sstate = 0;
358             }
359         }
360         /*
361          * Set Triac to match temperature
362          */
363         if(run) {
364             delta = cur - (tempk - 273);
365             if(rstate == 0) {
366                 if(delta > 0) {
367                     tron = 1;
368                     if(delta > 8) {
369                         /* For some reason, the Triac currently doesn't
370                          * trigger on one of the AC half-cycles below 0.7
371                          * ms. */
372                         trdelay = 7;
373                     } else {
374                         trdelay = 75 - (delta * 5);
375                     }
376                 } else {
377                     tron = 0;
378                     rstate = 1;
379                 }
380             } else if(rstate == 1) {
381                 tron = 0;
382                 if(delta >= 2)
383                     rstate = 0;
384             }
385         } else {
386             tron = 0;
387         }
388 #endif
389         /*
390           dsp[0] = bindisp((ttimea & 0xff00) >> 8);
391           dsp[1] = bindisp(ttimea & 0x00ff);
392         */
393         /*
394           disphex((ttimea & 0xff000) >> 12);
395         */
396 #if 0
397         /*
398           Temp display
399         */
400         if(ttimea < 20000) {
401             display((ttimea / 100) % 100);
402             dsp[0] |= SEGP;
403             if(ttimea >= 10000)
404                 dsp[1] |= SEGP;
405         } else {
406             display(ttimea / 1000);
407         }
408 #endif
409 #if 0
410         /*
411          * ZVD debug
412          */
413         if(zok) {
414             if(++cur > 99)
415                 cur = 0;
416             display(cur);
417             zok = 0;
418         }
419 #endif
420 #if 0
421         /*
422           Phony Triac control
423          */
424         if(pval != 0) {
425             cur += pval;
426             if(cur < 0)
427                 cur = 0;
428             if(cur > 99)
429                 cur = 99;
430             display(cur);
431             trdelay = 99 - cur;
432             pval = 0;
433         }
434         if(sstate == 2) {
435             tron = !tron;
436             sstate = 0;
437         }
438         if(tron)
439             dsp[1] |= SEGP;
440         else
441             dsp[1] &= ~SEGP;
442 #endif
443 #if 0
444         /*
445           Pulse counter display
446         */
447         cur += pval;
448         pval = 0;
449         if(sstate == 2) {
450             cur = stime;
451             sstate = 0;
452         }
453         if(cur > 99)
454             cur = 99;
455         if(cur < -99)
456             cur = -99;
457         if(cur < 0) {
458             display(-cur);
459             dsp[0] |= SEGP;
460         } else {
461             display(cur);
462         }
463         if(PINB & 4)
464             dsp[1] |= SEGP;
465 #endif
466     }
467 }
468
469 ISR(SIG_INTERRUPT0)
470 {
471     ztime = 0;
472     zok = 1;
473 }
474
475 ISR(SIG_INTERRUPT1)
476 {
477     unsigned long now;
478     
479     now = getticks();
480     if(tstate == 0) {
481         tstate = 1;
482         if(tlock != 2)
483             ttime = now - tstart;
484         tstart = now;
485         PORTD |= 2;
486         tlock = 1;
487     }
488 }
489
490 ISR(SIG_OUTPUT_COMPARE0A)
491 {
492     if(trstate == 0) {
493         ztime++;
494         if(tron && (ztime >= trdelay)) {
495             PORTD |= 1;
496             trstate = 1;
497             trtime = 0;
498         }
499     } else if(trstate == 1) {
500         trtime++;
501         if(trtime >= 5) {
502             PORTD &= ~1;
503             trstate = 0;
504         }
505     }
506 }
507
508 ISR(SIG_OUTPUT_COMPARE2A)
509 {
510     ledcycle();
511 }
512
513 ISR(SIG_OVERFLOW1)
514 {
515     oticks++;
516 }
517
518 ISR(SIG_PIN_CHANGE0)
519 {
520     if((sstate == 0) && !(PINB & 4)) {
521         stime = oticks;
522         sstate = 1;
523     }
524     if((sstate == 1) && (PINB & 4)) {
525         stime = oticks - stime;
526         sstate = 2;
527     }
528     if(pstate == 0) {
529         if((PINB & 2) == 0) {
530             pstate = 1;
531         } else if((PINB & 1) == 0) {
532             pstate = 2;
533         }
534     } else if(pstate == 1) {
535         if((PINB & 1) == 0) {
536             pval++;
537             pstate = 3;
538         } else {
539             pstate = 0;
540         }
541     } else if(pstate == 2) {
542         if((PINB & 2) == 0) {
543             pval--;
544             pstate = 3;
545         } else {
546             pstate = 0;
547         }
548     } else {
549         if((PINB & 2) && (PINB & 1))
550             pstate = 0;
551     }
552 }