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