Простой кухонный таймер 4симв.TM1637, энкодер, аккум.18650

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

Простой кухонный таймер, после включения энкодером устанавливается количество минут. Долгое нажатие на энкодер запускает таймер. Через 10 секунд бездействия дисплей на минимальную ярскость переходит, через минуту устройство уходит в спящий режим. В режиме непосредственно обратного отсчета через минуту просто отключается дисплей. Нажать на энкодер или повернуть - экран заново загорается.

потребление всей схемы при питании от 5 вольт:
  23 мА - индикатор TM1637 на минимальной яркости
  21 мА - с отключенным индикатором TM1637
  120 мкА - спящий режим МК, ожидание движения энкодера
 
потребление всей схемы при питании от аккумулятора через повышайку:
  50...80 мА - индикаторы на максимальной яркости
  29 мА - индикатор TM1637 на минимальной яркости
  23 мА - с отключенным индикатором TM1637
  520 мкА - спящий режим МК, ожидание движения энкодера
 
#include "TM1637.h" // https://github.com/DetSimen/TM1637 // http://arduino.ru/forum/otvlechennye-temy/tm1637
#include <avr/sleep.h>
#include <avr/interrupt.h>
#include <avr/wdt.h>

#define min_step_encoder 5 // сколько минут прибавлять/убавлять при одном шелчке энкодера
#define pin_sw_encoder 2 // int0
#define pin_clk_encoder 3 // int1
#define pin_dt_encoder 4
#define pin_beeper 5
#define pin_dio_tm1637 8
#define pin_clk_tm1637 9

/* 21.08.2020 atmega328p от кварца 16МГц, потребление всей схемы при питании от 5 вольт
  23 мА - индикатор TM1637 на минимальной яркости
  21 мА - с отключенным индикатором TM1637
  120 мкА - спящий режим МК, ожидание движения энкодера*/

/* 20.08.2020 atmega328p от внутреннего RC генератора 8МГц, потребление всей схемы при питании от 5 вольт
  16 мА - индикатор TM1637 на минимальной яркости
  14 мА - с отключенным индикатором TM1637
  120 мкА - спящий режим МК, ожидание движения энкодера*/

TM1637 Display(pin_clk_tm1637, pin_dio_tm1637, enTM1637Type::Time);

volatile int currEncoder;
unsigned long timer_every_sec;
unsigned char currentSec;
unsigned char mainTimerMin;
bool mainMode;
volatile unsigned long unusedTimer;

void setup() {
  // put your setup code here, to run once:
  initAll();
}

void loop() {
  // put your main code here, to run repeatedly:
  if (swEncoder()) {
    if (mainMode) {
      offAllAndSleep();
      return;
    } else if (mainTimerMin) {
      mainMode = true;
      timer_every_sec = millis();
      currentSec = 0;
    }
  }
  signed char cme = moveEncoder();
  if ((cme != 0) && (!mainMode)) {
    changeTimer(cme);
    showTM1637(false);
  }
  if ((millis() - timer_every_sec) >= 1000UL) {
    timer_every_sec = millis();
    if (mainMode) {
      if (actionTimer()) {
        initTM1637();
        Display.SetBrightness(7);
        Display.Print("bEEP");
        analogWrite(pin_beeper, 255);
        delay(15000);
        offAllAndSleep();
        return;
      }
    }
    showTM1637(false);
  }
}

void initTM1637() {
  pinMode(pin_clk_tm1637, OUTPUT);
  pinMode(pin_dio_tm1637, OUTPUT);
  Display.Start();
}

void offTM1637() {
  Display.Clear();
  Display.Stop();
  digitalWrite(pin_clk_tm1637, LOW); pinMode(pin_clk_tm1637, INPUT);
  digitalWrite(pin_dio_tm1637, LOW); pinMode(pin_dio_tm1637, INPUT);
}

void mcuSleep() {
  cli(); wdt_disable();
  uint8_t x = (MCUCR & ~(1 << BODSE)) | (1 << BODS);
  MCUCR = x | (1 << BODSE); MCUCR = x;
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
  cbi(ADCSRA, ADEN);
  set_sleep_mode(SLEEP_MODE_PWR_DOWN); sei();
  sleep_enable();
  sleep_mode();
}

void initEncoder() {
  pinMode(pin_sw_encoder, INPUT);
  pinMode(pin_dt_encoder, INPUT);
  pinMode(pin_clk_encoder, INPUT);
  attachInterrupt(1, intEncoder, FALLING);
}

void initBeeper() {
  pinMode(pin_beeper, OUTPUT);
  digitalWrite(pin_beeper, LOW);
}

void offBeeper() {
  digitalWrite(pin_beeper, LOW); pinMode(pin_beeper, INPUT);
}

