В приложении bluetooth elektroniks

это уже для меня сложнее, без помощи не разберусь . Спасибо!

пока первый вариант пытаюсь

const int led1 = 2;
const int led2 = 3;
const int led3 = 4;

// Время для каждого LED (мс)
unsigned long duration1 = 5000;  // LED1
unsigned long duration2 = 10000; // LED2
unsigned long duration3 = 15000; // LED3

unsigned long startTime = 0;
unsigned long currentDuration = 0;

int stage = 0;        // 0=стоп, 1=LED1, 2=LED2, 3=LED3
bool running = false; // цикл стартует только после команды START

void setup() {
  Serial.begin(9600);

  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);

  Serial.println("Система готова");
}

void loop() {

  // Проверка команд с телефона
  if (Serial.available()) {
    String cmd = Serial.readStringUntil('\n');
    cmd.trim();

    if (cmd == "S" && !running) {
      stage = 1;
      running = true;
      activateStage();
      Serial.println("СТАРТ");
    }

    if (cmd == "X") stopAll();

    // Изменение времени только при необходимости
    if (cmd.startsWith("T1")) duration1 = cmd.substring(2).toInt() * 1000UL;
    if (cmd.startsWith("T2")) duration2 = cmd.substring(2).toInt() * 1000UL;
    if (cmd.startsWith("T3")) duration3 = cmd.substring(2).toInt() * 1000UL;
  }

  // Переход к следующему этапу
  if (running && millis() - startTime >= currentDuration) {
    nextStage();
  }
}

void activateStage() {

  digitalWrite(led1, LOW);
  digitalWrite(led2, LOW);
  digitalWrite(led3, LOW);

  if (stage == 1) currentDuration = duration1;
  if (stage == 2) currentDuration = duration2;
  if (stage == 3) currentDuration = duration3;

  if (stage == 1) digitalWrite(led1, HIGH);
  if (stage == 2) digitalWrite(led2, HIGH);
  if (stage == 3) digitalWrite(led3, HIGH);

  startTime = millis();

  Serial.print("LED ");
  Serial.print(stage);
  Serial.println(" включен");
}

void nextStage() {
  stage++;
  if (stage > 3) {
    Serial.println("Цикл завершен");
    stopAll();
    return;
  }
  activateStage();
}

void stopAll() {
  digitalWrite(led1, LOW);
  digitalWrite(led2, LOW);
  digitalWrite(led3, LOW);

  running = false;
  stage = 0;

  Serial.println("СТОП");
}

Итак делюсь проделанной работой благодаря чат GPT (какое удовольствие работать )

Значит сейчас у меня работает:
:white_check_mark: HC-06 через пины 0/1
:white_check_mark: Кнопка START
:white_check_mark: Кнопка STOP
:white_check_mark: Автоматический цикл 1 → 2 → 3
:white_check_mark: Таймеры

При отправлении S в приложении запускается автоматический цикл

в приложении приходит состоянии Лед1 Лед2 Лед три пишет таймер 123 и пишет когда закончен цикл.

Спасибо огромное Pyotr, MMM, BABOS!!! Без вас я бы не дотумкался

Теперь сделал еще

:control_knobs: Выбор времени с телефона

S
START, запускает цикл LED1→LED2→LED3
X
STOP, останавливает цикл
T1+число
Изменяет время LED1 (сек)
T2+число
Изменяет время LED2 (сек)
T3+число
Изменяет время LED3 (сек)

    Serial.println("LED3 включен");

это что вам все таки надо было просто в монитор порта вывести ? или это пульт ваш понимает и включает нужную лампочку ?
что бы вам помочь, нужен пример кода, что бы понять как вы управляете лампочкой, и это отображается в пульте…
так что я вам совсем не помог, и самоустранился от помощи))) по причине отсутствия от вас кода…

Ну почитай тогда:

:smiley:

