Merge branch 'master' of git.dolda2000.com:/srv/git/r/kokare
[kokare.git] / kokare.c
1 #include <avr/io.h>
2 #include <avr/interrupt.h>
3 #include <inttypes.h>
4
5 #define SEGA 128
6 #define SEGB 64
7 #define SEGC 4
8 #define SEGD 16
9 #define SEGE 32
10 #define SEGF 2
11 #define SEGG 1
12 #define SEGP 8
13
14 uint8_t font[16] = {
15     SEGA | SEGB | SEGC | SEGD | SEGE | SEGF,
16     SEGB | SEGC,
17     SEGA | SEGB | SEGD | SEGE | SEGG,
18     SEGA | SEGB | SEGC | SEGD | SEGG,
19     SEGB | SEGC | SEGF | SEGG,
20     SEGA | SEGC | SEGD | SEGF | SEGG,
21     SEGA | SEGC | SEGD | SEGE | SEGF | SEGG,
22     SEGA | SEGB | SEGC,
23     SEGA | SEGB | SEGC | SEGD | SEGE | SEGF | SEGG,
24     SEGA | SEGB | SEGC | SEGD | SEGF | SEGG,
25     SEGA | SEGB | SEGC | SEGE | SEGF | SEGG,
26     SEGC | SEGD | SEGE | SEGF | SEGG,
27     SEGA | SEGD | SEGE | SEGF,
28     SEGB | SEGC | SEGD | SEGE | SEGG,
29     SEGA | SEGD | SEGE | SEGF | SEGG,
30     SEGA | SEGE | SEGF | SEGG,
31 };
32 /* LED */
33 uint8_t dsp[2] = {0, 0};
34 char leda = 0;
35 char ledc = 0;
36 /* Timer */
37 char of = 0;
38 int oticks = 0;
39 unsigned long mnow;
40 /* Pulse counter */
41 char pstate = 0;
42 char pval = 0;
43 /* Switch */
44 char sstate = 0;
45 int stime = 0;
46 /* Temp sensor */
47 char tstate = 0;
48 char tlock = 0;
49 unsigned long tstart;
50 unsigned long ttime;
51 unsigned long ttimea = 10000;
52 char tavgok = 0;
53 /* Zero-cross detector*/
54 char zok = 0;
55 unsigned long ztime;
56 /* Triac */
57 char trstate = 0;
58 char tron = 0;
59 unsigned long trtime;
60 unsigned short trdelay = 0;
61
62 void init(void)
63 {
64     /* Timer init */
65     TCCR1A = 0;
66     TCCR1B = 1;
67     TIMSK1 = 1;
68     
69     /*
70      * B0..2 = Pulse sensor
71      * B3..5 = ISP
72      * B6..7 = CLK
73      */
74     DDRB = 0x38;
75     PORTB = 0x07;
76     PCMSK0 = 0x07;
77     PCICR = 0x01;
78     /*
79      * C0..5 = LEDA0..5
80      * C6 = /RESET
81      * C7 = NC
82      */
83     DDRC = 0x3f;
84     PORTC = 0x00;
85     /*
86      * D0 = Triac
87      * D1 = NTC FET
88      * D2 = ZCD (INT0)
89      * D3 = NTC Op-amp (INT1)
90      * D4..5 = LEDA6..7
91      * D6..7 = LEDC0..1
92      */
93     DDRD = 0xf3;
94     PORTD = 0x00;
95     EICRA = 0x0d;
96     EIMSK = 0x03;
97 }
98
99 unsigned char bindisp(unsigned char num)
100 {
101     unsigned char ret;
102     
103     ret = 0;
104     if(num & 1)
105         ret |= SEGA;
106     if(num & 2)
107         ret |= SEGB;
108     if(num & 4)
109         ret |= SEGC;
110     if(num & 8)
111         ret |= SEGD;
112     if(num & 16)
113         ret |= SEGE;
114     if(num & 32)
115         ret |= SEGF;
116     if(num & 64)
117         ret |= SEGG;
118     if(num & 128)
119         ret |= SEGP;
120     return(ret);
121 }
122
123 void display(char num)
124 {
125     dsp[0] = font[(num / 10) % 10];
126     dsp[1] = font[num % 10];
127 }
128
129 void disphex(unsigned char num)
130 {
131     dsp[0] = font[(num & 0xf0) >> 4];
132     dsp[1] = font[num & 0x0f];
133 }
134
135 unsigned long getticks(void)
136 {
137     return(TCNT1 + (((unsigned long)oticks) << 16));
138 }
139
140 void ledcycle(void)
141 {
142     static uint16_t last = 0;
143     uint8_t c, d, v;
144     
145     if(TCNT1 - last > 500) {
146         last = TCNT1;
147         if(++leda >= 8) {
148             leda = 0;
149             if(++ledc >= 2)
150                 ledc = 0;
151         }
152         if(dsp[ledc] & (1 << leda)) {
153             if(leda < 6) {
154                 c = 1 << leda;
155                 d = 0;
156             } else {
157                 c = 0;
158                 d = 0x10 << (leda - 6);
159             }
160             d |= ledc?0x40:0x80;
161         } else {
162             c = d = 0;
163         }
164         PORTC = c;
165         PORTD = (PORTD & 0x0f) | d;
166     }
167 }
168
169 void tempcycle(void)
170 {
171     if(tstate == 0) {
172         if((PIND & 8) && (tlock == 0)) {
173             PORTD |= 2;
174             tstart = mnow;
175             tstate = 1;
176         }
177     } else if(tstate == 1) {
178         if(mnow - tstart > 1000) {
179             PORTD &= ~2;
180             tstate = 0;
181             tstart = mnow;
182         }
183     }
184 }
185
186 void calcavg(void)
187 {
188     if(tlock == 1) {
189         tlock = 2;
190         ttimea = ((ttimea * 15) + ttime) >> 4;
191         tlock = 0;
192         tavgok = 1;
193     }
194 }
195
196 void triaccycle(void)
197 {
198     if(trstate == 0) {
199         if(tron && zok && (mnow > ztime + trdelay)) {
200             PORTD |= 1;
201             zok = 0;
202             trstate = 1;
203             trtime = mnow;
204         }
205     } else if(trstate == 1) {
206         if(mnow > trtime + 500) {
207             PORTD &= ~1;
208             trstate = 0;
209         }
210     }
211 }
212
213 int main(void)
214 {
215     int state, cur;
216     unsigned long utime;
217     
218     state = 0;
219     cur = 99;
220     init();
221     sei();
222     display(0);
223
224     while(1) {
225         mnow = getticks();
226         ledcycle();
227         tempcycle();
228         calcavg();
229         triaccycle();
230
231 #if 0
232         /*
233          * User interface
234          */
235         if(state == 0) {
236             /* Display temperature */
237             if(tavgok) {
238                 tavgok = 0;
239                 if(ttimea < 20000) {
240                     display((ttimea / 100) % 100);
241                     dsp[0] |= SEGP;
242                     if(ttimea >= 10000)
243                         dsp[1] |= SEGP;
244                 } else {
245                     display(ttimea / 1000);
246                 }
247             }
248             if(pval != 0) {
249                 state = 1;
250                 utime = mnow;
251             }
252         } else if(state == 1) {
253             /* Triac control */
254             if(pval != 0) {
255                 cur += pval;
256                 pval = 0;
257                 if(cur < 0)
258                     cur = 0;
259                 if(cur > 99)
260                     cur = 99;
261                 display(cur);
262                 trdelay = 10000 - ((unsigned short)cur * 100);
263                 utime = mnow;
264             }
265             if(mnow - utime > 1000000) {
266                 state = 0;
267             }
268         }
269         if(sstate == 2) {
270             tron = !tron;
271             sstate = 0;
272         }
273 #endif
274         /*
275           dsp[0] = bindisp((ttimea & 0xff00) >> 8);
276           dsp[1] = bindisp(ttimea & 0x00ff);
277         */
278         /*
279           disphex((ttimea & 0xff000) >> 12);
280         */
281 #if 0
282         /*
283           Temp display
284         */
285         if(ttimea < 20000) {
286             display((ttimea / 100) % 100);
287             dsp[0] |= SEGP;
288             if(ttimea >= 10000)
289                 dsp[1] |= SEGP;
290         } else {
291             display(ttimea / 1000);
292         }
293 #endif
294 #if 1
295 #endif
296         /*
297          * ZVD debug
298          */
299         if(zok) {
300             if(++cur > 99)
301                 cur = 0;
302             display(cur);
303             zok = 0;
304         }
305 #if 0
306         /*
307           Phony Triac control
308          */
309         if(pval != 0) {
310             cur += pval;
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             pval = 0;
318         }
319         if(sstate == 2) {
320             tron = !tron;
321             sstate = 0;
322         }
323 #endif
324 #if 0
325         /*
326           Pulse counter display
327         */
328         cur += pval;
329         pval = 0;
330         if(sstate == 2) {
331             cur = stime;
332             sstate = 0;
333         }
334         if(cur > 99)
335             cur = 99;
336         if(cur < -99)
337             cur = -99;
338         if(cur < 0) {
339             display(-cur);
340             dsp[0] |= SEGP;
341         } else {
342             display(cur);
343         }
344 #endif
345     }
346 }
347
348 ISR(SIG_INTERRUPT0)
349 {
350     ztime = getticks();
351     zok = 1;
352 }
353
354 ISR(SIG_INTERRUPT1)
355 {
356     unsigned long now;
357     
358     now = getticks();
359     if(tstate == 0) {
360         tstate = 1;
361         if(tlock != 2)
362             ttime = now - tstart;
363         tstart = now;
364         PORTD |= 2;
365         tlock = 1;
366     }
367 }
368
369 ISR(SIG_OVERFLOW1)
370 {
371     of = 1;
372     oticks++;
373 }
374
375 ISR(SIG_PIN_CHANGE0)
376 {
377     if((sstate == 0) & ((PINB & 1) == 0)) {
378         stime = oticks;
379         sstate = 1;
380     }
381     if((sstate == 1) & ((PINB & 1) == 1)) {
382         stime = oticks - stime;
383         sstate = 2;
384     }
385     if(pstate == 0) {
386         if((PINB & 2) == 0) {
387             pstate = 1;
388         } else if((PINB & 4) == 0) {
389             pstate = 2;
390         }
391     } else if(pstate == 1) {
392         if((PINB & 4) == 0) {
393             pval++;
394             pstate = 3;
395         } else {
396             pstate = 0;
397         }
398     } else if(pstate == 2) {
399         if((PINB & 2) == 0) {
400             pval--;
401             pstate = 3;
402         } else {
403             pstate = 0;
404         }
405     } else {
406         if((PINB & 2) && (PINB & 4))
407             pstate = 0;
408     }
409 }