bool swEncoder() {
  static bool lastStatus;
  static bool currStatus;
  static bool startCalc = 0;
  static unsigned long firstTime;
  currStatus = digitalRead(pin_sw_encoder);
  if (currStatus != lastStatus) {
    unusedTimer = millis();
    if (!currStatus) {
      if (!startCalc) {
        startCalc = true;
        firstTime = unusedTimer;
      }
    } else {
      startCalc = false;
    }
  } else {
    if (startCalc && (!currStatus)) {
      if ((millis() - firstTime) >= 3000UL) {
        startCalc = false; return true;
      }
    }
  }
  lastStatus = currStatus;
  return false;
}

void intEncoder() {
  static unsigned long lastInt;
  unusedTimer = millis();
  if ((unusedTimer - lastInt) >= 100UL) {
    if (digitalRead(pin_clk_encoder) == digitalRead(pin_dt_encoder)) ++currEncoder; else --currEncoder;
    lastInt = unusedTimer;
  }
}

signed char moveEncoder() {
  signed char exitSt = 0;
  static int lastEncoder; cli();
  if (lastEncoder != currEncoder) {
    if (currEncoder > lastEncoder) exitSt = 1; else exitSt = -1;
    lastEncoder = currEncoder;
  } sei();
  return exitSt;
}

void initAll() {
  initTM1637();
  initEncoder();
  initBeeper();
  mainTimerMin = 0;
  mainMode = false;
  unusedTimer = millis();
  showTM1637(true);
}

void offAllAndSleep() {
  offTM1637();
  offBeeper();
  mcuSleep();
  initAll();
}

void showTM1637(bool flReset) {
  static unsigned char lastSt; // 1-full br 2 - minimal br 3 - off tm1637
  if (flReset) {
    lastSt = 1;
    Display.SetBrightness(7);
    Display.Clear();
    return;
  }
  if ((millis() - unusedTimer) >= 60000UL) {
    if (lastSt == 3) {
      return;
    } else {
      lastSt = 3;
      if (mainMode) offTM1637(); else offAllAndSleep();
      return;
    }
  } else if ((millis() - unusedTimer) >= 10000UL) {
    if (lastSt != 2) {
      lastSt = 2;
      Display.SetBrightness(0);
    }
  } else if (lastSt != 1) {
    if (lastSt == 3) initTM1637();
    lastSt = 1;
    Display.SetBrightness(7);
  }
  if (mainMode) {
    Display.ToggleColon();
    if (mainTimerMin > 59) {
      Display.PrintAt(0, ' ');
      Display.PrintAt(1, (mainTimerMin / 60 + '0'));
      Display.PrintAt(2, ((mainTimerMin % 60) / 10 + '0'));
      Display.PrintAt(3, ((mainTimerMin % 60) % 10 + '0'));
    } else {
      if ((mainTimerMin % 60) > 9) Display.PrintAt(0, ((mainTimerMin % 60) / 10 + '0')); else Display.PrintAt(0, ' ');
      if (mainTimerMin) Display.PrintAt(1, ((mainTimerMin % 60) % 10 + '0')); else Display.PrintAt(1, ' ');
      Display.PrintAt(2, (currentSec / 10 + '0'));
      Display.PrintAt(3, (currentSec % 10 + '0'));
    }
  } else {
    Display.PrintAt(0, ' ');
    if (mainTimerMin > 59) { // show hours
      Display.ShowPoint(true);
      Display.PrintAt(1, (mainTimerMin / 60 + '0'));
      Display.PrintAt(2, ((mainTimerMin % 60) / 10 + '0'));
      Display.PrintAt(3, ((mainTimerMin % 60) % 10 + '0'));
    } else {
      Display.ShowPoint(false);
      Display.PrintAt(1, ' ');
      if ((mainTimerMin % 60) > 9) Display.PrintAt(2, ((mainTimerMin % 60) / 10 + '0')); else Display.PrintAt(2, ' ');
      Display.PrintAt(3, ((mainTimerMin % 60) % 10 + '0'));
    }
  }
}

bool actionTimer() {
  if (!currentSec) {
    if (!mainTimerMin) {
      return true;
    } else {
      --mainTimerMin;
    }
    currentSec = 59;
  } else {
    --currentSec;
  }
  return false;
}

void changeTimer(signed char cmec) {
  if (cmec == 1) {
    mainTimerMin += min_step_encoder;
    if (mainTimerMin >= 240) mainTimerMin = 240;
  } else {
    if (mainTimerMin <= min_step_encoder) mainTimerMin = 0; else mainTimerMin -= min_step_encoder;
  }
}

 

-
 

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

Хорошо, но "маловато будет" :)

