Cycle the display from the Timer2 interrupt.
[kokare.git] / kokare.c
... / ...
CommitLineData
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
15uint8_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 */
34uint8_t dsp[2] = {0, 0};
35char leda = 0;
36char ledc = 0;
37/* Timer */
38volatile char of = 0;
39volatile int oticks = 0;
40unsigned long mnow;
41/* Pulse counter */
42volatile char pstate = 0;
43char pval = 0;
44/* Switch */
45volatile char sstate = 0;
46int stime = 0;
47/* Temp sensor */
48volatile char tstate = 0;
49volatile char tlock = 0;
50unsigned long tstart;
51unsigned long ttime;
52unsigned long ttimea = 10000;
53char tavgok = 0;
54/* Conversion loop */
55int tempk;
56volatile ktok = 0;
57/* Zero-cross detector*/
58volatile char zok = 0;
59volatile char ztime = 0;
60/* Triac */
61char trstate = 0;
62char tron = 0;
63volatile char trtime;
64volatile char trdelay = 0;
65
66void 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
115unsigned 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
139void display(char num)
140{
141 dsp[0] = font[(num / 10) % 10];
142 dsp[1] = font[num % 10];
143}
144
145void disphex(unsigned char num)
146{
147 dsp[0] = font[(num & 0xf0) >> 4];
148 dsp[1] = font[num & 0x0f];
149}
150
151unsigned long getticks(void)
152{
153 return(TCNT1 + (((unsigned long)oticks) << 16));
154}
155
156void 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
181void 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
202void 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
212void 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
256int 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
414ISR(SIG_INTERRUPT0)
415{
416 ztime = 0;
417 zok = 1;
418}
419
420ISR(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
435ISR(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
453ISR(SIG_OUTPUT_COMPARE2A)
454{
455 ledcycle();
456}
457
458ISR(SIG_OVERFLOW1)
459{
460 of = 1;
461 oticks++;
462}
463
464ISR(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}