1 лайк
//================ФИНАЛЬНЫЙ СКЕТ РАЗДВИЖНЫХ ИЛИ ОТКАТНЫХ ВОРОТ ОДИН УЛЬРАЗВУКОВОЙ ДАТЧИК РАССТОЯНИЯ И ДВА ФОТОДАТЧИКА================


#include <Arduino.h>

// ===== PINS =====
#define STEP_PIN 3
#define DIR_PIN  2

#define TRIG_PIN 8
#define ECHO_PIN 9

#define PHOTO1_PIN 12
#define PHOTO2_PIN 13

// LM339 open collector: usually LOW = active
const int PHOTO_ACTIVE_LEVEL = LOW;

// ===== PARAMETERS (BT commands) =====
int NEAR_CM = 40;
int FAR_CM  = 50;

const int STEPS_PER_REV = 200;   // поменяй на 400, если микрошаг = 400 шаг/об
long doorSteps = 1200;           // Nxxxx or Rn*STEPS_PER_REV

unsigned int PULSE_US = 10;      // для TB6600 достаточно 5..10 us
unsigned int SPEED_US = 1200;    // Sxxxx (200..3000), больше = медленнее

unsigned long closeDelayMs = 2000; // Dxxxx (200..60000)
unsigned long reopenHoldMs = 2000; // Hxxxx (0..10000)
unsigned long reopenHoldStart = 0;

bool forceOpenToZero = false;

// ===== TELEMETRY =====
const unsigned long SEND_INTERVAL_MS = 1000;
unsigned long lastSendMs = 0;

const unsigned long SENSOR_PERIOD_MS = 120;
unsigned long lastSensorMs = 0;

// ===== SENSOR VALUES =====
long lastCm = -1;

// --- ultrasonic confirm ---
const int US_CONFIRM = 5;
int nearCnt = 0, farCnt = 0;
bool nearOk = false, farOk = false;

const unsigned long REVERSE_HOLD_MS = 500;
unsigned long nearOkSinceMs = 0;

// --- photo confirm ---
const int PHOTO_CONFIRM = 3;
int photoCnt1 = 0, photoCnt2 = 0;
bool photoOk1 = false, photoOk2 = false;

// ===== MOTION / POSITION =====
enum Motion { IDLE, OPENING, CLOSING };
Motion motion = IDLE;

// posSteps: 0 = open, doorSteps = closed
long posSteps = 0;

// Close timer
bool closeTimerActive = false;
unsigned long closeTimerStart = 0;

// Step generator (non-blocking)
unsigned long lastStepUs = 0;
bool stepHigh = false;
unsigned long stepHighSinceUs = 0;

// ---------- HC-SR04 ----------
long readCmOnce() {
  digitalWrite(TRIG_PIN, LOW); delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH); delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);

  unsigned long d = pulseIn(ECHO_PIN, HIGH, 25000UL);
  if (d == 0) return -1;
  return (long)(d / 58);
}

long readCmFiltered() {
  long sum = 0; int cnt = 0;
  for (int i = 0; i < 3; i++) {
    long cm = readCmOnce();
    if (cm > 0) { sum += cm; cnt++; }
    delay(8);
  }
  if (cnt == 0) return -1;
  return sum / cnt;
}

// ---------- STEPPER ----------
void setDirForMotion(Motion m) {
  // если направление перепутано — поменяй HIGH/LOW местами
  if (m == OPENING) digitalWrite(DIR_PIN, HIGH);
  if (m == CLOSING) digitalWrite(DIR_PIN, LOW);
  delayMicroseconds(50);
}

void startOpening() {
  if (posSteps <= 0) { motion = IDLE; posSteps = 0; return; }
  motion = OPENING;
  setDirForMotion(OPENING);
}

void startClosing() {
  if (posSteps >= doorSteps) { motion = IDLE; posSteps = doorSteps; return; }
  motion = CLOSING;
  setDirForMotion(CLOSING);
}

void stopMotion() { motion = IDLE; }

