Очередной таймер полив домашнего цветка
- Войдите на сайт для отправки комментариев
Втр, 13/03/2018 - 12:47
Очередной таймер на 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);
}

