#include #include #include #include #include #include #include #include "version.h" #include "main.h" #include "display.h" #include "1wire/1wire.h" #include "sensors.h" #include "menu.h" #include "delay.h" #include "debug.h" uint32_t ledval[4], ledacc[4]; /* 0: led1 colour * 1: led1 brightness * 2: led2 * 3: led3 */ uint8_t run_mainloop; //set to 1 if mainloop needs running uint8_t run_1wireloop; //set to 1 if 1wire loop needs running uint8_t buttlold, buttrold, butttold; uint8_t butttbounce; uint8_t buttonevent; int8_t buttoninc; uint8_t EEMEM display_stored_brightness; uint8_t EEMEM display_stored_contrast; uint8_t EEMEM flowtemp_stored; uint8_t EEMEM flowtemp_stored_range; uint8_t EEMEM flowtemp_stored_alarm; uint8_t flowtemp; uint8_t flowtemp_range; uint8_t flowtemp_alarm; uint8_t volatile timer1_acc; void hardinit(){ /* initializes the hardware */ // DDRB: XXXXX111 DDRB = 0xff; // DDRC: -X000111 DDRC = 0x07; // DDRD: 1XXXXXXX; DDRD = 0x80; // no pullups; all digital outputs can take care of themselves PORTB = 0x00; PORTC = 0x00; PORTD = 0x00; /* our event driver gets called with 10kHz frequency * (to allow for proper LED PWM) * Thats 100us or 800 cycles. * Priority is: 1wire-bit first, then buttons, then LED-PWMs, then LCD, then the rest of 1wire. * Sending a 1wire-bit takes about 70us. */ TCCR0 = 0x02; // prescaler: clk/8 TCNT0 = 0xff-100; // 100 cycles of 1us each TIMSK |= 0x01; // enable interrupt /* hardware pwm for brightness/contrast: */ TCCR1A = _BV(COM1A1) | _BV(COM1A0) | _BV(COM1B1) | _BV(WGM10); TCCR1B = _BV(WGM12) | _BV(CS11); // clk/8 prescaler, 4kHz PWM-freq. TIMSK &=( (~_BV(3)) & (~_BV(4)) & (~_BV(5))); //disable all timer1-interrupts TIMSK |= _BV(2); // but enable overflow OCR1A = 0xff-15; // contrast OCR1B = 200; // brightness // init LCD: lcd_init(1); lcd_clrscr(1); // 1wire needs no own init, bus search is done in softinit sei(); } void softinit(){ lcd_defchar(1, LCD_CHAR_HALFBAR, lcd_halfbar_char); lcd_defchar(1, LCD_CHAR_BAR, lcd_bar_char); lcd_defchar(1, LCD_CHAR_DEGREE, lcd_degree_char); sensors_search(); menu_init(); set_display_brightness(load_display_brightness()); set_display_contrast(load_display_contrast()); set_flowtemp(load_flowtemp()); set_flowtemp_range(load_flowtemp_range()); set_flowtemp_alarm(load_flowtemp_alarm()); sei(); } void mainloop(){ // called with about 80Hz static uint8_t ctr_subsec; // counts to 79, wraps around every second static uint8_t ctr_sec; // counts to 255, use with modulo for rare events int16_t vorlaufdiff; uint16_t ledbrightness; menu_display(); ctr_subsec++; if(ctr_subsec >= 80){ ctr_subsec = 0; ctr_sec++; // starting here: stuff that happens every second (or rarer) sensors_startconv(); if(ctr_sec % 32 == 0){ sensors_search(); // overrides sensors_startconv } } /* warning for flow too hot */ /* "inverted" blink-code compared to duo-led */ if (sensoravg[sensor_which[0]]/256 >= flowtemp_alarm) { if (ctr_subsec < 40) { ledval[3] = 0; } else { ledval[3] = 65535; } } /* do colour/brightness for duo-led*/ if (sensoravg[sensor_which[0]]/256 > flowtemp) { ledval[0] = 0; // red } else { ledval[0] = 65535; // green } vorlaufdiff = sensoravg[sensor_which[0]]/256 - (int16_t)flowtemp; vorlaufdiff = vorlaufdiff > 0 ? vorlaufdiff : -vorlaufdiff; if (vorlaufdiff <= flowtemp_range / 4) { // flowtemp OK ledbrightness = 0; } else { // flowtemp out of range if (vorlaufdiff < flowtemp_range) { // inside range, scale brightness linearly with difference ledbrightness = (4 * vorlaufdiff - flowtemp_range) * 256 / 3 / flowtemp_range; } else { // outside margin, blink as a warning if (ctr_subsec < 40) { ledbrightness = 255; } else { ledbrightness = 0; } } } ledval[1] = ledbrightness * ledbrightness; } void main(){ hardinit(); softinit(); for(;;){ if(run_1wireloop){ run_1wireloop=0; sensors_1wirebitloop(); } if(run_mainloop){ run_mainloop=0; mainloop(); } } } void buttonpoll(){ // runs with 1.2kHz uint8_t l,r,t,flanks,dir; l=BUTTPIN & _BV(BUTTLPIN); r=BUTTPIN & _BV(BUTTRPIN); t=BUTTPIN & _BV(BUTTTPIN); // debounce code if (t != butttold && !butttbounce ) { butttold = t; butttbounce = BUTT_BOUNCE; if (t == 0) { // active low buttonevent |= BUTTEV_PUSH; } } flanks=0; dir=0; if (l != buttlold) { flanks += 1; } if (r != buttrold) { flanks += 1; dir = 1; } if (flanks == 1){ // we need to have exactly one flank, 0 flanks are no // change, and 2 flanks are too fast (error) if (l) { dir ^= 1; } if (r) { dir ^= 1; } if ((r && l) || (!r && !l)) { buttoninc += dir ? -1 : 1; } } buttlold = l; buttrold = r; if(butttbounce){ butttbounce -= 1; } } void ledsoftpwm(){ // LED softpwm: uint8_t i; for(i=1; i<4; ++i){ ledacc[i] += ledval[i]; if(ledacc[i]>0xffff){ ledacc[i] -= 0xffff; if(i==1){ ledacc[0] += ledval[0]; if(ledacc[0]>0xffff){ ledacc[0] -= 0xffff; LED1PORT |= _BV(LED1APIN); LED1PORT &= ~_BV(LED1BPIN); } else { LED1PORT |= _BV(LED1BPIN); LED1PORT &= ~_BV(LED1APIN); } } if(i==2){ LED2PORT &= ~_BV(LED2PIN); } if(i==3){ LED3PORT &= ~_BV(LED3PIN); } } else { if(i==1){ LED1PORT &= ~(_BV(LED1BPIN) | _BV(LED1APIN)); } if(i==2){ LED2PORT |= _BV(LED2PIN); } if(i==3){ LED3PORT |= _BV(LED3PIN); } } } } void set_display_brightness(uint8_t display_brightness) { // set "runtime-brightness", will be lost at poweroff! if (display_brightness < 1 || display_brightness > 16) { // erratic values display_brightness = 10; } OCR1B = (display_brightness * display_brightness) - 1; } void store_display_brightness(uint8_t new_brightness) { // store brightness-value to eeprom for next boot if (new_brightness < 1 || new_brightness > 16) { // erratic values, abort return; } uint8_t cur_brightness = eeprom_read_byte(&display_stored_brightness); if (new_brightness != cur_brightness) { // value hast changed, save to eeprom eeprom_write_byte(&display_stored_brightness, new_brightness); } } uint8_t load_display_brightness() { uint8_t display_brightness = eeprom_read_byte(&display_stored_brightness); if (display_brightness < 1 || display_brightness > 16) { // erratic values display_brightness = 10; store_display_brightness(display_brightness); } return display_brightness; } void set_display_contrast(uint8_t display_contrast) { // set "runtime-contrast", will be lost at poweroff! if (display_contrast > 32) { // erratic values display_contrast = 16; } OCR1A = 0xff - 64 + 2 * display_contrast; } void store_display_contrast(uint8_t new_contrast) { // store contrast-value to eeprom for next boot if (new_contrast > 32) { // erratic values return; } uint8_t cur_contrast = eeprom_read_byte(&display_stored_contrast); if (new_contrast != cur_contrast) { // value hast changed, save to eeprom eeprom_write_byte(&display_stored_contrast, new_contrast); } } uint8_t load_display_contrast() { uint8_t display_contrast = eeprom_read_byte(&display_stored_contrast); if (display_contrast > 32) { // erratic values display_contrast = 16; store_display_contrast(display_contrast); } return display_contrast; } void set_flowtemp(uint8_t new_flowtemp) { // set "runtime-flowtemp", will be lost at poweroff! if ((new_flowtemp > FLOWTEMP_MAX) || (new_flowtemp < FLOWTEMP_MIN)) { // erratic values flowtemp = FLOWTEMP_DEFAULT; } flowtemp = new_flowtemp; } void store_flowtemp(uint8_t new_flowtemp) { // store flowtemp-value to eeprom for next boot if ((new_flowtemp > FLOWTEMP_MAX) || (new_flowtemp < FLOWTEMP_MIN)) { // erratic values return; } uint8_t cur_flowtemp = eeprom_read_byte(&flowtemp_stored); if (new_flowtemp != cur_flowtemp) { // value hast changed, save to eeprom eeprom_write_byte(&flowtemp_stored, new_flowtemp); } } uint8_t load_flowtemp() { flowtemp = eeprom_read_byte(&flowtemp_stored); if ((flowtemp > FLOWTEMP_MAX) || (flowtemp < FLOWTEMP_MIN)) { // erratic values flowtemp = FLOWTEMP_DEFAULT; store_flowtemp(flowtemp); } return flowtemp; } void set_flowtemp_range(uint8_t new_flowtemp_range) { // set "runtime-flowtemp_range", will be lost at poweroff! if (new_flowtemp_range > FLOWTEMP_RANGE_MAX) { // erratic values flowtemp_range = FLOWTEMP_RANGE_DEFAULT; } flowtemp_range = new_flowtemp_range; } void store_flowtemp_range(uint8_t new_flowtemp_range) { // store flowtemp-value to eeprom for next boot if (new_flowtemp_range > FLOWTEMP_RANGE_MAX) { // erratic values return; } uint8_t cur_flowtemp_range = eeprom_read_byte(&flowtemp_stored_range); if (new_flowtemp_range != cur_flowtemp_range) { // value has changed, save to eeprom eeprom_write_byte(&flowtemp_stored_range, new_flowtemp_range); } } uint8_t load_flowtemp_range() { flowtemp_range = eeprom_read_byte(&flowtemp_stored_range); if (flowtemp_range > FLOWTEMP_RANGE_MAX) { // erratic values flowtemp_range = FLOWTEMP_RANGE_DEFAULT; store_flowtemp_range(flowtemp_stored_range); } return flowtemp_range; } void set_flowtemp_alarm(uint8_t new_flowtemp_alarm) { // set "runtime-flowtemp_alarm", will be lost at poweroff! flowtemp_alarm = new_flowtemp_alarm; } void store_flowtemp_alarm(uint8_t new_flowtemp_alarm) { // store flowtemp-alarm-value to eeprom for next boot uint8_t cur_flowtemp_alarm = eeprom_read_byte(&flowtemp_stored_alarm); if (new_flowtemp_alarm != cur_flowtemp_alarm) { // value has changed, save to eeprom eeprom_write_byte(&flowtemp_stored_alarm, new_flowtemp_alarm); } } uint8_t load_flowtemp_alarm() { flowtemp_alarm = eeprom_read_byte(&flowtemp_stored_alarm); if (flowtemp_alarm > FLOWTEMP_ALARM_MAX) { // erratic values flowtemp_alarm = FLOWTEMP_ALARM_DEFAULT; store_flowtemp_alarm(flowtemp_stored_alarm); } return flowtemp_alarm; } ISR(TIMER0_OVF_vect){ static uint8_t counter; TCNT0 = 0xff-100; counter+=1; ledsoftpwm(); if(counter%8 == 0){ //1.2kHz buttonpoll(); } if(counter%128 == 0){ //ca. 80Hz run_mainloop = 1; } run_1wireloop = 1; // 10kHz } /* ISR(TIMER1_OVF_vect, ISR_NAKED){ asm volatile ("in %0, %1\n" : "=r" (sreg_store) : "I" (_SFR_IO_ADDR(SREG))); timer1_acc++; asm volatile ("out %1, %0\n" : "=r" (sreg_store) : "I" (_SFR_IO_ADDR(SREG))); reti(); }*/ ISR(TIMER1_OVF_vect){ timer1_acc++; }