Очередной таймер полив домашнего цветка

Нет ответов
andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Очередной таймер на Attiny85 полив домашнего цветка

Две кнопки управления

Длительное одновременное нажатие 1 и 2 кнопки - переход в режим настроек

В режиме настроек:

кнопка 1 - изменение времени полива от 1 до 9 секунд

кнопка 2 - период полива в днях от 1 до 9

длительное нажатие кнопки 1 - тестовый полив и выход из режима настроек

длительное 1 и 2 - сброс таймеров, начало отсчета от 0 и выход из режима настроек

#include <avr/io.h>
#include <util/delay.h>
#include "EEPROM.h"
#include "tm1637.h"

#define pos_eeprom_pump_sec 0x25
#define pos_eeprom_count_days 0x27
#define pos_eeprom_current_days 0x29

#define period_read_key 100UL
#define min_count_key_down 2 // 0.2 sec 
#define min_count_key_long 20 // 2 sec
#define max_count_key_short 10 // 1 sec
#define max_time_show_options 20000UL // 20 sec

#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

// PB0 pin 5 - TM1637_DIO_PIN
#define PB0_OUT sbi(DDRB,PB0)
#define PB0_IN cbi(DDRB,PB0)
#define PB0_HIGH sbi(PORTB,PB0)
#define PB0_LOW cbi(PORTB,PB0)
// PB1 pin 6 - TM1637_CLK_PIN
#define PB1_OUT sbi(DDRB,PB1)
#define PB1_IN cbi(DDRB,PB1)
#define PB1_HIGH sbi(PORTB,PB1)
#define PB1_LOW cbi(PORTB,PB1)
// PB2 pin 7 - relay pump
#define PB2_OUT sbi(DDRB,PB2)
#define PB2_IN cbi(DDRB,PB2)
#define PB2_HIGH sbi(PORTB,PB2)
#define PB2_LOW cbi(PORTB,PB2)
// PB3 pin 2 - key 1
#define PB3_OUT sbi(DDRB,PB3)
#define PB3_IN cbi(DDRB,PB3)
#define PB3_HIGH sbi(PORTB,PB3)
#define PB3_LOW cbi(PORTB,PB3)
#define PB3_READ bitRead(PINB,PB3)
// PB4 pin 3 - key 2
#define PB4_OUT sbi(DDRB,PB4)
#define PB4_IN cbi(DDRB,PB4)
#define PB4_HIGH sbi(PORTB,PB4)
#define PB4_LOW cbi(PORTB,PB4)
#define PB4_READ bitRead(PINB,PB4)

unsigned long key_time;

byte day_counting; // current counting
byte hour_counting = 0; // current counting
byte sec_pumping; // default/minimum 1 sec pump
byte day_period; // default/minimum 1 day pump

byte count_key1_down = 0;
byte mode_key1 = 0; // 0-none 1-short 2-long
boolean key1_is_begin = false;
boolean key1_next = true;

byte count_key2_down = 0;
byte mode_key2 = 0; // 0-none 1-short 2-long
boolean key2_is_begin = false;
boolean key2_next = true;

byte work_mode = 0; // 0-counting 1-options 2-pumping 3-test pump
unsigned long time_options_mode;
unsigned long time_pumping_mode;

byte point_togl = 0; // display point

unsigned long timer_sec = 0; // show display timer
unsigned long timer_hour = 0; // every hour - main timer

void setup() {
  // put your setup code here, to run once:
  PB3_IN; PB3_HIGH; // key 1
  PB4_IN; PB4_HIGH; // key 2
  PB2_OUT; PB2_LOW; // relay OFF
  // load conf from eeprom
  sec_pumping = EEPROM.read(pos_eeprom_pump_sec);
  day_period = EEPROM.read(pos_eeprom_count_days);
  day_counting = EEPROM.read(pos_eeprom_current_days);
  TM1637_init();
  TM1637_set_brightness(6);
}

