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