void updateStepper() {
  if (motion == IDLE) return;

  // reached fully open
  if (motion == OPENING && posSteps <= 0) {
    posSteps = 0;
    stopMotion();

    if (forceOpenToZero) reopenHoldStart = millis();
    forceOpenToZero = false;
    return;
  }

  // reached fully closed
  if (motion == CLOSING && posSteps >= doorSteps) {
    posSteps = doorSteps;
    stopMotion();
    return;
  }

  unsigned long now = micros();

  if (stepHigh) {
    if (now - stepHighSinceUs >= PULSE_US) {
      digitalWrite(STEP_PIN, LOW);
      stepHigh = false;

      if (motion == OPENING) posSteps--;
      else if (motion == CLOSING) posSteps++;
    }
    return;
  }

  if (now - lastStepUs >= SPEED_US) {
    digitalWrite(STEP_PIN, HIGH);
    stepHigh = true;
    stepHighSinceUs = now;
    lastStepUs = now;
  }
}

// ---------- CONFIRM HELPERS ----------
static inline void updateUltrasonicConfirm(long cm) {
  if (cm < 0) {
    nearCnt = farCnt = 0;
    nearOk = farOk = false;
    nearOkSinceMs = 0;
    return;
  }

  if (cm < NEAR_CM) {
    nearCnt++;
    farCnt = 0;
  } else if (cm > FAR_CM) {
    farCnt++;
    nearCnt = 0;
  } else {
    nearCnt = 0;
    farCnt = 0;
  }

  bool prevNearOk = nearOk;
  nearOk = (nearCnt >= US_CONFIRM);
  farOk  = (farCnt  >= US_CONFIRM);

  unsigned long ms = millis();
  if (nearOk && !prevNearOk) nearOkSinceMs = ms;
  if (!nearOk) nearOkSinceMs = 0;
}

static inline void updatePhotoConfirm(bool raw1, bool raw2) {
  if (raw1) photoCnt1++; else photoCnt1 = 0;
  if (raw2) photoCnt2++; else photoCnt2 = 0;

  photoOk1 = (photoCnt1 >= PHOTO_CONFIRM);
  photoOk2 = (photoCnt2 >= PHOTO_CONFIRM);
}

// ---------- STATUS / COMMANDS ----------
void printStatus() {
  Serial.print("STAT;DelayMs="); Serial.print(closeDelayMs);
  Serial.print(";DoorSteps="); Serial.print(doorSteps);
  Serial.print(";HoldMs="); Serial.print(reopenHoldMs);
  Serial.print(";Near="); Serial.print(NEAR_CM);
  Serial.print(";Far="); Serial.print(FAR_CM);
  Serial.print(";SpeedUs="); Serial.print(SPEED_US);

  Serial.print(";cm="); Serial.print(lastCm);
  Serial.print(";nearOk="); Serial.print(nearOk ? 1 : 0);
  Serial.print(";farOk="); Serial.print(farOk ? 1 : 0);
  Serial.print(";B1="); Serial.print(photoOk1 ? 1 : 0);
  Serial.print(";B2="); Serial.print(photoOk2 ? 1 : 0);

  Serial.print(";pos="); Serial.print(posSteps);
  Serial.print(";motion="); Serial.println((int)motion);
}

