2 #include <avr/interrupt.h>
16 SEGA | SEGB | SEGC | SEGD | SEGE | SEGF,
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,
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,
34 uint8_t dsp[2] = {0, 0};
38 volatile int oticks = 0;
41 volatile char pstate = 0;
44 volatile char sstate = 0;
47 volatile char tstate = 0;
48 volatile char tlock = 0;
51 unsigned long ttimea = 10000;
56 /* Zero-cross detector*/
57 volatile char zok = 0;
58 volatile char ztime = 0;
63 volatile char trdelay = 0;
68 * Timer 0 cycles the Triac
69 * Timer 1 is used for global timing
70 * Timer 2 cycles the LED display
85 * B0..2 = Pulse sensor
104 * D3 = NTC Op-amp (INT1)
114 unsigned char bindisp(unsigned char num)
138 void display(char num)
140 dsp[0] = font[(num / 10) % 10];
141 dsp[1] = font[num % 10];
144 void disphex(unsigned char num)
146 dsp[0] = font[(num & 0xf0) >> 4];
147 dsp[1] = font[num & 0x0f];
151 * This version is used outside interrupts.
152 * It spins until no overflow has happened.
154 unsigned long getticks(void)
161 r = TCNT1 + (((unsigned long)oticks) << 16);
162 } while(v != oticks);
167 * This version is used in interrupts
169 unsigned long getticks2(void)
175 r = v + (((unsigned long)oticks) << 16);
176 if((TIFR1 & 0x01) && !(v & 0x8000))
191 if(dsp[ledc] & (1 << leda)) {
197 d = 0x10 << (leda - 6);
204 PORTD = (PORTD & 0x0f) | d;
210 if((PIND & 8) && (tlock == 0)) {
217 } else if(tstate == 1) {
218 if(mnow - tstart > 1000) {
232 ttimea = ((ttimea * 15) + ttime) >> 4;
240 static char state = 0;
241 static unsigned long last = 0;
242 static float a, ra, l, t;
246 * t = RC * ln(2) => R = t / (C * ln(2))
247 * R = A * exp(B / T) => T = B / ln(R / A)
248 * T = B / ln(R / (A * C * ln(2)))
250 * a = ttimea as float
251 * C = 1e6 / (A * C * ln(2))
255 * Note, temperature is in Kelvin
260 if((mnow - last > 200000) && tavgok) {
266 } else if(state == 1) {
269 } else if(state == 2) {
272 } else if(state == 3) {
275 } else if(state == 4) {
305 /* Display temperature */
308 if((tempk >= 273) && (tempk <= 372)) {
309 display(tempk - 273);
311 dsp[0] = dsp[1] = SEGG;
327 } else if(state == 1) {
339 dsp[0] = dsp[1] = SEGG;
342 if(mnow - utime > 1000000)
348 } else if(state == 2) {
349 /* Display raw temp time reading */
351 display((ttimea / 100) % 100);
356 display(ttimea / 1000);
364 * Set Triac to match temperature
367 if(tempk - 273 < cur) {
369 if(cur - (tempk - 273) > 5) {
370 /* For some reason, the Triac currently doesn't
371 * trigger on one of the AC half-cycles below 0.7
374 } else if(cur - (tempk - 273) >= 3) {
376 } else if(cur - (tempk - 273) >= 2) {
389 dsp[0] = bindisp((ttimea & 0xff00) >> 8);
390 dsp[1] = bindisp(ttimea & 0x00ff);
393 disphex((ttimea & 0xff000) >> 12);
400 display((ttimea / 100) % 100);
405 display(ttimea / 1000);
444 Pulse counter display
482 ttime = now - tstart;
489 ISR(SIG_OUTPUT_COMPARE0A)
493 if(tron && (ztime >= trdelay)) {
498 } else if(trstate == 1) {
507 ISR(SIG_OUTPUT_COMPARE2A)
519 if((sstate == 0) && !(PINB & 4)) {
523 if((sstate == 1) && (PINB & 4)) {
524 stime = oticks - stime;
528 if((PINB & 2) == 0) {
530 } else if((PINB & 1) == 0) {
533 } else if(pstate == 1) {
534 if((PINB & 1) == 0) {
540 } else if(pstate == 2) {
541 if((PINB & 2) == 0) {
548 if((PINB & 2) && (PINB & 1))