Оцифровка кинопленки при помощи Arduino UNO

Тема в разделе "Arduino & Shields", создана пользователем Bryaker, 17 мар 2017.

  1. Bryaker

    Bryaker Нуб

    Уважаемые форумчане, прошу помочь в корректном написании скетча и подключении. К Arduino UNO подключен шаговый двигатель через драйвер DRV8825. Стоят три двухпозиционные кнопки для контроля прижимного механизма и пленки. На кинопроекторе кнопки: Старт, Стоп, Пауза. Так же есть web-камера USB. Цикл таков:
    Нажата кнопка Пуск на проекторе=>(Начало цикла) Опрашиваются цифровые пины контрольных кнопок (каждый раз в начале цикла). Если 6==0 && 5==0 && 4==1 , то цикл запускается, иначе выдается сообщение на PC о неисправности (Ошибка кнопки 1; Ошибка кнопки 2;Ошибка кнопки 3;Ошибка кнопки 1,2;Ошибка кнопки 1,3;Ошибка кнопки 2,3;Ошибка кнопки 1,2,3;)=>Если условия верны, то двигатель делает один оборот на 360 градусов=>Передается сигнал на PC (нажатие сочетания клавиш shift+p), что инициирует снятие камерой фото=>Задержка на 30ms (Конец цикла).
    После нажатия кнопки Пуск - цикл должен повторяться 3000раз, после чего поступит сигнал на зуммер. Если нажали кнопку Пауза то контроллер должен ждать пока не будет снова нажата кнопка старт и продолжить с того же повторения цикла на котором остановился. Если любая из 3 кнопок контроля изменила свое состояние, то контроллер должен ждать пока условие не станет снова верным, будет нажата Пауза, а потом снова Старт, и продолжит с того же повторения на котором остановился. Кнопка Стоп останавливает цикл и сбрасывает счетчик количества повторов.
    Заранее признателен за любую помощь!
     
  2. Unixon

    Unixon Оракул Модератор

    Как-то так ...
    Код (C++):

    #define PIN_SW_START 6
    #define PIN_SW_STOP 5
    #define PIN_SW_PAUSE 4
    #define PIN_M_STEP 7
    #define PIN_M_DIR 8
    #define PIN_BEEPER 9

    #define N_SW 3
    #define SW_BIT_START 0
    #define SW_BIT_STOP  1
    #define SW_BIT_PAUSE 2

    #define SW_PRESSED LOW
    #define M_STEP_ACTIVE HIGH
    #define M_DIR_FORWARD HIGH
    #define M_STEPS_PER_FRAME 360

    #define DELAY_M_STEP_US 1
    #define DELAY_FRAME_MS 30
    #define DELAY_BEEP_MS 500
    #define BEEP_FREQ_HZ 4000

    #define N_FRAME_COUNT 3000

    #define STATE_START 0
    #define STATE_CONTINUE 1
    #define STATE_WAIT_KEY 2
    #define STATE_PAUSE 3
    #define STATE_ERROR 4
    #define STATE_STOP 5

    #define SERIAL_BAUDRATE 9600

    uint8_t state = STATE_START;
    int frame_counter = 0;
    bool repeat_frame = false;

    void initStepper()
    {
      // initialize DRV8825
      // setup dir/step pins
      pinMode(PIN_M_STEP, OUTPUT);
      pinMode(PIN_M_DIR, OUTPUT);
      digitalWrite(PIN_M_STEP, !M_STEP_ACTIVE);
      digitalWrite(PIN_M_DIR, M_DIR_FORWARD);
    }

    void moveFrameForward()
    {
      for (uint8_t i=0; i<M_STEPS_PER_FRAME; i++)
      {
       digitalWrite(PIN_M_STEP, M_STEP_ACTIVE);
       digitalWrite(PIN_M_STEP, !M_STEP_ACTIVE);
       delayMicroseconds(DELAY_M_STEP_US);
      }
    }

    uint8_t getSwitchState()
    {
      uint8_t bits;
      if (SW_PRESSED==digitalRead(PIN_SW_START)) bits |= _BV(SW_BIT_START);
      if (SW_PRESSED==digitalRead(PIN_SW_STOP))  bits |= _BV(SW_BIT_STOP);
      if (SW_PRESSED==digitalRead(PIN_SW_PAUSE)) bits |= _BV(SW_BIT_PAUSE);
      return bits;
    }

    void shootFrame()
    {
      Keyboard.press(KEY_LEFT_CTRL);
      Keyboard.press('P');
      Keyboard.releaseAll();
      delay(DELAY_FRAME_MS);
    }

    void beep()
    {
      tone(PIN_BEEPER, BEEP_FREQ_HZ, DELAY_BEEP_MS);
    }

    void setup()
    {
      Serial.begin(SERIAL_BAUDRATE);
      Keyboard.begin();
      initStepper();
      pinMode(PIN_BEEPER, OUTPUT);
      noTone(PIN_BEEPER);
    }

    void loop()
    {
      uint8_t sw_state = getSwitchState();
      switch(state)
      {
       case STATE_START:
       {
        if (sw_state)
        {
         if (sw_state==_BV(SW_BIT_START))
         {
          while (getSwitchState()); // wait for key relese
          frame_counter = 0;
          repeat_frame = false;
          state = STATE_CONTINUE;
         }
         else state = STATE_ERROR;
        }
        break;
       }
       case STATE_CONTINUE:
       {
        if (sw_state)
        {
         if (sw_state==_BV(SW_BIT_PAUSE))
         {
          while (getSwitchState());
          state = STATE_PAUSE;
         }
         else if (sw_state==_BV(SW_BIT_STOP))
         {
          while (getSwitchState());
          state = STATE_STOP;
         }

         {
          state = STATE_WAIT_KEY;
         }
        }
        else
        {
         if (!repeat_frame) moveFrameForward();
         shootFrame();
         delay(DELAY_FRAME_MS);
         frame_counter++;
         if (frame_counter>=N_FRAME_COUNT)
         {
          beep();
          state = STATE_STOP;
         }
        }
        break;
       }
       case STATE_WAIT_KEY:
       {
        if (sw_state==_BV(SW_BIT_PAUSE))
        {
         while (getSwitchState());
         state = STATE_PAUSE;
        }
        break;
       }
       case STATE_PAUSE:
       {
        if (sw_state==_BV(SW_BIT_START))
        {
         while (getSwitchState());
         repeat_frame = true;
         state = STATE_CONTINUE;
        }
        break;
       }
       case STATE_ERROR:
       {
        Serial.print("Switches jammed: ");
        for (uint8_t i=0; i<N_SW; i++)
        {
         if (sw_state&_BV(i))
         {
          if (i) Serial.print(',');
          Serial.print(i+1);
         }
         Serial.println();
        }
        state = STATE_START;
        break;
       }
       case STATE_STOP:
       {
        frame_counter = 0;
        repeat_frame = false;
        state = STATE_START;
        break;
       }
      }
    }
     
    Кириллstrelok, Bryaker, Tomasina и 2 другим нравится это.
  3. Unixon

    Unixon Оракул Модератор

    Можно еще антидребезг добавить
    Код (C++):
    #define DELAY_DEBOUNCE_MS 100

    uint8_t getRawSwitchState()
    {
      uint8_t bits;
      if (SW_PRESSED==digitalRead(PIN_SW_START)) bits |= _BV(SW_BIT_START);
      if (SW_PRESSED==digitalRead(PIN_SW_STOP))  bits |= _BV(SW_BIT_STOP);
      if (SW_PRESSED==digitalRead(PIN_SW_PAUSE)) bits |= _BV(SW_BIT_PAUSE);
      return bits;
    }

    uint8_t getSwitchState()
    {
      uint8_t bits0, bits1  = getRawSwitchState();
      do
      {
        bits0 = bits1;
        delay(DELAY_DEBOUNCE_MS);
        bits1 = getRawSwitchState();
      }
      while (bits1!=bits0);
      return bits0;
    }
     
    Последнее редактирование: 17 мар 2017
    Bryaker, ИгорьК и arkadyf нравится это.
  4. Bryaker

    Bryaker Нуб

    Благодарю за столь быструю помощь! Но в описании системы я не достаточно полно описал кнопки (переключатели) . Всего их получается 6. Три на проекторе (Старт, Стоп, Пауза), подключенные к 3,2 пинам, и три кнопки (концевые переключатели) установлены для контроля прижимного механизма и натяжения пленки, они как раз и подключены к пинам 6,5,4. При правильном положении пленки в начале цикла на 6 и 5 пинах low, а на 4 high. Извините за неточное описание.
     
    Последнее редактирование: 17 мар 2017
  5. Bryaker

    Bryaker Нуб

    И сразу ещё уточню про переключатели на проекторе : нажатие на Старт переводит ее только в положение "включено" , Пауза только при включенном Старте (переводится во "включено" /"выключено") , Стоп механически переводит кнопки Старт и Пауза в состояние "выключено" .
     
  6. Bryaker

    Bryaker Нуб

    Немного изменил код (добавил 3 кнопки контроля натяжения) и попробовал скомпилировать, но неудачно. Вероятно не хочет Keyboard.h работать с Arduino UNO.
    Вот сам скетч (прошу посмотреть опытным взглядом, не напортачил ли я в нем):
    Код (C++):
    #include <Keyboard.h>

    #define PIN_SW_START 7
    #define PIN_SW_STOP 6
    #define PIN_SW_PAUSE 5
    #define PIN_M_STEP 9
    #define PIN_M_DIR 8
    #define PIN_BEEPER 13
    #define PIN_SW_LOCK 4 // проверка прижима пленки
    #define PIN_SW_UL 3 // проверка натяжения на верхней петле
    #define PIN_SW_DL 2 // проверка натяжения на верхней петле

    #define N_SW 3
    #define SW_BIT_START 0
    #define SW_BIT_STOP  1
    #define SW_BIT_PAUSE 2
    #define SW_BIT_LOCK 3
    #define SW_BIT_UL 4
    #define SW_BIT_DL 5

    #define SW_PRESSED LOW
    #define M_STEP_ACTIVE HIGH
    #define M_DIR_FORWARD HIGH
    #define M_STEPS_PER_FRAME 360

    #define DELAY_M_STEP_US 1
    #define DELAY_FRAME_MS 30
    #define DELAY_BEEP_MS 500
    #define BEEP_FREQ_HZ 4000

    #define N_FRAME_COUNT 3000

    #define STATE_START 0
    #define STATE_CONTINUE 1
    #define STATE_WAIT_KEY 2
    #define STATE_PAUSE 3
    #define STATE_STOP 4
    #define STATE_ERRORLOCK 5
    #define STATE_ERRORUL 6
    #define STATE_ERRORDL 7

    #define SERIAL_BAUDRATE 9600

    uint8_t state = STATE_START;
    int frame_counter = 0;
    bool repeat_frame = false;

    void initStepper()
    {
      // initialize DRV8825
      // setup dir/step pins
      pinMode(PIN_M_STEP, OUTPUT);
      pinMode(PIN_M_DIR, OUTPUT);
      digitalWrite(PIN_M_STEP, !M_STEP_ACTIVE);
      digitalWrite(PIN_M_DIR, M_DIR_FORWARD);
    }

    void moveFrameForward()
    {
      for (uint8_t i=0; i<M_STEPS_PER_FRAME; i++)
      {
       digitalWrite(PIN_M_STEP, M_STEP_ACTIVE);
       digitalWrite(PIN_M_STEP, !M_STEP_ACTIVE);
       delayMicroseconds(DELAY_M_STEP_US);
      }
    }

    uint8_t getSwitchState()
    {
      uint8_t bits;
      if (SW_PRESSED==digitalRead(PIN_SW_START)) bits |= _BV(SW_BIT_START);
      if (SW_PRESSED==digitalRead(PIN_SW_STOP))  bits |= _BV(SW_BIT_STOP);
      if (SW_PRESSED==digitalRead(PIN_SW_PAUSE)) bits |= _BV(SW_BIT_PAUSE);
      if (SW_PRESSED==digitalRead(PIN_SW_LOCK)) bits |= _BV(SW_BIT_LOCK);
      if (SW_PRESSED==digitalRead(PIN_SW_UL))  bits |= _BV(SW_BIT_UL);
      if (SW_PRESSED==digitalRead(PIN_SW_DL)) bits |= _BV(SW_BIT_DL);
      return bits;
    }

    void shootFrame()
    {
      Keyboard.press(KEY_LEFT_CTRL);
      Keyboard.press('P');
      Keyboard.releaseAll();
      delay(DELAY_FRAME_MS);
    }

    void beep()
    {
      tone(PIN_BEEPER, BEEP_FREQ_HZ, DELAY_BEEP_MS);
    }

    void setup()
    {
      Serial.begin(SERIAL_BAUDRATE);
      Keyboard.begin();
      initStepper();
      pinMode(PIN_BEEPER, OUTPUT);
      noTone(PIN_BEEPER);
    }

    void loop()
    {
      uint8_t sw_state = getSwitchState();
      switch(state)
      {
       case STATE_START:
       {
        if (sw_state)
        {
         if (sw_state==_BV(SW_BIT_START))
         {
          while (getSwitchState()); // wait for key relese
          frame_counter = 0;
          repeat_frame = false;
          state = STATE_CONTINUE;
         }
       
        }
        break;
       }
       case STATE_CONTINUE:
       {
        if (sw_state)
        {
         if (sw_state==_BV(SW_BIT_PAUSE))
         {
          while (getSwitchState());
          state = STATE_PAUSE;
         }
         else if (sw_state==_BV(SW_BIT_STOP))
         {
          while (getSwitchState());
          state = STATE_STOP;
         }

         {
          state = STATE_WAIT_KEY;
         }
        }
        else
        {
         if (!repeat_frame) moveFrameForward();
         shootFrame();
         delay(DELAY_FRAME_MS);
         frame_counter++;
         if (frame_counter>=N_FRAME_COUNT)
         {
          beep();
          state = STATE_STOP;
         }
        }
        break;
       }
       case STATE_WAIT_KEY:
       {
        if (sw_state==_BV(SW_BIT_PAUSE))
        {
         while (getSwitchState());
         state = STATE_PAUSE;
        }
        break;
       }
       case STATE_PAUSE:
       {
        if (sw_state==_BV(SW_BIT_START))
        {
         while (getSwitchState());
         repeat_frame = true;
         state = STATE_CONTINUE;
        }
        break;
       }
       case STATE_ERRORLOCK:
       {
        Serial.print("The film is not clamed: ");
        for (uint8_t i=0; i<N_SW; i++)
        {
         if (sw_state&_BV(i))
         {
          if (i) Serial.print(',');
          Serial.print(i+1);
         }
         Serial.println();
        }
        state = STATE_CONTINUE;
        break;
       }
       case STATE_ERRORUL:
       {
        Serial.print("Upper loop misfeed: ");
        for (uint8_t i=0; i<N_SW; i++)
        {
         if (sw_state&_BV(i))
         {
          if (i) Serial.print(',');
          Serial.print(i+1);
         }
         Serial.println();
        }
        state = STATE_CONTINUE;
        break;
       }
       case STATE_ERRORDL:
       {
        Serial.print("Upper loop misfeed: ");
        for (uint8_t i=0; i<N_SW; i++)
        {
         if (sw_state&_BV(i))
         {
          if (i) Serial.print(',');
          Serial.print(i+1);
         }
         Serial.println();
        }
        state = STATE_CONTINUE;
        break;
       }
       case STATE_STOP:
       {
        frame_counter = 0;
        repeat_frame = false;
        state = STATE_START;
        break;
       }
      }
    }
    А вот отчет компилятора:
    Код (Text):

    In file included from C:\Users\bryak\OneDrive\Документы\Arduino\OcifrovkaVideo\OcifrovkaVideo.ino:1:0:

    C:\Users\bryak\OneDrive\Документы\Arduino\libraries\Keyboard\src/Keyboard.h:29:2: warning: #warning "Using legacy HID core (non pluggable)" [-Wcpp]

    #warning "Using legacy HID core (non pluggable)"

      ^

    C:\Users\bryak\OneDrive\Документы\Arduino\OcifrovkaVideo\OcifrovkaVideo.ino: In function 'void shootFrame()':

    OcifrovkaVideo:82: error: 'Клавиатура' не найдена. Убедитесь входит ли скетч в код '#include <Keyboard.h>'?
    OcifrovkaVideo:82: error: 'KEY_LEFT_CTRL' was not declared in this scope

    C:\Users\bryak\OneDrive\Документы\Arduino\OcifrovkaVideo\OcifrovkaVideo.ino: In function 'void setup()':

    OcifrovkaVideo:96: error: 'Клавиатура' не найдена. Убедитесь входит ли скетч в код '#include <Keyboard.h>'?
    exit status 1
    'Клавиатура' не найдена. Убедитесь входит ли скетч в код '#include <Keyboard.h>'?
    Выбирал плату LEonardo - компиляция успешная, но мне надо под UNO... :(
     
  7. Unixon

    Unixon Оракул Модератор

    Возьмите Leonardo / Iskra Neo, это будет проще. Конечно, можно извратиться и с Uno, либо перешить мостовую атмегу и USB, либо на V-USB что-то там наколхозить, но это все IMO лишние сложности. Вам нужен МК с USB, который изначально умеет прикидываться USB HID устройством.
     
  8. Bryaker

    Bryaker Нуб

    Спасибо за совет, видимо придётся взять Leonardo. А в код, который Вы любезно мне предоставили, я верно добавил три кнопки, не нарушил логику?
     
  9. Unixon

    Unixon Оракул Модератор

    Бегло просмотрел код. Нигде нет переходов в новые состояния STATE_ERROR<что-то там>, N_SW осталось старым, хотя кнопок теперь 6, SW_PRESSED для разных кнопок у вас разное, соотв. нужна другая константа (ну либо можно прямо в процедуру прописать уровни).