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