Таймеры – это часы, используемые для измерения временных интервалов. Существуют два типа таймеров. Первый тип используется для счета от нуля и выше – он применяется для измерения прошедшего времени, данный тип таймера называют секундомером. А второй тип таймера считает вниз (до нуля) от времени, заданным пользователем – этот тип таймера называют таймером обратного отсчета.
В этой статье мы рассмотрим создание таймера обратного отсчета на основе платы Arduino. Для получения информации о текущем времени в данном проекте мы не будем использовать модуль часов реального времени (Real Time Clock, RTC). Длительность временного промежутка для счета будет задаваться с помощью клавиатуры 4х4 и ЖК дисплея 16×2. Когда таймер будет досчитывать до нуля будет издаваться звуковой сигнал с помощью зуммера.
Необходимые компоненты
- Плата Arduino Uno (купить на AliExpress).
- ЖК дисплей 16х2 (купить на AliExpress).
- Клавиатура (клавишная панель) 4х4 (купить на AliExpress).
- Зуммер (Buzzer) (купить на AliExpress).
- Кнопка.
- Потенциометр (10 кОм) (купить на AliExpress).
- Резистор 10 кОм (купить на AliExpress).
- Резистор 100 Ом (купить на AliExpress).
- Соединительные провода.
Работа схемы
Схема таймера обратного отсчета на основе платы Arduino представлена на следующем рисунке.
Объяснение программы для Arduino
Полный код программы приведен в конце статьи, здесь же рассмотрим его наиболее существенные фрагменты.
Сначала в программе необходимо подключить библиотеки для работы с клавиатурой и ЖК дисплеем и инициализировать необходимые переменные.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include <LiquidCrystal.h> #include <Keypad.h> long int set1; long int set2; long int set3; long int set4; long int j; int t1, t2, t3, t4, t5, t6; int r1, r2, r3; char key; String r[8]; String hours; String minutes; String seconds; |
Далее в программе мы сообщаем количество строк и столбцов в используемой нами клавиатуре и задаем карту клавиш клавиатуры.
1 2 3 4 5 6 7 8 9 |
const byte ROWS = 4; // четыре строки const byte COLS = 4; // четыре столбца char keys[ROWS][COLS] = { {'1','2','3','A'}, {'4','5','6','B'}, {'7','8','9','C'}, {'*','0','#','D'} }; |
Затем мы сообщаем плате Arduino к каким ее контактам подключены контакты строк и столбцов клавиатуры, а также контакты ЖК дисплея.
1 2 3 |
byte rowPins[ROWS] = { 6, 7, 8, 9 }; // подсоедините контакты клавиатуры ROW0, ROW1, ROW2 и ROW3 к этим контактам Arduino byte colPins[COLS] = { 10, 11, 12, 13 };// подсоедините контакты клавиатуры COL0, COL1, COL2 и COL3 к этим контактам Arduino LiquidCrystal lcd(A0, A1, 5, 4, 3, 2); // создаем объект ЖК дисплея с параметрами (rs, enable, d4, d5, d6, d7) |
Следующая команда создает объект клавиатуры в программе.
1 |
Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS ); |
В функции setFeedingTime() после нажатия кнопки мы можем ввести время, с которого начнется отсчет, для начала счета после этого необходимо нажать клавишу D на клавиатуре.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
void setFeedingTime() { feed = true; int i=0; lcd.clear(); lcd.setCursor(0,0); lcd.print("Set feeding Time"); lcd.clear(); lcd.print("HH:MM:SS"); lcd.setCursor(0,1); while(1){ key = kpd.getKey(); char j; if(key!=NO_KEY){ lcd.setCursor(j,1); lcd.print(key); r[i] = key-48; i++; j++; if (j==2 || j == 5) { lcd.print(":"); j++; } delay(500); } if (key == 'D') {key=0; break; } } lcd.clear(); } |
В функции void setup() мы инициализируем ЖК дисплей и последовательную связь, а также задаем режим работы (на ввод или вывод данных) для используемых контактов.
1 2 3 4 5 6 7 8 9 |
void setup() { lcd.begin(16,2); Serial.begin(9600); pinMode(A0, OUTPUT); pinMode(A1, OUTPUT); pinMode(A3, INPUT); pinMode(A4, OUTPUT); } |
Работа проекта
Принцип работы проекта достаточно прост. После запуска программы на экране ЖК дисплея высветится надпись “Arduino Timer” и она будет гореть до тех пор пока вы не нажмете кнопку. После нажатия кнопки программа попросит вас ввести время, с которого начнется обратный отсчет, при помощи вызова функции “setFeedingTime”. Время вводится с помощью клавиатуры. После ввода времени необходимо нажать клавишу ‘D’ на клавиатуре чтобы сохранить введенное время и начать обратный отсчет.
Далее в функции loop() мы будем выполнять ряд вычислений чтобы осуществить уменьшение счета (секунда за секундой) и показывать на ЖК дисплее оставшееся до истечения таймера время в формате HH:MM:SS. Более подробно все эти процессы показаны на видео, приведенном в конце статьи.
Когда таймер обратного отсчета достигнет нуля зуммер начнет издавать звуки (100 раз если его не прервать). Чтобы остановить сигнал зуммера необходимо нажать и удерживать кнопку. Также нажать кнопку можно в любое время если вы хотите остановить таймер.
Исходный код программы
Текст программы снабжен комментариями, помогающими легче понять его смысл.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
#include <LiquidCrystal.h> #include <Keypad.h> const byte ROWS = 4; // четыре строки const byte COLS = 4; // четыре столбца long int set1; long int set2; long int set3; long int set4; long int j; String hours; String minutes; String seconds; // Define the Keymap char keys[ROWS][COLS] = { {'1','2','3','A'}, {'4','5','6','B'}, {'7','8','9','C'}, {'*','0','#','D'} }; byte rowPins[ROWS] = { 6, 7, 8, 9 };// подсоедините контакты клавиатуры ROW0, ROW1, ROW2 и ROW3 к этим контактам Arduino byte colPins[COLS] = { 10, 11, 12, 13 };// подсоедините контакты клавиатуры COL0, COL1, COL2 и COL3 к этим контактам Arduino Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS ); LiquidCrystal lcd(A0, A1, 5, 4, 3, 2); // создаем объект ЖК дисплея с параметрами (rs, enable, d4, d5, d6, d7) int t1, t2, t3, t4, t5, t6; int r1, r2, r3; boolean feed = true; // условие для срабатывания сигнализации char key; String r[8]; void setFeedingTime() { feed = true; int i=0; lcd.clear(); lcd.setCursor(0,0); lcd.print("Set feeding Time"); lcd.clear(); lcd.print("HH:MM:SS"); lcd.setCursor(0,1); while(1){ key = kpd.getKey(); char j; if(key!=NO_KEY){ lcd.setCursor(j,1); lcd.print(key); r[i] = key-48; i++; j++; if (j==2 || j == 5) { lcd.print(":"); j++; } delay(500); } if (key == 'D') {key=0; break; } } lcd.clear(); } void setup() { lcd.begin(16,2); Serial.begin(9600); pinMode(A0, OUTPUT); pinMode(A1, OUTPUT); pinMode(A3, INPUT); pinMode(A4, OUTPUT); } void loop() { lcd.setCursor(0,0); lcd.print("Arduino Timer"); //Serial.println(A3); if (digitalRead(A3)==1) // { lcd.clear(); setFeedingTime(); for(int i = 0; i < 6; i++) // в этом цикле мы передаем заданное значение времени в окно монитора последовательной связи { Serial.print(r[i]); Serial.println(); } hours = String (r[0]) + String (r[1]) ; //объединяем два значения целого типа r[0] и r[1] в одну строку и сохраняем ее в переменную "hours" minutes = String (r[2]) + String (r[3]) ; // объединяем два значения целого типа r[2] и r[3] в одну строку и сохраняем ее в переменную "minutes" seconds = String (r[4]) + String (r[5]) ; // объединяем два значения целого типа r[4] и r[5] в одну строку и сохраняем ее в переменную "seconds" set1 = (hours.toInt()*3600); // конвертируем часы в секунды set2 = (minutes.toInt() * 60); //конвертируем минуты в секунды set3 = seconds.toInt(); set4 = (hours.toInt() * 3600)+ (minutes.toInt() * 60) + seconds.toInt(); //объединяем set1, set2 и set3 вместе в набор set4 Serial.print("set4"); Serial.print(set4); Serial.println(); lcd.setCursor(0,0); lcd.print("Countdown begins"); delay(1000); lcd.clear(); for(long int j = set4; j >= 0; j--) // этот цикл используется для уменьшения общего времени счета в секундах { Serial.println(j); lcd.setCursor(0,0); lcd.print("HH:MM:SS"); long int HH = j / 3600; // конвертируем оставшееся время в часы lcd.setCursor(0,1); Serial.println(HH); if (HH < 10) { lcd.print('0'); } lcd.print(HH); lcd.print(":"); long int MM = (j - (HH*3600))/60 ; // конвертируем оставшееся время в минуты lcd.setCursor(3,1); Serial.println(MM); if (MM < 10) { lcd.print('0'); } lcd.print(MM); lcd.print(":"); long int SS = j - ((HH*3600)+(MM*60)); // конвертируем оставшееся время в секунды lcd.setCursor(6,1); Serial.println(SS); if (SS < 10) { lcd.print('0'); } lcd.print(SS); delay(1000); if (digitalRead(A3)==1){break;} if (j == 0) { lcd.clear(); lcd.setCursor(0,0); lcd.print("Timer Stop"); lcd.setCursor(2,1); lcd.print("-Ring-Ring-"); for(int k =0; k<= 100; k++) // этот цикл используется для того чтобы зуммер звучал 100 раз после того как таймер достигнет нуля { digitalWrite(A4,HIGH); delay(300); digitalWrite(A4,LOW); delay(300); if (digitalRead(A3)==1){break;} } } } } } |
17 ответов к “Таймер обратного отсчета на Arduino”
Здравствуйте! Хотел спросиить насчет таймера — как увеличить его точность? Поможет ли в этом модуль реального времени? Спасибо!
Добрый вечер. Да, с помощью модуля реального времени увеличить точность можно. Пример его подключения к плате Ардуино можно посмотреть в этой статье.
Все класно. Но как добавить дни? Пробовал, не получается…
А в чем конкретно возникает проблема? Посмотрел текст программы, вроде бы проблем не увидел чтобы дни добавить
Я дни добавил, но проблема с алгоритмом просчета времени..
Вот скетч. Если не трудно, помогите с алгоритмом…
Извините, в первом не то скинул…
Вот что получилось…
#include
#include
const byte ROWS = 4; // четыре строки
const byte COLS = 4; // четыре столбца
long int set0;
long int set1;
long int set2;
long int set3;
long int set4;
long int j;
String days;
String hours;
String minutes;
String seconds;
char keys[ROWS][COLS] = { // Визначте розкладку клавіш
{‘1’, ‘2’, ‘3’, ‘A’},
{‘4’, ‘5’, ‘6’, ‘B’},
{‘7’, ‘8’, ‘9’, ‘C’},
{‘*’, ‘0’, ‘#’, ‘D’}
};
byte rowPins[ROWS] = { 6, 7, 8, 9 };// подсоедините контакты клавиатуры ROW0, ROW1, ROW2 и ROW3 к этим контактам Arduino
byte colPins[COLS] = { 10, 11, 12, 13 };// подсоедините контакты клавиатуры COL0, COL1, COL2 и COL3 к этим контактам Arduino
Keypad kpd = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
LiquidCrystal lcd(A0, A1, 5, 4, 3, 2); // создаем объект ЖК дисплея с параметрами (rs, enable, d4, d5, d6, d7)
int t1, t2, t3, t4, t5, t6;
int r1, r2, r3;
boolean feed = true; // условие для срабатывания сигнализации
char key;
String r[9];
void setFeedingTime()
{
feed = true;
int i = 0;
lcd.clear();
lcd.setCursor(3, 0);
lcd.print(«Setup Time»);
delay(500);
lcd.clear();
lcd.print(«DD:HH:MM:SS»);
lcd.setCursor(0, 1);
while (1) {
key = kpd.getKey();
char j;
if (key != NO_KEY) {
lcd.setCursor(j, 1);
lcd.print(key);
r[i] = key — 48;
i++;
j++;
if (j == 2 || j == 5 || j == 8)
{
lcd.print(«:»); j++;
}
delay(500);
}
if (key == ‘D’)
{
key = 0;
digitalWrite(A5, HIGH);
break;
}
}
lcd.clear();
}
void setup()
{
lcd.begin(16, 2);
Serial.begin(9600);
pinMode(A3, INPUT);
pinMode(A4, OUTPUT);
pinMode(A5, OUTPUT);
}
void loop()
{
lcd.setCursor(5, 0);
lcd.print(«Timer»); //Serial.println(A3);
if (digitalRead(A3) == 1)
{
lcd.clear();
setFeedingTime();
for (int i = 0; i = 0; j—) // этот цикл используется для уменьшения
{ //общего времени счета в секундах
Serial.println(j);
lcd.setCursor(0, 0);
lcd.print(«DD:HH:MM:SS»);
long int DD = (j / 86400); // конвертируем оставшееся время в дни
lcd.setCursor(0, 1);
Serial.println(DD);
if (DD < 10) {
lcd.print('0');
}
lcd.print(DD);
lcd.print(":");
long int HH = j / 3600; // конвертируем оставшееся время в часы
lcd.setCursor(3, 1);
Serial.println(HH);
if (HH < 10) {
lcd.print('0');
}
lcd.print(HH);
lcd.print(":");
long int MM = (j — (HH * 3600)) / 60 ; // конвертируем оставшееся время в минуты
lcd.setCursor(6, 1);
Serial.println(MM);
if (MM < 10) {
lcd.print('0');
}
lcd.print(MM);
lcd.print(":");
long int SS = j — ((HH * 3600) + (MM * 60)); // конвертируем оставшееся время в секунды
lcd.setCursor(9, 1);
Serial.println(SS);
if (SS < 10) {
lcd.print('0');
}
lcd.print(SS);
delay(1000);
if (j == 0)
{
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Timer Stop");
lcd.setCursor(2, 1);
lcd.print("-Ring-Ring-");
for (int k = 0; k <= 3; k++) // этот цикл используется для того чтобы зуммер звучал 100 раз после того как таймер достигнет нуля
{
digitalWrite(A4, HIGH);
delay(1000);
digitalWrite(A4, LOW);
delay(300);
lcd.clear();
if (digitalRead(A3) == 1) {
break;
}
}
}
}
}
}
Ну как минимум у вас в этом цикле ошибка: for (int i = 0; i = 0; j—)
Получается что он у вас не выполнится ни разу. И почему если цикл по i, то декрементируется переменная j? Явно что то не то
Это я исправил. Но вот когда я настраиваю, к примеру DD-01, HH-24, MM-00, SS-00, то дни остаются и в графе НН — часы умножаются на количество дней, и получается — DD-01, HH-48. Как это исправить? Благодарю?
А у вас массив r корректными значениями при этом заполняется или нет? Можете сказать что в нем после того как вы введете время
Да, масив r заполняется конкретными числами, и после запуска цикла кнопкой D, отсчет идет. Но если я использую только часы без дней, то процес происходит нормально. Если же ввожу данные в днях, к примеру DD-11 HH-00, то после запуска эквивалент точно такого же времени, но только в часах отображается и в часах — DD-11 и HH-264(24*11=264). А должно было бы быть — DD-10 HH-24 при отсчете. То есть программа дублирует дни в часах, чего не должно быть.
Вот моя поблема при моем незнании как это исправить…
Я не знаю, как изменить алгоритм отсчета, чтобы даные правильно распределялись между днями, часами, минутами и секундами.
Огромное спасибо за подсказки. Решил проблему.
От админа: хорошо, и вам успехов в дальнейших самоделках
классно
Удалось собрать данный проект? Стабильно работает?
А почему не поставить ЖК дисплей на 4-ре вывода? Или как альтернативный вариант на TM1637.
Можете и поставить
А он и так в 4-битном режиме подключен в этом проекте. Или вы хотите подключить его по протоколу I2C?