РАБОТАЕМ ПО ТАЙМЕРУ В ARDUINO
Я думаю все знают классический алгоритм создания таймера на millis() – счётчике аптайма:
Классический таймер на millis()
Несколько таймеров
Данный алгоритм позволяет спокойно переходить через переполнение millis() без потери периода, но имеет один большой минус – время считается с момента последнего вызова таймера, и при наличии задержек в коде таймер будет накапливать погрешность, отклоняясь от “ритма”. Недавно я придумал более точный алгоритм таймера на миллис, который соблюдает свой период даже после пропуска хода!
Улучшенный таймер
Данный таймер имеет механику классического таймера с хранением переменной таймера, а его период всегда кратен PERIOD и не сбивается. Эту конструкцию можно упростить до
В этом случае алгоритм получается короче, кратность периодов сохраняется, но теряется защита от пропуска вызова и переполнения millis().
В этой библиотеке реализован полноценный таймер на счётчике аптайма, позволяющий даже “приостановить” счёт (не приостанавливая сам аптайм).
Примечание: таких таймеров можно создать сколько душе угодно (пока хватит памяти), что позволяет создавать сложные программы с кучей подзадач, но для функционирования данного таймера нужен “чистый” loop с минимальным количеством задержек, или вообще без них. Всё таки таймер “опрашивается” в ручном режиме. Таймер, который не боится задержек, делается на прерывании таймера, смотрите вот эту библиотеку.
БИБЛИОТЕКА GYVERTIMER
GyverTimer v3.2
GTimer – полноценный таймер на базе системных millis() / micros(), обеспечивающий удобную мультизадачность и работу с временем, используя всего одно родное прерывание таймера (Timer 0)
- Миллисекундный и микросекундный таймер
- Два режима работы:
- Режим интервала: таймер “срабатывает” каждый заданный интервал времени
- Режим таймаута: таймер “срабатывает” один раз по истечении времени (до следующего перезапуска)
Поддерживаемые платформы: все Arduino (используются стандартные Wiring-функции)
ДОКУМЕНТАЦИЯ
Документация
Конструктор
Класс GTimer позволяет работать как с миллисекундным, так и с микросекундным таймером. В общем виде пример выглядит так:
Где type это MS (,мс, миллисекундный таймер) или US (мкс, микросекундный), period – период в мс или мкс соответственно.
Настройки по умолчанию
- При создании таймера можно ничего не указывать : GTimer myTimer; , тогда таймер будет сконфигурирован как миллисекундный и не запустится
- Если указать только тип таймера (MS/US) GTimer myTimer(MS); , таймер настроится на выбранный режим (мс/мкс) и не запустится
- Если указать тип таймера и интервал GTimer myTimer(US, 5000); , таймер настроится на выбранный режим (мс/мкс) и запустится в режиме интервала
Режимы работы
Таймер может работать в режиме интервалов и в режиме таймаута:
- Интервалы. Запуск – метод setInterval(время) с указанием времени. В режиме интервалов таймер срабатывает (метод isReady() возвращает true) каждый раз при достижении указанного периода и автоматически перезапускается. Удобно для периодических действий
- Таймаут. Запуск – метод setTimeout(время) с указанием времени. В режиме таймаута таймер срабатывает (метод isReady() возвращает true) только один раз при достижении указанного периода и автоматически отключается. Для повторного запуска нужно вызвать .setTimeout() с указанием периода, или просто .start() – запустит таймер на новый круг с прежним периодом
Управление таймером
Для управления состоянием таймера есть следующие методы:
- start() – запускает (перезапускает) таймер с последним установленным временем
- stop() – останавливает таймер
- resume() – продолжает отсчёт таймера с момента остановки
- reset() – сбрасывает таймер (отсчёт периода/таймаута начинается заново)
- isEnabled() – возвращает true, если таймер работает (если он не stop() или не вышел таймаут)
цифровая электроника вычислительная техника встраиваемые системы
Простой Arduino-счетчик на 7-сегментном индикаторе
Это простой проект на Arduino, заключающийся в создании счетчика на обычном 7-сегментном индикаторе с общим катодом. Код, приведенный ниже, позволяет при нажатии кнопки запускать счет от 0 до 9.
Вся схема может быть запитана от стандартной 9-вольтовой батарейки или от любого Arduino-совместимого блока питания.
7-сегментный индикатор – очень простое устройство. Он представляет собой комбинацию 8 светодиодов (восьмой светодиод отвечает за точку) с общим катодом, которые можно включать в определенной последовательности так, чтобы они образовывали цифры. Следует обратить внимание, что в данном случае выводы 3 и 8 отведены под катод.
Ниже показана таблица соответствия выводов Arduino и выводов индикатора.
Наверняка у многих валяется вот такая светодиодная панелька:
Правильное название: семисегментный индикатор
Он получил такое названия благодаря тому, что в его корпусе находится 7 сегментов — светодиодов (часто добавляют ещё 8-й — точку).
Сейчас они не актуальны. Проще LCD экран подключить, он меньше выводов занимает, да и работать с ним проще. Однако иногда такие индикаторы могут быть полезен. Например, когда нужно отобразить только какую-либо цифру и ничего более. Плюс, они дешевле экранчиков.
Работать с семисегментом надо как со сборкой светодиодов (с общим катодом или анодом). Распиновку можно узнать, прозванивая ножки мультиметром. У меня получилось так: ( общий катод)
Каждый сегмент — это отдельный светодиод (красный или зелёный). Если подключаем к источнику 5V, то последовательно с каждым из них нужно подключить по резистору (150-300 ом) — чтобы не перегорели.
А соединять с Arduino я предлагаю через сдвиговый регистр 74HC595N (интерфейс SPI)
схема на BreadBoard:
Принципиальную схему не смог нарисовать в sPlan (нет 28-пиновой Atmega), так-что сделал в Fritzing:
Описание схемы:
— ноги 15,1,2,3,4.5,6,7 — это выходы регистра. Их подключаем к соответствующим ногам индикатора (A к Q0, B к Q1, C к Q3, ну и т. д.. Главное, чтобы было по порядку — тогда часть программирования будет проще)
— ноги 8 и 16 — это питание микросхемы (подключаем к GND и +5V Arduino)
— 10 ногу к +5V
— 13 ногу к GND
— Ноги 14, 12, 11 — управляющие пины шины SPI .
11 (SH_CP) — тактовая шина (clock) к 13 контакту Arduino (не принципиально)
12 (ST_CP) — защёлка (latch) к 12 контакту Arduino (не принципиально)
14 (DS) — данные (data) к 8 контакту Arduino (не принципиально)
Прошивка
Код очень простой. Мы даже не будем использовать библиотеку SPI. Посылать данные будем функцией shiftOut()
Она будет отправлять регистру 1 байт (8 бит). Каждый сегмент — это 1 бит. ( Если отправить вот такой байт: 0b10000000, то получим такую вот картину: (зажжётся первый сегмент — А)
Суть: Зажигая определённую комбинацию сегментов, мы получаем на экране цифру. Так, например, если зажечь сегменты B и С то загорится единичка. A, B, C — семёрка, и т. д..
Сам код: SevSeg1_SPI.ino
Список радиоэлементов
Обозначение | Тип | Номинал | Количество | Примечание | Магазин | Мой блокнот |
---|---|---|---|---|---|---|
Плата Arduino | 1 | Поиск в Utsource | В блокнот | |||
Сдвиговый регистр | 1 | Поиск в Utsource | В блокнот | |||
Резистор | 100-300 Ом | 8 | Поиск в Utsource | В блокнот | ||
Семисегментный индикатор | 1 | Поиск в Utsource | В блокнот | |||
Добавить все |
Прикрепленные файлы:
Оценить статью
- Техническая грамотность
Средний балл статьи: 0 Проголосовало: 0 чел.
Комментарии (4) | Я собрал ( 0 ) | Подписаться
Для добавления Вашей сборки необходима регистрация
#define CLOCK 13 //SH_CP
#define DATA 12 //DS
#define LATCH 8 //ST_CP
int val = 0;
//настраиваем контакты на выход
pinMode(CLOCK, OUTPUT);
pinMode(DATA, OUTPUT);
pinMode(LATCH, OUTPUT);
//отключаем LATCH (чтобы регистр не ждал данных)
digitalWrite(LATCH, HIGH);
>
0b12345678
*/
switch (val) <
case -1: //точка
shiftOut(DATA, CLOCK, LSBFIRST, 0b00000001);
break;
case 0: //0
shiftOut(DATA, CLOCK, LSBFIRST, 0b11111100);
break;
case 1: //1
shiftOut(DATA, CLOCK, LSBFIRST, 0b01100000);
break;
case 2: //2
shiftOut(DATA, CLOCK, LSBFIRST, 0b11011010);
break;
case 3: //3
shiftOut(DATA, CLOCK, LSBFIRST, 0b11110010);
break;
case 4: //4
shiftOut(DATA, CLOCK, LSBFIRST, 0b01100110);
break;
case 5: //5
shiftOut(DATA, CLOCK, LSBFIRST, 0b10110110);
break;
case 6: //6
shiftOut(DATA, CLOCK, LSBFIRST, 0b10111110);
break;
case 7: //7
shiftOut(DATA, CLOCK, LSBFIRST, 0b11100000);
break;
case 8: //8
shiftOut(DATA, CLOCK, LSBFIRST, 0b11111110);
break;
case 9: //9
shiftOut(DATA, CLOCK, LSBFIRST, 0b11110110);
break;
case 10: //A
shiftOut(DATA, CLOCK, LSBFIRST, 0b11101110);
break;
case 11: //b
shiftOut(DATA, CLOCK, LSBFIRST, 0b00111110);
break;
case 12: //C
shiftOut(DATA, CLOCK, LSBFIRST, 0b10011100);
break;
case 13: //d
shiftOut(DATA, CLOCK, LSBFIRST, 0b01111010);
break;
case 14: //E
shiftOut(DATA, CLOCK, LSBFIRST, 0b10011110);
break;
case 15: //F
shiftOut(DATA, CLOCK, LSBFIRST, 0b10001110);
break;
case 16: //G
shiftOut(DATA, CLOCK, LSBFIRST, 0b10111100);
break;
case 17: //H
shiftOut(DATA, CLOCK, LSBFIRST, 0b01101110);
break;
case 18: //I
shiftOut(DATA, CLOCK, LSBFIRST, 0b01100000);
break;
case 19: //J
shiftOut(DATA, CLOCK, LSBFIRST, 0b01110000);
break;
case 20: //L
shiftOut(DATA, CLOCK, LSBFIRST, 0b00011100);
break;
case 21: //n
shiftOut(DATA, CLOCK, LSBFIRST, 0b00101010);
break;
case 22: //O
shiftOut(DATA, CLOCK, LSBFIRST, 0b11111100);
break;
case 23: //P
shiftOut(DATA, CLOCK, LSBFIRST, 0b11001110);
break;
case 24: //q
shiftOut(DATA, CLOCK, LSBFIRST, 0b11100110);
break;
case 25: //S
shiftOut(DATA, CLOCK, LSBFIRST, 0b10110110);
break;
case 26: //U
shiftOut(DATA, CLOCK, LSBFIRST, 0b01111100);
break;
//некоторые буквы невозможно отобразить. их нет в списке
>
//включаем LATCH (Начинаем общение)
digitalWrite(LATCH, HIGH);
if(val==26) <
val=-2;
>
delay(1000);
val=val+1;
>
#define CLOCK 13 //SH_CP 11 74СН
#define DATA 12 //DS 14 74СН
#define LATCH 8 //ST_CP 12 74СН
// — распиновка сегментов
byte numberSegments[10] = <
0b11111101, 0b01100000, 0b11011010, 0b11110010, 0b01100110,
0b10110110, 0b10111110, 0b11100000, 0b11111110, 0b11110110,
>;
//настраиваем контакты на выход
pinMode(CLOCK, OUTPUT);
pinMode(DATA, OUTPUT);
pinMode(LATCH, OUTPUT);
//отключаем LATCH (чтобы регистр не ждал данных)
digitalWrite(LATCH, HIGH);
>
void loop() <
for (int i = 0; i