Better Triac triggering.
[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 /* Zero-cross detector*/
53 char zok = 0;
54 unsigned long ztime;
55 /* Triac */
56 char trstate = 0;
57 char tron = 0;
58 unsigned long trtime;
59 unsigned short trdelay = 0;
60
61 void init(void)
62 {
63     /* Timer init */
64     TCCR1A = 0;
65     TCCR1B = 1;
66     TIMSK1 = 1;
67     
68     /*
69      * B0..2 = Pulse sensor
70      * B3..5 = ISP
71      * B6..7 = CLK
72      */
73     DDRB = 0x30;
74     PORTB = 0x07;
75     PCMSK0 = 0x07;
76     PCICR = 0x01;
77     /*
78      * C0..5 = LEDA0..5
79      * C6 = /RESET
80      * C7 = NC
81      */
82     DDRC = 0x3f;
83     PORTC = 0x00;
84     /*
85      * D0 = Triac
86      * D1 = NTC FET
87      * D2 = ZCD (INT0)
88      * D3 = NTC Op-amp (INT1)
89      * D4..5 = LEDA6..7
90      * D6..7 = LEDC0..1
91      */
92     DDRD = 0xf3;
93     PORTD = 0x00;
94     EICRA = 0x0d;
95     EIMSK = 0x03;
96 }
97
98 unsigned char bindisp(unsigned char num)
99 {
100     unsigned char ret;
101     
102     ret = 0;
103     if(num & 1)
104         ret |= SEGA;
105     if(num & 2)
106         ret |= SEGB;
107     if(num & 4)
108         ret |= SEGC;
109     if(num & 8)
110         ret |= SEGD;
111     if(num & 16)
112         ret |= SEGE;
113     if(num & 32)
114         ret |= SEGF;
115     if(num & 64)
116         ret |= SEGG;
117     if(num & 128)
118         ret |= SEGP;
119     return(ret);
120 }
121
122 void display(char num)
123 {
124     dsp[0] = font[(num / 10) % 10];
125     dsp[1] = font[num % 10];
126 }
127
128 void disphex(unsigned char num)
129 {
130     dsp[0] = font[(num & 0xf0) >> 4];
131     dsp[1] = font[num & 0x0f];
132 }
133
134 unsigned long getticks(void)
135 {
136     return(TCNT1 + (((unsigned long)oticks) << 16));
137 }
138
139 void ledcycle(void)
140 {
141     static uint16_t last = 0;
142     uint8_t c, d, v;
143     
144     if(TCNT1 - last > 500) {
145         last = TCNT1;
146         if(++leda >= 8) {
147             leda = 0;
148             if(++ledc >= 2)
149                 ledc = 0;
150         }
151         if(dsp[ledc] & (1 << leda)) {
152             if(leda < 6) {
153                 c = 1 << leda;
154                 d = 0;
155             } else {
156                 c = 0;
157                 d = 0x10 << (leda - 6);
158             }
159             d |= ledc?0x40:0x80;
160         } else {
161             c = d = 0;
162         }
163         PORTC = c;
164         PORTD = (PORTD & 0x0f) | d;
165     }
166 }
167
168 void tempcycle(void)
169 {
170     if(tstate == 0) {
171         if((PIND & 8) && (tlock == 0)) {
172             PORTD |= 2;
173             tstart = mnow;
174             tstate = 1;
175         }
176     } else if(tstate == 1) {
177         if(mnow - tstart > 1000) {
178             PORTD &= ~2;
179             tstate = 0;
180             tstart = mnow;
181         }
182     }
183 }
184
185 void calcavg(void)
186 {
187     if(tlock == 1) {
188         tlock = 2;
189         ttimea = ((ttimea * 15) + ttime) >> 4;
190         tlock = 0;
191     }
192 }
193
194 void triaccycle(void)
195 {
196     if(trstate == 0) {
197         if(tron && zok && (mnow > ztime + trdelay)) {
198             PORTD |= 1;
199             zok = 0;
200             trstate = 1;
201             trtime = mnow;
202         }
203     } else if(trstate == 1) {
204         if(mnow > trtime + 500) {
205             PORTD &= ~1;
206             trstate = 0;
207         }
208     }
209 }
210
211 int main(void)
212 {
213     int cur;
214     
215     cur = 0;
216     init();
217     sei();
218     display(0);
219
220     while(1) {
221         mnow = getticks();
222         ledcycle();
223         tempcycle();
224         calcavg();
225         triaccycle();
226
227         /*
228           dsp[0] = bindisp((ttimea & 0xff00) >> 8);
229           dsp[1] = bindisp(ttimea & 0x00ff);
230         */
231         /*
232           disphex((ttimea & 0xff000) >> 12);
233         */
234 #if 0
235         /*
236           Temp display
237         */
238         if(ttimea < 20000) {
239             display((ttimea / 100) % 100);
240             dsp[0] |= SEGP;
241             if(ttimea >= 10000)
242                 dsp[1] |= SEGP;
243         } else {
244             display(ttimea / 1000);
245         }
246 #endif
247 #if 1
248         /*
249           Phony Triac control
250          */
251         if(pval != 0) {
252             cur += pval;
253             if(cur < 0)
254                 cur = 0;
255             if(cur > 99)
256                 cur = 99;
257             display(cur);
258             trdelay = 10000 - ((unsigned short)cur * 100);
259             pval = 0;
260         }
261         if(sstate == 2) {
262             tron = !tron;
263             sstate = 0;
264         }
265 #endif
266 #if 0
267         /*
268           Pulse counter display
269         */
270         cur += pval;
271         pval = 0;
272         if(sstate == 2) {
273             cur = stime;
274             sstate = 0;
275         }
276         if(cur > 99)
277             cur = 99;
278         if(cur < -99)
279             cur = -99;
280         if(cur < 0) {
281             display(-cur);
282             dsp[0] |= SEGP;
283         } else {
284             display(cur);
285         }
286 #endif
287     }
288 }
289
290 ISR(SIG_INTERRUPT0)
291 {
292     ztime = getticks();
293     zok = 1;
294 }
295
296 ISR(SIG_INTERRUPT1)
297 {
298     unsigned long now;
299     
300     now = getticks();
301     if(tstate == 0) {
302         tstate = 1;
303         if(tlock != 2)
304             ttime = now - tstart;
305         tstart = now;
306         PORTD |= 2;
307         tlock = 1;
308     }
309 }
310
311 ISR(SIG_OVERFLOW1)
312 {
313     of = 1;
314     oticks++;
315 }
316
317 ISR(SIG_PIN_CHANGE0)
318 {
319     if((sstate == 0) & ((PINB & 1) == 0)) {
320         stime = oticks;
321         sstate = 1;
322     }
323     if((sstate == 1) & ((PINB & 1) == 1)) {
324         stime = oticks - stime;
325         sstate = 2;
326     }
327     if(pstate == 0) {
328         if((PINB & 2) == 0) {
329             pstate = 1;
330         } else if((PINB & 4) == 0) {
331             pstate = 2;
332         }
333     } else if(pstate == 1) {
334         if((PINB & 4) == 0) {
335             pval++;
336             pstate = 3;
337         } else {
338             pstate = 0;
339         }
340     } else if(pstate == 2) {
341         if((PINB & 2) == 0) {
342             pval--;
343             pstate = 3;
344         } else {
345             pstate = 0;
346         }
347     } else {
348         if((PINB & 2) && (PINB & 4))
349             pstate = 0;
350     }
351 }