Часы на TM 1638 + Arduino/
- Войдите на сайт для отправки комментариев
Пнд, 10/10/2016 - 22:18
Прикупил я на АЛИ платку с восьмёрочками и кнопочками, и была у меня PRO MINI 5V.
Ну и вспомнилось пионерское детство.
В итоге получились часы с будильниками и таймером.
Постарался задействовать все кнопочки и светодиодики. кнопочки иногда задумчивы и их нужно чуть придерживать в нажатом положении.
Будильники и таймер могут пикать и/или дёргать ножки.
Есть параметр ajustment, значение которого (в секундах) прибавляется в полночь.
Постарался почистить чудеса, но может ещё остались.
#include <Time.h>
#include <TimeLib.h>
#include <TM1638.h>
TM1638 module(3, 4, 2);
const unsigned long firstStartTime = 1483228800;
const byte timerPort = 9;
const byte beepPort = 12;
const byte alarm_1Port = 10;
const byte alarm_2Port = 11;
const byte sunday = 1;
const byte saturday = 7;
const byte allWorkDays = 8;
const byte allWeekEnd = 9;
const byte allDays = 10;
unsigned int escToTimeShowMode;
byte btn;
byte showMode = 1;
byte lastShowMode = 1;
int adjustmentTime;
boolean flag;
boolean flag_esc;
time_t tempForTimer = 300;
time_t timer = 300;
time_t tempForAlarm_1 = 25200;
time_t alarm_1 = 25200;
time_t tempForAlarm_2 = 32400;
time_t alarm_2 = 32400;
time_t alarm_1PortIsUp;
time_t alarm_2PortIsUp;
byte alarm_1WeekDay = allWorkDays;
byte alarm_2WeekDay = allWeekEnd;
boolean beepIsOn;
boolean beepCaller;
boolean timerIsOn;
boolean alarm_1IsOn;
boolean alarm_2IsOn;
boolean alarm_1PortIsOn;
boolean alarm_2PortIsOn;
byte timerMode = 1;
byte alarm_1Mode = 1;
byte alarm_2Mode = 1;
const char strHour[] = "HOUr ";
const char strMinute[] = "MIN ";
const char strSec[] = "SEC ";
const char strDay[] = "dAY ";
const char strMonth[] = "MontH ";
const char strYear[] = "YEAr20";
const char strAdjustment[] = "AdJUS ";
const char strTimer[] = "tI M E r";
const char strAlarm_1[] = "ALArM 1";
const char strAlarm_2[] = "ALArM 2";
const char strBeep[] = "bEEP ";
const char strRelay[] = "rEL ";
const char strOn[] = "ON";
const char strOff[] = "OFF";
const char strYes[] = "YES";
const char strNo[] = " NO";
void show (byte showMode);
int getValueForCorrect (const char str[], int value, int minValue, byte maxValue);
void setTimeDate();
void adjustTimeEveryDay ();
void setTimer();
byte restOfTimerTime();
void timerRun ();
void doBeep (boolean caller);
void showStrTimerAlarm (const char str_[]);
void doPause (unsigned int pause_);
void setAlarm_1();
void alarm_1Run ();
void setAlarm_2();
void alarm_2Run ();
void show(byte sMode)
{
byte n;
byte m;
int left;
int middle;
int right;
char* separator[] = {"-", "_", "~", "*", "o"};
flag_esc = false;
switch (sMode)
{
case 1:
{
left = hour();
middle = minute();
right = second();
n = 0; m = 0;
if (alarm_1IsOn) n = 3;
if (alarm_2IsOn) m = 4;
if ((lastShowMode != 1 ) || (! timerIsOn))
{
for (byte i=0; i < 8; i++)
{
module.setLED (0,i);
}
}
if (timerIsOn)
{
for (byte i=0; i < restOfTimerTime(); i++)
{
module.setLED (TM1638_COLOR_RED,i);
}
}
lastShowMode = 1;
}
break;
case 2:
{
left = hour(alarm_1);
middle = minute(alarm_1);
right = second(alarm_1);
n = 3; m = 3;
if (alarm_1IsOn) m = 0;
if (lastShowMode != 2)
{
for (byte i=0; i < 8; i++)
{
module.setLED (0,i);
}
}
if (alarm_1WeekDay < 8) module.setLED (TM1638_COLOR_RED, alarm_1WeekDay - 1);
if (alarm_1WeekDay == 8)
{
for (byte i=1; i < 6; i++)
{
module.setLED (1,i);
}
}
if (alarm_1WeekDay == 9)
{
module.setLED (TM1638_COLOR_RED, 6);
module.setLED (TM1638_COLOR_RED, 0);
}
if (alarm_1WeekDay == 10)
{
for (byte i=0; i < 8; i++)
{
module.setLED (1,i);
}
}
lastShowMode = 2;
}
break;
case 3:
{
left = day();
middle = month();
right = year() - 2000;
n = 1; m = 1;
if (lastShowMode != 3)
{
for (byte i=0; i < 8; i++)
{
module.setLED (0,i);
}
}
module.setLED (TM1638_COLOR_RED, weekday ()-1);
lastShowMode = 3;
}
break;
case 4:
{
left = hour(alarm_2);
middle = minute(alarm_2);
right = second(alarm_2);
n = 4; m = 4;
if (alarm_2IsOn) n = 0;
if (lastShowMode != 4)
{
for (byte i=0; i < 8; i++)
{
module.setLED (0,i);
}
}
if (alarm_2WeekDay < 8) module.setLED (TM1638_COLOR_RED, alarm_2WeekDay - 1);
if (alarm_2WeekDay == 8)
{
for (byte i=1; i < 6; i++)
{
module.setLED (1,i);
}
}
if (alarm_2WeekDay == 9)
{
module.setLED (TM1638_COLOR_RED, 6);
module.setLED (TM1638_COLOR_RED, 0);
}
if (alarm_2WeekDay == 10)
{
for (byte i=0; i < 8; i++)
{
module.setLED (1,i);
}
}
lastShowMode = 4;
}
break;
case 8:
{
left = hour(timer);
middle = minute(timer);
right = second(timer);
n = 2; m = 2;
if (lastShowMode != 8)
{
for (byte i=0; i < 8; i++)
{
module.setLED (0,i);
}
}
lastShowMode = 8;
}
break;
}
module.setDisplayDigit(byte ((left - (left % 10)) / 10), byte (0), false);
module.setDisplayDigit(byte (left % 10), byte (1), false);
module.setDisplayDigit(byte ((middle - (middle % 10)) / 10), byte (3), false);
module.setDisplayDigit(byte (middle % 10), byte(4), false);
module.setDisplayDigit(byte ((right - (right % 10)) / 10), byte (6), false);
module.setDisplayDigit(byte (right % 10), byte (7), false);
module.setDisplayToString(separator[n], false, 2);
module.setDisplayToString(separator[m], false, 5);
byte b = module.getButtons();
if(lastShowMode == 8 && b == 128) timerIsOn = true;
if(lastShowMode == 2 && b == 128) alarm_1IsOn = true;
if(lastShowMode == 4 && b == 128) alarm_2IsOn = true;
}
void doPause(unsigned int pause_)
{
unsigned long pause = millis();
if (millis () < pause) pause = millis();
while (millis () - pause < pause_)
{}
pause = millis();
}
int getValueForCorrect (const char str[], int value, int minValue, byte maxValue)
{
byte flagForOut;
byte buttn;
do
{
doPause (400);
buttn = module.getButtons();
if (buttn == 0) flagForOut++;
if (flagForOut > 200)
{
flag_esc = true;
flag = true;
return value;
}
switch (buttn)
{
case 1:
case 2:
case 4:
case 8:
{
flag_esc = true;
flag = true;
return value;
}
break;
case 32:
{
flagForOut = 0;
value++;
if (value >= maxValue) value = maxValue;
}
break;
case 64:
{
flagForOut = 0;
value--;
if (value <= minValue) value = minValue;
}
break;
case 128:
{
flag = true;
return value;
}
break;
}
if (value < 0 )
{
module.setDisplayToString (str);
module.setDisplayToString("-", false, 5);
module.setDisplayDigit (( (value % 10) - value) / 10, byte (6), false);
module.setDisplayDigit ( -value % 10, byte (7), false);
}
if ((maxValue == 1) && (value == 1))
{
module.setDisplayToString (str);
module.setDisplayToString(strYes, false, 5);
}
if ((maxValue == 1) && (value == 0))
{
module.setDisplayToString (str);
module.setDisplayToString(strNo, false, 5);
}
if (maxValue > 1 && value >= 0)
{
module.setDisplayToString (str);
module.setDisplayDigit ((value - (value % 10)) / 10, byte (6), false);
module.setDisplayDigit ( value % 10, byte (7), false);
}
}
while (buttn != 16);
return value;
}
void setTimeDate()
{
int copyAdjustmentTime = adjustmentTime;
flag = false;
flag_esc = false;
time_t timeForSet = now ();
int setHour = hour (timeForSet);
int setMinute = minute (timeForSet);
const byte setSecond = 0;
int setDay = day (timeForSet);
int setMonth = month (timeForSet);
int setYear = year (timeForSet) - 2000;
for (byte i=0; i < 8; i++)
{
module.setLED (0,i);
}
do
{
setHour = getValueForCorrect(strHour, setHour, 0, 23);
if (flag) continue;
setMinute = getValueForCorrect(strMinute, setMinute, 0, 59);
if (flag) continue;
setDay = getValueForCorrect(strDay, setDay, 1, 31);
if (flag) continue;
setMonth = getValueForCorrect(strMonth, setMonth, 1, 12);
if (flag) continue;
setYear = getValueForCorrect(strYear, setYear, 15, 99);
if (flag) continue;
adjustmentTime = getValueForCorrect(strAdjustment, adjustmentTime, -60, 60);
if (flag) continue;
}
while (!flag);
if (!flag_esc) setTime (setHour, setMinute, setSecond, setDay, setMonth, setYear);
else adjustmentTime = copyAdjustmentTime;
}
byte restOfTimerTime()
{
return byte((tempForTimer + 0.03 * tempForTimer - timer) / (tempForTimer / 8));
}
void setTimer()
{
byte copyTimerMode = timerMode;
int timerMode_1 = int(timerMode) & 0b00000001;
int timerMode_2 = ((int(timerMode) - timerMode_1) & 0b00000010) / 2;
byte hour_ = hour (timer);
byte min_ = minute (timer);
byte sec_ = second (timer);
flag = false;
flag_esc = false;
showStrTimerAlarm (strTimer);
do
{
min_ = getValueForCorrect(strMinute, min_, 0, 59);
if (flag) continue;
hour_ = getValueForCorrect(strHour, hour_, 0, 23);
if (flag) continue;
sec_ = getValueForCorrect(strSec, sec_, 0, 59);
if (flag) continue;
timerMode_1 = getValueForCorrect(strBeep, timerMode_1, 0, 1);
if (flag) continue;
timerMode_2 = getValueForCorrect(strRelay, timerMode_2, 0, 1);
timerMode = byte(timerMode_1) + 2 * byte(timerMode_2) ;
if (flag) continue;
}
while (!flag);
if (!flag_esc)
{
if ((min_ == 0) && (hour_ == 0) && (sec_ == 0)) sec_ = 3;
timer = hour_ * 3600 + min_ * 60 + sec_;
timerIsOn = true;
}
else
{
timer = tempForTimer;
timerMode = copyTimerMode;
timerIsOn = false;
}
}
void showStrTimerAlarm (const char str_[])
{
module.setDisplayToString (str_);
doPause (800);
}
void timerRun ()
{ if (timerMode ==2 || timerMode ==3) digitalWrite (timerPort, HIGH);
static byte seconds = second();
if (seconds != second())
{
timer --;
seconds = second();
}
if (timer == 0)
{
timerIsOn = false;
timer = tempForTimer;
digitalWrite (timerPort, LOW);
if (timerMode == 1 || timerMode == 3)
{
beepIsOn = true;
beepCaller = false;
doBeep (beepCaller);
}
}
}
void alarm_1Run ()
{
byte dayOfWeek = byte(weekday());
byte hourNow = byte(hour());
byte minuteNow = byte(minute());
byte secondNow = byte(second());
bool flagIs;
if (hourNow == 0 && adjustmentTime > 0 && alarm_1 < adjustmentTime) alarm_1 = adjustmentTime + 15;
if (dayOfWeek == alarm_1WeekDay) flagIs = true;
else if (dayOfWeek > sunday && dayOfWeek < saturday && alarm_1WeekDay == allWorkDays) flagIs = true;
else if ((dayOfWeek == sunday || dayOfWeek == saturday) && alarm_1WeekDay == allWeekEnd) flagIs = true;
else if (alarm_1WeekDay == allDays) flagIs = true;
else flagIs = false;
if (flagIs && (hourNow == hour (alarm_1))) flagIs = true;
else flagIs = false;
if (flagIs && (minuteNow == minute (alarm_1))) flagIs = true;
else flagIs = false;
if (flagIs && (secondNow == second (alarm_1))) flagIs = true;
else flagIs = false;
if (flagIs && (alarm_1Mode == 1 || alarm_1Mode == 3))
{
if(alarm_1WeekDay < allWorkDays) alarm_1IsOn = false;
beepCaller = true;
beepIsOn = true;
doBeep (beepCaller);
}
if (flagIs && (alarm_1Mode == 2 || alarm_1Mode == 3))
{
if(alarm_1WeekDay < allWorkDays) alarm_1IsOn = false;
alarm_1PortIsUp = now();
alarm_1PortIsOn = true;
}
}
void alarm_2Run ()
{
byte dayOfWeek = weekday();
byte hourNow = hour();
byte minuteNow = minute();
byte secondNow = second();
bool flagIs;
if (hourNow == 0 && adjustmentTime > 0 && alarm_2 < adjustmentTime) alarm_2 = adjustmentTime + 15;
if (dayOfWeek == alarm_2WeekDay) flagIs = true;
else if (dayOfWeek > sunday && dayOfWeek < saturday && alarm_2WeekDay == allWorkDays) flagIs = true;
else if ((dayOfWeek == sunday || dayOfWeek == saturday) && alarm_2WeekDay == allWeekEnd) flagIs = true;
else if (alarm_2WeekDay == allDays) flagIs = true;
else flagIs = false;
if (flagIs && (hourNow == hour (alarm_2))) flagIs = true;
else flagIs = false;
if (flagIs && (minuteNow == minute (alarm_2))) flagIs = true;
else flagIs = false;
if (flagIs && (secondNow == second (alarm_2))) flagIs = true;
else flagIs = false;
if (flagIs && (alarm_2Mode == 1 || alarm_2Mode == 3))
{
if(alarm_2WeekDay < allWorkDays) alarm_2IsOn = false;
beepCaller = true;
beepIsOn = true;
doBeep (beepCaller);
}
if (flagIs && ((alarm_2Mode == 2) || (alarm_2Mode == 3)))
{
if(alarm_2WeekDay < allWorkDays) alarm_2IsOn = false;
alarm_2PortIsUp = now();
alarm_2PortIsOn = true;
}
}
void doBeep (bool caller)
{
static byte beepTimes;
if (beepIsOn)
{
tone (beepPort, 900);
doPause (700);
noTone(beepPort);
doPause (300);
beepTimes ++;
if ((beepTimes > 15) && (!caller))
{
beepTimes = 0;
beepIsOn = false;
}
if ((beepTimes > 63) && caller)
{
beepTimes = 0;
beepIsOn = false;
}
if (btn > 0)
{
beepIsOn = false;
beepTimes = 0;
}
}
}
void adjustTimeEveryDay ()
{
static time_t timeForAdjust;
static boolean flag_t;
if (hour (timeForAdjust)== 23 && hour () == 0 && flag_t)
{
adjustTime (long(adjustmentTime));
flag_t = false;
}
if (hour() == 22) flag_t = true;
timeForAdjust = now ();
}
void setAlarm_1()
{
byte copyAlarm_1WeekDay = alarm_1WeekDay;
byte copyAlarm_1Mode = alarm_1Mode;
int alarm_1Mode_1 = int(alarm_1Mode) & 0b00000001;
int alarm_1Mode_2 = ((int(alarm_1Mode) - alarm_1Mode_1) & 0b00000010) / 2;
byte hour_ = hour (alarm_1);
byte min_ = minute (alarm_1);
byte sec_ = second (alarm_1);
flag = false;
flag_esc = false;
showStrTimerAlarm (strAlarm_1);
do
{
hour_ = getValueForCorrect(strHour, hour_, 0, 23);
if (flag) continue;
min_ = getValueForCorrect(strMinute, min_, 0, 59);
if (flag) continue;
sec_ = getValueForCorrect(strSec, sec_, 0, 59);
if (flag) continue;
alarm_1WeekDay = getValueForCorrect(strDay, alarm_1WeekDay, 1, 10);
if (flag) continue;
alarm_1Mode_1 = getValueForCorrect(strBeep, alarm_1Mode_1, 0, 1);
if (flag) continue;
alarm_1Mode_2 = getValueForCorrect(strRelay, alarm_1Mode_2, 0, 1);
alarm_1Mode = byte(alarm_1Mode_1) + 2 * byte(alarm_1Mode_2) ;
if (flag) continue;
}
while (!flag);
if (!flag_esc)
{
alarm_1 = hour_ * 3600 + min_ * 60 + sec_;
alarm_1IsOn = true;
}
else
{
alarm_1 = tempForAlarm_1;
alarm_1Mode = copyAlarm_1Mode;
alarm_1WeekDay = copyAlarm_1WeekDay;
alarm_1IsOn = false;
alarm_1PortIsOn = false;
}
}
void setAlarm_2()
{
byte copyAlarm_2WeekDay = alarm_2WeekDay;
byte copyAlarm_2Mode = alarm_2Mode;
int alarm_2Mode_1 = int(alarm_2Mode) & 0b00000001;
int alarm_2Mode_2 = ((int(alarm_2Mode) - alarm_2Mode_1) & 0b00000010) / 2;
byte hour_ = hour (alarm_2);
byte min_ = minute (alarm_2);
byte sec_ = second (alarm_2);
flag = false;
flag_esc = false;
showStrTimerAlarm (strAlarm_2);
do
{
hour_ = getValueForCorrect(strHour, hour_, 0, 23);
if (flag) continue;
min_ = getValueForCorrect(strMinute, min_, 0, 59);
if (flag) continue;
sec_ = getValueForCorrect(strSec, sec_, 0, 59);
if (flag) continue;
alarm_2WeekDay = getValueForCorrect(strDay, alarm_2WeekDay, 1, 10);
if (flag) continue;
alarm_2Mode_1 = getValueForCorrect(strBeep, alarm_2Mode_1, 0, 1);
if (flag) continue;
alarm_2Mode_2 = getValueForCorrect(strRelay, alarm_2Mode_2, 0, 1);
alarm_2Mode = byte(alarm_2Mode_1) + 2 * byte(alarm_2Mode_2) ;
if (flag) continue;
}
while (!flag);
if (!flag_esc)
{
alarm_2 = hour_ * 3600 + min_ * 60 + sec_;
alarm_2IsOn = true;
}
else
{
alarm_2 = tempForAlarm_2;
alarm_2Mode = copyAlarm_2Mode;
alarm_2WeekDay = copyAlarm_2WeekDay;
alarm_2IsOn = false;
alarm_2PortIsOn = false;
}
}
void setup()
{
setTime (firstStartTime);
pinMode (timerPort, OUTPUT);
pinMode (beepPort, OUTPUT);
pinMode (alarm_1Port, OUTPUT);
pinMode (alarm_2Port, OUTPUT);
}
void loop()
{
if (hour() == 22 || hour() == 23 || hour() == 0) adjustTimeEveryDay ();
if (timerIsOn) timerRun();
if (alarm_1IsOn) alarm_1Run();
if (alarm_2IsOn) alarm_2Run();
if (beepIsOn) doBeep (beepCaller);
if (alarm_1PortIsOn && (now() - alarm_1PortIsUp) < 60 && btn == 0) digitalWrite (alarm_1Port, HIGH);
else
{
alarm_1PortIsOn = false;
digitalWrite (alarm_1Port, LOW);
}
if (alarm_2PortIsOn && (now() - alarm_2PortIsUp) < 60 && btn == 0) digitalWrite (alarm_2Port, HIGH);
else
{
alarm_2PortIsOn = false;
digitalWrite (alarm_2Port, LOW);
}
btn = module.getButtons();
switch (btn)
{
case 1:
{
escToTimeShowMode = 0;
showMode = 3;
show (showMode);
}
break;
case 2:
{
escToTimeShowMode = 0;
showMode = 2;
show (showMode);
}
break;
case 4:
{
escToTimeShowMode = 0;
showMode = 4;
show (showMode);
}
break;
case 8:
{
escToTimeShowMode = 0;
showMode = 8;
show (showMode);
}
break;
case 16:
{
if (showMode == 1 || showMode == 3) setTimeDate();
if (showMode == 8)
{
setTimer();
tempForTimer = timer;
}
if (showMode == 2)
{
lastShowMode = 16;
setAlarm_1();
tempForAlarm_1 = alarm_1;
}
if (showMode == 4)
{
lastShowMode = 16;
setAlarm_2();
tempForAlarm_2 = alarm_2;
}
}
break;
default :
{
if (showMode == 1 || showMode == 3) showMode = 1;
if (showMode == 2)
{
escToTimeShowMode ++;
if (escToTimeShowMode > 20000)
{
showMode = 1;
}
else showMode = 2;
}
if (showMode == 4)
{
escToTimeShowMode ++;
if (escToTimeShowMode > 20000)
{
showMode = 1;
}
else showMode = 4;
}
if (showMode == 8 && !timerIsOn)
{
escToTimeShowMode ++;
if (escToTimeShowMode > 50000)
{
showMode = 1;
}
else showMode = 8;
}
show (showMode);
}
break;
}
}
Приделал RTC и сделал сохранение настроек в EEPROM.
Описание:
Самая левая кнопка (1) - часы, (отмена), дата:
Кнопка 2 - будильник - 1,(отмена),;
Кнопка 3 - будильник - 2,(отмена),;
Кнопка 4- таймер,(отмена),;
Кнопка 5 - setup;
Кнопка 6 - +;
Кнопка 7 - -;
Кнопка 8 - enter;
При работе таймера в режиме "Часы" светодиодики показывают пропорционально прошедшее время.
Индикация информативна.
#include <Time.h> #include <TimeLib.h> #include <elapsedMillis.h> #include <Wire.h> #include <DS1307RTC.h> // a basic DS1307 library that returns time as a time_t #include <EEPROM.h> #include <TM1638.h> TM1638 module(3, 4, 2); const unsigned long firstStartTime = 1483228800; const byte timerPort = 9; const byte beepPort = 12; const byte alarm_1Port = 10; const byte alarm_2Port = 11; const byte sunday = 1; const byte saturday = 7; const byte allWorkDays = 8; const byte allWeekEnd = 9; const byte allDays = 10; const int eeTimerAddress = 0; const int eeTimerIsReSetAddress = 8; const int eeAlarm_1Address = 9; const int eeAlarm_1IsReSetAddress = 20; const int eeAlarm_2Address = 21; const int eeAlarm_2IsReSetAddress = 32; const int eeAdjustmentTimeAddress = 33; //last used EEPROM address is 34 unsigned int escToTimeShowMode; byte btn; byte showMode = 1; byte lastShowMode = 1; int adjustmentTime; boolean flag; boolean flag_esc; time_t timer = 300; time_t tempForTimer = timer; time_t alarm_1 = 25200; time_t tempForAlarm_1 = alarm_1; time_t alarm_2 = 32400; time_t tempForAlarm_2 = alarm_2; time_t alarm_1PortIsUp; time_t alarm_2PortIsUp; byte alarm_1WeekDay = allWorkDays; byte alarm_2WeekDay = allWeekEnd; byte timerIsReSet; byte alarm_1IsReSet; byte alarm_2IsReSet; boolean beepIsOn; boolean beepCaller; boolean timerIsOn; boolean alarm_1IsOn; boolean alarm_2IsOn; boolean alarm_1PortIsOn; boolean alarm_2PortIsOn; byte timerMode = 1; byte alarm_1Mode = 1; byte alarm_2Mode = 1; elapsedMillis timeElapsed; const char strHour[] = "HOUr "; const char strMinute[] = "MIN "; const char strSec[] = "SEC "; const char strDay[] = "dAY "; const char strMonth[] = "MontH "; const char strYear[] = "YEAr20"; const char strAdjustment[] = "AdJUS "; const char strTimer[] = "tI M E r"; const char strAlarm_1[] = "ALArM 1"; const char strAlarm_2[] = "ALArM 2"; const char strBeep[] = "bEEP "; const char strRelay[] = "rEL "; const char strYes[] = "YES"; const char strNo[] = " NO"; void show (byte showMode); int getValueForCorrect (const char str[], int value, int minValue, byte maxValue); void setTimeDate(); void adjustTimeEveryDay (); void setTimer(); byte restOfTimerTime(); void timerRun (); void doBeep (boolean caller); void showStrTimerAlarm (const char str_[]); bool doPause (unsigned int pause_, bool mode); void setAlarm_1(); void alarm_1Run (); void setAlarm_2(); void alarm_2Run (); void setup() { setSyncProvider(RTC.get); // the function to get the time from the RTC if (timeStatus() != timeSet) setTime (firstStartTime); pinMode (timerPort, OUTPUT); pinMode (beepPort, OUTPUT); pinMode (alarm_1Port, OUTPUT); pinMode (alarm_2Port, OUTPUT); timerIsReSet = EEPROM.read (eeTimerIsReSetAddress); if (timerIsReSet == 1) { EEPROM .get(0, timer); tempForTimer = timer; } alarm_1IsReSet = EEPROM.read (eeAlarm_1IsReSetAddress); if (alarm_1IsReSet == 1) { EEPROM .get(eeAlarm_1Address, alarm_1); tempForAlarm_1 = alarm_1; alarm_1WeekDay = EEPROM.read (17); alarm_1Mode = EEPROM.read (18); alarm_1IsOn = EEPROM.read (19); } alarm_2IsReSet = EEPROM.read (eeAlarm_2IsReSetAddress); if (alarm_2IsReSet == 1) { EEPROM .get(eeAlarm_2Address, alarm_2); tempForAlarm_2 = alarm_2; alarm_2WeekDay = EEPROM.read (29); alarm_2Mode = EEPROM.read (30); alarm_2IsOn = EEPROM.read (31); } EEPROM.get(eeAdjustmentTimeAddress, adjustmentTime); if (adjustmentTime < 60 || adjustmentTime > 60) adjustmentTime = 0; } void loop() { if (hour() == 22 || hour() == 23 || hour() == 0) adjustTimeEveryDay (); if (timerIsOn) timerRun(); if (alarm_1IsOn) alarm_1Run(); if (alarm_2IsOn) alarm_2Run(); if (beepIsOn) doBeep (beepCaller); if (alarm_1PortIsOn && (now() - alarm_1PortIsUp) < 60 && btn == 0) digitalWrite (alarm_1Port, HIGH); else { alarm_1PortIsOn = false; digitalWrite (alarm_1Port, LOW); } if (alarm_2PortIsOn && (now() - alarm_2PortIsUp) < 60 && btn == 0) digitalWrite (alarm_2Port, HIGH); else { alarm_2PortIsOn = false; digitalWrite (alarm_2Port, LOW); } btn = module.getButtons(); switch (btn) { case 1: { escToTimeShowMode = 0; showMode = 3; show (showMode); } break; case 2: { escToTimeShowMode = 0; showMode = 2; show (showMode); } break; case 4: { escToTimeShowMode = 0; showMode = 4; show (showMode); } break; case 8: { escToTimeShowMode = 0; showMode = 8; show (showMode); } break; case 16: { if (showMode == 1 || showMode == 3) setTimeDate(); if (showMode == 8) { setTimer(); tempForTimer = timer; } if (showMode == 2) { lastShowMode = 16; setAlarm_1(); tempForAlarm_1 = alarm_1; } if (showMode == 4) { lastShowMode = 16; setAlarm_2(); tempForAlarm_2 = alarm_2; } } break; default : { if (showMode == 1 || showMode == 3) showMode = 1; if (showMode == 2) { escToTimeShowMode ++; if (escToTimeShowMode > 20000) { showMode = 1; } else showMode = 2; } if (showMode == 4) { escToTimeShowMode ++; if (escToTimeShowMode > 20000) { showMode = 1; } else showMode = 4; } if (showMode == 8 && !timerIsOn) { escToTimeShowMode ++; if (escToTimeShowMode > 50000) { showMode = 1; } else showMode = 8; } show (showMode); } break; } } void adjustTimeEveryDay () { static time_t timeForAdjust; static boolean flag_t; if (hour (timeForAdjust)== 23 && hour () == 0 && flag_t) { adjustTime (long(adjustmentTime)); flag_t = false; } if (hour() == 22) flag_t = true; timeForAdjust = now (); } void alarm_1Run () { byte dayOfWeek = weekday(); byte hourNow = hour(); byte minuteNow = minute(); byte secondNow = second(); bool flagIs; if (hourNow == 0 && adjustmentTime > 0 && alarm_1 < adjustmentTime) alarm_1 = adjustmentTime + 15; if (dayOfWeek == alarm_1WeekDay) flagIs = true; else if (dayOfWeek > sunday && dayOfWeek < saturday && alarm_1WeekDay == allWorkDays) flagIs = true; else if ((dayOfWeek == sunday || dayOfWeek == saturday) && alarm_1WeekDay == allWeekEnd) flagIs = true; else if (alarm_1WeekDay == allDays) flagIs = true; else flagIs = false; if (flagIs && (hourNow == hour (alarm_1))) flagIs = true; else flagIs = false; if (flagIs && (minuteNow == minute (alarm_1))) flagIs = true; else flagIs = false; if (flagIs && (secondNow == second (alarm_1))) flagIs = true; else flagIs = false; if (flagIs && (alarm_1Mode == 1 || alarm_1Mode == 3)) { if(alarm_1WeekDay < allWorkDays) alarm_1IsOn = false; beepCaller = true; beepIsOn = true; doBeep (beepCaller); } if (flagIs && (alarm_1Mode == 2 || alarm_1Mode == 3)) { if(alarm_1WeekDay < allWorkDays) alarm_1IsOn = false; alarm_1PortIsUp = now(); alarm_1PortIsOn = true; } } void alarm_2Run () { byte dayOfWeek = weekday(); byte hourNow = hour(); byte minuteNow = minute(); byte secondNow = second(); bool flagIs; if (hourNow == 0 && adjustmentTime > 0 && alarm_2 < adjustmentTime) alarm_2 = adjustmentTime + 15; if (dayOfWeek == alarm_2WeekDay) flagIs = true; else if (dayOfWeek > sunday && dayOfWeek < saturday && alarm_2WeekDay == allWorkDays) flagIs = true; else if ((dayOfWeek == sunday || dayOfWeek == saturday) && alarm_2WeekDay == allWeekEnd) flagIs = true; else if (alarm_2WeekDay == allDays) flagIs = true; else flagIs = false; if (flagIs && (hourNow == hour (alarm_2))) flagIs = true; else flagIs = false; if (flagIs && (minuteNow == minute (alarm_2))) flagIs = true; else flagIs = false; if (flagIs && (secondNow == second (alarm_2))) flagIs = true; else flagIs = false; if (flagIs && (alarm_2Mode == 1 || alarm_2Mode == 3)) { if(alarm_2WeekDay < allWorkDays) alarm_2IsOn = false; beepCaller = true; beepIsOn = true; doBeep (beepCaller); } if (flagIs && ((alarm_2Mode == 2) || (alarm_2Mode == 3))) { if(alarm_2WeekDay < allWorkDays) alarm_2IsOn = false; alarm_2PortIsUp = now(); alarm_2PortIsOn = true; } } void doBeep (bool caller) { static byte beepTimes; if (beepIsOn) { tone (beepPort, 900); if (doPause (700, true)) { noTone(beepPort); beepTimes ++; doPause (300, false); } if ((beepTimes > 15) && (!caller)) { beepTimes = 0; beepIsOn = false; } if ((beepTimes > 63) && caller) { beepTimes = 0; beepIsOn = false; } if (btn > 0) { beepIsOn = false; beepTimes = 0; noTone(beepPort); } } } bool doPause(unsigned int pause_, bool mode) { startPause: if (timeElapsed > pause_) { timeElapsed = 0; return true; } else if(mode) return false; else goto startPause; } int getValueForCorrect (const char str[], int value, int minValue, byte maxValue) { byte flagForOut; byte buttn; do { doPause(300, false); buttn = module.getButtons(); if (buttn == 0) flagForOut++; if (flagForOut > 200) { flag_esc = true; flag = true; return value; } switch (buttn) { case 1: case 2: case 4: case 8: { flag_esc = true; flag = true; return value; } break; case 32: { flagForOut = 0; value++; if (value >= maxValue) value = maxValue; } break; case 64: { flagForOut = 0; value--; if (value <= minValue) value = minValue; } break; case 128: { flag = true; return value; } break; } if (value < 0 ) { module.setDisplayToString (str); module.setDisplayToString("-", false, 5); module.setDisplayDigit (( (value % 10) - value) / 10, byte (6), false); module.setDisplayDigit ( -value % 10, byte (7), false); } if ((maxValue == 1) && (value == 1)) { module.setDisplayToString (str); module.setDisplayToString(strYes, false, 5); } if ((maxValue == 1) && (value == 0)) { module.setDisplayToString (str); module.setDisplayToString(strNo, false, 5); } if (maxValue > 1 && value >= 0) { module.setDisplayToString (str); module.setDisplayDigit ((value - (value % 10)) / 10, byte (6), false); module.setDisplayDigit ( value % 10, byte (7), false); } } while (buttn != 16); return value; } byte restOfTimerTime() { return byte((tempForTimer + 0.03 * tempForTimer - timer) / (tempForTimer / 8)); } void showStrTimerAlarm (const char str_[]) { doPause (100, false); module.setDisplayToString (str_); doPause (1000, false); } void setAlarm_1() { byte copyAlarm_1WeekDay = alarm_1WeekDay; byte copyAlarm_1Mode = alarm_1Mode; int alarm_1Mode_1 = int(alarm_1Mode) & 0b00000001; int alarm_1Mode_2 = ((int(alarm_1Mode) - alarm_1Mode_1) & 0b00000010) / 2; byte hour_ = hour (alarm_1); byte min_ = minute (alarm_1); byte sec_ = second (alarm_1); flag = false; flag_esc = false; showStrTimerAlarm (strAlarm_1); do { hour_ = getValueForCorrect(strHour, hour_, 0, 23); if (flag) continue; min_ = getValueForCorrect(strMinute, min_, 0, 59); if (flag) continue; sec_ = getValueForCorrect(strSec, sec_, 0, 59); if (flag) continue; alarm_1WeekDay = getValueForCorrect(strDay, alarm_1WeekDay, 1, 10); if (flag) continue; alarm_1Mode_1 = getValueForCorrect(strBeep, alarm_1Mode_1, 0, 1); if (flag) continue; alarm_1Mode_2 = getValueForCorrect(strRelay, alarm_1Mode_2, 0, 1); alarm_1Mode = byte(alarm_1Mode_1) + 2 * byte(alarm_1Mode_2) ; if (flag) continue; } while (!flag); if (!flag_esc) { alarm_1 = hour_ * 3600 + min_ * 60 + sec_; alarm_1IsOn = true; EEPROM .put(eeAlarm_1Address, alarm_1); EEPROM.write (17, alarm_1WeekDay); EEPROM.write (18, alarm_1Mode); EEPROM.write (19, alarm_1IsOn); EEPROM.write (eeAlarm_1IsReSetAddress, 1); } else { alarm_1 = tempForAlarm_1; alarm_1Mode = copyAlarm_1Mode; alarm_1WeekDay = copyAlarm_1WeekDay; alarm_1IsOn = false; EEPROM.write (19, alarm_1IsOn); alarm_1PortIsOn = false; } } void setAlarm_2() { byte copyAlarm_2WeekDay = alarm_2WeekDay; byte copyAlarm_2Mode = alarm_2Mode; int alarm_2Mode_1 = int(alarm_2Mode) & 0b00000001; int alarm_2Mode_2 = ((int(alarm_2Mode) - alarm_2Mode_1) & 0b00000010) / 2; byte hour_ = hour (alarm_2); byte min_ = minute (alarm_2); byte sec_ = second (alarm_2); flag = false; flag_esc = false; showStrTimerAlarm (strAlarm_2); do { hour_ = getValueForCorrect(strHour, hour_, 0, 23); if (flag) continue; min_ = getValueForCorrect(strMinute, min_, 0, 59); if (flag) continue; sec_ = getValueForCorrect(strSec, sec_, 0, 59); if (flag) continue; alarm_2WeekDay = getValueForCorrect(strDay, alarm_2WeekDay, 1, 10); if (flag) continue; alarm_2Mode_1 = getValueForCorrect(strBeep, alarm_2Mode_1, 0, 1); if (flag) continue; alarm_2Mode_2 = getValueForCorrect(strRelay, alarm_2Mode_2, 0, 1); alarm_2Mode = byte(alarm_2Mode_1) + 2 * byte(alarm_2Mode_2) ; if (flag) continue; } while (!flag); if (!flag_esc) { alarm_2 = hour_ * 3600 + min_ * 60 + sec_; alarm_2IsOn = true; EEPROM.put(eeAlarm_2Address, alarm_2); EEPROM.write (29, alarm_2WeekDay); EEPROM.write (30, alarm_2Mode); EEPROM.write (31, alarm_2IsOn); EEPROM.write (eeAlarm_2IsReSetAddress, 1); } else { alarm_2 = tempForAlarm_2; alarm_2Mode = copyAlarm_2Mode; alarm_2WeekDay = copyAlarm_2WeekDay; alarm_2IsOn = false; EEPROM.write (31, alarm_2IsOn); alarm_2PortIsOn = false; } } void setTimeDate() { int copyAdjustmentTime = adjustmentTime; flag = false; flag_esc = false; time_t timeForSet = now (); int setHour = hour (timeForSet); int setMinute = minute (timeForSet); const byte setSecond = 0; int setDay = day (timeForSet); int setMonth = month (timeForSet); int setYear = year (timeForSet) - 2000; for (byte i=0; i < 8; i++) { module.setLED (0,i); } do { setHour = getValueForCorrect(strHour, setHour, 0, 23); if (flag) continue; setMinute = getValueForCorrect(strMinute, setMinute, 0, 59); if (flag) continue; setDay = getValueForCorrect(strDay, setDay, 1, 31); if (flag) continue; setMonth = getValueForCorrect(strMonth, setMonth, 1, 12); if (flag) continue; setYear = getValueForCorrect(strYear, setYear, 15, 99); if (flag) continue; adjustmentTime = getValueForCorrect(strAdjustment, adjustmentTime, -60, 60); if (flag) continue; } while (!flag); if (!flag_esc) { setTime (setHour, setMinute, setSecond, setDay, setMonth, setYear); timeForSet = now (); RTC.set(timeForSet); // set the RTC and the system time EEPROM.put(eeAdjustmentTimeAddress, adjustmentTime); } else adjustmentTime = copyAdjustmentTime; } void setTimer() { byte copyTimerMode = timerMode; int timerMode_1 = int(timerMode) & 0b00000001; int timerMode_2 = ((int(timerMode) - timerMode_1) & 0b00000010) / 2; byte hour_ = hour (timer); byte min_ = minute (timer); byte sec_ = second (timer); flag = false; flag_esc = false; showStrTimerAlarm (strTimer); do { min_ = getValueForCorrect(strMinute, min_, 0, 59); if (flag) continue; hour_ = getValueForCorrect(strHour, hour_, 0, 23); if (flag) continue; sec_ = getValueForCorrect(strSec, sec_, 0, 59); if (flag) continue; timerMode_1 = getValueForCorrect(strBeep, timerMode_1, 0, 1); if (flag) continue; timerMode_2 = getValueForCorrect(strRelay, timerMode_2, 0, 1); timerMode = byte(timerMode_1) + 2 * byte(timerMode_2) ; if (flag) continue; } while (!flag); if (!flag_esc) { if ((min_ == 0) && (hour_ == 0) && (sec_ == 0)) sec_ = 3; timer = hour_ * 3600 + min_ * 60 + sec_; timerIsOn = true; EEPROM .put(0, timer); EEPROM.write (eeTimerIsReSetAddress, 1); } else { timer = tempForTimer; timerMode = copyTimerMode; timerIsOn = false; } } void show(byte sMode) { byte n; byte m; int left; int middle; int right; char* separator[] = {"-", "_", "~", "*", "o"}; flag_esc = false; switch (sMode) { case 1: { left = hour(); middle = minute(); right = second(); n = 0; m = 0; if (alarm_1IsOn) n = 3; if (alarm_2IsOn) m = 4; if ((lastShowMode != 1 ) || (! timerIsOn)) { for (byte i=0; i < 8; i++) { module.setLED (0,i); } } if (timerIsOn) { for (byte i=0; i < restOfTimerTime(); i++) { module.setLED (TM1638_COLOR_RED,i); } } lastShowMode = 1; } break; case 2: { left = hour(alarm_1); middle = minute(alarm_1); right = second(alarm_1); n = 3; m = 3; if (alarm_1IsOn) m = 0; if (lastShowMode != 2) { for (byte i=0; i < 8; i++) { module.setLED (0,i); } } if (alarm_1WeekDay < 8) module.setLED (TM1638_COLOR_RED, alarm_1WeekDay - 1); if (alarm_1WeekDay == 8) { for (byte i=1; i < 6; i++) { module.setLED (1,i); } } if (alarm_1WeekDay == 9) { module.setLED (TM1638_COLOR_RED, 6); module.setLED (TM1638_COLOR_RED, 0); } if (alarm_1WeekDay == 10) { for (byte i=0; i < 8; i++) { module.setLED (1,i); } } lastShowMode = 2; } break; case 3: { left = day(); middle = month(); right = year() - 2000; n = 1; m = 1; if (lastShowMode != 3) { for (byte i=0; i < 8; i++) { module.setLED (0,i); } } module.setLED (TM1638_COLOR_RED, weekday ()-1); lastShowMode = 3; } break; case 4: { left = hour(alarm_2); middle = minute(alarm_2); right = second(alarm_2); n = 4; m = 4; if (alarm_2IsOn) n = 0; if (lastShowMode != 4) { for (byte i=0; i < 8; i++) { module.setLED (0,i); } } if (alarm_2WeekDay < 8) module.setLED (TM1638_COLOR_RED, alarm_2WeekDay - 1); if (alarm_2WeekDay == 8) { for (byte i=1; i < 6; i++) { module.setLED (1,i); } } if (alarm_2WeekDay == 9) { module.setLED (TM1638_COLOR_RED, 6); module.setLED (TM1638_COLOR_RED, 0); } if (alarm_2WeekDay == 10) { for (byte i=0; i < 8; i++) { module.setLED (1,i); } } lastShowMode = 4; } break; case 8: { left = hour(timer); middle = minute(timer); right = second(timer); n = 2; m = 2; if (lastShowMode != 8) { for (byte i=0; i < 8; i++) { module.setLED (0,i); } } lastShowMode = 8; } break; } module.setDisplayDigit(byte ((left - (left % 10)) / 10), byte (0), false); module.setDisplayDigit(byte (left % 10), byte (1), false); module.setDisplayDigit(byte ((middle - (middle % 10)) / 10), byte (3), false); module.setDisplayDigit(byte (middle % 10), byte(4), false); module.setDisplayDigit(byte ((right - (right % 10)) / 10), byte (6), false); module.setDisplayDigit(byte (right % 10), byte (7), false); module.setDisplayToString(separator[n], false, 2); module.setDisplayToString(separator[m], false, 5); byte b = module.getButtons(); if(lastShowMode == 8 && b == 128) timerIsOn = true; if(lastShowMode == 2 && b == 128) alarm_1IsOn = true; if(lastShowMode == 4 && b == 128) alarm_2IsOn = true; } void timerRun () { if (timerMode ==2 || timerMode ==3) digitalWrite (timerPort, HIGH); static byte seconds = second(); if (seconds != second()) { timer --; seconds = second(); } if (timer == 0) { timerIsOn = false; timer = tempForTimer; digitalWrite (timerPort, LOW); if (timerMode == 1 || timerMode == 3) { beepIsOn = true; beepCaller = false; doBeep (beepCaller); } } }простите ,а где скетч на часы
простите ,а где скетч на часы
я запретил.
Первый пример запустился сразу, второму для pro-mini нужен подбор библиотек чтобы уместился
Что-то около 40% флеша и примерно столько ОЗУ занимает, не помню точно. Проверялось всё на ПРО Мини. А библиотечки в начале файла описаны, поставить их в Arduino IDE очень просто.
Понятно. Просто у меня ПроМини с 328-ой атмегой.
Только у вас нашел исчерпывающую информацию и рабочие скетчи.Все отлично работает.Благодарю.
Шикарный пример, что. коли нет понимания - можно и с помощью millis забить процессорное время не хуже delay :) см функцию в строке 244 (первый скетч)
автор, "кнопки подтормаживают", да? :)
Второй скетч работает. Проверил на Меге, чуть-чуть подправил под свои нужды
b707, вы ехидный, в каждой теме нагадить нужно. Сделайте лучше, потом критикуйте
b707, вы ехидный, в каждой теме нагадить нужно. Сделайте лучше, потом критикуйте
Не в каждой, а только там, где выкладывают хрень. во втором коде такая же бредовая функция doPause(0). как в первом.
Второй скетч работает. Проверил на Меге, чуть-чуть подправил под свои нужды
b707, вы ехидный, в каждой теме нагадить нужно. Сделайте лучше, потом критикуйте
Он вам показал как вы при помощи миллис сделали фактически delay(). А вы сразу обижаетесь.
Ну. справедливости ради, во втором коде автор сделал попытку чуть улучшить код пресловутой функции doPause, чтобы она не была откровенной копией delay. В параметрах добавился второй член, как раз указывающий. будет пауза блокирующей или нет. Правда сам автор этой возможностью не пользуется (наверно, списал где-нибудь, не поняв сути?) -во всем коде программы неблокирующая пауза только в одном месте, а в других местах везде программа просто висит указанное кол-во миллисекунд.
Делаем вывод - то что код "работает" - это комплимент, на самом деле кнопки в нем должны тормозить, как и в коде из заглавного сообщения.
Он вам показал как вы при помощи миллис сделали фактически delay(). А вы сразу обижаетесь.
Ни в коем случае, какие обиды.
b707, сделайте как надо и выложите скетч - вот это будет нормально!
Возможно, даже скорее всего, автор списал не разобравшись. Ну и что? И я наверное 2/3 списываю - на то и форум, чтобы исправлять ошибки а не ехидничать. Соображаете в чем-то - отлично, научите других а не зазнавайтесь. Всегда же найдутся более умные
на то и форум, чтобы исправлять ошибки а не ехидничать.
Исправляют пусть сами. Если вам указали на ошибку - это уже огромная помощь, ибо исправить ошибку - это чаще всего вопрос технический, главное - знать, где она, ошибка....
на то и форум, чтобы исправлять ошибки а не ехидничать.
Исправляют пусть сами. Если вам указали на ошибку - это уже огромная помощь, ибо исправить ошибку - это чаще всего вопрос технический, главное - знать, где она, ошибка....
Мое мнение это зазнайство и скотство.
Посмотрите как общаются люди на Опеннет.РУ, поучитесь...
Мое мнение это зазнайство и скотство.
Посмотрите как общаются люди на Опеннет.РУ, поучитесь...
Внешняя разница имеется, но ни на одном форуме не любят тех, кто задает элементарные вопросы, не заглянув в гугл или в сотый раз ставит "проблемы", которые давно разобраны в ФАКе или в учебниках. Если человек хочет что-то узнать - он должен продемонстрировать свое желание учиться. "Тянуть за уши к знаниям", как в детском саду, тут никого не будут.
Мое мнение это зазнайство и скотство.
Посмотрите как общаются люди на Опеннет.РУ, поучитесь...
А что, на опеннете вашем на пост типа "Купил микротик, насобирал из кусков с интернета конфиг, заливаю - всё зависает. Проверьте!" все прямо кидаются и начинают в свои девайсы этот конфиг заливать, тестовую сеть собирать, да баги вылавливать?
.... все прямо кидаются и начинают в свои девайсы этот конфиг заливать, тестовую сеть собирать, да баги вылавливать?...
не, я пряи представил автора - как он идет по двору и видит дворника. который неправильно снег чистит. И как наш "не ехидный и не сволочной" сразу хватает у дворника лопату и давай шуровать - ведь он умеет лучше, а значит его долг почистить двор самостоятельно :)
Ну. справедливости ради, во втором коде автор сделал попытку чуть улучшить код пресловутой функции doPause, чтобы она не была откровенной копией delay. В параметрах добавился второй член, как раз указывающий. будет пауза блокирующей или нет. Правда сам автор этой возможностью не пользуется (наверно, списал где-нибудь, не поняв сути?) -во всем коде программы неблокирующая пауза только в одном месте, а в других местах везде программа просто висит указанное кол-во миллисекунд.
Делаем вывод - то что код "работает" - это комплимент, на самом деле кнопки в нем должны тормозить, как и в коде из заглавного сообщения.
Спасибо, что указали на ошибку.
Лирика: есть у меня один знакомый, тоже всё знает и всех учит по политической части, только вот не любмт его никто, даже его собаки.
В первом посте темы я написал, что вспомнил далёкое детсво. А составляя скетч, я вспоминал забытый лет 30 назад язык С. Теперь бы я написал такое СОВСЕМ по-другому, но мне это уже не интересно. А часики работают, хотя кнопочки и притормаживают. Жена пользуется.
Подскажите проект еще жив или нет?
пОГРЕШНОСТЬ ВРЕМЕНИ? в скетче на первом посте?