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