#include <Arduino.h> // Импорт стандартной библиотеки arduino
#include "Blinker.h" // Импорт класса мигающего светодиода
#define TEST_MODE 0
#define FillScale 0
#define HALFPERIOD 500
/**
* Объявление и инициализация переменных
*/
// Экземпляры объектов мигающих светодиодов
Blinker Led13;
Blinker Led4, Led11;
bool I_UP = 0, // Флаг режима движения вверх
I_DN = 0, // Флаг режима движения вниз
I_ZAP = 0, // Флаг аварии
TAKT =0; // Флаг наличия переднего фронта тактового сигнала
uint8_t I_RD = 0; // Режим работы контроллера
uint8_t SCENE = 0; // Номер сцены
bool ALARM = false; // Флаг аварии
int a0, // Сырые значения с аналоговых входов
a1,
a2,
a3,
a7;
/**
* Объявление функций (прототипов)
* Тут просто перечислены все функции, которые в принципе существуют.
* Если этого не сделать, то в некоторых версиях компилятора будет ошибка,
* так как функции будут вызываться раньше их объявления и определения
*/
void setup(); // Инициализирующая функции при старте МК (или сбросе)
void loop(); // Итерация бесконечного цикла работы ПО
void InitAnalog(); // Инициализация аналоговых пинов
void InitDigital(); // Инициализация цифровых пинов
void ReadMode(); // Чтение режима работы
void InitIndication();// Индикация инициализации прошивки
void AnalogRead(); // Чтение аналоговых пинов
void TaktDetect(); // Чтение тактового импульса
void AlarmDetect(); // Определение условий перехода в режим "авария" и выхода из него
void SceneControl();
void LedFillScale(uint8_t);
void LedFillScale0();
void LedFillScale1();
void LedFillScale2();
void LedFillScaleAlarm();
/**
* Определение функций (логика)
*/
//===============================================================================================================================================
//================= Нормальный режим работы ===================================================================================================
//===============================================================================================================================================
#if TEST_MODE == 0
// Функция инициализации
void setup()
{
Serial.begin(9600); // Инициализация последовательного порта (для терминала)
InitAnalog(); // Инициализация аналоговых входов
InitDigital(); // Инициализация цифровых выходов
ReadMode(); // Чтение режима работы
InitIndication(); // Инициализирующая индикация
}
// Итерация бесконечного цикла
void loop()
{
AnalogRead (); // Читаем входы и тактовые импульсы
AlarmDetect (); // Проверка режима аварии переключает переменную ALARM
// В нормальном режиме работы
if ( ALARM == false )
{
TaktDetect (); // Чтение тактового импульса
if ( TAKT )
{
SceneControl (); // Управление номером сцены
// А также управление 4 и 11 светодиодами
LedFillScale(FillScale); //Управление всеми остальными светодиодами
}
}
// В режиме аварии
else
LedFillScaleAlarm();
// Фоновые методы, обеспечивающие моргание
Led4.tick();
Led11.tick();
Led13.tick();
}
#else
//===============================================================================================================================================
//=================== Тестовый режим работы ===================================================================================================
//===============================================================================================================================================
// Функция инициализации
void setup()
{
Serial.begin(9600);
InitAnalog();
InitDigital();
}
// Итерация бесконечного цикла
void loop()
{
AnalogRead (); // Читаем входы и тактовые импульсы
// D9 повторяет A0; D6=A1; D8=A3; D7=A7; A2
digitalWrite(9, a0);
digitalWrite(6, a1);
digitalWrite(8, a3);
digitalWrite(7, a7);
}
#endif
//===============================================================================================================================================
//================= Инициализирующие функции ==================================================================================================
//===============================================================================================================================================
// Инициализация аналоговых пинов
void InitAnalog()// конфигурирование аналоговых пинов
{
pinMode(A0, INPUT); // I.UP
pinMode(A1, INPUT); // I.DN
pinMode(A2, INPUT); // I.Rd
pinMode(A3, INPUT); // I.TAKT, тактовый генератор
// Не используются
pinMode(A4, OUTPUT); digitalWrite(A4, LOW);// OR4
pinMode(A5, OUTPUT); digitalWrite(A5, LOW);// OR5
pinMode(A6, OUTPUT); digitalWrite(A6, LOW);// OR6
pinMode(A7, INPUT); // I.ZAP
}
// Инициализация цифровых пинов
void InitDigital()
{
pinMode(2, OUTPUT); // O.MOTOR реле светодиод Bl (голубой)
pinMode(3, OUTPUT); // O.DN реле концевое светодиод Bl (голубой)
Led4.init(4, HALFPERIOD); // VD1-R светодиод Red Flash
pinMode(5, OUTPUT); // VD2-L светодиод Green
pinMode(6, OUTPUT); // VD3-Y светодиод
pinMode(7, OUTPUT); // VD4-Y светодиод
pinMode(8, OUTPUT); // VD5-Y светодиод
pinMode(9, OUTPUT); // VD6-Y светодиод
pinMode(10, OUTPUT); // VD7-L светодиод Green
Led11.init(11, HALFPERIOD); // VD8-R светодиод Red Flash
pinMode(12, OUTPUT); // O.UP реле концевое светодиод Bl (голубой)
Led13.init(13); // Светодиод на плате
}
// Чтение режима работы контроллера при его старте
void ReadMode()
{
int a2 = analogRead (A2); // Читаем уровень с А2
if( a2 <= 300) // Двухпозиционный
I_RD = 0;
else if ( a2 >= 700 ) // Трехпозиционный
I_RD = 2;
else // Пускатель
I_RD = 1;
Serial.print("Режим ");
Serial.println(I_RD);
}
// Индикация успешной инициализации прошивки
void InitIndication()
{
static int Period = 500;
Led13.on();
delay( Period * 2 ); // Тире
Led13.off();
delay( Period ); // выкл
Led13.on();
delay( Period ); // Точка
Led13.off();
delay( Period ); // выкл
Led13.on();
delay( Period * 2 ); // Тире
Led13.off();
delay( Period ); // выкл
Led13.on();
delay( Period * 2 ); // Тире
Led13.off();
delay( Period ); // выкл
for (int i = 4; i != 12; ++i)
digitalWrite(i, HIGH);
delay ( 1000 );
for (int i = 4; i != 12; ++i)
digitalWrite(i, LOW);
}
//===============================================================================================================================================
//===================== Функции - тикеры ======================================================================================================
//===============================================================================================================================================
// Чтение аналоговых входов с гистерезисом
void AnalogRead ()
{
// Чтение входов-ключей с гистерезисом
a0 = analogRead (A0);
a1 = analogRead (A1);
a2 = analogRead (A2);
a3 = analogRead (A3);
a7 = analogRead (A7);
// Определение значений I_UP I_DN в зависимости от режима работы контроллера
switch (I_RD)
{
case 0: // Двухпозиционный
I_UP = a0 > 512;
I_DN = !I_UP;
break;
case 1: // Пускатель
if ( a0 < 512 )
I_UP = true;
else if ( a1 < 512 )
I_UP = false;
if ( a1 < 512 )
I_DN = true;
else if ( a0 < 512 )
I_DN = false;
break;
case 2: // Трехпозиционный
I_UP = a0 < 512;
I_DN = a1 < 512;
break;
default:
break;
}
Serial.print("UP ");
Serial.print(I_UP);
Serial.print("; ");
Serial.print("DN ");
Serial.println(I_DN);
}
// Определение условий перехода в режим "авария"
void AlarmDetect()
{
static bool a7_prev = false;
// Проверка сигналов в режиме НЕ КЗ
if ( I_RD > 0 )
if ( I_DN && I_UP )
ALARM = true;
// Проверка аварийного сигнала
if ( a7 > 512 )
ALARM = true;
if (ALARM)
{
Led4.start();
Led11.start();
Serial.println("ALARM!");
if ( a7 < 512 && a7_prev == true )
{
ALARM = false;
Serial.println("ALARM END!");
}
}
a7_prev = a7 > 512;
}
// Определенеи тактового импульса
void TaktDetect()
{
static const int GIST = 200;
static bool TAKT_PRED = 0; // Только при инициализации присваивается значение
// static сохраняет значение переменной между вызовами функции
// Такой аналог глобальной переменной, но с ограниченим области видимости
bool TAKT_TEK = TAKT_PRED; // Текущее значение пина
// Смотрим текущее значение с учетом мертвой зоны
if ( a3 > 512 + GIST )
TAKT_TEK = true;
else if ( a3 < 512 - GIST )
TAKT_TEK = false;
// Ловим фронт
if ( TAKT_PRED == false && TAKT_TEK == true )
{
TAKT = true;
delay( 50 ); // Заморозка при фронте
}
else if ( TAKT_PRED == true && TAKT_TEK == false )
TAKT = false;
TAKT_PRED = TAKT_TEK; // Запоминаем значение
}
// Управление номером сцены
// Управление сценой заключается в запуске соответствующего светодиода
void SceneControl()
{
if ( I_UP == false && I_DN == false )
{
Led4.stop();
Led11.stop();
Led11.on();
Led4.on();
}
else if ( I_UP && !I_DN )
{
SCENE = constrain(SCENE + 1, 0, 5);
Led11.start();
Led4.stop();
}
else if ( !I_UP && I_DN )
{
SCENE = constrain(SCENE - 1, 0, 5);
Led11.stop();
Led4.start();
}
else
{
ALARM = true;
Led4.start();
Led11.start();
}
if ( SCENE == 0 || SCENE == 5 )
{
Led4.stop();
Led11.stop();
}
TAKT = 0; // Поскольку фронт отработан, сбрасываем его флаг
Serial.print("Scene ");
Serial.println(SCENE);
}
void LedFillScale (uint8_t mode)
{
// Состояние не зависит от режима работы
digitalWrite(2, SCENE >= 3);
digitalWrite(3, SCENE == 0);
// 4 управляется в SceneControl()
digitalWrite(5, SCENE == 0);
// 6-9 управляется в зависимости от сцены
digitalWrite(10, SCENE == 5);
// 11 управляется в SceneControl()
digitalWrite(12, SCENE == 5);
switch (mode)
{
case 0:
LedFillScale0();
break;
case 1:
LedFillScale1();
break;
case 2:
LedFillScale2();
break;
default:
break;
}
}
void LedFillScale0()
{
digitalWrite(6, SCENE == 1);
digitalWrite(7, SCENE == 2);
digitalWrite(8, SCENE == 3);
digitalWrite(9, SCENE == 4);
}
void LedFillScale1()
{
digitalWrite(6, SCENE >= 1);
digitalWrite(7, SCENE >= 2);
digitalWrite(8, SCENE >= 3);
digitalWrite(9, SCENE >= 4);
}
void LedFillScale2()
{
digitalWrite(6, SCENE == 1 || SCENE == 2);
digitalWrite(7, SCENE == 2 || SCENE == 3);
digitalWrite(8, SCENE == 3 || SCENE == 4);
digitalWrite(9, SCENE == 4 || SCENE == 5);
}
void LedFillScaleAlarm()
{
// Код индикации 4 и 11 уже запущены в AlarmDetect
}