Познакомьтесь с обновлённой версией светофора. Светофор имеет 2 режима работы: полностью автоматический и ручной.
Мы определили три режима работы светофора: AUTO – режим движения автомобилей, FULLAUTO – режим работы светофора поочередно разрешающий движение автомобилей и пешеходов, PED – включение разрешающего сигнала для пешеходов, NOPED – аналог AUTO, отличие в запрете на обработку нажатия на кнопку.
В ручном режиме светофор разрешает движение автомобилям и включает зелёный свет пешеходам после нажатия на кнопку. Нажатие на кнопку вызывает аппаратное прерывание, которое устанавливает флаг butOn в значение true. Состояние флага butOn проверяется в основном цикле loop, только в состоянии AUTO.
Также режим работы светофора зависит от освещённости. К схеме подключен аналоговый датчик освещённости. В зависимости от освещённости программа в автоматически выбирает режим AUTO или FULLAUTO.
Изменение режимов происходит только после окончания выполнения текущего цикла.
В обновленной версии мы изменили структуру хранения сценариев. Текущая система позволяет иметь до 8 независимых каналов. Состояние канала описывается одним байтом. Сценарий представляет собой массив структур, включающих время выполнения и состояние каждого “кадра” сценария.
#include <Arduino.h>
#define Z1 0
#define Y1 1
#define R1 2
#define Z2 3
#define Y2 5
#define R2 4
#define SIZE_AR 5
#define SWITCH 3
#define LEVEL_LIGHT 150
int i1 = 0;
volatile boolean butOn = false;
int lightVal = 0;
//********************************************-- сценарии --**************************************************
//словарь состояний по разрядам:
//автомобильный: красный, желтый, зелёный; пешеходный: красный, зеленый
//один байт - одно состояние
uint8_t g1r = 0b00110; //машинам зелёный, пешеходма красный]
uint8_t g0r = 0b00010; //
uint8_t r11r = 0b10010;//красный и машинам и пешеходам
uint8_t r1g1 = 0b10001;//машинам красный, пешеходам зелёный
uint8_t r1g0 = 0b10000;
uint8_t ryr = 0b11010;
uint8_t y1 = 01000;
uint8_t y0 = 0;
//********************************************-- класс состояний --********************************************
enum class Stat {
AUTO, //0
PED, //1
NOPED, //2
FULLAUTO, //3
MANUALOFF, //4
};
//*********************************************
volatile Stat stat = Stat::AUTO;
uint32_t oldTime = 0;
int i = 0;
uint8_t arPin[] = {6, 4, 2, 10, 9, 11};
//*********************************************
void butt() {
detachInterrupt(digitalPinToInterrupt(SWITCH));
butOn = true;
}
//*********************************************
void testLed() {
for (uint16_t n = 0; n < sizeof(arPin); ++n) {
for (uint16_t m = 0; m < sizeof(arPin); ++m) {
digitalWrite(arPin[m], m == n);
delay(10);
}
delay(500);
}
}
//************************************************
void setup() {
for (uint16_t n = 0; n < sizeof(arPin); ++n)
pinMode(arPin[n], OUTPUT);
pinMode(SWITCH, INPUT);
Serial.begin(9600);
testLed();
attachInterrupt(digitalPinToInterrupt(SWITCH), butt, FALLING);
for (uint16_t m = 0; m < sizeof(arPin); ++m)
digitalWrite(arPin[m], LOW);
}
//***********************************************
struct Step { //шаг сценария
uint32_t dT; //время задержки
uint8_t scenario; //состояние
};
//сценарий - последовательность шагов состояний
Step scene1[] = {
{4000, g1r},
};
Step scene2[] = {
{250, g0r},
{250, g1r},
{250, g0r},
{250, g1r},
{250, g0r},
{250, g1r},
{3000, r1g1},
{250, r1g0},
{250, r1g1},
{250, r1g0},
{250, r1g1},
{250, r1g0},
{250, r1g1},
{2000, ryr},
};
Step sceneAUTO[] = {
{4000, g1r},
{250, g0r},
{250, g1r},
{250, g0r},
{250, g1r},
{250, g0r},
{250, g1r},
{3000, r1g1},
{250, r1g0},
{250, r1g1},
{250, r1g0},
{250, r1g1},
{250, r1g0},
{250, r1g1},
{1000, ryr},
};
Step sceneMANOFF[] = {
{250, y1},
{250, y0},
};
//************************************************
int func(Step * scene, int sizeAr, int& i) {
boolean flag = false;
for (int l = 0, k = 16; l < SIZE_AR; ++l, k/=2) {
digitalWrite(arPin[l], scene[i].scenario&k);
}
if (millis() - oldTime > scene[i].dT) {
oldTime = millis();
if (++i >= sizeAr) {
i = 0;
flag = true;
}
}
return flag;
}
//************************************************
void loop() {
lightVal = analogRead(A0);
switch (stat) {
case Stat::AUTO:
if (func(scene1, sizeof(scene1) / sizeof(Step), i1) && (butOn || lightVal < LEVEL_LIGHT)) {
if (butOn) {
stat = Stat::PED;
} else {
stat = Stat::FULLAUTO;
}
}
break;
case Stat::PED:
if (func(scene2, sizeof(scene2) / sizeof(Step), i1)) {
stat = Stat::NOPED;
}
break;
case Stat::NOPED:
if (func(scene1, sizeof(scene1) / sizeof(Step), i1)) {
stat = Stat::AUTO;
attachInterrupt(digitalPinToInterrupt(SWITCH), butt, FALLING);
butOn = false;
}
break;
case Stat::FULLAUTO:
if (func(sceneAUTO, sizeof(sceneAUTO) / sizeof(Step), i1)) {
if (lightVal > LEVEL_LIGHT) {
stat = Stat::AUTO;
}
}
break;
}
}