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