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