Мне, частенько, 2 или 3 таймера нужно на кухне. Люблю готовить. Добавив еще одну матрицу и кнопку можно получить 10 таймеров.

Кроме того неплохо-бы сохранять предыдущее значение таймера - крутить не от нуля.

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

Я все железки делаю под свои простые задачи :) так что развития конкретно данного проекта не будет. Вот с дребезгом контактов не доработал, энкодер пропускает, но надеюсь время найду - доделаю.
Опять же, каждое увеличение функционала - > увеличение кнопок/регуляторов, а в данном случае - просто замена механического таймера газовой плиты Gefest.

sadman41
Offline
Зарегистрирован: 19.10.2016

Врет mykaida, сдается мне. Тому, кто любит готовить, таймеры не нужны - он время чует. А вот ежели повар вместо готовки форум читает...

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

andycat, функции TM1637::Start()  и TM1637::Stop()  это protected функции класса, которые предваряют/завершают передачу данных в дисплей.  Для чего ты их приспособил к энергосбережению?  Для энергосбережения надо ноги в INPUT переводить и отключать в регистре энергосбережения пошти всё. :) 

 

void TM1637::Start(void) const    // выдает старт условие на шину
{
	digitalWrite(FClockPin, HIGH);
	digitalWrite(FDataPin, HIGH);
	digitalWrite(FDataPin, LOW);
	digitalWrite(FClockPin, LOW);
}


void TM1637::Stop(void) const // выдает стоп условие на шину
{
	digitalWrite(FClockPin, LOW);
	digitalWrite(FDataPin, LOW);
	digitalWrite(FClockPin, HIGH);
	digitalWrite(FDataPin, HIGH);
}

 

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

DetSimen, да когда начинал, понадеялся что это поможет индикаторам поменьше кушать (каюсь - даташит не читал), но не помогло, да так и осталось....
ЗЫ. Из 120 мкА потребления в спящем режиме, 99.99 % это именно индикатор, если переводить схему на более экономный источник питания, не помешает транзисторный ключ. У меня 18650 аккумуляторов много, не стал заморачиваться.

Kolya12008
Offline
Зарегистрирован: 01.06.2020

Здравствуйте! Можно схемку на этот таймер?

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017
Здравствуйте.
Схемки извините нет....
А этого недостаточно? :
 
define pin_sw_encoder 2 // int0
#define pin_clk_encoder 3 // int1
#define pin_dt_encoder 4
#define pin_beeper 5
#define pin_dio_tm1637 8
#define pin_clk_tm1637 9
 
Kolya12008
Offline
Зарегистрирован: 01.06.2020

andycat пишет:

Здравствуйте.
Схемки извините нет....
А этого недостаточно? :
 
define pin_sw_encoder 2 // int0
#define pin_clk_encoder 3 // int1
#define pin_dt_encoder 4
#define pin_beeper 5
#define pin_dio_tm1637 8
#define pin_clk_tm1637 9
 

Ок, спасибо!

Alman
Offline
Зарегистрирован: 03.03.2014

andycat, что я делаю не так? помогите решить проблему? я не силен в написании кода. смиренно прошу помощи :)

d:\DiskD\Arduino\timer_2\timer_2.ino: In function 'void initTM1637()':
d:\DiskD\Arduino\timer_2\timer_2.ino:77:17: error: 'void TM1637::Start() const' is protected within this context
Display.Start();
^
In file included from d:\DiskD\Arduino\timer_2\timer_2.ino:1:0:
d:\DiskD\Arduino\libraries\TM1637/TM1637.h:54:7: note: declared protected here
void Start(void) const; // выдает старт условие на шину
^~~~~
d:\DiskD\Arduino\timer_2\timer_2.ino: In function 'void offTM1637()':
d:\DiskD\Arduino\timer_2\timer_2.ino:82:16: error: 'void TM1637::Stop() const' is protected within this context
Display.Stop();
^
In file included from d:\DiskD\Arduino\timer_2\timer_2.ino:1:0:
d:\DiskD\Arduino\libraries\TM1637/TM1637.h:56:7: note: declared protected here
void Stop(void) const; // выдает стоп условие на шину
^~~~
Compilation error: Error: 2 UNKNOWN: exit status 1

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

тут ответ

http://arduino.ru/forum/proekty/prostoi-kukhonnyi-taimer-4simvtm1637-enk...

удалите в скетче строки 75 и 80 вызовы Start и Stop

 

 

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

Аккумулятора 18650 хватает на несколько месяцев при использовании таймера два...три раза в неделю. Больше всего сжирает конечно BEEPER.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

для приготовления яичницы таймер не нужен, нужна регулировка огня, а другое я не пробовал )))
PS вру, могу сварить суп харчо и компот