void handleSerial() {
  static char buf[40];
  static byte idx = 0;

  while (Serial.available()) {
    char c = Serial.read();

    if (c == '\n' || c == '\r') {
      if (idx == 0) continue;
      buf[idx] = '\0';
      idx = 0;

      if (!strcmp(buf, "STAT")) { printStatus(); return; }

      if (buf[0] == 'D') {
        long v = atol(buf + 1);
        if (v < 200) v = 200;
        if (v > 60000) v = 60000;
        closeDelayMs = (unsigned long)v;
        Serial.print("OK;DelayMs="); Serial.println(closeDelayMs);
        return;
      }

      if (buf[0] == 'N') {
        long v = atol(buf + 1);
        if (v < 10) v = 10;
        if (v > 50000) v = 50000;
        doorSteps = v;
        if (posSteps > doorSteps) posSteps = doorSteps;
        Serial.print("OK;DoorSteps="); Serial.println(doorSteps);
        return;
      }

      if (buf[0] == 'R') {
        long rev = atol(buf + 1);
        if (rev < 1) rev = 1;
        if (rev > 200) rev = 200;
        doorSteps = rev * (long)STEPS_PER_REV;
        if (posSteps > doorSteps) posSteps = doorSteps;
        Serial.print("OK;DoorSteps="); Serial.println(doorSteps);
        return;
      }

      if (buf[0] == 'H') {
        long v = atol(buf + 1);
        if (v < 0) v = 0;
        if (v > 10000) v = 10000;
        reopenHoldMs = (unsigned long)v;
        Serial.print("OK;HoldMs="); Serial.println(reopenHoldMs);
        return;
      }

      if (buf[0] == 'S') {
        long v = atol(buf + 1);
        if (v < 200) v = 200;
        if (v > 3000) v = 3000;
        SPEED_US = (unsigned int)v;
        Serial.print("OK;SpeedUs="); Serial.println(SPEED_US);
        return;
      }

      if (!strncmp(buf, "NEAR", 4)) {
        int v = atoi(buf + 4);
        if (v < 10) v = 10;
        if (v > 200) v = 200;
        NEAR_CM = v;
        Serial.print("OK;Near="); Serial.println(NEAR_CM);
        return;
      }

      if (!strncmp(buf, "FAR", 3)) {
        int v = atoi(buf + 3);
        if (v < NEAR_CM + 5) v = NEAR_CM + 5;
        if (v > 300) v = 300;
        FAR_CM = v;
        Serial.print("OK;Far="); Serial.println(FAR_CM);
        return;
      }

      Serial.println("ERR;Use D2000 N1200 R6 H3000 S1200 NEAR40 FAR50 STAT");
    } else {
      if (idx < sizeof(buf) - 1) buf[idx++] = c;
    }
  }
}

// ---------- SETUP ----------
void setup() {
  pinMode(STEP_PIN, OUTPUT);
  pinMode(DIR_PIN, OUTPUT);
  digitalWrite(STEP_PIN, LOW);

  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);

  pinMode(PHOTO1_PIN, INPUT_PULLUP);
  pinMode(PHOTO2_PIN, INPUT_PULLUP);

  Serial.begin(9600);
  Serial.println("SYSTEM READY (1x US + 2x PHOTO)  ENA=DISCONNECTED");
  printStatus();
}

