Закончил тестирование, всё работает. Для отладки – зелёный и красный светодиоды показывают перекрытие 1 и 2 каналов, соответственно. Жёлтый – имитация включения нагрузки. Индикатор – количество незавершённых пересечений.
Платы теперь только три вместо пяти.
Скетч дополнен блоком, симулирующим ждущий мультивибратор с перезапуском, остальное всё почти, как было, только теперь всё на прерываниях.
Код: Выделить всё
//
// Shirokov V.V. aka Massaraksh7, 18.06.2026
//
#define IN1 2
#define IN2 3
#define FIRE 4
#define FB1 5
#define FB2 6
#define R_WAIT 0
#define R_DIR 1
#define R_BACK 2
#define R_DO_DIR 3
#define R_DO_BACK 4
#define MAX_VIS 9 //---Максимальное число посетителей
int count,rate;
int m1[3],m2[3];
int adata[10][8]={ 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 7, 8, 9,10,11,12, 0, 0,
8, 9, 0, 0, 0, 0, 0, 0, // 1
7, 8,11,10,13, 0, 0, 0, // 2
7, 8, 9,10,13, 0, 0, 0, // 3
8, 9,12,13, 0, 0, 0, 0, // 4
7, 9,10,12,13, 0, 0, 0, // 5
7, 9,10,11,12,13, 0, 0, // 6
7, 8, 9, 0, 0, 0, 0, 0, // 7
7, 8, 9,10,11,12,13, 0, // 8
7, 8, 9,10,12,13, 0, 0}; // 9
volatile int sign1,sign2; //---Сигнал 0 или 1
volatile int tim0; //---счётчик основного цикла
//---Записать цифру в индикатор
void setDig(int n) {
int i,j;
for (j=7;j<=13;j++)digitalWrite(j,LOW);
for (i=0;i<8;i++)
{
if (adata[n][i]==0)break;
digitalWrite(adata[n][i],HIGH);
}
}
//---Прочитать состояние входов и записать в буфер
void ReadAndShift() {
m1[2]=m1[1];m1[1]=m1[0];m1[0]=sign1;
m2[2]=m2[1];m2[1]=m2[0];m2[0]=sign2;
if (sign1==0) digitalWrite(FB1,LOW); else digitalWrite(FB1,HIGH);
if (sign2==0) digitalWrite(FB2,LOW); else digitalWrite(FB2,HIGH);
}
//---Очистка буфера
void clearBuf() {
int i;
for(i=0;i<3;i++){m1[i]=0;m2[i]=0;}
}
//---Подключить нагрузку
void fireON() {
digitalWrite(FIRE,HIGH);
}
//---Отключить нагрузку
void fireOFF() {
digitalWrite(FIRE,LOW);
}
//---Прерывание таймера 1 канала
ISR(TIMER1_COMPA_vect) {
sign1=1;
}
//---Прерывание таймера 2 канала
ISR(TIMER2_COMPA_vect) {
sign2=1;
}
//---Прерывание по переднему фронту 1 канала
void cannal_1() {
sign1=0;
TCNT1=0;
}
//---Прерывание по переднему фронту 2 канала
void cannal_2() {
sign2=0;
TCNT2=0;
}
//---300 мкс - основной цикл
void startTimer0() {
cli();
TCCR0A |= (1 << WGM01);
TCCR0B |= (1 << CS01) | (1 << CS00);
OCR0A = 74;
TIMSK0 |= (1 << OCIE0A);
sei();
}
//---90 мкс - 1 канал
void startTimer1() {
cli();
TCCR1A = 0;
TCCR1B = 0;
TCCR1B |= (1 << WGM12);
OCR1A = 1439;
TIMSK1 |= (1 << OCIE1A);
TCCR1B |= (1 << CS10);
sei();
}
//---90 мкс - 2 канал
void startTimer2() {
cli();
TCCR2A = 0;
TCCR2B = 0;
TCCR2A |= (1 << WGM21);
TCCR2B |= (1 << CS21);
OCR2A = 179;
TIMSK2 |= (1 << OCIE2A);
sei();
}
//---Инициализация
void setup() {
int j;
for (j=7;j<=13;j++)pinMode(j,OUTPUT);
pinMode(IN1,INPUT);pinMode(IN2,INPUT);
pinMode(FIRE,OUTPUT);pinMode(FB1,OUTPUT);pinMode(FB2,OUTPUT);
digitalWrite(FIRE,LOW);digitalWrite(FB1,LOW);digitalWrite(FB2,LOW);
count=0;rate=R_WAIT;
clearBuf();
sign1=1;sign2=1;
//---Запустить таймеры
tim0=1;
startTimer0();
startTimer1();startTimer2();
//---Запустить внешние прерывания
attachInterrupt(digitalPinToInterrupt(IN1),cannal_1,RISING);
attachInterrupt(digitalPinToInterrupt(IN2),cannal_2,RISING);
}
//---Основной цикл по таймеру 0
ISR(TIMER0_COMPA_vect) {
tim0--;if (tim0!=0) return;
tim0=1;
if (rate==R_WAIT) //---Режим ожидания основной
{
ReadAndShift();
if (m1[0]==0 && m1[1]==0 && m1[2]==0 && m2[0]==1 && m2[1]==1 && m2[2]==1){rate=R_BACK;return;}
if (m1[0]==1 && m1[1]==1 && m1[2]==1 && m2[0]==0 && m2[1]==0 && m2[2]==0){rate=R_DIR;return;}
return;
}
if (rate==R_DIR) //---Режим возможного пересечения вперёд
{
ReadAndShift();
if (m1[0]==0 && m1[1]==0 && m1[2]==0 && m2[0]==0 && m2[1]==0 && m2[2]==0){rate=R_WAIT;return;}
if (m1[0]==1 && m1[1]==1 && m1[2]==1 && m2[0]==1 && m2[1]==1 && m2[2]==1){rate=R_DO_DIR;return;}
return;
}
if (rate==R_BACK) //---Режим возможного пересечения назад
{
ReadAndShift();
if (m1[0]==0 && m1[1]==0 && m1[2]==0 && m2[0]==0 && m2[1]==0 && m2[2]==0){rate=R_WAIT;return;}
if (m1[0]==1 && m1[1]==1 && m1[2]==1 && m2[0]==1 && m2[1]==1 && m2[2]==1){rate=R_DO_BACK;return;}
return;
}
if (rate==R_DO_DIR) //---Точно пересечение вперёд
{
if (count<MAX_VIS) count++;
setDig(count);
if (count==1) fireON();
tim0=2000;clearBuf();
rate=R_WAIT;
return;
}
if (rate==R_DO_BACK) //---Точно пересечение назад
{
if (count>0) count--;
setDig(count);
if (count==0) fireOFF();
tim0=2000;clearBuf();
rate=R_WAIT;
return;
}
}
void loop() {
while (0==0) {};
}
И, да, для тех, кто пропустил предыдущую потерянную ветку, подобное устройство уже работает у меня дней 10, без единого сбоя.