Only run the conversion cycle at 5 Hz.
[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;
9ac074a9 227 last = mnow;
2f37b902
FT
228 }
229 } else if(state == 1) {
230 ra = a * C;
231 state = 2;
232 } else if(state == 2) {
233 l = log(ra);
234 state = 3;
235 } else if(state == 3) {
236 t = B / l;
237 state = 4;
238 } else if(state == 4) {
239 tempk = (int)t;
240 ktok = 1;
241 state = 0;
242 }
243}
244
59d1e985
FT
245void triaccycle(void)
246{
247 if(trstate == 0) {
248 if(tron && zok && (mnow > ztime + trdelay)) {
249 PORTD |= 1;
250 zok = 0;
251 trstate = 1;
495bea06 252 trtime = mnow;
59d1e985
FT
253 }
254 } else if(trstate == 1) {
495bea06
FT
255 if(mnow > trtime + 500) {
256 PORTD &= ~1;
257 trstate = 0;
258 }
59d1e985
FT
259 }
260}
261
31415646
FT
262int main(void)
263{
c1346a55
FT
264 int state, cur;
265 unsigned long utime;
31415646 266
c1346a55
FT
267 state = 0;
268 cur = 99;
31415646
FT
269 init();
270 sei();
271 display(0);
59d1e985 272
31415646 273 while(1) {
59d1e985 274 mnow = getticks();
31415646
FT
275 ledcycle();
276 tempcycle();
277 calcavg();
2f37b902 278 convcycle();
59d1e985 279 triaccycle();
31415646 280
63e3aac7 281#if 1
c1346a55
FT
282 /*
283 * User interface
284 */
285 if(state == 0) {
286 /* Display temperature */
2f37b902
FT
287 if(ktok) {
288 ktok = 0;
289 if((tempk >= 273) && (tempk <= 372)) {
290 display(tempk - 273);
c1346a55 291 } else {
2f37b902 292 dsp[0] = dsp[1] = SEGG;
c1346a55
FT
293 }
294 }
295 if(pval != 0) {
296 state = 1;
297 utime = mnow;
298 }
2f37b902
FT
299 if(sstate == 2) {
300 sstate = 0;
301 if(stime > 10) {
302 state = 2;
303 } else {
304 tron = !tron;
305 }
306 }
c1346a55
FT
307 } else if(state == 1) {
308 /* Triac control */
309 if(pval != 0) {
310 cur += pval;
311 pval = 0;
312 if(cur < 0)
313 cur = 0;
314 if(cur > 99)
315 cur = 99;
316 display(cur);
317 trdelay = 10000 - ((unsigned short)cur * 100);
318 utime = mnow;
319 }
320 if(mnow - utime > 1000000) {
321 state = 0;
322 }
2f37b902
FT
323 if(sstate == 2) {
324 tron = !tron;
325 sstate = 0;
326 }
327 } else if(state == 2) {
328 if(ttimea < 20000) {
329 display((ttimea / 100) % 100);
330 dsp[0] |= SEGP;
331 if(ttimea >= 10000)
332 dsp[1] |= SEGP;
333 } else {
334 display(ttimea / 1000);
335 }
336 if(sstate == 2) {
337 state = 0;
338 sstate = 0;
339 }
c1346a55
FT
340 }
341#endif
31415646
FT
342 /*
343 dsp[0] = bindisp((ttimea & 0xff00) >> 8);
344 dsp[1] = bindisp(ttimea & 0x00ff);
345 */
346 /*
347 disphex((ttimea & 0xff000) >> 12);
348 */
495bea06 349#if 0
59d1e985
FT
350 /*
351 Temp display
352 */
31415646
FT
353 if(ttimea < 20000) {
354 display((ttimea / 100) % 100);
355 dsp[0] |= SEGP;
356 if(ttimea >= 10000)
357 dsp[1] |= SEGP;
358 } else {
359 display(ttimea / 1000);
360 }
59d1e985 361#endif
2378926d 362#if 0
72ef9ac1
FT
363 /*
364 * ZVD debug
365 */
366 if(zok) {
367 if(++cur > 99)
368 cur = 0;
369 display(cur);
370 zok = 0;
371 }
63e3aac7 372#endif
c1346a55 373#if 0
495bea06
FT
374 /*
375 Phony Triac control
376 */
377 if(pval != 0) {
378 cur += pval;
379 if(cur < 0)
380 cur = 0;
381 if(cur > 99)
382 cur = 99;
383 display(cur);
384 trdelay = 10000 - ((unsigned short)cur * 100);
385 pval = 0;
386 }
387 if(sstate == 2) {
388 tron = !tron;
389 sstate = 0;
390 }
4f42f213
FT
391 if(tron)
392 dsp[1] |= SEGP;
393 else
394 dsp[1] &= ~SEGP;
495bea06 395#endif
59d1e985 396#if 0
31415646 397 /*
59d1e985
FT
398 Pulse counter display
399 */
31415646
FT
400 cur += pval;
401 pval = 0;
402 if(sstate == 2) {
403 cur = stime;
404 sstate = 0;
405 }
406 if(cur > 99)
407 cur = 99;
408 if(cur < -99)
409 cur = -99;
410 if(cur < 0) {
411 display(-cur);
412 dsp[0] |= SEGP;
413 } else {
414 display(cur);
415 }
4f42f213
FT
416 if(PINB & 4)
417 dsp[1] |= SEGP;
59d1e985 418#endif
31415646
FT
419 }
420}
421
422ISR(SIG_INTERRUPT0)
423{
59d1e985
FT
424 ztime = getticks();
425 zok = 1;
31415646
FT
426}
427
428ISR(SIG_INTERRUPT1)
429{
430 unsigned long now;
431
432 now = getticks();
433 if(tstate == 0) {
434 tstate = 1;
435 if(tlock != 2)
436 ttime = now - tstart;
437 tstart = now;
438 PORTD |= 2;
439 tlock = 1;
440 }
441}
442
443ISR(SIG_OVERFLOW1)
444{
445 of = 1;
446 oticks++;
447}
448
449ISR(SIG_PIN_CHANGE0)
450{
4f42f213 451 if((sstate == 0) && !(PINB & 4)) {
31415646
FT
452 stime = oticks;
453 sstate = 1;
454 }
4f42f213 455 if((sstate == 1) && (PINB & 4)) {
31415646
FT
456 stime = oticks - stime;
457 sstate = 2;
458 }
459 if(pstate == 0) {
460 if((PINB & 2) == 0) {
461 pstate = 1;
2378926d 462 } else if((PINB & 1) == 0) {
31415646
FT
463 pstate = 2;
464 }
465 } else if(pstate == 1) {
2378926d 466 if((PINB & 1) == 0) {
31415646
FT
467 pval++;
468 pstate = 3;
469 } else {
470 pstate = 0;
471 }
472 } else if(pstate == 2) {
473 if((PINB & 2) == 0) {
474 pval--;
475 pstate = 3;
476 } else {
477 pstate = 0;
478 }
479 } else {
2378926d 480 if((PINB & 2) && (PINB & 1))
31415646
FT
481 pstate = 0;
482 }
483}