// ---------- LOOP ----------
void loop() {
  handleSerial();
  updateStepper();

  unsigned long ms = millis();

  if (ms - lastSensorMs >= SENSOR_PERIOD_MS) {
    lastSensorMs = ms;

    // read sensors
    lastCm = readCmFiltered();

    bool raw1 = (digitalRead(PHOTO1_PIN) == PHOTO_ACTIVE_LEVEL);
    bool raw2 = (digitalRead(PHOTO2_PIN) == PHOTO_ACTIVE_LEVEL);

    updateUltrasonicConfirm(lastCm);
    updatePhotoConfirm(raw1, raw2);

    bool anyPhoto = (photoOk1 || photoOk2);

    // telemetry
    if (ms - lastSendMs >= SEND_INTERVAL_MS) {
      lastSendMs = ms;
      Serial.print("*D");  Serial.println(lastCm);
      Serial.print("*B1"); Serial.println(photoOk1 ? 1 : 0);
      Serial.print("*B2"); Serial.println(photoOk2 ? 1 : 0);
    }

    // --- PHOTO SAFETY: force open to zero and block closing ---
    if (anyPhoto) {
      closeTimerActive = false;
      if (motion == CLOSING || (motion == IDLE && posSteps > 0)) {
        forceOpenToZero = true;
        startOpening();
      }
      return; // пока фото активно — не закрываем
    }

    // --- US SAFETY: if closing and nearOk stable -> force open to zero ---
    if (motion == CLOSING && nearOk) {
      if (nearOkSinceMs != 0 && (ms - nearOkSinceMs >= REVERSE_HOLD_MS)) {
        closeTimerActive = false;
        forceOpenToZero = true;
        startOpening();
      }
      return;
    }

    // block closing while forced opening not finished
    if (forceOpenToZero) return;

    // hold after emergency open
    if (reopenHoldStart != 0) {
      if (ms - reopenHoldStart < reopenHoldMs) return;
      reopenHoldStart = 0;
    }

    // --- normal logic ---
    if (nearOk) {
      closeTimerActive = false;
      if (motion == IDLE && posSteps > 0) startOpening();
      return;
    }

    if (farOk) {
      if (posSteps < doorSteps && motion == IDLE) {
        if (!closeTimerActive) {
          closeTimerActive = true;
          closeTimerStart = ms;
        } else if (ms - closeTimerStart >= closeDelayMs) {
          closeTimerActive = false;
          startClosing();
        }
      }
    }
  }
}

ОСНОВНЫЕ КОМАНДЫ ДЛЯ ПРИЛОЖЕНИЯ Serial Bluetooth Terminal

(в приложении Bluetooth Electroniks корректно не отправляет символы ответ от Ардуино не приходит не добился)

  1. STAT

    STAT
    Показывает текущее состояние:
    расстояние с обоих датчиков
    near/far статус
    состояние фотодатчиков
    позицию двери (pos)
    режим движения (motion)
    текущие параметры (скорость, задержки и т.д.)

  2. Sxxxx — скорость двигателя

    S1200
    Меняет скорость движения (в микросекундах между шагами).
    Чем больше число → тем медленнее движение.
    Пример:
    S700 — быстрее
    S1200 — медленнее
    S2000 — очень медленно
    Диапазон: 200–3000

  3. Dxxxx — задержка закрытия

    D3000
    Задержка перед закрытием после того, как стало “far”.
    В миллисекундах.
    D2000 = 2 секунды
    D5000 = 5 секунд

  4. Hxxxx — пауза после аварийного открытия

    H3000
    После аварийного открытия (ультразвук или фото) дверь ждёт это время перед возможным закрытием.

  5. Nxxxx — количество шагов до полного закрытия

    N1200
    Устанавливает длину хода двери в шагах.
    Используется если ты считаешь ход в шагах

  6. Rxx — обороты двигателя

R6
Устанавливает длину хода в оборотах.

  1. NEARxx — порог “близко”

NEAR40
Если расстояние меньше этого значения — считается “человек рядом”.
8) FARxx — порог “далеко”

FAR55
Если расстояние больше этого значения — считается “никого нет”.
:warning: FAR должен быть больше NEAR минимум на 5 см.
Как логика работает сейчас
Любой ультразвук < NEAR → открытие
Оба ультразвука > FAR → закрытие
Любой фотобарьер активен → открытие до нуля
Во время закрытия срабатывание датчика → полный реверс

  1. Пример нормальных рабочих настроек
    S1200
    D3000
    H3000
    NEAR40
    FAR55
    R6

Я использовал фотобарьры микросхемой LM339

ультразвуковой датчики расстояния HC-SR04

драйвер для шагового двигателя ТВ6600

блютуз HC-06 на пины 0/1 (поэтому пишем только через Serial при загрузке блютуз отключаем с RX/TX если блютуз на других пинах 2/3 пишем через SoftwareSerial )

Про ENA- (Enable в драйвере а именно минус я закоротил вместе с DIR - PUL-и на минус в Ардуино а плюс ENA никуда не подлючал)

Концевики пока не подключал пока испытываю какие есть и будут ощибки