сделать/доделать скетч для слайдера видеокамеры

Тема в разделе "Закажу проект", создана пользователем Denis Ivanov, 28 мар 2017.

  1. Denis Ivanov

    Denis Ivanov Нуб

    Здравствуйте господа,

    Cобственно есть наполовину написанный скетч для слайдера с шаговым мотором NEMA17. Исполнитель не смог продолжить проект по личным обстоятельствам, поэтому мне надо довести его до конца или переделать.

    Сам не разбираюсь совсем, знаний хватило собрать механическую часть самому и электроннику по схеме от исполнителя.

    В наличии вот этот Кит Ардуино и Мотор.



    Требования:

    Включение/выключения движения длинным нажатием на энкодер. Смена направления коротким. Регулировка скорости вращением. Должно работать как до запуска так и на ходу, с отображением на дисплее направления движения, текущей скорости, ну и точного положения раз уж все равно шаги считаем.

    Автоматическая смена направления при достижении конечных пунктов слайдера.

    Как ручные, так и автоматические остановки/смены направления с плавным торможением-разгоном.

    Конечные остановки без датчиков, высчитываются по количеству шагов мотора, что требует калибровку при старте.

    алгоритм калибровки: при заранее измеренном количестве шагов, при старте системы дисплей выдает слово Calibration? и стрелку направления домой (в крайнее положение в сторону мотора). вручную сдвигаю каретку в домашнее положение, и нажимаю на энкодер, подтверждая что каретка находится в домашнем положении. режим движения автоматически переключается в обратное направление. При нажатии на старт едет заданное количество шагов, там останавливается и едет назад, до домашнего крайнего положения, и так далее.



    Что имеем:

    Первый вариант скетча, видимо без конечных остановок но с возможностью померять шаги залит в Ардуину, дисплей включается, показывает вольтаж, реагирует на нажатия энкодера на включение выключение, регулировка скорости не работает корректно, мотор щелкает но не включается.

    собрано вот по такой схеме

    [​IMG]





    Скетч:

    Код (C++):
    /************************************
      Проект:   слайдер для видеокамеры
      Заказчик: Денис Иванов
      E-mail:
    *************************************/


    #include <U8glib.h>
    #define pinE  10
    #define pinRW 9
    #define pinDI 8
    U8GLIB_ST7920_128X64 u8g(pinE, pinRW, pinDI, U8G_PIN_NONE);
    //U8GLIB_KS0108_128 u8g(8, 9, 10, 11, 4, 5, 6, 7, 18, 14, 15, 17, 16);     // 8Bit Com: D0..D7: 8,9,10,11,4,5,6,7 en=18, cs1=14, cs2=15,di=17,rw=16

    /* Вывод, который будет измерять напряжение батареи. Напряжение на вывод подаётся
       через резистивный делитель. Верхнее плечо - 510 кОм, нижнее плечо - 33 кОм.
       Максимальное напряжение, подаваемое на делитель - 18.1В. При этом с делителя на
       вход микроконтроллера будет поступать 1.1В, т.е. максимальное опорное. */

    #define pinU  A0

    /* Номера выврдов, к которым подключен энкодер */
    #define pinEncoderA       2
    #define pinEncoderB       3
    #define pinEncoderButton  12

    /* Номера выводов, к которым подключен драйвер A4988 шагового двигателя NEMA17 */
    #define pinStep       22
    #define pinDirection  23

    #include <AccelStepper.h>
    AccelStepper mystepper(1, pinStep, pinDirection); // Инициализация ШД для управления внешним драйвером


    /* Функция измерения напряжения батареи */
    float getBattaryU(void) {
      float U = 0.0;
      uint16_t adc = 0;
      for(uint8_t i=0; i<10; i++) adc += analogRead(pinU);  // Считываем показания АЦП 10 раз для повышения точности
      adc /= 10;                                            // Вычисляем среднее значение АЦП
      U = float(adc) * 18.1 / 1023.0;                       // Вычисляем реальное значение напряжения батареи
      return U;                                             // Возвращаем усреднённое значение напряжения
    }

    volatile int stepperSpeed = 10;  // Скорость ШД
    volatile long steps = 0;
    volatile bool calibration = false;


    void setup() {
      analogReference(INTERNAL1V1);             // Включаем внутренний ИОН на 1.1В
      attachInterrupt(0, encoder, RISING);      // Внешнее прерывание для обработки 1-го вывода энкодера
      pinMode(pinEncoderB, INPUT_PULLUP);       // Настройка на вход второго вывода энкодера
      pinMode(pinEncoderButton, INPUT_PULLUP);  // Настройка на вход вывода для кнопки энкодера

      /* Настройка параметров ШД */
      pinMode(pinStep, OUTPUT);
      pinMode(pinDirection, OUTPUT);
      mystepper.setMaxSpeed(400);               // Максимальная скорость, шагов в секунду (для NEMA17 - 2 оборота в секунду)
      mystepper.setAcceleration(10.0);          // Ускорение ШД, шагов в секунду
      mystepper.setSpeed(0);                    // Начальная скорость равна 0

      // Настройка таймера Т2 для опроса кнопки энкодера в прерывании
      TCCR2A = 0x00; TCCR2B = 0x07; TCNT2 = 0x00; TIMSK2 = 0x01;
      sei();
      Serial.begin(9600);
    }

    volatile uint8_t menuFlag = 0;

    /* Прерывание для обработки вращения энкодера */
    void encoder() {
        if(digitalRead(pinEncoderB) == HIGH) {
          stepperSpeed++;
          if(stepperSpeed > 400) stepperSpeed = 0;
        }
        else {
          stepperSpeed--;
          if(stepperSpeed < 0) stepperSpeed = 400;
        }
    }

    /* Функция обработки нажатия кнопки энкодера */
    volatile bool flagPress = false;
    volatile bool longPress = false;
    volatile unsigned long timePress = 0;

    volatile uint8_t button() {
      /* Определение момента нажатия кнопки */
      if((!flagPress) && (!longPress) && (digitalRead(pinEncoderButton) == LOW)) {
        delay(50);
        if(digitalRead(pinEncoderButton) == LOW) {
          flagPress = true;
          timePress = millis();
        }
      }

      /* Определение момента удержания кнопки */
      if((flagPress) && (!longPress) && (millis() - timePress > 1500)) {
        longPress = true;
        timePress = millis();
        return 2;
      }

      /* Определение момента отпускания кнопки */
      if((digitalRead(pinEncoderButton) == HIGH) && (flagPress)) {
        delay(50);
        if(digitalRead(pinEncoderButton) == HIGH) {
          if(longPress) { flagPress = false; longPress = false; return 0; }
          else if(!longPress) { flagPress = false; longPress = false; return 1; }
        }
      }
      return 0;
    }
    volatile bool stepperDirection = false;
    /* Прерывание для обработки нажатия кнопки энкодера */
    ISR(TIMER2_OVF_vect) {
      switch(button()) {
        case 1:
          stepperDirection = !stepperDirection;
         // return;
        break;

        case 2:
          calibration = !calibration;
         // return;
        break;
      }
    }

    /* Функция отображения меню */
    void menu() {
      u8g.firstPage();
      do
      {
        u8g.setFont(u8g_font_6x12);
       // u8g.drawBox(0, 13, 128, 1);
        u8g.setPrintPos(0, 12); u8g.print("U_battary="); u8g.print(getBattaryU()); u8g.print("V    ");
     
        u8g.setPrintPos(0, 24); u8g.print(stepperSpeed); u8g.print("step/s; "); u8g.print(float(stepperSpeed) / 200.0); u8g.print("turn/s");

        if(!stepperDirection) {u8g.setPrintPos(0, 36); u8g.print("Direction: --->");}
        else {u8g.setPrintPos(0, 36); u8g.print("Direction: <---");}
     
        if(!calibration) {u8g.setPrintPos(0, 48); u8g.print("Push encoder to start");}
        else {u8g.setPrintPos(0, 48); u8g.print("Push encoder to stop ");}

        u8g.setPrintPos(0, 60); u8g.print("STEPS:"); u8g.print(steps);
     
        switch(menuFlag) {
          case 0:
         
          break;
        }
      } while(u8g.nextPage());
    }

    int dir = 0; long CP=mystepper.currentPosition();
    void loop() {
      menu();
      if(!stepperDirection) dir = 1;
      else dir = -1;
      if(calibration) {
        mystepper.setSpeed(stepperSpeed);
        mystepper.runSpeed();
        steps = mystepper.currentPosition() - CP;
      }
    }
     
  2. sslobodyan

    sslobodyan Гик

    Денис, указав сроки выполнения заказа и сумму благодарности, вы гораздо быстрее подберете исполнителя.