Якщо ви хочете відстежувати час без використання delay(), вам знадобиться функція millis(), яка дозволяє програмі працювати без зупинки. У цьому проєкті ми створимо цифровий пісочний годинник із використанням Arduino, шести світлодіодів і датчика нахилу. Кожні 10 хвилин буде загорятися новий LED, а через годину усі шість світлодіодів будуть увімкнені. Головна особливість цього проєкту – використання millis() для підрахунку часу замість звичайного delay(), що дозволяє мікроконтролеру виконувати інші завдання, поки відбувається відлік. Також ми застосуємо датчик нахилу, який працює як звичайний вимикач і дозволяє обнулити таймер при зміні положення пристрою.
У цьому проєкті ви створите цифровий пісочний годинник, який вмикатиме один світлодіод кожні десять хвилин. Дізнавайтеся, скільки часу ви працюєте над своїми проєктами, використовуючи вбудований таймер Arduino.
До цього часу, коли вам потрібно було виконати щось через певний інтервал часу за допомогою Arduino, ви використовували delay(). Це зручно, але трохи обмежує можливості. Коли Arduino викликає delay(), він призупиняє свою поточну роботу на весь час затримки. Це означає, що в цей час не можуть виконуватись жодні інші вхідні чи вихідні операції. Затримки також не дуже корисні для відстеження часу. Наприклад, якщо вам потрібно виконувати дію кожні 10 секунд, використання затримки на 10 секунд буде досить незручним.
Функція millis() допомагає вирішити ці проблеми. Вона відстежує час роботи Arduino у мілісекундах. Ви використовували її раніше в Проєкті 6, коли створювали таймер для калібрування.
До цього ви оголошували змінні як int. Int (ціле число) є 16-бітним числом, яке містить значення від -32 768 до 32 767. Це здається великим діапазоном, але якщо Arduino рахує 1000 разів на секунду за допомогою millis(), то int переповниться менш ніж за хвилину.
Тип даних long – це 32-бітне число, яке містить значення від -2 147 483 648 до 2 147 483 647. Оскільки час не може бути від’ємним, змінна для збереження millis() оголошується як unsigned long.
Коли тип даних позначено як unsigned, він може містити лише додатні значення, що дозволяє рахувати ще більше. Unsigned long може містити значення до 4 294 967 295, чого вистачає для збереження часу на майже 50 днів. Порівнюючи поточне значення millis() із заданим, можна визначити, чи минув необхідний інтервал часу.
Коли ви перевертаєте пісочний годинник, датчик нахилу змінює свій стан, що запускає новий цикл увімкнення світлодіодів.
Датчик нахилу працює так само, як звичайний перемикач, тобто має два стани – увімкнено/вимкнено. Його особливість у тому, що він визначає орієнтацію об’єкта. Зазвичай усередині датчика знаходиться невелика камера з металевою кулькою. Коли пристрій нахиляється, кулька перекочується і замикає контакти, створюючи електричний зв’язок.
Завдяки шести світлодіодам ваш цифровий пісочний годинник працюватиме рівно одну годину, як випливає з його назви.
Підключіть живлення та заземлення до макетної плати.
Підключіть анод (довшу ніжку) шести світлодіодів до цифрових контактів 2-7. Підключіть світлодіоди до землі через резистори на 220 Ом.
Підключіть один провід перемикача нахилу до 5 В. Інший підключіть до резистора 10 кОм із заземленням. Під’єднайте місце з’єднання до цифрового контакту 8
Вам не потрібно підключати Arduino до комп’ютера, щоб це працювало. Спробуйте створити підставку з картону або пінопласту та живіть Arduino за допомогою батареї, щоб зробити портативну версію. Ви можете створити обкладинку з деякими цифровими індикаторами поруч із світлом.
Перемикачі нахилу – чудові недорогі інструменти для визначення орієнтації чогось. Акселерометри – ще один тип датчиків нахилу, але вони видають набагато більше інформації. Вони також значно дорожчі. Якщо ви просто дивитесь, чи щось піднято чи опущено, датчик нахилу працює чудово.
Оголосіть іменовану константу. Вам знадобиться кілька глобальних змінних у вашій програмі, щоб усе працювало правильно. Для початку створіть константу з назвою switchPin. Це буде ім’я піна, до якого підключено датчик нахилу.
Створіть змінну для збереження часу. Оголосіть змінну типу unsigned long. Вона зберігатиме час останньої зміни стану світлодіода.
Присвойте імена змінним для входів і виходів. Створіть змінну для стану датчика нахилу, а також ще одну змінну для попереднього стану датчика. Ви використовуватимете ці дві змінні, щоб порівнювати стан датчика між ітераціями loop().
Оголосіть змінну для збереження інтервалу між подіями. Остання змінна, яку потрібно створити, – це інтервал між увімкненням кожного світлодіода. Вона матиме тип long. За 10 хвилин (час між увімкненням світлодіодів) проходить 600 000 мілісекунд. Якщо потрібно змінити інтервал між увімкненням світлодіодів, змініть це значення.
Задайте напрямок цифрових пінів. У функції setup() необхідно оголосити підключені світлодіоди (піни 2-7) як виходи (OUTPUT). Для цього використовується цикл for(), який дозволяє зробити це всього за три рядки коду. Також необхідно оголосити switchPin як вхід (INPUT).
Перевірте час від моменту запуску програми. Коли починається виконання loop(), потрібно отримати поточний час роботи Arduino за допомогою millis() і зберегти його у локальну змінну currentTime.
Оцініть, скільки часу минуло від попередньої ітерації циклу. Використовуючи if(), перевірте, чи минув достатній інтервал часу для увімкнення наступного світлодіода. Для цього потрібно відняти previousTime від currentTime і перевірити, чи це значення більше за змінну interval. Якщо минуло 600 000 мілісекунд (10 хвилин), потрібно оновити значення змінної previousTime, присвоївши їй currentTime.
const int switchPin = 8;
unsigned long previousTime = 0;
int switchState = 0;
int prevSwitchState = 0;
int led = 2;
long interval = 600000;
void setup() {
for(int x = 2;x<8;x++){
pinMode(x, OUTPUT);
}
pinMode(switchPin, INPUT);
}
void loop(){
unsigned long currentTime = millis();
if(currentTime - previousTime > interval) {
previousTime = currentTime;
Увімкніть світлодіод і підготуйте наступний. Змінна previousTime зберігає час останнього увімкнення світлодіода. Після встановлення previousTime увімкніть світлодіод і збільште значення змінної led. При наступному проходженні інтервалу часу загориться наступний світлодіод.
Перевірте, чи всі світлодіоди увімкнені. Додайте ще одну if-умову до програми, щоб перевірити, чи світлодіод на піні 7 увімкнено. Поки що не потрібно нічого робити на цьому етапі — рішення про те, що станеться після завершення години, буде прийнято пізніше.
Зчитайте значення датчика. Тепер, коли ви перевірили час, потрібно дізнатися, чи змінився стан датчика нахилу. Зчитайте його значення у змінну switchState.
Скиньте змінні до початкових значень, якщо це необхідно. За допомогою if-умови перевірте, чи switchState відрізняється від prevSwitchState. Оператор != перевіряє, чи switchState не дорівнює prevSwitchState. Якщо значення різні, вимкніть усі світлодіоди, поверніть led до першого піна і скиньте таймер, встановивши previousTime = currentTime.
Збережіть поточний стан датчика. Наприкінці loop() збережіть switchState у змінну prevSwitchState, щоб у наступному циклі можна було порівняти його з новим значенням.
Після того як ви завантажите програму на плату, перевірте час за годинником. Через 10 хвилин має загорітися перший світлодіод. Кожні 10 хвилин після цього буде загорятися наступний світлодіод. Через годину всі шість світлодіодів повинні бути увімкнені.
Якщо ви перевернете схему, датчик нахилу змінить свій стан, світлодіоди вимкнуться, і таймер почне відлік спочатку.
digitalWrite(led, HIGH);
led++;
if(led == 7){
}
}
switchState = digitalRead(switchPin);
if(switchState != prevSwitchState){
for(int x = 2;x<8;x++){
digitalWrite(x, LOW);
}
led = 2;
previousTime = currentTime;
}
prevSwitchState = switchState;
}
Коли годинник досягає однієї години і всі шість світлодіодів увімкнені, вони просто залишаються увімкненими. Чи можете ви придумати спосіб привернути увагу, коли година закінчиться? Звуковий сигнал або миготіння світлодіодів можуть бути хорошими варіантами.
Змінна led може бути використана для перевірки того, чи всі світлодіоди увімкнені, і це хороше місце, щоб додати індикацію закінчення часу. На відміну від пісочного годинника, заповненого піском, світлодіоди можуть загорятися у двох напрямках – вгору або вниз, залежно від орієнтації датчика нахилу. Чи зможете ви використати switchState, щоб визначити, у якому напрямку мають загорятися світлодіоди?
Для вимірювання часу між подіями використовуйте функцію millis(). Оскільки вона генерує великі числа, які не можна зберігати в int, слід використовувати тип unsigned long для їх збереження.