#include #include #include #define TEMP_PIN 0 #define IMPULS0_PIN 1 #define IMPULS1_PIN 2 #define TAST_PIN 3 #define FET0_PIN 0 #define FET1_PIN 1 #define TIMEOUT 51 /* 2 seconds */ const uint16_t TARGET_TEMP_MAX = 1520; uint8_t led_color = 0; uint8_t setting_timeout = 0; uint8_t adc_pos = 0; uint16_t adc_sum = 0; uint16_t temperature_adc = 0; uint16_t target = 0; uint16_t temperature = 0; uint8_t heat_output = 0; uint8_t heat_pwm = 0; uint8_t heat_on[2] = {0, 0}; uint8_t heat_off[2] = {0, 0}; uint8_t input_state = 0; uint8_t dev_state = 0; /* gray code to change lookup table, index is old state .. new state */ int8_t state_change[16] = {0, 1, -1, 0, -1, 0, 0, 1, 1, 0, 0, -1, 0, -1, 1, 0}; ISR(TIM1_OVF_vect) { /* timeout for displaying target temperature */ if(setting_timeout) {setting_timeout--;} /* incremtening softpwm, toggling output if needed */ heat_pwm++; if(heat_pwm == heat_on[0]) {PORTB |= (1 << FET0_PIN);} if(heat_pwm == heat_off[0]) {PORTB &= ~(1 << FET0_PIN);} if(heat_pwm == heat_on[1]) {PORTB |= (1 << FET1_PIN);} if(heat_pwm == heat_off[1]) {PORTB &= ~(1 << FET1_PIN);} } ISR(PCINT0_vect) { uint8_t new_state = (PORTA & ((1 << IMPULS1_PIN) | (1 << IMPULS0_PIN) | (1 << TAST_PIN))) >> 1; uint8_t diff = new_state ^ input_state; if(!diff) {return;} if(diff & (1 << TAST_PIN) && new_state & (1 << TAST_PIN)) { dev_state = !dev_state; } int8_t change = state_change[((input_state & 3) << 2) | (new_state & 3)]; if(change) { target += change; setting_timeout = TIMEOUT; } input_state = new_state; } uint8_t control_output(uint16_t current_temp, uint16_t target_temp) { if (current_temp > target_temp) { return 0; } else { return (uint8_t)((uint16_t)((uint32_t)((uint32_t)255*target_temp)/current_temp)/TARGET_TEMP_MAX); } } // Measure: 5V --- 10k --- --- PTY81-121 -- GND // | // uC ADC pin (with 1.11V reference) uint16_t linearize_temp(uint16_t temp_in) { uint16_t temp_out = TARGET_TEMP_MAX; //burning // made from datasheet by: // for i in 677 740 807 877 951 1029 1111 1196 1286 1378 1475 1575 1679 1786 1896 2003 2103 2189; do calc 5*$i/9860*65472/1.11; done static const uint16_t coeffs[] = { // in, out 20250, 0, // -20 celsius 22134, 0, // -10 celsius 24138, 0, // 0 celsius 26232, 100, // 10 celsius 28445, 200, 30778, 300, 33231, 400, // 40 celsius 35773, 500, // .. 38465, 600, 41216, 700, 44118, 800, 47109, 900, 50220, 1000, 53420, 1100, 56711, 1200, 59911, 1300, 62902, 1400, 65474, 1500, // 150 celsius 65535, 1520, // made-up, not from datasheet }; uint8_t i=2; for (; i < (sizeof(coeffs)>>1)-2; i+=2) { if ( temp_in < coeffs[i] ) { temp_out = (uint16_t) ( coeffs[i-1] + (uint32_t) ( (uint32_t) (temp_in-coeffs[i-2]) * (coeffs[i+1]-coeffs[i-1]) ) / (coeffs[i]-coeffs[i-2])); break; } } return temp_out; } void io_init(void) { PORTA = (1 << TAST_PIN) | (1 << IMPULS1_PIN) | (1 << IMPULS0_PIN);/* enable pullups on inputs */ PORTB = 0; DDRA = (1 << PA7);/* led outputs ... */ DDRB = (1 << PB2) | (1 << FET0_PIN) | (1 << FET1_PIN);/* ... and FET output */ input_state = PORTA & ((1 << IMPULS1_PIN) | (1 << IMPULS0_PIN) | (1 << TAST_PIN)); } void led_init(void) { TCCR0A = (1 << COM0A1) | (1 << COM0B1) | (1 << COM0B0) | (1 << WGM01) | (1 << WGM00);/* pwm enable: fast, A not inverted, B inverted */ TCCR0B = (1 << CS02) | (1 << CS00);/* prescaler / 1024 */ OCR0A = OCR0B = led_color; } void led_set(uint16_t value) { OCR0A = OCR0B = led_color = value >> 8; } void led_off(void) { OCR0A = 0; OCR0B = 255; } void adc_init(void) { ADMUX = (1 << REFS1) | (TEMP_PIN << MUX0);/* Vref = 1.1, pin selection */ ADCSRA = (1 << ADEN) | (1 << ADATE);/* adc enable, triggered */ ADCSRB = (1 << ADTS2);/* trigger on counter 0 overflow */ DIDR0 = (1 << TEMP_PIN);/* disable digital input on adc pin */ /* result in (ADCH << 8) | ADCL, accessable as ADC? */ } void heat_init(void) { TCCR1B = (1 << WGM12) | (1 << CS10);/* some mode allowing to set timer TOP, no prescaler */ TIMSK1 = (1 << TOIE1);/* interupt on overflow */ OCR1A = 39063; /* insert loading of heat setting here */ } void input_init(void) { GIMSK = (1 << PCIE0);/* interrupt on change on PORT A */ PCMSK0 = (1 << TAST_PIN) | (1 << IMPULS1_PIN) | (1 << IMPULS0_PIN); } int main(void) { /* if we store the last setting somewhere calculate led_color from it before calling led_init() */ io_init(); led_init(); adc_init(); heat_init(); input_init(); for(;;) { if(ADCSRA & (1 << ADIF)) { /* new adc result */ ADCSRA |= (1 << ADIF); adc_sum += ADC; if(++adc_pos == 64) { temperature_adc = adc_sum; adc_sum = 0; adc_pos = 0; temperature = linearize_temp(temperature_adc); if(dev_state) { heat_output = control_output(temperature, target); heat_on[0] = 0; heat_on[1] = 128; heat_off[0] = heat_output; heat_off[1] = heat_output + 128; } else { heat_on[0] = heat_on[1] = heat_off[0] = heat_off[1] = 0; } } } if(!dev_state) {led_off();} else if(setting_timeout) {led_set(target);} else {led_set(temperature);} } return 0; }