#include "GyverTM1637.h"
#include "EncButton.h"
volatile boolean interruptFlag = false; // переменная флаг прерывания
//uint32_t Now, tmr;
uint32_t timer = 0; // переменная таймера
uint8_t select = 0; //выбираем переменные фаз для редактирования светофора 1 - красный 2 - зеленый
//boolean encholding; //флаг на удержание кнопки энкодера
int mode = 0; //0 - горит красный // 1 - горит зеленый
int LED_PIN; //переменная, в которую будем подставлять пины светодиодов для переключения
int T_PERIOD = 0; //сюда будем подставлять значения интервалов светодиодов
int DISP_MAX = 30;
int counter = 0; // счетчик цикла
unsigned int R_PERIOD = 6; // период переключения красного
unsigned int G_PERIOD = 8; //период переключения зеленого
unsigned int Y_PERIOD = 2; //период переключения желтого
//Назначили пины
//дисплей
#define CLK 11
#define DIO 12
//определили дисплей
GyverTM1637 disp(CLK, DIO);
//светодиоды
#define LED_RED 4
#define LED_YELLOW 5
#define LED_GREEN 6
//энкодер
#define ENCODER_CLK 8 //п
#define ENCODER_DT 7
#define PIN_ENC_BUTTON 3
//определили энкодер
EncButton enc(ENCODER_CLK, ENCODER_DT, PIN_ENC_BUTTON);
int valEnc = 0; // будем управлять этой переменной при повороте энкодера
int holdEnc = 0; //считаем длительные нажатия
void setup() {
Serial.begin(9600); // открыли порт для связи
// назначаем пины на светодиоды
pinMode(LED_RED, OUTPUT); //red
pinMode(LED_YELLOW, OUTPUT); //yellow
pinMode(LED_GREEN, OUTPUT); //green
//включаем все светодиоды
digitalWrite(LED_RED, HIGH);
digitalWrite(LED_YELLOW, HIGH);
digitalWrite(LED_GREEN, HIGH);
//пауза 1 секунда
delay(1000);
//выключаем все светодиоды
digitalWrite(LED_RED, LOW);
digitalWrite(LED_YELLOW, LOW);
digitalWrite(LED_GREEN, LOW);
// подключили кнопку на D2 и GND
pinMode(2, INPUT_PULLUP);
//аппаратное прерывание на пине D2 - 0
// FALLING - при нажатии на кнопку будет сигнал 0
// CHANGE - любое нажатие на кнопку изменит сигнал и мы его поймаем аппаратным прерыванием
//как только будет нажатие на кнопку, вызываем функцию btnIsr, которая меняет флаг interruptFlag на true
attachInterrupt(0, btnIsr, FALLING);
//disp.clear(); // очистить
//включили дисплей, дали яркость
disp.brightness(7); // яркость 0-7
disp.displayByte(_L, _E, _O, _empty); // вывести текст
delay(1000);
disp.displayByte( _empty, _5, _empty, _B); // вывести текст 5В
delay(1000);
disp.clear(); // очистить дисплей
}
//обработка прерывания
//функция будет вызываться каждый раз, когда будет нажата кнопка
//и менять флаг interruptFlag на true
void btnIsr() {
interruptFlag = true; // + нажатие
}
//поворот энкодера
//функция обрабатывает поворот энкодера и работает от 0 до 9
//Функция берет значение счетчика, меняет его при повороте и возвращает valEnc
//и еще выводит текущее значение valEnc на дисплей
void encTurnVal (){
valEnc = counter;
if (enc.right()) {
valEnc += 1;
if (valEnc > DISP_MAX) {
valEnc=DISP_MAX;
}
}
if (enc.left()) {
valEnc -= 1;
if (valEnc < Y_PERIOD) {
valEnc = Y_PERIOD;
}
}
disp.displayInt(valEnc);
return valEnc;
}
void loop() {
//постоянно опрашиваем энкодер
enc.tick();
//Serial.println(interruptFlag); // выводим
////////////////////////////
///////////////////////////
//
// ОСНОВНОЙ ЦИКЛ ПРОГРАММЫ
// Светофор горит, длительность фаз определена в переменных
// R_PERIOD Y_PERIOD G_PERIOD
//
// Основное цикл программы выполняется только, если не было активировано прерывание кнопкой
//
if (!interruptFlag) {
//выбираем режим работы
switch (mode) {
//красный
case 0:
LED_PIN = LED_RED;
T_PERIOD = R_PERIOD;
// выполнить, если значение == 0
break;
//Зеленый
case 1:
LED_PIN = LED_GREEN;
T_PERIOD = G_PERIOD;
// выполнить, если значение == 1
break;
}
if (millis() - timer >= 1000) { // таймер на millis()
timer = millis(); // сброс
// действие с counter - наш i-ый светодиод например
digitalWrite(LED_PIN, HIGH);
if (counter >= T_PERIOD - Y_PERIOD){
digitalWrite(LED_YELLOW, HIGH);
} else {
digitalWrite(LED_YELLOW, LOW);
}
Serial.println(counter);
//disp.clear();
disp.displayByte( _empty, _empty, _empty, _empty);
disp.displayInt(T_PERIOD - counter);
//disp.display(3, T_PERIOD-counter);
counter++; // прибавляем счётчик
if (counter > T_PERIOD)
{
digitalWrite(LED_PIN, LOW);
digitalWrite(LED_YELLOW, LOW);
counter = 0;
mode++;
if (mode>1) mode = 0;
//if (mode == 0) {
// mode = 1;
//} else if (mode == 1) {
// mode = 0;
//}
} // закольцовываем изменение
}
}
////////////////////////////////////////////////////////
//Режим "прерывания" флаг interruptFlag = true, основной цикл выполняться не будет, пока
//не сбросим флаг на false
//здесь редактируем длительности фаз сфетофора
//
if (interruptFlag) {
//для отладки выведем в серийный порт
//Serial.println(interruptFlag);
//Serial.println("Interrupt!");
//////////////////////////
//редактируем фазы
//////////////////////////
//
//горит тот светодиод, для которого делаем фазу - 1 - красный, 2 - зеленый
//считаем клики
// нажимаем кнопку энкодера и попадаем в редактирование красного, потом зеленого
//
if (enc.click()) {
select +=1;
if (select == 1 || select > 2) {
//disp.display(3, valEnc);
//Serial.println(String("красный: ") + select);
//в режиме редактирования красного - горит красный
digitalWrite(LED_RED, HIGH);
digitalWrite(LED_YELLOW, LOW);
digitalWrite(LED_GREEN, LOW);
select = 1;
} else if (select == 2){
//disp.display(0, select);
//disp.display(3, valEnc);
//Serial.println(String("зеленый: ") + select);
//в режиме редактирования зеленого - горит зеленый
digitalWrite(LED_RED, LOW);
digitalWrite(LED_YELLOW, LOW);
digitalWrite(LED_GREEN, HIGH);
//select = 0;
}
}
//здесь обрабатываем настройку светодиода, которыйвыбрали.
//вызываем
//Смотрим какая фаза редактируется 1 - красная 2 - зеленая
//заодно проверяем, крутится ли ручка
//если плохо будет срабатывать вложенный if enc.right || можно удалить
if (select == 1) {
//Serial.println(String("красный: ") + select);
counter = R_PERIOD;
encTurnVal();
R_PERIOD = valEnc;
disp.display(0, select);
disp.displayInt(valEnc);
//disp.display(3, valEnc);
} else if (select == 2) {
//Serial.println(String("зеленый: ") + select);
counter = G_PERIOD;
encTurnVal();
G_PERIOD = valEnc;
disp.display(0, select);
disp.displayInt(valEnc);
//disp.display(3, valEnc);
}
//
//Если нажать и держать на кнопку энкодера, то выйдем из режима прерывания
//сбрасываем interruptFlag на false и программа работает по основному циклу
//
if (enc.hold()) {
//Serial.println("start");
digitalWrite(LED_RED, HIGH);
digitalWrite(LED_YELLOW, HIGH);
digitalWrite(LED_GREEN, HIGH);
disp.displayByte( _empty, _empty, _empty, _empty);
delay(1000);
//запуск
digitalWrite(LED_RED, LOW);
digitalWrite(LED_YELLOW, LOW);
digitalWrite(LED_GREEN, LOW);
disp.clear();
interruptFlag = false;
}
}
}