Run Triac cycle in Timer0 interrupt.
[kokare.git] / kokare.c
... / ...
CommitLineData
1#include <avr/io.h>
2#include <avr/interrupt.h>
3#include <inttypes.h>
4#include <math.h>
5
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
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 */
34#define LCDELAY 1000
35uint8_t dsp[2] = {0, 0};
36char leda = 0;
37char ledc = 0;
38/* Timer */
39volatile char of = 0;
40volatile int oticks = 0;
41unsigned long mnow;
42/* Pulse counter */
43volatile char pstate = 0;
44char pval = 0;
45/* Switch */
46volatile char sstate = 0;
47int stime = 0;
48/* Temp sensor */
49volatile char tstate = 0;
50volatile char tlock = 0;
51unsigned long tstart;
52unsigned long ttime;
53unsigned long ttimea = 10000;
54char tavgok = 0;
55/* Conversion loop */
56int tempk;
57volatile ktok = 0;
58/* Zero-cross detector*/
59volatile char zok = 0;
60volatile char ztime = 0;
61/* Triac */
62char trstate = 0;
63char tron = 0;
64volatile char trtime;
65volatile char trdelay = 0;
66
67void init(void)
68{
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;
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 */
86 DDRB = 0x38;
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
157 if(TCNT1 - last > LCDELAY) {
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 }
176 cli();
177 PORTC = c;
178 PORTD = (PORTD & 0x0f) | d;
179 sei();
180 }
181}
182
183void tempcycle(void)
184{
185 if(tstate == 0) {
186 if((PIND & 8) && (tlock == 0)) {
187 cli();
188 PORTD |= 2;
189 sei();
190 tstart = mnow;
191 tstate = 1;
192 }
193 } else if(tstate == 1) {
194 if(mnow - tstart > 1000) {
195 cli();
196 PORTD &= ~2;
197 sei();
198 tstate = 0;
199 tstart = mnow;
200 }
201 }
202}
203
204void calcavg(void)
205{
206 if(tlock == 1) {
207 tlock = 2;
208 ttimea = ((ttimea * 15) + ttime) >> 4;
209 tlock = 0;
210 tavgok = 1;
211 }
212}
213
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;
240 last = mnow;
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
258int main(void)
259{
260 int state, cur;
261 unsigned long utime;
262
263 state = 0;
264 cur = 99;
265 init();
266 sei();
267 display(0);
268
269 while(1) {
270 mnow = getticks();
271 ledcycle();
272 tempcycle();
273 calcavg();
274 convcycle();
275
276#if 1
277 /*
278 * User interface
279 */
280 if(state == 0) {
281 /* Display temperature */
282 if(ktok) {
283 ktok = 0;
284 if((tempk >= 273) && (tempk <= 372)) {
285 display(tempk - 273);
286 } else {
287 dsp[0] = dsp[1] = SEGG;
288 }
289 }
290 if(pval != 0) {
291 state = 1;
292 utime = mnow;
293 }
294 if(sstate == 2) {
295 sstate = 0;
296 if(stime > 10) {
297 state = 2;
298 } else {
299 tron = !tron;
300 }
301 }
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);
312 trdelay = 99 - cur;
313 utime = mnow;
314 }
315 if(mnow - utime > 1000000) {
316 state = 0;
317 }
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 }
335 }
336#endif
337 /*
338 dsp[0] = bindisp((ttimea & 0xff00) >> 8);
339 dsp[1] = bindisp(ttimea & 0x00ff);
340 */
341 /*
342 disphex((ttimea & 0xff000) >> 12);
343 */
344#if 0
345 /*
346 Temp display
347 */
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 }
356#endif
357#if 0
358 /*
359 * ZVD debug
360 */
361 if(zok) {
362 if(++cur > 99)
363 cur = 0;
364 display(cur);
365 zok = 0;
366 }
367#endif
368#if 0
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);
379 trdelay = 99 - cur;
380 pval = 0;
381 }
382 if(sstate == 2) {
383 tron = !tron;
384 sstate = 0;
385 }
386 if(tron)
387 dsp[1] |= SEGP;
388 else
389 dsp[1] &= ~SEGP;
390#endif
391#if 0
392 /*
393 Pulse counter display
394 */
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 }
411 if(PINB & 4)
412 dsp[1] |= SEGP;
413#endif
414 }
415}
416
417ISR(SIG_INTERRUPT0)
418{
419 ztime = 0;
420 zok = 1;
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
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
456ISR(SIG_OVERFLOW1)
457{
458 of = 1;
459 oticks++;
460}
461
462ISR(SIG_PIN_CHANGE0)
463{
464 if((sstate == 0) && !(PINB & 4)) {
465 stime = oticks;
466 sstate = 1;
467 }
468 if((sstate == 1) && (PINB & 4)) {
469 stime = oticks - stime;
470 sstate = 2;
471 }
472 if(pstate == 0) {
473 if((PINB & 2) == 0) {
474 pstate = 1;
475 } else if((PINB & 1) == 0) {
476 pstate = 2;
477 }
478 } else if(pstate == 1) {
479 if((PINB & 1) == 0) {
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 {
493 if((PINB & 2) && (PINB & 1))
494 pstate = 0;
495 }
496}