#include #include #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 */ #define LED_GREEN_TEMP 300 //#define LED_RED_TEMP 1000 #define LED_RED_TEMP 800 #define TARGET_TEMP_MIN 300 #define TARGET_TEMP_MAX 1050 uint8_t setting_timeout = 0; uint8_t adc_pos = 0; uint16_t adc_sum = 0; uint16_t target = 0; uint16_t temperature = 0; // all temperatures are in tenth of degrees celsius uint8_t heat_pwm = 0; // softpwm counter uint8_t heat_power = 0; // requested heating power; 0..255 //uint8_t heat_on[2] = {0, 128}; //uint8_t heat_off[2] = {128, 0}; uint8_t input_state = 0; uint8_t dev_state = 0; // whether the device is on or off uint8_t led_is_on = 0; // whether led is on or off; used to start/stop timer 0 #define TOGGLE_TIMEOUT 5 #define TEN_SECONDS 256 #define ONE_MINUTE 1536 #define ONE_HOUR 92160 uint8_t toggle_timeout = 0; uint16_t startup = TEN_SECONDS; uint8_t eeprom_write = 0; uint16_t eeprom_clk = ONE_MINUTE; uint32_t shutdown = 2 * (uint32_t) ONE_HOUR; /* 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}; //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(toggle_timeout) {toggle_timeout--;} if(setting_timeout) {setting_timeout--;} if(startup) {startup--;} if(eeprom_clk) {eeprom_clk--;} else { eeprom_write = 1; eeprom_clk = ONE_MINUTE; } if(shutdown) {shutdown--;} else {dev_state = 0;} /* incremtening softpwm, toggling output if needed */ heat_pwm++; if(heat_pwm == 0 && heat_power > 0) { PORTB |= (1 << FET0_PIN); } else if(heat_pwm > heat_power) { PORTB &= ~(1 << FET0_PIN); } if(heat_pwm == 128 && heat_power > 0) { PORTB |= (1 << FET1_PIN); } else if( ((heat_pwm + 128) & 0xff) > heat_power ) { PORTB &= ~(1 << FET1_PIN); } /* 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 = (PINA & ((1 << IMPULS1_PIN) | (1 << IMPULS0_PIN) | (1 << TAST_PIN))) >> 1; uint8_t diff = new_state ^ input_state; if(!diff) {return;} if(!toggle_timeout && diff & (1 << (TAST_PIN - 1)) && new_state & (1 << (TAST_PIN - 1))) { dev_state = !dev_state; toggle_timeout = TOGGLE_TIMEOUT; if(dev_state) { device_on(); } else { device_off(); } } int8_t change = state_change[((input_state & 3) << 2) | (new_state & 3)]; if(change) { target += change * 6;//0.6K * 4 per step 10; // 1 celsius per step if(target < TARGET_TEMP_MIN) {target = TARGET_TEMP_MIN;} else if(target > TARGET_TEMP_MAX) {target = TARGET_TEMP_MAX;} //if(target < LED_GREEN_TEMP) {target = LED_GREEN_TEMP;} //else if(target > LED_RED_TEMP) {target = LED_RED_TEMP;} setting_timeout = TIMEOUT; } shutdown = 2 * (uint32_t) ONE_HOUR; input_state = new_state; } inline uint8_t control_output(void) { if(temperature > target) { return 0; } else if(temperature + 100 > target) { return (target - temperature) * 192 / 100; } else { return 255;//192; //return (uint8_t)((uint16_t)((uint32_t)((uint32_t)255*target)/temperature)/TARGET_TEMP_MAX); } } // Measure: 5V --- 10k --- --- PTY81-121 -- GND // | // uC ADC pin (with 1.11V reference) inline 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[] PROGMEM = { // 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, TARGET_TEMP_MAX // 152 celsius, made-up, not from datasheet }; uint8_t i=2; for(; i < sizeof(coeffs) / sizeof(coeffs[0]); i += 2) { if(temp_in < pgm_read_word(&coeffs[i])) { temp_out = (uint16_t) ( pgm_read_word(&coeffs[i-1]) + (uint32_t) ( (uint32_t) (temp_in - pgm_read_word(&coeffs[i-2])) * (pgm_read_word(&coeffs[i+1])-pgm_read_word(&coeffs[i-1])) ) / (pgm_read_word(&coeffs[i])-pgm_read_word(&coeffs[i-2]))); break; } } return temp_out; } inline 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 = PINA & ((1 << IMPULS1_PIN) | (1 << IMPULS0_PIN) | (1 << TAST_PIN)); } inline void led_init(void) { TCCR0A = (1 << COM0A1) | (1 << COM0B1) | (1 << COM0A0) | (1 << WGM01) | (1 << WGM00);/* pwm enable: fast, A inverted, B not */ TCCR0B = (1 << CS00);/* no prescaler */ OCR0A = OCR0B = 0; } inline void led_set(uint16_t value) { uint8_t pwmval; if (LED_GREEN_TEMP <= value && value < LED_RED_TEMP) { pwmval = ((uint32_t) (value-LED_GREEN_TEMP) * 255)/(LED_RED_TEMP-LED_GREEN_TEMP); } else if (value <= LED_GREEN_TEMP) { pwmval = 0; } else { pwmval = 255; } OCR0A = pwmval; OCR0B = pwmval; } inline void led_off(void) { // OCR0A = 0; // OCR0B = 255; } inline void device_off(void) { TCCR0B = 0; // stop pwm TCCR0A = 0; // disconnect outputs; ADCSRA &= ~(1< 96) {heat_power = 96;} } else { heat_power = 0; } } } //if(!dev_state) {led_off();} // now done in interrupt else if(setting_timeout) {led_set(target);} else {led_set(temperature);} if(eeprom_write && dev_state) { while(EECR & (1 << EEPE)) {;} EEARL = 0; EEDR = (target >> 8) & 0xff; EECR |= (1 << EEMPE); EECR |= (1 << EEPE); while(EECR & (1 << EEPE)) {;} EEARL = 1; EEDR = target & 0xff; EECR |= (1 << EEMPE); EECR |= (1 << EEPE); eeprom_write = 0; } if(!dev_state) { set_sleep_mode(SLEEP_MODE_IDLE); sleep_mode(); // timer1 interrupt will wake us again, as will PCINT } } return 0; }