Cycle the display from the Timer2 interrupt.
[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 uint8_t dsp[2] = {0, 0};
35 char leda = 0;
36 char ledc = 0;
37 /* Timer */
38 volatile char of = 0;
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)
140 {
141     dsp[0] = font[(num / 10) % 10];
142     dsp[1] = font[num % 10];
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     return(TCNT1 + (((unsigned long)oticks) << 16));
154 }
155
156 void ledcycle(void)
157 {
158     uint8_t c, d, v;
159     
160     if(++leda >= 8) {
161         leda = 0;
162         if(++ledc >= 2)
163             ledc = 0;
164     }
165     if(dsp[ledc] & (1 << leda)) {
166         if(leda < 6) {
167             c = 1 << leda;
168             d = 0;
169         } else {
170             c = 0;
171             d = 0x10 << (leda - 6);
172         }
173         d |= ledc?0x40:0x80;
174     } else {
175         c = d = 0;
176     }
177     PORTC = c;
178     PORTD = (PORTD & 0x0f) | d;
179 }
180
181 void tempcycle(void)
182 {
183     if(tstate == 0) {
184         if((PIND & 8) && (tlock == 0)) {
185             cli();
186             PORTD |= 2;
187             sei();
188             tstart = mnow;
189             tstate = 1;
190         }
191     } else if(tstate == 1) {
192         if(mnow - tstart > 1000) {
193             cli();
194             PORTD &= ~2;
195             sei();
196             tstate = 0;
197             tstart = mnow;
198         }
199     }
200 }
201
202 void calcavg(void)
203 {
204     if(tlock == 1) {
205         tlock = 2;
206         ttimea = ((ttimea * 15) + ttime) >> 4;
207         tlock = 0;
208         tavgok = 1;
209     }
210 }
211
212 void convcycle(void)
213 {
214     static char state = 0;
215     static unsigned long last = 0;
216     static float a, ra, l, t;
217     
218     /*
219      * Theoretically:
220      *  t = RC * ln(2) => R = t / (C * ln(2))
221      *  R = A * exp(B / T) => T = B / ln(R / A)
222      *  T = B / ln(R / (A * C * ln(2)))
223      * In the following: 
224      *  a = ttimea as float
225      *  C = 1e6 / (A * C * ln(2))
226      *  ra = a * C
227      *  l = ln(ra)
228      *  t = B / l
229      * Note, temperature is in Kelvin
230      */
231 #define C 9.792934
232 #define B 4020.0
233     if(state == 0) {
234         if((mnow - last > 200000) && tavgok) {
235             a = (float)ttimea;
236             state = 1;
237             tavgok = 0;
238             last = mnow;
239         }
240     } else if(state == 1) {
241         ra = a * C;
242         state = 2;
243     } else if(state == 2) {
244         l = log(ra);
245         state = 3;
246     } else if(state == 3) {
247         t = B / l;
248         state = 4;
249     } else if(state == 4) {
250         tempk = (int)t;
251         ktok = 1;
252         state = 0;
253     }
254 }
255
256 int main(void)
257 {
258     int state, cur;
259     unsigned long utime;
260     
261     state = 0;
262     cur = 99;
263     init();
264     sei();
265     display(0);
266
267     while(1) {
268         mnow = getticks();
269         tempcycle();
270         calcavg();
271         convcycle();
272
273 #if 1
274         /*
275          * User interface
276          */
277         if(state == 0) {
278             /* Display temperature */
279             if(ktok) {
280                 ktok = 0;
281                 if((tempk >= 273) && (tempk <= 372)) {
282                     display(tempk - 273);
283                 } else {
284                     dsp[0] = dsp[1] = SEGG;
285                 }
286             }
287             if(pval != 0) {
288                 state = 1;
289                 utime = mnow;
290             }
291             if(sstate == 2) {
292                 sstate = 0;
293                 if(stime > 10) {
294                     state = 2;
295                 } else {
296                     tron = !tron;
297                 }
298             }
299         } else if(state == 1) {
300             /* Triac control */
301             if(pval != 0) {
302                 cur += pval;
303                 pval = 0;
304                 if(cur < 0)
305                     cur = 0;
306                 if(cur > 99)
307                     cur = 99;
308                 display(cur);
309                 trdelay = 99 - cur;
310                 utime = mnow;
311             }
312             if(mnow - utime > 1000000) {
313                 state = 0;
314             }
315             if(sstate == 2) {
316                 tron = !tron;
317                 sstate = 0;
318             }
319         } else if(state == 2) {
320             if(ttimea < 20000) {
321                 display((ttimea / 100) % 100);
322                 dsp[0] |= SEGP;
323                 if(ttimea >= 10000)
324                     dsp[1] |= SEGP;
325             } else {
326                 display(ttimea / 1000);
327             }
328             if(sstate == 2) {
329                 state = 0;
330                 sstate = 0;
331             }
332         }
333 #endif
334         /*
335           dsp[0] = bindisp((ttimea & 0xff00) >> 8);
336           dsp[1] = bindisp(ttimea & 0x00ff);
337         */
338         /*
339           disphex((ttimea & 0xff000) >> 12);
340         */
341 #if 0
342         /*
343           Temp display
344         */
345         if(ttimea < 20000) {
346             display((ttimea / 100) % 100);
347             dsp[0] |= SEGP;
348             if(ttimea >= 10000)
349                 dsp[1] |= SEGP;
350         } else {
351             display(ttimea / 1000);
352         }
353 #endif
354 #if 0
355         /*
356          * ZVD debug
357          */
358         if(zok) {
359             if(++cur > 99)
360                 cur = 0;
361             display(cur);
362             zok = 0;
363         }
364 #endif
365 #if 0
366         /*
367           Phony Triac control
368          */
369         if(pval != 0) {
370             cur += pval;
371             if(cur < 0)
372                 cur = 0;
373             if(cur > 99)
374                 cur = 99;
375             display(cur);
376             trdelay = 99 - cur;
377             pval = 0;
378         }
379         if(sstate == 2) {
380             tron = !tron;
381             sstate = 0;
382         }
383         if(tron)
384             dsp[1] |= SEGP;
385         else
386             dsp[1] &= ~SEGP;
387 #endif
388 #if 0
389         /*
390           Pulse counter display
391         */
392         cur += pval;
393         pval = 0;
394         if(sstate == 2) {
395             cur = stime;
396             sstate = 0;
397         }
398         if(cur > 99)
399             cur = 99;
400         if(cur < -99)
401             cur = -99;
402         if(cur < 0) {
403             display(-cur);
404             dsp[0] |= SEGP;
405         } else {
406             display(cur);
407         }
408         if(PINB & 4)
409             dsp[1] |= SEGP;
410 #endif
411     }
412 }
413
414 ISR(SIG_INTERRUPT0)
415 {
416     ztime = 0;
417     zok = 1;
418 }
419
420 ISR(SIG_INTERRUPT1)
421 {
422     unsigned long now;
423     
424     now = getticks();
425     if(tstate == 0) {
426         tstate = 1;
427         if(tlock != 2)
428             ttime = now - tstart;
429         tstart = now;
430         PORTD |= 2;
431         tlock = 1;
432     }
433 }
434
435 ISR(SIG_OUTPUT_COMPARE0A)
436 {
437     if(trstate == 0) {
438         ztime++;
439         if(tron && (ztime >= trdelay)) {
440             PORTD |= 1;
441             trstate = 1;
442             trtime = 0;
443         }
444     } else if(trstate == 1) {
445         trtime++;
446         if(trtime >= 5) {
447             PORTD &= ~1;
448             trstate = 0;
449         }
450     }
451 }
452
453 ISR(SIG_OUTPUT_COMPARE2A)
454 {
455     ledcycle();
456 }
457
458 ISR(SIG_OVERFLOW1)
459 {
460     of = 1;
461     oticks++;
462 }
463
464 ISR(SIG_PIN_CHANGE0)
465 {
466     if((sstate == 0) && !(PINB & 4)) {
467         stime = oticks;
468         sstate = 1;
469     }
470     if((sstate == 1) && (PINB & 4)) {
471         stime = oticks - stime;
472         sstate = 2;
473     }
474     if(pstate == 0) {
475         if((PINB & 2) == 0) {
476             pstate = 1;
477         } else if((PINB & 1) == 0) {
478             pstate = 2;
479         }
480     } else if(pstate == 1) {
481         if((PINB & 1) == 0) {
482             pval++;
483             pstate = 3;
484         } else {
485             pstate = 0;
486         }
487     } else if(pstate == 2) {
488         if((PINB & 2) == 0) {
489             pval--;
490             pstate = 3;
491         } else {
492             pstate = 0;
493         }
494     } else {
495         if((PINB & 2) && (PINB & 1))
496             pstate = 0;
497     }
498 }