Давно было намерение сделать универсальный таймер, который можно было бы использовать для разных процессов, где требуется выдержка определённого времени и, который бы мог включать/отключать, по истечении времени, различную нагрузку, вплоть до устройств на ~220 В. Время пришло. Схема и программа разработаны. Основой этого таймера послужили проекты Таймер для катушки Мишина и МТР-1.2 (термометр-регулятор).
Как часто бывает, начальный проект всегда имеет какие-то недостатки и более оптимальное решение приходит уже после того, как углубляешься в тему. Так и в этом случае с таймером. После проверки первой версии, пришёл к написанию второй, которую считаю гораздо лучше, оптимальнее и имеющую большие возможности.
Начиная с версии v2.2 дополнительно применена условная компиляция, что позволило легко выбирать вариант логики управления кнопками: HIGH или LOW.
Начиная с версии v2.4 появилась возможность выбирать количество разрядов в индикаторе (3 или 4).
Начиная с версии v3 появился циклический режим работы. Можно задавать время паузы.
Версия v4 – минималистичная. Как версия v1, но код улучшен. Индикатор семисегментный часовой покупной, кнопки простые.
Кнопкой [Часы] устанавливаются часы до 99 часов (чуть больше 4-х суток), в первых двух разрядах таймера.
Кнопкой [Минуты] устанавливаются минуты до 59, в третьем и четвёртом разрядах. Часы и минуты разделены точкой второго разряда.
Кнопкой [Старт/Стоп] производится пуск и остановка таймера. Если таймер запущен, то разделительная точка второго разряда мигает. Если таймер остановлен, то точка второго разряда светится постоянно. Точка четвёртого разряда указывает на подключение модуля реле. Если модуль реле отключен, то точка четвёртого разряда не светится.
При одновременно нажатии на кнопки [Часы] и [Минуты] производится сброс установленного времени и на индикаторе выводится [0.00], первый незначащий 0 гасится.
При одновременно нажатии на кнопки [Минуты] и [Старт/Стоп] производится подключение [0.00.] или отключение [0.00] модуля реле, так как бывает, что не всегда необходимо управлять какой-то нагрузкой, поэтому сделал так, чтобы модуль реле можно было бы отключить программно, сигнал же об окончании работы таймера осуществляется звуком через буззер.
Таймер v2
Управляется таймер так же тремя кнопками, но их значение другое:
[MODE] – Выбор параметра настройки
[MINUS] – Убавить
[PLUS] – Прибавить
С помощью этих кнопок теперь возможно устанавливать время в двух режимах:
hh.mm(.) – часы.минуты(.)
mm.ss(.) – минуты.секунды(.)
Возможно через меню настроек:
Включение/Отключение звука
Включение/Отключение активности модуля реле
Установка яркости индикатора [0...7]
По нажатию на кнопку MODE происходит переход в настройки. Каждое нажатие – переход к следующему параметру. В крайнем левом разряде выводится номер пункта меню настройки. Так на индикаторе будет выводится следующая информация:
Индикация текущего времени*: hh.mm(.) | mm.ss(.)
Выбран режим hh.mm (часы.минуты) - на индикаторе: 10.00(.)[1.00(.)]
Выбран режим mm.ss (минуты.секунды) - на индикаторе: 10.01(.)[1.01(.)]
Установка часов|минут – на индикаторе: 20.хх [2.xx(.)], где хх = 0...99
Установка минут|секунд – на индикаторе: 30.хх [3.xx(.)], где хх = 0...59
Активность реле включена – на индикаторе: 40.01. [4.00.] - свечение точки DIG4*
Активность реле отключена – на индикаторе: 40.00 [4.00] - точка DIG4* не светится
Активность зуммера включена – на индикаторе: 50.01(.)[5.01(.)]
Активность зуммера отключена – на индикаторе: 50.00(.)[5.00(.)]
Яркость индикатора – на индикаторе: 60.0х[6.0x(.)], где х = 0...7
Запуск таймера производится кнопкой PLUS.
Остановка запущенного таймера на паузу производится кнопками PLUS, MINUS. При работе таймера кнопка MODE блокируется. Настройка таймера возможна только при остановленном таймере.
В момент сигнала об окончании работы таймера, остановить сигнал можно нажатием на любую кнопку.
Управление достаточно интуитивное и позволяет легко настраивать и пользоваться таймером.
Таймер v3
Эта версия имеет некоторое дополнение для активизации циклического режима работы, поэтому добавлены ещё три пункта в меню настройки. Для совместимости с трёхразрядным индикатором, в меню настроек значение mode выводится во втором разряде для 4-х разрядного индикатора и в первом разряде трёх разрядного индикатора. Теперь на индикаторе выводится следующая информация:
Индикация текущего времени*: hh.mm(.) | mm.ss(.)
Выбран режим hh.mm (часы.минуты) - на индикаторе: 1.00(.)
Выбран режим mm.ss (минуты.секунды) - на индикаторе: 1.01(.)
Установка часов|минут – на индикаторе: 2.xx(.), где хх = 0...99
Установка минут|секунд – на индикаторе: 3.xx(.), где хх = 0...59
Активность реле включена – на индикаторе: 4.00. - свечение точки DIG4*
Активность реле отключена – на индикаторе: 4.00 - точка DIG4* не светится
Активность зуммера включена – на индикаторе: 5.01(.)
Активность зуммера отключена – на индикаторе: 5.00(.)
Яркость индикатора – на индикаторе: 6.0x(.), где х = 0...7
Активность циклического режима включена – на индикаторе: 7.01(.)
Активность циклического режима отключена – на индикаторе: 7.00(.)
Установка* часов|минут – на индикаторе: 8.хх, где хх = 0...99
Установка* минут|секунд – на индикаторе: 9.xx(.), где хх = 0...59
Таймер v4
Описание управления таймером версии v4...
Управляется таймер тремя кнопками [HOUR], [MIN], [START]:
[HOUR] – Установка часов
[MIN] – Установка минут
[START] – короткое нажатие – Старт/Стоп Таймера
[START] – долгое нажатие (2 секунды) – Реле активно/Реле пассивно
[HOUR] + [MIN] – Сброс времени в [0:00]
Схема
Основой универсального таймера является плата Ардуино (Arduino Uno, Arduino Nano, Arduino Pro Mini и подобные). Управление осуществляется сенсорными кнопками TTP223, конечно можно вместо них использовать и обычные кнопки.
Индикация таймера осуществляется на четырёх разрядном семисегментном светодиодном индикаторе. В первом варианте схемы (только для версии v1) используется индикатор с общим катодом, который управляется сдвиговым регистром SN74HC595N. В настоящее время это вполне рабочий бюджетный вариант.
Исполнительным устройство является модуль реле K1, с управляющим сигналом высокого уровня (только для версии v1). У меня самодельный модуль, но возможно использование любого модуля и покупного в том числе.
По окончании работы таймера выдаётся звуковой сигнал через буззер активного типа BA1. Выключатель SA2 позволяет отключать звук окончания работы таймера, к примеру, когда окончание работы таймера приходится на ночное время.
Питание таймера осуществляется от внешнего источника питания +5В.
Второй вариант схемы в качестве индикатора использует модуль на TM1637. Для контроллера TM1637 используются светодиодные семисегментные индикаторы с общим анодом. В данном случае модуль самодельный, если использовать покупной модуль, то в нём должна быть возможность управления точками разрядов.
В версии v2 программы таймера используется логика управления низким уровнем выходными устройствами. Кнопки имеют несколько другие функции, поэтому схема изменилась. Попутно отпала необходимость в выключателе звука SA2. Для совместимости вариантов, управляющие пины остались прежними. Исходя из логики управления низким уровнем выходными устройствами, изготовил модуль реле, который управляется (включается) подачей на вход сигнала низкого уровня - LOW.
С версии v2.2 программы таймера сделана возможность выбирать логику управления кнопками. Возможно использовать сенсорные кнопки типа TTP223 (с логикой HIGH), или обычные кнопки (с логикой LOW). Так же для совместимости вариантов, управляющие пины остались прежними. Реализация совместимости программная.
В версии v3.1 программы таймера использован покупной 4-х разрядный индикатор часового типа. Поэтому для индикации активности реле используется дополнительный светодиод HL1. Схема подключения немного упрощена. Подключения идут на пины последовательно.
Ниже вариант схемы с использованием обычных кнопок и логикой управления LOW. Описание смотрите ниже на странице Таймер v3.1.
Так же как и в версии v3.1 в версии v4 программы таймера использован покупной 4-х разрядный индикатор часового типа и для индикации активности реле используется дополнительный светодиод HL1. Буззер, он же Биппер, подключен через транзистор BC547, можно 2N2222, КТ3102, КТ315 и им подобные. Реле можно ставить с любой логикой управления, выбирается в скетче через условное программирование. В данном случае реле с логикой управления HIGH.
Макетирование схемы
Вначале программа отлаживалась на макете. Ниже фото макета схемы 1. На фото модуль с кнопками снят. Программа проверялась на Arduino Pro Mini.
Далее отлаживалась программа для схемы 2. Модуль индикатора собран на четырёх разрядном индикаторе LN-5644-11Q(общий анод). Микросхема TM1637 припаяна к плате стенда проверки индикаторов. В момент запуска таймера включается модуль реле. На фото видно свечение зелёного светодиода на модуле реле (управление высоким уровнем). Подключение модуля реле указывается свечением точки четвёртого разряда (DIG4).
Скетч
Ниже приводится скетч версии v1 второго варианта схемы с индикатором на TM1637. Скетч версии v1 первого варианта схемы на индикаторе с управлением через сдвиговый регистр SN74HC595N можно скачать в Приложении.
Подготовка к публикации, скетч смотрите в Приложении
После тестирования первой версии скетча, пришёл к мнению, что требуется значительная переделка управления, чтобы с помощью всего трёх кнопок создать полное управление всеми функциями универсального таймера. Была создана версия v2.
В итоге получилось создать меню настроек в котором 7 пунктов mode =
Индикация текущего времени: hh.mm(.) | mm.ss(.) (зависит от режима 1)
Режим hh.mm (часы.минуты) - 0 | режим mm.ss (минуты.секунды) - 1
Версия v2.4 не имеет циклического режима, просто таймер. Скетч этой версии можно посмотреть ниже по нажатию на соответствующую кнопку (скрыл, чтобы не загромождать страницу). Новинка этой версии: применена условная компиляция, чтобы легко можно было перейти на логику управления кнопками либо LOW, либо HIGH. Дополнительно, используя условную компиляцию, удалось быстро перенастраивать скетч на использование индикатора, имеющего всего три разряда. Модуль индикатора смотрите по ссылке: Модуль на TM1637, модификация платы v4.
/*************************************************************
2022-03-11 Mr.ALB Универсальный таймер на TM1637
Индикатор 7-сегментный 4-х разрядный (можно 3-х)
LN5644 - общий анод! Можно любой другой,
но с общим анодом!
Кнопки TP223 - сенсорные (можно обычные).
https://mralb.ru/sections/programming/arduino_24.php#content_center
В версии v1 Кнопки:
1. HOUR – Установка часов
2. MIN – Установка минут
3. START – Старт/Стоп
С помощью кнопки HOUR устанавливаются часы до 99
(чуть больше 4-х суток).
С помощью кнопки MIN устанавливаются минуты до 59.
Кнопкой START осуществляется пуск и остановка таймера.
Кнопки MIN и START нажать одновременно
для включения/выключения активности реле.
Индикация активности реле – светящаяся точка 4-го разряда.
Кнопки MIN и HOUR нажать одновременно
для обнуления установленного времени.
Работа таймера – мигание точки 2-го разряда.
Таймер в режиме паузы или ожидания пуска – постоянно светящаяся
точка 2-го разряда.
Ранее установленное время после окончания работы таймера сохраняется
и новый пуск таймера осуществляется только нажатием кнопки START.
2022-04-14 Mr.ALB Переделка на полное управление тремя кнопками
2022-04-15 Mr.ALB написана v2.0
- Имеется меню режимов настройки.
- Возможно устанавливать время в двух режимах:
1. hh.mm(.)
2. mm.ss(.)
- Вкл./Откл. звука
- Вкл./Откл. реле
- установка яркости индикатора 0...7
2022-04-16 Mr.ALB v2.1 оптимизация кода
2022-04-17 Mr.ALB v2.2 адаптация под LGT8F + создание
адаптивной компиляции под разную логику кнопок.
Теперь можно использовать кнопки с логикой
управления высоким уровнем HIGH или кнопки с
логикой управления низким уровнем LOW
2022-04-20 Mr.ALB v2.3 предварительный сигнал при остатке
времени 5 мин
2022-04-28 Mr.ALB v2.4 логика управления кнопками TTP223 - LOW
+ отладка + оптимизация + выбор индикатора
на 3 или 4 разряда
Кнопки TTP223 (логика HIGH) или обычные (логика LOW):
1. MODE – Выбор режима
2. PLUS – Прибавить +
3. MINUS – Убавить -
* Примечание: Если у TTP223 замкнута перемычка А, то
* выбрать логику управления #define LOGICA 0
Соединения:
DIO - пин 2
CLK - пин 3
Buzzer - пин 9
MODE - пин 10
MINUS - пин 11
PLUS - пин 12
Реле - пин А0
2022-04-15 Скетч использует 4012 байт
2022-04-16 Скетч использует 3854 байт
2022-04-17 Скетч использует 5596 байт - режим отладки
2022-04-18 Скетч использует 4246 байт - режим откладки отключен
2022-04-19 Скетч использует 4080 байт ARDUINO_UNO
2022-04-20 Скетч использует 4110 байт ARDUINO_UNO
2022-04-28 Скетч использует 4072 байт Индикатор 4 разряда
2022-04-28 Скетч использует 4078 байт Индикатор 3 разряда
Архив с проектом: https://disk.yandex.ru/d/B4miN-and3bNtQ
****************************************************************/#include<TimerOne.h>// Подключение библиотеки Таймер1#include"TM1637_mralb2.h"// Библиотека для TM1637#define OUT A0
#define BUZZER 9
#define BT_MODE 10
#define BT_MINUS 11
#define BT_PLUS 12
#define MAXBEEP 16 // Сколько раз бикнет буззер#define DEF_WAIT_BUTTON 26 // Подтверждение кнопки#define DELAY_CLICK 21 // Время клика#define DELAY_BT 350 // Пауза после нажатия кнопки
// Включение режима отладки
// Если нет надобности, то строку ниже закоментировать
//#define DEBUG
// Определение типа используемой платы#define ARDUINO_UNO
//#define LGT8F
// Установите логику управления кнопками в вашей схеме
// Логика управления 1 - HIGH | 0 - LOW#define LOGICA 1
// Определение символов#define DP 10
#define PUSTO 11
#define CLK 3
#define DIO 2
#define MAXDIGIT 4 // Сколько всего разрядов в индикаторе 3|4TM1637 disp(CLK, DIO); // Создание объекта индикатора
; // Объявление и инициализация
// Массив символовstaticint8_t symb[] =
{
0x3f, 0x06, 0x5b,// 0, 1, 2
0x4f, 0x66, 0x6d,// 3, 4, 5,
0x7d, 0x07, 0x7f,// 6, 7, 8,
0x6f, 0x80, 0x00,// 9, 10 - точка, 11 - пусто,
};
// Структура разрядов дисплеяstruct Disp
{
byte high; // Разряды индикатора DID1, DIG2byte low; // Разряды индикатора DIG3, DIG4byte bright = 3; // Яркость 0...7
};
// Создание переменной типа Disp
Disp sdisp;
/* Глобальные переменные для времени */uint32_t t1, dt;
// Структура переменной времениstruct Tim
{
byte hh;
byte hh_set;
byte mm;
byte mm_set;
byte ss;
byte ss_set;
};
// Создание переменной типа Tim
Tim stime;
// Структура переменной флаговstruct Flag
{
bool runTimer =false; // Флаг работы таймераbool rele =true; // Флаг подключения релеbool buzz =true; // Флаг активности звукаbool modeTime2 =false; // Флаг mm.ss(.)
};
// Создание переменной типа Flag
Flag sflag;
// Переменная для прерывания, мигание точекvolatileboolean flag_point =true;
byte mode = 0; // Пункт меню 0 - вывод времени// Объявление функции сигнала Buzzer-a
// Окончание времени таймераvoid fnAlarmTimer
(
byte max_beep = MAXBEEP,unsignedint delay_beep = 500
);
// Объявление функции сканирования кнопки TTP223boolean fnScanButton
(
byte buttonPin,byte buttonWait = DEF_WAIT_BUTTON
);
// Объявление функции пиканья кнопкиvoid fnClickButton
(
unsignedint delay_ms = DELAY_CLICK
);
/***********************
Функция настройки
************************/voidsetup()
{
#ifdef DEBUG
Serial.begin(115200);
#endif#if (LOGICA == 1)
// Если логика управления кнопками 1 - HIGHpinMode(BT_MODE,INPUT); // Выбор режимаpinMode(BT_PLUS,INPUT); // Прибавить +pinMode(BT_MINUS,INPUT); // Убавить -#else// Если логика управления кнопками 0 - LOWpinMode(BT_MODE,INPUT_PULLUP); // Выбор режимаpinMode(BT_PLUS,INPUT_PULLUP); // Прибавить +pinMode(BT_MINUS,INPUT_PULLUP); // Убавить -#endif// Логика управления реле 0 - LOWpinMode(OUT,OUTPUT); // Управляющий выходdigitalWrite(OUT,HIGH); // Отключим выход// Логика управления звуком 0 - LOWpinMode(BUZZER,OUTPUT); // ЗуммерdigitalWrite(BUZZER,HIGH); // Отключим выход
disp.brightness(sdisp.bright);
// Для Ардуино Уно, загасить светодиод на пин13
// В других Ардуино не нужно#ifdef ARDUINO_UNO
pinMode(LED_BUILTIN,OUTPUT);
digitalWrite(LED_BUILTIN,LOW);
#endif// Инициализация прерывания на 500 мс
// Для мигания точекTimer1.initialize(500000);
// Проверка символов индикатора
// и работы звука буззера
fnDisplayTest();
//flag_point = true;
// Вывод текущего времени
fnPrintDisp(stime.hh, stime.mm);
} // End setup
/***************************
Рабочая программа
**************************/
// Статусы кнопокbool st_bt_minus,
st_bt_plus,
st_bt_mode;
voidloop()
{
// Проверка состояния кнопки BT_MODE
/*******************************************************
Всего 7 пунктов меню:
0 - Индикация текущего времени: hh.mm(.)|mm.ss(.)
1 - Режим hh.mm - 0 | режим mm.ss - 1
2 - Установка часов|минут 0...99
3 - Установка минут|секунд 0...59
4 - Активность реле 0|1 00.00. - точка DIG4
5 - Активность зуммера 0|1
6 - Яркость индикатора 0...7
При запущенном таймере меню заблокировано
*******************************************************/
// Условная компиляция. Выбор логики управления#if (LOGICA == 1)
if (digitalRead(BT_MODE))st_bt_mode =HIGH;
#elseif (!digitalRead(BT_MODE))st_bt_mode =HIGH;
#endifif (st_bt_mode &&!sflag.runTimer)
{
st_bt_mode =LOW;
fnMenuMode(); // Меню выбора режима
}
// Текущее время работы программы в мс
t1 =millis();
if (dt > t1) dt = t1; // Защита от переполнения t1// Автоматической возвращение из меню параметров
// к индикации времени через 10 секунд бездействияif ((t1 - dt > 10000) && mode != 0) mode = 0;
// Вывод текущего значения на дисплей
// Выбор установленных значений на индикаторswitch (mode)
{
case 1:// Альтернативное время
sdisp.low = sflag.modeTime2;
break;
case 2:// Значение в разрядах DIG1, DIG2if (sflag.modeTime2)
sdisp.low = stime.mm;
else
sdisp.low = stime.hh;
break;
case 3:// Значение в разрядах DIG3, DIG4if (sflag.modeTime2)
sdisp.low = stime.ss;
else
sdisp.low = stime.mm;
break;
case 4:// Активность реле
sdisp.low = sflag.rele;
break;
case 5:// Активность буззера
sdisp.low = sflag.buzz;
break;
case 6:// Уровень яркости 0...7
sdisp.low = sdisp.bright;
}
fnPrintTime(mode); // Выводим текущее время
/******************** setting *********************/
// Настройка альтернативного времени mm.ss(.)if (mode == 1)
{
sflag.modeTime2 = fnSetParamMode(sflag.modeTime2,false,true);
sdisp.low = sflag.modeTime2;
#if(MAXDIGIT==3)
if (sflag.modeTime2 && stime.mm_set > 9)stime.mm_set = 9;
#endif
sdisp.high = mode;
}
// Установка часов - hours|minitsif (mode == 2)
{
if (sflag.modeTime2)
{
#if(MAXDIGIT==4)
stime.mm_set = fnSetParamMode(stime.mm_set, 0, 99);
#elif(MAXDIGIT==3)
stime.mm_set = fnSetParamMode(stime.mm_set, 0, 9);
#endif
}
else
{
#if(MAXDIGIT==4)
stime.hh_set = fnSetParamMode(stime.hh_set, 0, 99);
#elif(MAXDIGIT==3)
stime.hh_set = fnSetParamMode(stime.hh_set, 0, 9);
#endif
}
// Установка минут - minits|secondsif (mode == 3)
{
if (sflag.modeTime2)
stime.ss_set = fnSetParamMode(stime.ss_set, 0, 59);
else
stime.mm_set = fnSetParamMode(stime.mm_set, 0, 59);
// Установим текущее время, если таймер не запущенif (!sflag.runTimer)
{
if (sflag.modeTime2)
{
stime.ss = stime.ss_set;
sdisp.low = stime.ss_set;
}
else
{
stime.mm = stime.mm_set;
sdisp.low = stime.mm_set;
}
}
sdisp.high = mode;
}
// Настройка активности реле - releif (mode == 4)
{
sflag.rele = fnSetParamMode(sflag.rele,false,true);
// Выключим выходif (!sflag.rele)digitalWrite(OUT,HIGH);
sdisp.low = sflag.rele;
sdisp.high = mode;
}
// Настройка активности звука - buzz/click/alarmif (mode == 5)
{
sflag.buzz = fnSetParamMode(sflag.buzz,false,true);
sdisp.low = sflag.buzz;
sdisp.high = mode;
}
// Настройка яркости индикатора - brightnessif (mode == 6)
{
sdisp.bright = fnSetParamMode(sdisp.bright, 0, 7);
disp.brightness(sdisp.bright);
sdisp.low = sdisp.bright;
sdisp.high = mode;
}
/****************** End setting ******************/
/****************** START TIMER ******************/
st_bt_plus =LOW;
st_bt_minus =LOW;
// Условная компиляция. Выбор логики управления#if (LOGICA == 1)
if (digitalRead(BT_PLUS))st_bt_plus =HIGH;
#elseif (!digitalRead(BT_PLUS))st_bt_plus =HIGH;
#endif// Если таймер ещё не запущенif (!sflag.runTimer && st_bt_plus)
{ // Было нажатие кнопки BT_PLUS - старт таймераif
(
mode == 0 &&
(
(
(stime.hh_set != 0 || stime.mm_set != 0) &&!sflag.modeTime2
) ||
(
(stime.mm_set != 0 || stime.ss_set != 0) &&
sflag.modeTime2
)
)
)
{
delay(500);
// Запуск таймера
sflag.runTimer =true;
fnClickButton();
// Подключение прерыванияTimer1.attachInterrupt(blink_point);
// Включим выходif (sflag.rele)digitalWrite(OUT,LOW);
stime.mm_set = stime.mm;
stime.hh_set = stime.hh;
if (sflag.modeTime2)
stime.ss_set = stime.ss;
dt = t1;
}
}
else
{
#if (LOGICA == 1)
if (digitalRead(BT_PLUS))st_bt_plus =HIGH;
if (digitalRead(BT_MINUS))st_bt_minus =HIGH;
#elseif (!digitalRead(BT_PLUS))st_bt_plus =HIGH;
if (!digitalRead(BT_MINUS))st_bt_minus =HIGH;
#endifif
( // Если таймер запущен, то
// кнопками BT_MINUS, BT_PLUS
// остановить на паузу
sflag.runTimer ==true&&
(st_bt_plus || st_bt_minus)
)
{ // Остановим таймер на ПАУЗУ
st_bt_plus =LOW;
fnStopTimer();
// Установим новые значения
stime.mm_set = stime.mm;
stime.hh_set = stime.hh;
if (sflag.modeTime2)
stime.ss_set = stime.ss;
flag_point =true;
}
}
/**************** END START TIMER ****************/
/**************** CONTROL TIMING ****************/
// Проверка пройденной минутыif
(
(sflag.runTimer ==true&&
((t1 - dt) >= 60000) &&!sflag.modeTime2) ||
(sflag.runTimer ==true&&
((t1 - dt) >= 1000) &&
sflag.modeTime2)
)
{
if (sflag.modeTime2)
{
#ifdef DEBUG
Serial.print(stime.mm);
Serial.print(":");
if (stime.ss < 10)Serial.print("0");
Serial.println(stime.ss);
#endifif (stime.ss != 0) stime.ss--;
else
{
if (stime.mm != 0)
{
stime.ss = 59;
stime.mm--;
}
}
}
else
{
#ifdef DEBUG
Serial.print(stime.hh);
Serial.print(":");
if (stime.mm < 10)Serial.print("0");
Serial.println(stime.mm);
#endifif (stime.mm != 0) stime.mm--;
else
{
if (stime.hh != 0)
{
stime.mm = 59;
stime.hh--;
}
}
}
// beep-beep если осталось 5 минif
(
(stime.hh == 0 && stime.mm == 5 &&!sflag.modeTime2) ||
(stime.mm == 5 && stime.ss == 0 && sflag.modeTime2)
)
{
fnClickButton();
delay(300);
fnClickButton();
}
if
(
(stime.hh == 0 && stime.mm == 0 &&!sflag.modeTime2) ||
(stime.mm == 0 && stime.ss == 0 && sflag.modeTime2)
)
{ // Завершение времени таймера
fnStopTimer(); // Стоп таймер
fnAlarmTimer(); // Сигнал окончания таймера
// Восстановим начальные установки
// для нового запуска
stime.mm = stime.mm_set;
stime.hh = stime.hh_set;
if (sflag.modeTime2)
stime.ss = stime.ss_set;
flag_point =true;
}
dt = t1; // Установка отсчёта новой минуты
}
/************* END CONTROL TIMING ***************/
// Выводим текущее время
fnPrintTime(mode);
} // End loop
/******************************************
*********** ПОДПРОГРАММЫ **************
******************************************/
/*************************
Функция мигания точек
************************/void blink_point()
{
flag_point =!flag_point;
}
/******************************
Функция: Стоп таймер
*****************************/void fnStopTimer()
{
sflag.runTimer =false;
if (sflag.buzz)fnClickButton();
if (sflag.rele)
digitalWrite(OUT,HIGH); // Отключим выходTimer1.detachInterrupt(); // Остановка прерыванияdelay(300);
}
/***********************************************
Функция: сигнал таймера
Включаем сигнал, если активен звук
Сигнал пульсирующий:
.5 секунды звук
.5 секунды пауза
2022-04-16 Mr.ALB v2
2022-04-20 Mr.ALB v2.2 добавлены аргументы:
max_beep - сколько раз бикнет,
delay_beep - время звука
***********************************************/void fnAlarmTimer
(
byte max_beep = MAXBEEP,unsignedint delay_beep = 500
)
{
long t;
// Если активен звукif (sflag.buzz)
{
fnPrintDisp(0, 0);
for (byte j = 0; j < max_beep; j++)
{
t =millis();
// Вывод текущего времени
//fnPrintDisp(stime.hh, stime.mm);while (millis() - t < delay_beep)
{
// Звук .5 секундыdigitalWrite(BUZZER,LOW);
// Если нажата любая кнопка
// Выход из цикла while()#if (LOGICA == 1)
if (digitalRead(BT_MINUS))st_bt_minus =HIGH;
if (digitalRead(BT_PLUS))st_bt_plus =HIGH;
if (digitalRead(BT_MODE))st_bt_mode =HIGH;
#elseif (!digitalRead(BT_MINUS))st_bt_minus =HIGH;
if (!digitalRead(BT_PLUS))st_bt_plus =HIGH;
if (!digitalRead(BT_MODE))st_bt_mode =HIGH;
#endifif (st_bt_minus || st_bt_plus || st_bt_mode)
{
st_bt_minus =LOW;
st_bt_plus =LOW;
st_bt_mode =LOW;
break;
}
}
t =millis();
while (millis() - t < delay_beep)
{
// Пауза .5 секундыdigitalWrite(BUZZER,HIGH);
// Если нажата любая кнопка
// Выход из цикла while()#if (LOGICA == 1)
if (digitalRead(BT_MINUS))st_bt_minus =HIGH;
if (digitalRead(BT_PLUS))st_bt_plus =HIGH;
if (digitalRead(BT_MODE))st_bt_mode =HIGH;
#elseif (!digitalRead(BT_MINUS))st_bt_minus =HIGH;
if (!digitalRead(BT_PLUS))st_bt_plus =HIGH;
if (!digitalRead(BT_MODE))st_bt_mode =HIGH;
#endifif (st_bt_minus || st_bt_plus || st_bt_mode)
{
st_bt_minus =LOW;
st_bt_plus =LOW;
st_bt_mode =LOW;
break;
}
}
// Если нажата любая кнопка
// Выход из цикла for()#if (LOGICA == 1)
if (digitalRead(BT_MINUS))st_bt_minus =HIGH;
if (digitalRead(BT_PLUS))st_bt_plus =HIGH;
if (digitalRead(BT_MODE))st_bt_mode =HIGH;
#elseif (!digitalRead(BT_MINUS))st_bt_minus =HIGH;
if (!digitalRead(BT_PLUS))st_bt_plus =HIGH;
if (!digitalRead(BT_MODE))st_bt_mode =HIGH;
#endifif (st_bt_minus || st_bt_plus || st_bt_mode)
{
st_bt_minus =LOW;
st_bt_plus =LOW;
st_bt_mode =LOW;
break;
}
}
fnClickButton();
delay(DELAY_BT);
}
} // End fnAlarmTimer
/********************************************
Вывод на индикатор в формате: 00.00(.)
2022-04-16 Mr.ALB v1.2
dig_high - число в разрядах DIG1, DIG2
dig_low - число в разрядах DIG3, DIG4
******************************************/void fnPrintDisp(byte dig_high,byte dig_low)
{
byte dig1 = dig_high / 10,
dig2 = dig_high % 10,
dig3 = dig_low / 10,
dig4 = dig_low % 10;
byte digit2, digit4;
// Вывод точки 2-го разрядаif (flag_point)
digit2 = symb[dig2] | symb[DP];
else digit2 = symb[dig2];
// Вывод точки 4-го разрядаif (sflag.rele)
digit4 = symb[dig4] | symb[DP];
else digit4 = symb[dig4];
// Вывод на индикатор#if (MAXDIGIT==4) // Если в индикаторе 4-е разрядаif (dig1 == 0) dig1 = PUSTO; // Гашение незначащего нуля
disp.displayByte(symb[dig1], digit2, symb[dig3], digit4);
#elif (MAXDIGIT == 3) // Если в индикаторе 3-и разряда
disp.displayByte(digit2, symb[dig3], digit4, symb[PUSTO]);
#endif
} // End fnPrintDisp
/*************************************************
Функция проверки всех сегментов
тест сегментов, поджигаем все на 2 сек
2022-01-02 Константин К.
2022-04-11 Mr.ALB переделка на вывод символов
************************************************/void fnDisplayTest()
{
// Проверка символов индикатораfor (byte i = 0; i <sizeof(symb); i++)
{
disp.displayByte(symb[i], symb[i], symb[i], symb[i]);
delay(DELAY_BT);
}
fnClickButton(30);
}
/**************************************
Функция звука нажатия кнопки
2022-04-12 Mr.ALB
2022-04-20 Mr.ALB v2.3
delay_ms - продолжительность звука
**************************************/void fnClickButton(unsignedint delay_ms = DELAY_CLICK)
{
if (sflag.buzz)
{
digitalWrite(BUZZER,LOW); // Звукdelay(DELAY_CLICK); // ЗадержкаdigitalWrite(BUZZER,HIGH); // Откл. звук
}
}
/***************************************************
Функция сканирования состояния кнопки
Кнопка TTP223 (сенсорная)
Активное состояние HIGH, но
если на TTP223 замкнута перемычка А,
то активное состояние LOW
2022-04-14 Mr.ALB
but_pin - номер пина кнопки
but_wait - ожидание устойчивого состояния
***************************************************/boolean fnScanButton(byte buttonPin,byte buttonWait = DEF_WAIT_BUTTON)
{
boolean current;
byte count = 0;
for (byte i = 0; i < buttonWait; i++)
{
// Опрос состояния кнопки#if (LOGICA == 1)
current =digitalRead(buttonPin);
#else
current =!digitalRead(buttonPin);
#endifif (current ==LOW&& count != 0) count--;
if (current ==HIGH) count++;
delay(2);
}
// Возвращаем истину, если подтверждений > 0return ((count > 0) ?true:false);
}
/**************************************************
Функция: установка параметра в mode
2022-04-16 Mr.ALB v1
*************************************************/byte fnSetParamMode
(
byte mode_param,// Устанавливаемый параметрbyte mode_param_min,// Минимальное значениеbyte mode_param_max // Максимальное значение
)
{
if (fnScanButton(BT_PLUS))
{ // Нажата кнопка "Плюс"if (mode_param != mode_param_max) mode_param++;
fnClickButton(21);
}
if (fnScanButton(BT_MINUS))
{ // Нажата кнопка "Минус"if (mode_param != mode_param_min) mode_param--;
fnClickButton(21);
}
delay(21);
return mode_param;
}
/*********************************************
Функция вывода времени
********************************************/void fnPrintTime(byte mode)
{
if (mode == 0)
{ // Выводим текущее времяif (sflag.modeTime2)
fnPrintDisp(stime.mm, stime.ss);
else
fnPrintDisp(stime.hh, stime.mm);
}
else// Иначе выводим значение параметра
fnPrintDisp(sdisp.high, sdisp.low);
}
/******************************************
Функция меню выбора режима
*****************************************/void fnMenuMode()
{
delay(DELAY_BT);
// Было нажатие кнопку "mode"
// Переходим на следующий пункт
mode++;
fnClickButton();
if (mode > 6) mode = 0;
sdisp.high = mode;
// Установка автоматического выхода
// в режим индикации времениif (mode != 0) dt = t1;
#ifdef DEBUG // ОтладкаSerial.print("mode= ");
Serial.println(mode);
#endif
}
Версия v3
Как и хотел, сделал новую версию v3, в которой реализован циклический режим работы.
В меню настроек добавилось ещё три пункта и теперь всего 10 пунктов mode =
Индикация текущего времени: hh.mm(.) | mm.ss(.) (зависит от режима 1)
Режим hh.mm (часы.минуты) - 0 | режим mm.ss (минуты.секунды) - 1
Установка паузы: часов|минут – 0...99 (при mode=7 и выбрано 1)
Установка паузы: минут|секунд – 0...59 (при mode=7 и выбрано 1)
Стоит отметить, что если в пункте 7 не установлена активность циклического режима, то пункты 8 и 9 не выводятся. Если в пункте 7 установлена активность циклического режима, но значения времени для паузы не установлены, то при запуске таймера значения времени для паузы будут как и в активном режиме, т.е. длительность паузы будет равна длительности активного режима.
Скетч v3 можно посмотреть ниже по нажатию на соответствующую кнопку.
/*************************************************************
2022-03-11 Mr.ALB Универсальный таймер на TM1637
Индикатор 7-сегментный 4-х разрядный (можно 3-х)
LN5644 - общий анод! Можно любой другой,
но с общим анодом!
Кнопки TP223 - сенсорные (можно обычные).
https://mralb.ru/sections/programming/arduino_24.php#content_center
В версии v1 Кнопки:
1. HOUR – Установка часов
2. MIN – Установка минут
3. START – Старт/Стоп
С помощью кнопки HOUR устанавливаются часы до 99
(чуть больше 4-х суток).
С помощью кнопки MIN устанавливаются минуты до 59.
Кнопкой START осуществляется пуск и остановка таймера.
Кнопки MIN и START нажать одновременно
для включения/выключения активности реле.
Индикация активности реле – светящаяся точка 4-го разряда.
Кнопки MIN и HOUR нажать одновременно
для обнуления установленного времени.
Работа таймера – мигание точки 2-го разряда.
Таймер в режиме паузы или ожидания пуска – постоянно светящаяся
точка 2-го разряда.
Ранее установленное время после окончания работы таймера сохраняется
и новый пуск таймера осуществляется только нажатием кнопки START.
2022-04-14 Mr.ALB Переделка на полное управление тремя кнопками
2022-04-15 Mr.ALB написана v2.0
- Имеется меню режимов настройки.
- Возможно устанавливать время в двух режимах:
1. hh.mm(.)
2. mm.ss(.)
- Вкл./Откл. звука
- Вкл./Откл. реле
- установка яркости индикатора 0...7
2022-04-16 Mr.ALB v2.1 оптимизация кода
2022-04-17 Mr.ALB v2.2 адаптация под LGT8F + создание
адаптивной компиляции под разную логику кнопок.
Теперь можно использовать кнопки с логикой
управления высоким уровнем HIGH или кнопки с
логикой управления низким уровнем LOW
2022-04-20 Mr.ALB v2.3 предварительный сигнал при остатке
времени 5 мин
2022-04-28 Mr.ALB v2.4 логика управления кнопками TTP223 - LOW
+ отладка + оптимизация + выбор индикатора
на 3 или 4 разряда
2022-05-26 Mr.ALB v2.5 Запись параметров в EEPROM
2022-05-28 Mr.ALB v3.0 Циклический режим
Кнопки TTP223 (логика HIGH) или обычные (логика LOW):
1. MODE – Выбор режима
2. MINUS – Убавить -
3. PLUS – Прибавить +
Примечание: Если у TTP223 замкнута перемычка А, то
выбрать логику управления #define LOGICA 0
Соединения:
DIO - пин 2
CLK - пин 3
Buzzer - пин 9
MODE - пин 10
MINUS - пин 11
PLUS - пин 12
Реле - пин А0
2022-04-15 Скетч использует 4012 байт
2022-04-16 Скетч использует 3854 байт
2022-04-17 Скетч использует 5596 байт - режим отладки
2022-04-18 Скетч использует 4246 байт - режим откладки отключен
2022-04-19 Скетч использует 4080 байт ARDUINO_UNO
2022-04-20 Скетч использует 4110 байт ARDUINO_UNO
2022-04-28 Скетч использует 4072 байт Индикатор 4 разряда
2022-04-28 Скетч использует 4078 байт Индикатор 3 разряда
2022-05-26 v2.5 Скетч использует 4294 байт +EEPROM
2022-05-28 v3.0 Скетч использует 4798 байт +циклический режим
Архив с проектом: https://disk.yandex.ru/d/KeRrmf0r7zUHmA
****************************************************************/#include<TimerOne.h>// Подключение библиотеки Таймер1#include<EEPROM.h>// Для EEPROM, запись яркости#include"TM1637_mralb2.h"// Библиотека для TM1637// Контакты I/O#define OUT A0
#define BUZZER 9
#define BT_MODE 10
#define BT_MINUS 11
#define BT_PLUS 12
#define MAXBEEP 16 // Сколько раз бикнет буззер#define DEF_WAIT_BUTTON 26 // Подтверждение кнопки#define DELAY_CLICK 21 // Время клика#define DELAY_BT 350 // Пауза после нажатия кнопкиbyte max_menu = 7; // Кол-во пунктов меню
/******************************************************
Включение режима отладки
Если нет надобности, то строку ниже закоментировать
*****************************************************/
//#define DEBUG
/*****************************************************
Определение типа используемой платы
****************************************************/#define MK 0 // Определяем тип микроконтроллера
; // 0 - Arduino Uno R3
; // 1 - Arduino Nano, Arduino Pro Mini
; // 2 - LGT8F328P, WAVGAT Pro Mini
; // 3 - WAVGAT Nano - Китайская подделка_
; // под Arduino Nano ATMega328// Выбор микроконтроллера#if (MK == 0)
#define ARDUINO_UNO // AVR ATMega328#endif#if (MK == 1)
#define AVR
#endif#if (MK == 2)
#define LGT8F // Китайский аналог ATMega328#endif#if (MK == 3)
#define WAVGAT_NANO // Китайская подделка_
; // под Nano AVR ATMega328#endif/******************************************************
Установите логику управления кнопками в вашей схеме
Логика управления 1 - HIGH | 0 - LOW
Для кнопок TTP223 лучше 1 - HIGH
Для обычных кнопок лучше 0 - LOW
******************************************************/#define LOGICA 1
/*****************************
ИНДИКАТОР
4-х разрядный 7 сигментный
под управлением TM1637
*****************************/
// Подключение управления#define DIO 2
#define CLK 3
// Сколько всего разрядов в индикаторе 3|4#define MAXDIGIT 4
TM1637 disp(CLK, DIO); // Создание объекта индикатора
; // Объявление и инициализация// Массив символов на индикатореstaticint8_t symb[] =
{ //GFEDCBA
0x3f, 0x06, 0x5b, 0x4f,//0, 1, 2, 3
0x66, 0x6d, 0x7d, 0x07,//4, 5, 6, 7 1100110, 1101101, 1111101,
0x7f, 0x6f, 0x77, 0x7c,//8, 9, A, b (A-10, b-11)
0x39, 0x5e, 0x79, 0x71,//C, d, E, F (C-12, d-13, E-14, F-15)
0x63, 0x73, 0x00,//°, P, , - (°-16, P-17, Пусто-18),
0x40, 0x80 //-, . (минус-19, .-20)
};
// Определение символов на индикаторе#define CELSIUM 12
#define DEGREE 16
#define SPRESS 17
#define PUSTO 18
#define MINUS 19
#define DP 20
// Структура разрядов дисплеяstruct myDisp
{
byte high; // Разряды индикатора DID1, DIG2byte low; // Разряды индикатора DIG3, DIG4byte bright = 3; // Яркость 0...7
};
// Создание переменной типа Disp
myDisp sdisp;
/* Глобальные переменные для времени */uint32_t t1, dt;
// Структура переменной времениstruct myTim
{
byte hh; // Текущее времяbyte mm;
byte ss;
byte hh_set; // Время действияbyte mm_set;
byte ss_set;
byte hhp_set; // Время паузыbyte mmp_set;
byte ssp_set;
};
// Создание переменной типа Tim
myTim stime;
// Структура переменной флаговstruct sFlag
{
bool runTimer =false; // Флаг работы таймераbool rele =true; // Флаг подключения релеbool buzz =true; // Флаг активности звукаbool modeTime2 =false; // Флаг mm.ss(.)bool cycl =false; // Флаг циклического режимаbool pause =false; // Флаг паузы цикла
};
// Создание переменной типа Flag
sFlag flag;
// Переменная для прерывания, мигание точекvolatileboolean flag_point =true;
byte mode = 0; // Пункт меню: 0 - вывод времени// Структура переменной адресов для EEPROMstruct myAddress
{
int br = 3; // Адрес яркости 3int rele = 5; // Адрес реле 5int cycl = 8; // Адрес циклического режима
};
// Создание переменной типа myAddress
myAddress addrEEPROM;
/*******************************************
* Оъявление функций
******************************************/
// Объявление функции сигнала Buzzer-a
// Окончание времени таймераvoid fnAlarmTimer
(
byte max_beep = MAXBEEP,unsignedint delay_beep = 500
);
// Объявление функции сканирования кнопки TTP223boolean fnScanButton
(
byte buttonPin,byte buttonWait = DEF_WAIT_BUTTON
);
// Объявление функции пиканья кнопкиvoid fnClickButton
(
unsignedint delay_ms = DELAY_CLICK
);
/*=======================
Функция настройки
========================*/voidsetup()
{
#ifdef DEBUG
Serial.begin(9600);
#endif#ifdef WAVGAT_NANO
Serial.begin(9600); // Последовательный пор для отладки
// Bits of CLKPR#define CLKOE1 6
#define CLKOE0 5
#define CLKOE 5
bool BIT;
CLKPR |= (1 << 7);
CLKPR &=~(1 << 1); // CLKPS0 установим в 0Serial.println(F(" Test - CLKPR: 0x03"));
Serial.print(F("CLKPCE CLKPOEN1 CLKOEN0 -"));
Serial.println(F("CLKPS3 CLKPS2 CLKPS1 CLKPS0"));
Serial.print(F(" "));
BIT = (CLKPR & (bit(CLKPCE)));
Serial.print(BIT); Serial.print(F(" "));
BIT = (CLKPR & (bit(CLKOE1)));
Serial.print(BIT); Serial.print(F(" "));
BIT = (CLKPR & (bit(CLKOE0)));
Serial.print(BIT); Serial.print(F(" "));
Serial.print("-"); Serial.print(F(" "));
BIT = (CLKPR & (bit(CLKPS3)));
Serial.print(BIT); Serial.print(F(" "));
BIT = (CLKPR & (bit(CLKPS2)));
Serial.print(BIT); Serial.print(F(" "));
BIT = (CLKPR & (bit(CLKPS1)));
Serial.print(BIT); Serial.print(F(" "));
BIT = (CLKPR & (bit(CLKPS0)));
Serial.println(BIT);
Serial.println();
#endif#if (LOGICA == 1)
// Если логика управления кнопками 1 - HIGHpinMode(BT_MODE,INPUT); // Выбор режимаpinMode(BT_PLUS,INPUT); // Прибавить +pinMode(BT_MINUS,INPUT); // Убавить -#else// Если логика управления кнопками 0 - LOWpinMode(BT_MODE,INPUT_PULLUP); // Выбор режимаpinMode(BT_PLUS,INPUT_PULLUP); // Прибавить +pinMode(BT_MINUS,INPUT_PULLUP); // Убавить -#endif// Логика управления реле 0 - LOWpinMode(OUT,OUTPUT); // Управляющий выходdigitalWrite(OUT,HIGH); // Отключим выход// Логика управления звуком 0 - LOWpinMode(BUZZER,OUTPUT); // ЗуммерdigitalWrite(BUZZER,HIGH); // Отключим выход#if (MK==0 || MK == 1 || MK == 2)
// Установка значений из EEPROM
// Считывание яркости из EEPROM
// Для AVR & LGT8Fbyte b;
// Получим значение из EEPROMEEPROM.get(addrEEPROM.br, b);
if
(
b >= 0 &&
b < 8 &&
b != sdisp.bright
)
sdisp.bright = b; // Установим яркость из EEPROM#endif
disp.brightness(sdisp.bright);
// Для Ардуино Уно, загасить светодиод на пин13
// В других Ардуино не нужно#ifdef ARDUINO_UNO
pinMode(LED_BUILTIN,OUTPUT);
digitalWrite(LED_BUILTIN,LOW);
#endif// Инициализация прерывания на 500 мс
// Для мигания точекTimer1.initialize(500000);
// Получим значение из EEPROMEEPROM.get(addrEEPROM.rele, b);
if
(
(b ==false|| b ==true) &&
b != flag.rele
)
flag.rele = b; // Установим флаг реле из EEPROM
// Получим значение из EEPROMEEPROM.get(addrEEPROM.cycl, b);
if
(
(b ==false|| b ==true) &&
b != flag.cycl
)
flag.cycl = b; // Установим флаг цикла из EEPROM// Кол-во пунктов меню
// Если не циклический режим, то max_menu = 7if (flag.cycl) max_menu = 9;
// Проверка символов индикатора
// и работы звука буззера
fnDisplayTest();
// Вывод текущего времени
fnPrintDisp(stime.hh, stime.mm);
} // End setup
/***************************
Рабочая программа
**************************/
// Статусы кнопокbool st_bt_minus,
st_bt_plus,
st_bt_mode;
voidloop()
{
/*******************************************************
Проверка состояния кнопки BT_MODE
Всего 7 пунктов меню:
0 - Индикация текущего времени: hh.mm(.)|mm.ss(.)
1 - Режим hh.mm - 0 | режим mm.ss - 1
2 - Установка часов|минут 0...99
3 - Установка минут|секунд 0...59
4 - Активность реле 0|1 00.00. - точка DIG4
5 - Активность зуммера 0|1
6 - Яркость индикатора 0...7
7 - Активность циклического таймера
8 - Установка паузы часов|минут 0...99
9 - Установка минут|секунд 0...59
При запущенном таймере меню заблокировано
*******************************************************/
// Условная компиляция. Выбор логики управления#if (LOGICA == 1)
if (digitalRead(BT_MODE))st_bt_mode =HIGH;
#elseif (!digitalRead(BT_MODE))st_bt_mode =HIGH;
#endifif (st_bt_mode &&!flag.runTimer)
{
st_bt_mode =LOW;
fnMenuMode(); // Меню выбора режима
}
// Текущее время работы программы в мс
t1 =millis();
if (dt > t1) dt = t1; // Защита от переполнения t1// Автоматической возвращение из меню параметров
// к индикации времени через 10 секунд бездействияif ((t1 - dt > 16000) && mode != 0) mode = 0;
// Выбор установленных значений на индикаторswitch (mode)
{
case 1:// Альтернативное время 0|1
sdisp.low = flag.modeTime2;
break;
case 2:// Значение в разрядах DIG1, DIG2if (flag.modeTime2)
sdisp.low = stime.mm_set;
else
sdisp.low = stime.hh_set;
break;
case 3:// Значение в разрядах DIG3, DIG4if (flag.modeTime2)
sdisp.low = stime.ss_set;
else
sdisp.low = stime.mm_set;
break;
case 4:// Активность реле
sdisp.low = flag.rele;
break;
case 5:// Активность буззера
sdisp.low = flag.buzz;
break;
case 6:// Уровень яркости 0...7
sdisp.low = sdisp.bright;
break;
case 7:// Активность циклического режима
sdisp.low = flag.cycl;
break;
case 8:// Время паузы в разрядах DIG1, DIG2if (flag.modeTime2)
sdisp.low = stime.mmp_set;
else
sdisp.low = stime.hhp_set;
break;
case 9:// Время паузы в разрядах DIG3, DIG4if (flag.modeTime2)
sdisp.low = stime.ssp_set;
else
sdisp.low = stime.mmp_set;
}
fnPrintTime(mode); // Выводим текущее время
/******************** setting *********************/byte m; // Вспомогательная переменная
// Настройка альтернативного времени mm.ss(.)if (mode == 1)
{
flag.modeTime2 = fnSetParamMode(flag.modeTime2,false,true);
sdisp.low = flag.modeTime2;
#if(MAXDIGIT==3) // Индикатор 3 разрядаif (flag.modeTime2 && stime.mm_set > 9)stime.mm_set = 9;
#endif
} // end mode=1
// Установка часов - hours|minitsif (mode == 2)
{
if (flag.modeTime2)
{
#if(MAXDIGIT==4)
stime.mm_set = fnSetParamMode(stime.mm_set, 0, 99);
#elif(MAXDIGIT==3)
stime.mm_set = fnSetParamMode(stime.mm_set, 0, 9);
#endif
}
else
{
#if(MAXDIGIT==4)
stime.hh_set = fnSetParamMode(stime.hh_set, 0, 99);
#elif(MAXDIGIT==3)
stime.hh_set = fnSetParamMode(stime.hh_set, 0, 9);
#endif
}
//===============================================================
// Установим текущее время, если таймер не запущенif (!flag.runTimer &&!flag.pause)
{
if (flag.modeTime2)
{
stime.mm = stime.mm_set;
sdisp.low = stime.mm_set;
}
else
{
stime.hh = stime.hh_set;
sdisp.low = stime.hh_set;
}
}
//===============================================================
} // end mode=2
// Установка минут - minits|secondsif (mode == 3)
{
if (flag.modeTime2)
stime.ss_set = fnSetParamMode(stime.ss_set, 0, 59);
else
stime.mm_set = fnSetParamMode(stime.mm_set, 0, 59);
// Установим текущее время, если таймер не запущенif (!flag.runTimer)
{
if (flag.modeTime2)
{
stime.ss = stime.ss_set;
sdisp.low = stime.ss_set;
}
else
{
stime.mm = stime.mm_set;
sdisp.low = stime.mm_set;
}
}
} // end mode=3
// Настройка активности реле - releif (mode == 4)
{
m = flag.rele;
flag.rele = fnSetParamMode(flag.rele,false,true);
// Выключим выходif (!flag.rele)digitalWrite(OUT,HIGH);
sdisp.low = flag.rele;
if (m != flag.rele) // Запись в EEPROMEEPROM.put(addrEEPROM.rele, flag.rele);
} // end mode=4
// Настройка активности звука - buzz/click/alarmif (mode == 5)
{
flag.buzz = fnSetParamMode(flag.buzz,false,true);
sdisp.low = flag.buzz;
} // end mode=5
// Настройка яркости индикатора - brightnessif (mode == 6)
{
m = sdisp.bright;
sdisp.bright = fnSetParamMode(sdisp.bright, 0, 7);
sdisp.low = sdisp.bright;
if (m != sdisp.bright)
{
disp.brightness(sdisp.bright); // Установка яркости
// Запись в EEPROMEEPROM.put(addrEEPROM.br, sdisp.bright);
}
} // end mode=6
// Настройка активности циклического режимаif (mode == 7)
{
m = flag.cycl;
flag.cycl = fnSetParamMode(flag.cycl,false,true);
// Выключим выходif (!flag.cycl)
{
digitalWrite(OUT,HIGH);
max_menu = 7;
}
else
max_menu = 9;
sdisp.low = flag.cycl;
if (m != flag.cycl) // Запись в EEPROMEEPROM.put(addrEEPROM.cycl, flag.cycl);
} // end mode=7
// Установка часов паузы - hours|minitsif (mode == 8)
{
if (flag.modeTime2)
{
#if(MAXDIGIT==4)
m = 99;
#elif(MAXDIGIT==3)
m = 9;
#endif
stime.mmp_set = fnSetParamMode(stime.mmp_set, 0, m);
}
else
{
#if(MAXDIGIT==4)
m = 99;
#elif(MAXDIGIT==3)
m = 9;
#endif
stime.hhp_set = fnSetParamMode(stime.hhp_set, 0, m);
}
} // end mode=8
// Установка минут паузы - minits|secondsif (mode == 9)
{
if (flag.modeTime2)
stime.ssp_set = fnSetParamMode(stime.ssp_set, 0, 59);
else
stime.mmp_set = fnSetParamMode(stime.mmp_set, 0, 59);
} // end mode=9
/******************* End setting *******************/
/************* Проверка текущего режима ************/if (mode != 0)
{ // Если настройка в менюTimer1.detachInterrupt();
flag.runTimer =false;
flag_point =true; // Включить точки
sdisp.high = mode;
}
else// (mode=0)
{ // Вывод информации на индикатор
// Обнулим состояние кнопок
st_bt_plus =LOW;
st_bt_minus =LOW;
// Условная компиляция. Выбор логики управления#if (LOGICA == 1)
if (digitalRead(BT_PLUS)) st_bt_plus =HIGH;
#elseif (!digitalRead(BT_PLUS))st_bt_plus =HIGH;
#endif/****************** START TIMER ******************/
// Если таймер ещё не запущен нажата кнопка Плюс+
// Запустим таймерif (!flag.runTimer &&!flag.pause && st_bt_plus)
{ // Было нажатие кнопки BT_PLUS - старт таймераif
(
(
(stime.hh_set != 0 || stime.mm_set != 0) &&!flag.modeTime2
) ||
(
(stime.mm_set != 0 || stime.ss_set != 0) &&
flag.modeTime2
)
)
{
delay(500);
fnStartTimer(); // Запуск таймера
dt = t1;
}
}
else
{ // Таймер запущен
// Проверим нажатие на кнопки Минус- или Плюс+#if (LOGICA == 1)
if (digitalRead(BT_PLUS))st_bt_plus =HIGH;
if (digitalRead(BT_MINUS))st_bt_minus =HIGH;
#elseif (!digitalRead(BT_PLUS))st_bt_plus =HIGH;
if (!digitalRead(BT_MINUS))st_bt_minus =HIGH;
#endif// Нажата кнопка Минус- или Плюс+if (st_bt_plus || st_bt_minus)
{
if (flag.buzz)fnClickButton(); // Клик кнопкиif (flag.runTimer)
{
// Установка нового времени действия
stime.mm_set = stime.mm;
stime.hh_set = stime.hh;
if (flag.modeTime2)
stime.ss_set = stime.ss;
}
else flag.pause =false;
fnStopTimer(); // Остановим таймерdelay(300);
dt = t1;
}
} // end else
/**************** END START TIMER ****************/
/**************** CONTROL TIMING *****************/
// Проверка пройденной минуты/секундыif (flag.runTimer || flag.cycl && flag.pause)
{
if
(
// Прошла минута
(((t1 - dt) >= 60000) &&!flag.modeTime2) ||// Прошла секунда
(((t1 - dt) >= 1000) && flag.modeTime2)
)
{
if (flag.modeTime2)
{ // Время: mm.ssif (stime.ss != 0) stime.ss--;
else
{
if (stime.mm != 0)
{
stime.ss = 59;
stime.mm--;
}
}
}
else// !flag.modeTime2
{ // Время: hh.mmif (stime.mm != 0) stime.mm--;
else
{
if (stime.hh != 0)
{
stime.mm = 59;
stime.hh--;
}
}
}
dt = t1; // Установка отсчёта новой минуты
}
if// Закончилось время
(
(stime.hh == 0 && stime.mm == 0 &&!flag.modeTime2) ||
(stime.ss == 0 && stime.mm == 0 && flag.modeTime2)
)
{
if (flag.runTimer)
{
fnStopTimer(); // Остановим таймерif (flag.cycl)
fnStartPause(); // Запустим паузу
}
else
{
if (flag.pause)flag.pause =false;
fnStartTimer();
}
if (!flag.cycl)
{
// Установка времени действия
stime.mm = stime.mm_set;
stime.hh = stime.hh_set;
if (flag.modeTime2)
stime.ss = stime.ss_set;
fnAlarmTimer(); // Сигнал окончания времени
}
}
} // end контроль пройденной минуты/секунды
/************* END CONTROL TIMING ****************/
} // end else (mode=0)
/********** end Проверка текущего режима ***********/
// Выводим текущее время
fnPrintTime(mode);
} // End loop
/******************************************
*********** ПОДПРОГРАММЫ **************
******************************************/
/*************************
Функция мигания точек
************************/void blink_point()
{
flag_point =!flag_point;
}
/**************************************
Функция звука нажатия кнопки
2022-04-12 Mr.ALB
2022-04-20 Mr.ALB v2.3
delay_ms - продолжительность звука
**************************************/void fnClickButton(unsignedint delay_ms = DELAY_CLICK)
{
if (flag.buzz)
{
digitalWrite(BUZZER,LOW); // Звукdelay(DELAY_CLICK); // ЗадержкаdigitalWrite(BUZZER,HIGH); // Откл. звук
}
}
/********************************************
Функция: Старт пауза циклического режима
2022-05-28 Mr.ALB
*******************************************/void fnStartPause()
{
flag.pause =true;
// Подключение прерыванияTimer1.attachInterrupt(blink_point);
// Установим значения паузыif
(
(stime.hhp_set == 0 && stime.mmp_set == 0 &&!flag.modeTime2) ||
(stime.ssp_set == 0 && stime.mmp_set == 0 && flag.modeTime2)
)
{
// Если значения паузы не выставлены, то
// паузу делаем равной времени активности
stime.mm = stime.mm_set;
if (flag.modeTime2)
stime.ss = stime.ss_set;
else
stime.hh = stime.hh_set;
}
else
{
// Если есть значения паузы
stime.mm = stime.mmp_set;
if (flag.modeTime2)
stime.ss = stime.ssp_set;
else
stime.hh = stime.hhp_set;
}
if (flag.rele)
digitalWrite(OUT,HIGH); // Отключим выход
}
/********************************************
Функция: Старт таймер
2022-05-28 Mr.ALB
*******************************************/void fnStartTimer()
{
flag.runTimer =true;
// Подключение прерыванияTimer1.attachInterrupt(blink_point);
if (flag.buzz)fnClickButton(); // Клик кнопкиif (flag.rele)
digitalWrite(OUT,LOW); // Включим выход, если реле
// Установка времени действия
stime.mm = stime.mm_set;
stime.hh = stime.hh_set;
if (flag.modeTime2)
stime.ss = stime.ss_set;
}
/********************************************
Функция: Стоп таймер
2022-05-28 Mr.ALB
*******************************************/void fnStopTimer()
{
flag.runTimer =false;
flag_point =true;
Timer1.detachInterrupt(); // Остановка прерыванияif (flag.buzz)fnClickButton(); // Клик кнопкиif (flag.rele)
digitalWrite(OUT,HIGH); // Отключим выходdelay(300);
}
/***********************************************
Функция: сигнал таймера
Включаем сигнал, если активен звук
Сигнал пульсирующий:
.5 секунды звук
.5 секунды пауза
2022-04-16 Mr.ALB v2
2022-04-20 Mr.ALB v2.2 добавлены аргументы:
max_beep - сколько раз бикнет,
delay_beep - время звука
***********************************************/void fnAlarmTimer
(
byte max_beep = MAXBEEP,unsignedint delay_beep = 500
)
{
long t;
// Если активен звукif (flag.buzz)
{
fnPrintDisp(0, 0);
for (byte j = 0; j < max_beep; j++)
{
t =millis();
// Вывод текущего времени
//fnPrintDisp(stime.hh, stime.mm);while (millis() - t < delay_beep)
{
// Звук .5 секундыdigitalWrite(BUZZER,LOW);
// Если нажата любая кнопка
// Выход из цикла while()#if (LOGICA == 1)
if (digitalRead(BT_MINUS))st_bt_minus =HIGH;
if (digitalRead(BT_PLUS))st_bt_plus =HIGH;
if (digitalRead(BT_MODE))st_bt_mode =HIGH;
#elseif (!digitalRead(BT_MINUS))st_bt_minus =HIGH;
if (!digitalRead(BT_PLUS))st_bt_plus =HIGH;
if (!digitalRead(BT_MODE))st_bt_mode =HIGH;
#endifif (st_bt_minus || st_bt_plus || st_bt_mode)
{
st_bt_minus =LOW;
st_bt_plus =LOW;
st_bt_mode =LOW;
break;
}
}
t =millis();
while (millis() - t < delay_beep)
{
// Пауза .5 секунды
digitalWrite(BUZZER,HIGH);
// Если нажата любая кнопка
// Выход из цикла while()#if (LOGICA == 1)
if (digitalRead(BT_MINUS))st_bt_minus =HIGH;
if (digitalRead(BT_PLUS))st_bt_plus =HIGH;
if (digitalRead(BT_MODE))st_bt_mode =HIGH;
#elseif (!digitalRead(BT_MINUS))st_bt_minus =HIGH;
if (!digitalRead(BT_PLUS))st_bt_plus =HIGH;
if (!digitalRead(BT_MODE))st_bt_mode =HIGH;
#endifif (st_bt_minus || st_bt_plus || st_bt_mode)
{
st_bt_minus =LOW;
st_bt_plus =LOW;
st_bt_mode =LOW;
break;
}
}
// Если нажата любая кнопка
// Выход из цикла for()#if (LOGICA == 1)
if (digitalRead(BT_MINUS))st_bt_minus =HIGH;
if (digitalRead(BT_PLUS))st_bt_plus =HIGH;
if (digitalRead(BT_MODE))st_bt_mode =HIGH;
#elseif (!digitalRead(BT_MINUS))st_bt_minus =HIGH;
if (!digitalRead(BT_PLUS))st_bt_plus =HIGH;
if (!digitalRead(BT_MODE))st_bt_mode =HIGH;
#endifif (st_bt_minus || st_bt_plus || st_bt_mode)
{
st_bt_minus =LOW;
st_bt_plus =LOW;
st_bt_mode =LOW;
break;
}
}
fnClickButton();
delay(DELAY_BT);
}
} // End fnAlarmTimer
/********************************************
Вывод на индикатор в формате: 00.00(.)
2022-04-16 Mr.ALB v1.2
dig_high - число в разрядах DIG1, DIG2
dig_low - число в разрядах DIG3, DIG4
******************************************/void fnPrintDisp(byte dig_high,byte dig_low)
{
byte dig1 = dig_high / 10,
dig2 = dig_high % 10,
dig3 = dig_low / 10,
dig4 = dig_low % 10;
byte digit2, digit4;
// Вывод точки 2-го разрядаif (flag_point)
digit2 = symb[dig2] | symb[DP];
else digit2 = symb[dig2];
// Вывод точки 4-го разрядаif (flag.rele)
digit4 = symb[dig4] | symb[DP];
else digit4 = symb[dig4];
// Вывод на индикатор#if (MAXDIGIT==4) // Если в индикаторе 4-е разрядаif (dig1 == 0) dig1 = PUSTO; // Гашение незначащего нуля
disp.displayByte(symb[dig1], digit2, symb[dig3], digit4);
#elif (MAXDIGIT == 3) // Если в индикаторе 3-и разряда
disp.displayByte(digit2, symb[dig3], digit4, symb[PUSTO]);
#endif
} // End fnPrintDisp
/*************************************************
Функция проверки всех сегментов
тест сегментов, поджигаем все на 2 сек
2022-01-02 Константин К.
2022-04-11 Mr.ALB переделка на вывод символов
************************************************/void fnDisplayTest()
{
// Проверка символов индикатораfor (byte i = 0; i <sizeof(symb); i++)
{
disp.displayByte(symb[i], symb[i], symb[i], symb[i]);
delay(DELAY_BT);
}
fnClickButton(30);
}
/***************************************************
Функция сканирования состояния кнопки
Кнопка TTP223 (сенсорная)
Активное состояние HIGH, но
если на TTP223 замкнута перемычка А,
то активное состояние LOW
2022-04-14 Mr.ALB
but_pin - номер пина кнопки
but_wait - ожидание устойчивого состояния
***************************************************/boolean fnScanButton
(byte buttonPin,byte buttonWait = DEF_WAIT_BUTTON)
{
boolean current;
byte count = 0;
for (byte i = 0; i < buttonWait; i++)
{
// Опрос состояния кнопки#if (LOGICA == 1)
current =digitalRead(buttonPin);
#else
current =!digitalRead(buttonPin);
#endifif (current ==LOW&& count != 0) count--;
if (current ==HIGH) count++;
delay(2);
}
// Возвращаем истину, если подтверждений > 0return ((count > 0) ?true:false);
}
/**************************************************
Функция: установка параметра в mode
2022-04-16 Mr.ALB v1
*************************************************/byte fnSetParamMode
(
byte mode_param,// Устанавливаемый параметрbyte mode_param_min,// Минимальное значениеbyte mode_param_max // Максимальное значение
)
{
if (fnScanButton(BT_PLUS))
{ // Нажата кнопка "Плюс"if (mode_param != mode_param_max) mode_param++;
fnClickButton(21);
}
if (fnScanButton(BT_MINUS))
{ // Нажата кнопка "Минус"if (mode_param != mode_param_min) mode_param--;
fnClickButton(21);
}
delay(21);
return mode_param;
}
/*********************************************
Функция вывода времени
mode - режим индикации
********************************************/void fnPrintTime(byte mode)
{
if (mode == 0)
{ // Выводим текущее время
// В зависимости от уставки в mode=1if (flag.modeTime2)
fnPrintDisp(stime.mm, stime.ss);
else
fnPrintDisp(stime.hh, stime.mm);
}
else// Иначе выводим значение:
// mode и его параметра
fnPrintDisp(sdisp.high, sdisp.low);
}
/******************************************
Функция меню выбора режима
*****************************************/void fnMenuMode()
{
delay(DELAY_BT);
// Было нажатие кнопку "mode"
// Переходим на следующий пункт
mode++;
fnClickButton();
if (mode > max_menu) mode = 0;
sdisp.high = mode;
// Установка автоматического выхода
// в режим индикации времениif (mode != 0) dt = t1;
}
Конструкция v3.0
Завершением проекта всегда будет законченная конструкция устройства. После чего любое устройство может свободно использоваться потребителем.
Собрал вариант на покупном модуле индикатора с TM1637 и обычных кнопках. На стенде с кнопками используются три левых кнопки. Общий у них GND. Логика управления кнопками переключена в скетче на LOW.
В качестве МК использован китайский вариант LGT8F328, который установлен на плату подобную Arduino Nano. Попутно стоит заметить, что эта плата очень капризная и всё время виснет, особенно в режиме отладки, когда необходимо контролировать процессы через монитор последовательного порта. Для устранения этого недостатка были дополнительно припаяны два SMD конденсатора ёмкостью по 100nF между выводами платы IN(Внешнее питание) и GND и между +5V и GND. После такой небольшой доработки плата с LGT8F328 работает без сбоев.
Вместо реле в этом макете используется красный светодиод.
Этот вариант практически любой может реализовать очень легко, так как все части схемы доступны.
Конструкция таймера представляет из себя модуль электроники, где собраны в этажерку плата с модулем индикатора и плата с Arduino. В моём варианте использовал плату WAVGAT Pro Mini. Обращу внимание, что контакты для программирования у неё зеркальные по сравнению с Arduino Pro Mini на контроллере AVR ATMega328P. На основной плате установлен зуммер и небольшая плата с панелькой для сенсорных кнопок. Отдельно от основной платы имеется модуль реле. Он закреплён на держателе из пластика ABS. Соединения между модулями и платой с кнопками с помощью шлейфов на разъёмах. Корпус сделал из пластмассы ABS толщиной 2 мм. Он состоит из двух частей: нижней и верхней. Соединяются они между собой защёлками.
К модулю электроники подпаяна плата с разъёмом microUSB, через который осуществляется питание таймера.
Опробовал таймер. Установил в параметре 4 активность реле. На фото ниже видно, что при работе таймера светится индикатор включения реле в нижнем правом углу.
Для удобного пользования наклеил поясняющие этикетки. Файл с этикетками смотрите в Приложении.
С левой стороны таймера есть отверстия под контакты программирования и под питание +5В через разъём microUSB.
Проверка работы Универсального таймера v3.0
Продолжительность фильма 3:59 [мм:сс]
Проверка работы таймера в сборе. Питание осуществляется от зарядного устройства на 5В для телефона через разъём microUSB. Описание параметров см. выше в подразделе Версия v3. Осталось наклеить этикетки с надписями.
Таймер v3.1
Попользовавшись таймером пришёл к мнению, что требуется выделить параметр каким-то образом, поэтому в первом разряде выводится нижнее подчёркивание (сегмент D), что позволяет характерно выделить номер параметра от установленного в первых разрядах времени.
Так как этот таймер ещё писал и под свою Ардуино на микроконтроллере ATTiny44A, в которой применял разные ухищрения по снижению размера кода и оптимальности его написания, то решил и версию v3.1 написать аналогично, используя для управления индикатором оптимизированные функции.
Ещё можно отметить, что в данной версии использовал покупной индикатор часового типа, что позволяет легко купить и использовать без всяких самоделок.
Как указывал выше, создал по просьбам подписчиков минимизированную версию таймера. Он прост в управлении, но при этом теряет немного функционала. Конструкция этого таймера ниже в картинках.
Схема таймера собрана на монтажной плате размерами 40*60 мм. Модуль реле собран сразу на этой плате. Ардуино использовано Pro Mini на ATMega168P, хоть оно и избыточно, так как сам скетч использует 3220 байт, но это сделано для простоты повторения проекта, можно поставить и Pro Mini на ATMega328P, для схемы и скетча это не принципиально. Кнопки управления припаяны на этой основной плате. Плата индикатора подключается через разъём. Так же через разъём подключается и светодиод активности реле.
Разъём питания MicroUSB установлен на переходной плате, она припаяна на основную плату.
Но этом виде показано как установлен клеммник для подключения внешней нагрузки.
Плата помещается в корпус изготовленный из пластика ABS толщиной 2,5мм. Размеры корпуса 67*48*40 мм. Он состоит из двух половин. В верней половине установлена плата с индикатором на TM1637 и светодиод активности реле. В нижнюю половину установлена основная плата. В корпусе имеются отверстие под разъём питания слева в нижней половине, на лицевой панеле верхней половины корпуса есть отверстие для звука зуммера и отверстие для отвертки на клеммник реле.
Когда реле активно, то на передней панеле светится светодиод. При запуске таймера будет происходить переключение контактов реле. Если реле не активно, то таймер работает просто для отсчёта установленного времени. По окончании времени срабатывает зуммер.
На данный момент проект закончен, но можно чего-нибудь потом и доработать. Пока нужно попользоваться и уже в ходе использования может быть выявятся неудобства или недостатки. Время покажет. А пока спасибо за внимание.
Анатолий Беляев.
На развитие сайта и проектов Arduino
Ниже на форме выберите/укажите сумму и источник перевода: Кошелёк Ю-money или Карта банка: Visa, MasterCard, МИР, Alfa-bank