Updated thermistor constant.
[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)
6e7ff37b
FT
231 * T = B / ln(t / (A * C * ln(2)))
232 * Where:
233 * t = The measured time (s)
234 * R = The resistance of the thermistor (Ohm)
235 * C = The capacitance of the capacitor (F)
236 * T = The temperature (K)
237 * A, B are the thermistor-specific constants
238 *
239 * In the following code:
2f37b902 240 * a = ttimea as float
6e7ff37b 241 * C = 1e-6 / (A * C * ln(2))
2f37b902
FT
242 * ra = a * C
243 * l = ln(ra)
244 * t = B / l
245 * Note, temperature is in Kelvin
246 */
9f1265b0 247#define C 10.819112 /* A is 0.1333469 */
2f37b902
FT
248#define B 4020.0
249 if(state == 0) {
250 if((mnow - last > 200000) && tavgok) {
251 a = (float)ttimea;
252 state = 1;
253 tavgok = 0;
9ac074a9 254 last = mnow;
2f37b902
FT
255 }
256 } else if(state == 1) {
257 ra = a * C;
258 state = 2;
259 } else if(state == 2) {
260 l = log(ra);
261 state = 3;
262 } else if(state == 3) {
263 t = B / l;
264 state = 4;
265 } else if(state == 4) {
266 tempk = (int)t;
267 ktok = 1;
268 state = 0;
269 }
270}
271
31415646
FT
272int main(void)
273{
1eabd7a9 274 int state, cur, run, rstate, delta;
c1346a55 275 unsigned long utime;
31415646 276
9a754855
FT
277 state = 1;
278 cur = eeprom_read_byte(0);
279 if(cur < 0)
280 cur = 0;
281 if(cur > 100)
282 cur = 100;
174dfeb5 283 run = 0;
1eabd7a9 284 rstate = 0;
9a754855 285 utime = getticks();
31415646
FT
286 init();
287 sei();
9a754855
FT
288 if(cur < 100)
289 display(cur, 0, 0);
290 else
291 dsp[0] = dsp[1] = SEGG;
59d1e985 292
31415646 293 while(1) {
59d1e985 294 mnow = getticks();
31415646
FT
295 tempcycle();
296 calcavg();
2f37b902 297 convcycle();
31415646 298
63e3aac7 299#if 1
c1346a55
FT
300 /*
301 * User interface
302 */
303 if(state == 0) {
304 /* Display temperature */
2f37b902
FT
305 if(ktok) {
306 ktok = 0;
307 if((tempk >= 273) && (tempk <= 372)) {
cd47e1a3 308 display(tempk - 273, 0, run);
c1346a55 309 } else {
cd47e1a3
FT
310 dsp[0] = SEGG;
311 dsp[1] = SEGG | (run?SEGP:0);
c1346a55
FT
312 }
313 }
174dfeb5 314 if(pval != 0)
c1346a55 315 state = 1;
2f37b902
FT
316 if(sstate == 2) {
317 sstate = 0;
174dfeb5 318 if(stime > 10)
2f37b902 319 state = 2;
174dfeb5
FT
320 else
321 run = !run;
2f37b902 322 }
c1346a55 323 } else if(state == 1) {
174dfeb5 324 /* Temp setting */
c1346a55
FT
325 if(pval != 0) {
326 cur += pval;
327 pval = 0;
328 if(cur < 0)
329 cur = 0;
174dfeb5
FT
330 if(cur > 100)
331 cur = 100;
c1346a55
FT
332 utime = mnow;
333 }
9a754855 334 if(mnow - utime > 2000000) {
c1346a55 335 state = 0;
9a754855
FT
336 eeprom_write_byte(0, cur);
337 }
2f37b902 338 if(sstate == 2) {
174dfeb5 339 run = !run;
2f37b902
FT
340 sstate = 0;
341 }
66fcaf44
FT
342 if(cur < 100) {
343 display(cur, 0, run);
344 } else {
345 dsp[0] = SEGG;
346 dsp[1] = SEGG | (run?SEGP:0);
347 }
2f37b902 348 } else if(state == 2) {
174dfeb5 349 /* Display raw temp time reading */
2f37b902 350 if(ttimea < 20000) {
cd47e1a3 351 display((ttimea / 100) % 100, 1, ttimea >= 10000);
2f37b902 352 } else {
cd47e1a3 353 display(ttimea / 1000, 0, 0);
2f37b902
FT
354 }
355 if(sstate == 2) {
356 state = 0;
357 sstate = 0;
358 }
c1346a55 359 }
174dfeb5
FT
360 /*
361 * Set Triac to match temperature
362 */
363 if(run) {
1eabd7a9
FT
364 delta = cur - (tempk - 273);
365 if(rstate == 0) {
366 if(delta > 0) {
367 tron = 1;
368 if(delta > 8) {
369 /* For some reason, the Triac currently doesn't
370 * trigger on one of the AC half-cycles below 0.7
371 * ms. */
372 trdelay = 7;
373 } else {
3dc5ea11 374 trdelay = 75 - (delta * 5);
1eabd7a9 375 }
174dfeb5 376 } else {
1eabd7a9
FT
377 tron = 0;
378 rstate = 1;
174dfeb5 379 }
1eabd7a9 380 } else if(rstate == 1) {
174dfeb5 381 tron = 0;
1eabd7a9
FT
382 if(delta >= 2)
383 rstate = 0;
174dfeb5
FT
384 }
385 } else {
386 tron = 0;
387 }
c1346a55 388#endif
31415646
FT
389 /*
390 dsp[0] = bindisp((ttimea & 0xff00) >> 8);
391 dsp[1] = bindisp(ttimea & 0x00ff);
392 */
393 /*
394 disphex((ttimea & 0xff000) >> 12);
395 */
495bea06 396#if 0
59d1e985
FT
397 /*
398 Temp display
399 */
31415646
FT
400 if(ttimea < 20000) {
401 display((ttimea / 100) % 100);
402 dsp[0] |= SEGP;
403 if(ttimea >= 10000)
404 dsp[1] |= SEGP;
405 } else {
406 display(ttimea / 1000);
407 }
59d1e985 408#endif
2378926d 409#if 0
72ef9ac1
FT
410 /*
411 * ZVD debug
412 */
413 if(zok) {
414 if(++cur > 99)
415 cur = 0;
416 display(cur);
417 zok = 0;
418 }
63e3aac7 419#endif
c1346a55 420#if 0
495bea06
FT
421 /*
422 Phony Triac control
423 */
424 if(pval != 0) {
425 cur += pval;
426 if(cur < 0)
427 cur = 0;
428 if(cur > 99)
429 cur = 99;
430 display(cur);
c7732766 431 trdelay = 99 - cur;
495bea06
FT
432 pval = 0;
433 }
434 if(sstate == 2) {
435 tron = !tron;
436 sstate = 0;
437 }
4f42f213
FT
438 if(tron)
439 dsp[1] |= SEGP;
440 else
441 dsp[1] &= ~SEGP;
495bea06 442#endif
59d1e985 443#if 0
31415646 444 /*
59d1e985
FT
445 Pulse counter display
446 */
31415646
FT
447 cur += pval;
448 pval = 0;
449 if(sstate == 2) {
450 cur = stime;
451 sstate = 0;
452 }
453 if(cur > 99)
454 cur = 99;
455 if(cur < -99)
456 cur = -99;
457 if(cur < 0) {
458 display(-cur);
459 dsp[0] |= SEGP;
460 } else {
461 display(cur);
462 }
4f42f213
FT
463 if(PINB & 4)
464 dsp[1] |= SEGP;
59d1e985 465#endif
31415646
FT
466 }
467}
468
469ISR(SIG_INTERRUPT0)
470{
c7732766 471 ztime = 0;
59d1e985 472 zok = 1;
31415646
FT
473}
474
475ISR(SIG_INTERRUPT1)
476{
477 unsigned long now;
478
41fabc21 479 now = getticks();
31415646
FT
480 if(tstate == 0) {
481 tstate = 1;
482 if(tlock != 2)
483 ttime = now - tstart;
484 tstart = now;
485 PORTD |= 2;
486 tlock = 1;
487 }
488}
489
c7732766
FT
490ISR(SIG_OUTPUT_COMPARE0A)
491{
492 if(trstate == 0) {
493 ztime++;
494 if(tron && (ztime >= trdelay)) {
495 PORTD |= 1;
496 trstate = 1;
497 trtime = 0;
498 }
499 } else if(trstate == 1) {
500 trtime++;
501 if(trtime >= 5) {
502 PORTD &= ~1;
503 trstate = 0;
504 }
505 }
506}
507
8c536798
FT
508ISR(SIG_OUTPUT_COMPARE2A)
509{
510 ledcycle();
511}
512
31415646
FT
513ISR(SIG_OVERFLOW1)
514{
31415646
FT
515 oticks++;
516}
517
518ISR(SIG_PIN_CHANGE0)
519{
4f42f213 520 if((sstate == 0) && !(PINB & 4)) {
31415646
FT
521 stime = oticks;
522 sstate = 1;
523 }
4f42f213 524 if((sstate == 1) && (PINB & 4)) {
31415646
FT
525 stime = oticks - stime;
526 sstate = 2;
527 }
528 if(pstate == 0) {
529 if((PINB & 2) == 0) {
530 pstate = 1;
2378926d 531 } else if((PINB & 1) == 0) {
31415646
FT
532 pstate = 2;
533 }
534 } else if(pstate == 1) {
2378926d 535 if((PINB & 1) == 0) {
31415646
FT
536 pval++;
537 pstate = 3;
538 } else {
539 pstate = 0;
540 }
541 } else if(pstate == 2) {
542 if((PINB & 2) == 0) {
543 pval--;
544 pstate = 3;
545 } else {
546 pstate = 0;
547 }
548 } else {
2378926d 549 if((PINB & 2) && (PINB & 1))
31415646
FT
550 pstate = 0;
551 }
552}