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