void loop() {
  // put your main code here, to run repeatedly:
  unsigned long current_millis = millis();
  if ((current_millis - key_time) >= period_read_key) {
    key_time = current_millis;
    // operate key1
    if (PB3_READ == 0) {
      // key1 is down
      if (key1_is_begin) {
        if ((++count_key1_down) >= min_count_key_long) {
          // long click
          key1_is_begin = false;
          count_key1_down = 0;
          mode_key1 = 2;
        }
      } else {
        if (key1_next) {
          key1_is_begin = true;
          key1_next = false;
          count_key1_down = 0;
          mode_key1 = 0;
        }
      }
    } else {
      // key1 is up
      key1_next = true;
      if (key1_is_begin) {
        if  ((count_key1_down >= min_count_key_down) && (count_key1_down <= max_count_key_short)) {
          // short click
          key1_is_begin = false;
          count_key1_down = 0;
          mode_key1 = 1;
        } else {
          // no click
          key1_is_begin = false;
          count_key1_down = 0;
          mode_key1 = 0;
        }
      }
    }
    // end key1
    // operate key2
    if (PB4_READ == 0) {
      // key2 is down
      if (key2_is_begin) {
        if ((++count_key2_down) >= min_count_key_long) {
          // long click
          key2_is_begin = false;
          count_key2_down = 0;
          mode_key2 = 2;
        }
      } else {
        if (key2_next) {
          key2_is_begin = true;
          key2_next = false;
          count_key2_down = 0;
          mode_key2 = 0;
        }
      }
    } else {
      // key2 is up
      key2_next = true;
      if (key2_is_begin) {
        if  ((count_key2_down >= min_count_key_down) && (count_key2_down <= max_count_key_short)) {
          // short click
          key2_is_begin = false;
          count_key2_down = 0;
          mode_key2 = 1;
        } else {
          // no click
          key2_is_begin = false;
          count_key2_down = 0;
          mode_key2 = 0;
        }
      }
    }
    // end key2
  }
  // analize keys
  if ((mode_key1 == 2) && (mode_key2 == 2)) {
    if (work_mode == 0) {
      // enter to options mode
      time_options_mode = current_millis;
      TM1637_clear();
      ShowSecDay();
      work_mode = 1;
    } else {
      if (work_mode == 1) {
        // clear counting
        hour_counting = 0;
        day_counting = 0;
        // save options
        EEPROM.write(pos_eeprom_pump_sec, sec_pumping);
        EEPROM.write(pos_eeprom_count_days, day_period);
        EEPROM.write(pos_eeprom_current_days, day_counting);
        // exit options mode
        TM1637_clear();
        work_mode = 0;
      }
    }
  } else {
    if (mode_key1 == 2) {
      if (work_mode == 1) {
        // save options
        EEPROM.write(pos_eeprom_pump_sec, sec_pumping);
        EEPROM.write(pos_eeprom_count_days, day_period);
        // test pump
        time_pumping_mode = current_millis;
        TM1637_clear();
        work_mode = 3;
      }
    } else {
      if (mode_key1 == 1) {
        if (work_mode == 1) {
          time_options_mode = current_millis;
          // change pump sec
          if ((++sec_pumping) > 9) sec_pumping = 1;
          // show
          ShowSecDay();
        }
      } else {
        if (mode_key2 == 1) {
          if (work_mode == 1) {
            time_options_mode = current_millis;
            // change period pump days
            if ((++day_period) > 9) day_period = 1;
            // show
            ShowSecDay();
          }
        } else {
          // no keys
          if (work_mode == 1) {
            if ((current_millis - time_options_mode) >= max_time_show_options) {
              // save options
              EEPROM.write(pos_eeprom_pump_sec, sec_pumping);
              EEPROM.write(pos_eeprom_count_days, day_period);
              // exit options mode
              TM1637_clear();
              work_mode = 0;
            }
          }
        }
      }
    }
  }
  // end analize keys
  // analize pump mode
  if ((work_mode == 2) || (work_mode == 3)) {
    PB2_HIGH;
    if ((current_millis - time_pumping_mode) >= (sec_pumping * 1000)) {
      time_pumping_mode = current_millis;
      // end pumping
      PB2_LOW;
      TM1637_clear();
      work_mode = 0;
    }
  }
  // end pump mode
  // loop show display
  if ((current_millis - timer_sec) >= 1000UL) {
    timer_sec = current_millis;
    if (point_togl == 0) point_togl = 1; else point_togl = 0;
    TM1637_display_colon(point_togl);
    switch (work_mode) {
      case 0: {
          ShowTimer();
          break;
        }
      case 1: {
          ShowSecDay();
          break;
        }
      case 2: {
          ShowPump();
          break;
        }
      case 3: {
          ShowPump();
          break;
        }
    }
  }
  // timer every hour
  if ((work_mode == 0) || (work_mode == 3)) {
    if ((current_millis - timer_hour) >= 3600000UL) { // for test = 1000UL // by real 1 hour = 3600000UL ms
      timer_hour = current_millis;
      if ((++hour_counting) >= 24) {
        ++day_counting;
        hour_counting = 0;
        if (day_counting >= day_period) {
          // start pump
          time_pumping_mode = current_millis;
          TM1637_clear();
          work_mode = 2;
          day_counting = 0;
        }
        EEPROM.write(pos_eeprom_current_days, day_counting);
      }
    }
    // end hour timer
  }
  // end main loop
  mode_key1 = 0; mode_key2 = 0;
}

void ShowTimer() {
  TM1637_display_digit(TM1637_SET_ADR_00H, day_counting);
  TM1637_display_segments(TM1637_SET_ADR_01H, 0b01000000);
  TM1637_display_digit(TM1637_SET_ADR_02H, (hour_counting / 10));
  TM1637_display_digit(TM1637_SET_ADR_03H, (hour_counting % 10));
}

void ShowSecDay() {
  TM1637_display_segments(TM1637_SET_ADR_00H, 0b01000000);
  TM1637_display_digit(TM1637_SET_ADR_01H, sec_pumping);
  TM1637_display_segments(TM1637_SET_ADR_02H, 0b01000000);
  TM1637_display_digit(TM1637_SET_ADR_03H, day_period);
}

void ShowPump() {
  TM1637_display_segments(TM1637_SET_ADR_00H, 0b01000000);
  TM1637_display_segments(TM1637_SET_ADR_01H, 0b01000000);
  TM1637_display_digit(TM1637_SET_ADR_02H, ((millis() - time_pumping_mode) / 1000) / 10);
  TM1637_display_digit(TM1637_SET_ADR_03H, ((millis() - time_pumping_mode) / 1000) % 10);
}