Где может быть ошибка кода?

Тема в разделе "Arduino & Shields", создана пользователем sanik, 8 окт 2013.

  1. sanik

    sanik Гик

    А при выходе из ветки STEP2_GET_POTS значение potValue сбрасывается на ноль?
    Код (Text):
     case STEP2_GET_POTS:
        {
          potValue = analogRead(pin_dist);
          if(potValue >= 510 && potValue <= 520)// если rewX в пределах [510; 520] - остановить мотор
          StopMotor();
          if(potValue < 510)// если rewX в пределах (0; 510) - крутить в направлении 1
          RunMotor1();
          if(potValue > 520)// если rewX в пределах (520; 0) - крутить в направлении 2
          RunMotor2();
          Serial.println("Каретка установлена! Переходим к шагу 3");
          if(bouncerBtnSelect.read() == HIGH)// проверяем, нажата ли кнопка
          currentStep = STEP3_GET_POSITION;
        }
          break;
     
  2. Megakoteyka

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

    potValue - глобальная переменная. Она хранит свое значение до тех пор, пока ей не присвоят новое значение. Так что ничего никуда не сбрасывается, а только обновляется при вызове analogRead().
     
    Последнее редактирование: 21 окт 2013
  3. sanik

    sanik Гик

    Понятно значит она просто не задействована в других режимах...
    Вот попытался внести контроль над концевиками вывод сообщений сделал и прописал шаг6 теперь буду ждать когда освободитесь
    Код (Text):
    #include <Bounce.h>
    #include <Wire.h>
    #include <LiquidCrystal_I2C.h>

    LiquidCrystal_I2C lcd(0x27,16,2);

    // время подавления дребезга кнопок, мс
    #define DEBOUNCE_INTERVAL 20

    // номера пинов для кнопок
    #define btn_SELECT 3
    #define btn_PLUS  7
    #define btn_MINUS  6
    #define btn_START  4
    #define btn_STOP 2
    // номера пинов мотора
    #define pin_A 10
    #define pin_B 11
    #define pin_ENABLE 12
    // пин потенциометра
    #define pin_dist A1
    // пин датчика концевиков
    #define pin_Rd A2
    // пин фотоинтераптора
    #define pin_pos
    // максимальные значения
    #define MAX_POS_VALUE      ...// для положения каретки
    #define MAX_PAUSE_VALUE    ...// для времени паузы
    #define MAX_EXPOSURE_VALUE ...// для времени экспозиции
    #define MAX_SHOT_VALUE = 4000
    // шаги алгоритма
    typedef enum STEPS {
      STEP1_HELLO,
      STEP2_GET_POTS,
      STEP3_GET_POSITION,
      STEP4_GET_PAUSE,
      STEP5_GET_EXPOSURE,
      STEP6_GET_COUNT
    }

    // текущий шаг алгоритма
    STEPS currentStep = STEP1_HELLO;

    // создаем "давилки дребезга" для кнопок
    Bounce bouncerBtnSelect(btn_SELECT, DEBOUNCE_INTERVAL);
    Bounce bouncerBtnPlus(btn_PLUS, DEBOUNCE_INTERVAL);
    Bounce bouncerBtnMinus(btn_MINUS, DEBOUNCE_INTERVAL);
    Bounce bouncerBtnStart(btn_START, DEBOUNCE_INTERVAL);
    Bounce bouncerBtnStop(btn_STOP, DEBOUNCE_INTERVAL);
    void setup()
    {
      Serial.begin(9600);
      lcd.init();lcd.backlight();lcd.clear(); // инициализация дисплея, включаем подсветку, очищаем экран
    }

    int potValue  = 0; // значение потенциометра 1
    int pot2Value  = 0; // значение потенциометра 1
    int posValue  = 0; // значение положения каретки
    int pauseValue = 0; // значение времени паузы
    int exposValue = 0; // значение времени экспозиции
    int countValue = 0; // значение количества кадров
    int shootValue = 0; //значение счетчика кадров
    int control = 0; //значение датчика концевиков

    void hello()
    {
      lcd.setCursor(5, 0);lcd.print("Hello");delay(200);// установка курсора, печать надписи, задержка на 200 мс.
      lcd.setCursor(0, 1);lcd.print(" Slider Timelaps");delay(2000);
      lcd.clear();// очистка дисплея.
    }
    void RunMotor1()
    {
    digitalWrite (pin_A, LOW);
    digitalWrite(pin_B, HIGH);
    }
    void RunMotor2()
    {
      digitalWrite (pin_A, HIGH);
      digitalWrite(pin_B, LOW);
    }
    void StopMotor()
    {
      digitalWrite(pin_ENABLE, LOW);
    }
    void ENABLE()


    void loop()
    {
      bouncerBtnSelect.update();
      bouncerBtnPlus.update();
      bouncerBtnMinus.update();
      bouncerBtnStart.update();
      bouncerBtnStop.update();
      switch(currentStep)
      {
        case STEP1_HELLO:
          hello();
          currentStep = STEP2_GET_POTS;
          break;

        case STEP2_GET_POTS:
        lcd.setCursor(0,0);lcd.print("    Manyal  ");
        {
          potValue = analogRead(pin_dist);
          if(potValue >= 510 && potValue <= 520)// если rewX в пределах [510; 520] - остановить мотор
          StopMotor();
          if(potValue < 510)// если rewX в пределах (0; 510) - крутить в направлении 1
          RunMotor1();
          if(potValue > 520)// если rewX в пределах (520; 0) - крутить в направлении 2
          RunMotor2();
          control = analogRead(pin_Rd);// чтение кнцевика
          if(control>= 540 && control <= 550)// если положение 1
          // запрещаем крутить мотор в направлении 1
          if(control>= 450 && control <= 460)// если положение 2
          //запрещаем крутить мотор в направлении 2
          Serial.println("Каретка установлена! Переходим к шагу 3");
          if(bouncerBtnSelect.read() == HIGH)// проверяем, нажата ли кнопка
          currentStep = STEP3_GET_POSITION;
        }
          break;

        case STEP3_GET_POSITION:
        lcd.setCursor(0,0); lcd.print("Setting position");
        // гоним каертку на исходную позицию
        RunMotor1();
        //читаем датчик концевик, и останавливаем каретку в крайней позиции
        control = analogRead(pin_Rd);
        if(control>= 540 && control <= 550)
        StopMotor();
          // кнопка нажата и значение меньше максимально допустимого?
          if(bouncerBtnPlus.read() == HIGH && posValue < MAX_POS_VALUE)
            posValue++;
            lcd.setCursor(0,1); lcd.print("Position"); lcd.print(posValue);
          // кнопка нажата и значение больше минимально допустимого (нуля)?
          if(bouncerBtnMinus.read() == HIGH && posValue > 0)
            posValue--;
            lcd.setCursor(0,1); lcd.print("Position"); lcd.print(posValue);
          if(bouncerBtnSelect.read() == HIGH)
          {
            Serial.println("Установлено положение каретки! Переходим к шагу 4");
            currentStep = STEP4_GET_PAUSE;
          }
          break;

        case STEP4_GET_PAUSE:
        lcd.setCursor(0,0); lcd.print("Setting interval");
          if(bouncerBtnPlus.read() == HIGH && pauseValue < MAX_PAUSE_VALUE)
            pauseValue++;
            lcd.setCursor(0,1); lcd.print("Interval"); lcd.print(pauseValue);
          if(bouncerBtnMinus.read() == HIGH && pauseValue > 0)
            pauseValue--;
            lcd.setCursor(0,1); lcd.print("Interval"); lcd.print(pauseValue);
          if(bouncerBtnSelect.read() == HIGH)
          {
            Serial.println("...! Переходим к шагу 5");
            currentStep = STEP5_GET_EXPOSURE;
          }
          break;

        case STEP5_GET_EXPOSURE:
        lcd.setCursor(0,0); lcd.print("Setting exposure");
          if(bouncerBtnPlus.read() == HIGH && exposValue < MAX_EXPOSURE_VALUE)
            exposValue++;
            lcd.setCursor(0,1); lcd.print("exp time"); lcd.print(exposValue);
          if(bouncerBtnMinus.read() == HIGH && exposValue > 0)
            exposValue--;
            lcd.setCursor(0,1); lcd.print("exp time"); lcd.print(exposValue);
          if(bouncerBtnSelect.read() == HIGH)
          {
            Serial.println("...! Переходим к шагу 6");
            currentStep = STEP6_GET_COUNT;
          }
          break;

        case STEP6_GET_COUNT:
      lcd.setCursor(0,0); lcd.print("Setting shooting");
      if(bouncerBtnPlus.read() == HIGH && shootValue < MAX_SHOT_VALUE)
        shootValue++;
        lcd.setCursor(0,1); lcd.print("num shots"); lcd.print(shootValue);
        if(bouncerBtnMinus.read() == HIGH && shootValue > 0)
        shootValue--;
        lcd.setCursor(0,1); lcd.print("num shots"); lcd.print(shootValue);
       {
          currentStep = STEP7_GET_COUNT;
        }
          break;
      }
    }
     
    Последнее редактирование: 21 окт 2013
  4. sanik

    sanik Гик

    кстати ошибка там уже давно сидит
    ошибка.png
     
  5. Megakoteyka

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

    По порядку:
    1.
    Код (Text):
    lcd.setCursor(0,0);lcd.print("    Manyal  ");
    {
        ...
    }
    Зачем скобки? Скобки нужны для того, чтобы выполнился блок кода, идущий после if, for, while, do...
    В противном случае выполнится только один оператор.
    Например:
    if(a < b)
    c = 10;
    d = 20;
    В этом случае по условию выполнится только оператор c = 10;, а оператор d = 20; выполнится в любом случае. Чтобы выполнить оба оператора по условию, нужно заключить их в фигурные скобки - превратить в блок операторов.
    if(a < b)
    {
    c = 10;
    d = 20;
    }
    Теперь по условию выполнятся оба оператора.
    Если же мы просто вызываем функцию, нет никакого смысла обрамлять идущие после нее операторы фигурными скобками - они и так все выполнятся по очереди.

    2. Точка с запятой должна стоять после закрывающей фигурной скобки.
    Код (Text):
    typedef enum STEPS {
      STEP1_HELLO,
      STEP2_GET_POTS,
      STEP3_GET_POSITION,
      STEP4_GET_PAUSE,
      STEP5_GET_EXPOSURE,
      STEP6_GET_COUNT
    };
    3. Один оператор - одна строка!
    Вместо
    Код (Text):
    lcd.init();lcd.backlight();lcd.clear();
    следует писать
    Код (Text):
    lcd.init();
    lcd.backlight();
    lcd.clear();
    Экономия пары строк не стоит возникающей путаницы и усложнения читабельности кода.

    4. Почему концевики опрашиваются подобно потенциометрам? Концевик - это просто обычная кнопка. Если кнопка подключена к аналоговой ноге, то мы прочитаем 0, если она отпущена и максимальное значение, если она нажата. Или я чего-то не догоняю в Вашей схеме подключения.
     
  6. Megakoteyka

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

    Для кручения моторов накидал примерно такое чудище:
    Код (Text):
    #define MOTOR_MOVE 0
    #define MOTOR_STOP 1

    // длительность цикла мотора "вращение+стояние" - 128 мс
    #define MOTOR_CYCLE 128

    // "масштаб": то значение, на которое нужно разделить шкалу потенциометра
    // чтобы привести ее к шкале MOTOR_CYCLE
    int motorPotScale = 1024 / MOTOR_CYCLE;

    // значение с потенциометра
    int potValue = 0;
    // длительность вращения мотора
    int durationMove = 0;
    // длительность остановки мотора
    int durationStop = 128;
    // текущее состояние мотора
    int motorState = MOTOR_MOVE;
    // время начала очередного полуцикла работы мотора (вращения или стояния)
    long motorStartTime = 0;

    void setup()
    {
      _motorStartTime = millis();
    }

    void loop()
    {
      // читаем потенциометр
      potValue = analogRead(A0);
      // берем текущее время
      long currentTime = millis();

      // "цикл" работы мотора состоит из двух "полуциклов":
      // в первом полуцикле мотор вращается durationMove мс,
      // во втором полуцикле мотор стоит durationStop мс.
      // один "цикл" имеет длительность MOTOR_CYCLE мс,
      // следовательно, durationMove + durationStop == MOTOR_CYCLE.
      // (к циклам в программировании это не имеет отношения,
      // речь только о логике работы мотора)
      switch(motorState)
      {
        // вращение мотора
        case MOTOR_MOVE:
          // если с момента начала полуцикла вращения прошло
          // больше, чем durationMove, нужно остановить мотор,
          // изменить значение времени начала полуцикла на текущее
          // (теперь это будет время начала стояния мотора)
          // и перейти ко второму полуциклу
          if(motorStartTime + durationMove >= currentTime)
          {
            MotorStop();
            motorStartTime = currentTime;
            motorState = MOTOR_STOP;
          }
          break;
       
        // стояние мотора
        case MOTOR_STOP:
          // если с момента начала полуцикла стояния прошло
          // больше, чем durationStop, нужно запустить мотор,
          // изменить значение времени начала полуцикла на текущее
          // (теперь это будет время начала вращения мотора)
          // и перейти ко второму полуциклу
          if(motorStartTime + durationStop >= currentTime)
          {
            MotorStart();
            motorStartTime = currentTime;
            motorState = MOTOR_MOVE;
           
            // в конце второго полуцикла (а значит, в конце полного цикла работы мотора)
            // вычисляем новые значения длительностей вращения или стояния.
            // (здесь нужно будет добавить логику мертвой зоны потенциометра, чтобы в
            // районе середины потенциометра мотор стоял на месте, а не дергался туда-сюда
            // из-за погрешностей измерения)

            // берем середину значений потенциометра (potValue - 511)
            // и приводим ее к длительностям вращения и стояния мотора таким образом,
            // чтобы в сумме длительности давали MOTOR_CYCLE мс.
            durationMove = (potValue - 511) / motorPotScale;
            durationStop = 128 - durationMove;
          }
          break;
      }
    }
    Хоть немного понятна логика того, что я пытался изобразить? :)
    Завтра постараюсь объяснить подробней, если получится - на картинке изображу.
    Такие вещи в идеале надо живьем под пиво объяснять, бурно жестикулируя и рисуя карандашиком на листочке - гораздо понятней получается почему-то :)
     
  7. sanik

    sanik Гик

    концевики сидят на одном проводе подключены к одному аналоговому входу
    Концевики.png
     
  8. Megakoteyka

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

    Тады ой, где-то я этот момент пропустил :)
    С алгоритмом кручения-верчения получилось найти взаимопонимание?
     
  9. sanik

    sanik Гик


    Да без пива и тыканием носом точно не разберешь!!!
     
  10. Megakoteyka

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

    Можно устроить, если время и география позволяет :)
     
  11. sanik

    sanik Гик

    Это не мой косяк :) Я так и не могу разобраться где ставить скобки где точку а где точку с запятой Сейчас опять ругается на эти строки
    ошибка.png
     
  12. sanik

    sanik Гик

    Ага всего то 800 км.:)
     
  13. sanik

    sanik Гик

    Получается мы потенциометром меняем значение millis() А потом сравниваем с прошедшем временем после запуска контролера и при совпадении отдаем на съедение ШИМу Так я понял?
     
  14. Megakoteyka

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

    Можно в скайпе на выходных стыкнуться попробовать.
    Это оно ругается на вот это:
    Код (Text):
    #define MAX_POS_VALUE      ...// для положения каретки
    #define MAX_PAUSE_VALUE    ...// для времени паузы
    #define MAX_EXPOSURE_VALUE ...// для времени экспозиции
    Нужно вместо троеточий поставить значения по вкусу :)
    Смысл строки #define x 5 заключается в том, что компилятор тупо подставляет повсюду 5 вместо x. А если вместо 5 стоит "...", то компилятор вполне закономерно ругается.
     
  15. sanik

    sanik Гик

    Кстати для времени ограничение ставить в мс. или в сек.?
     
  16. Megakoteyka

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

    Не-не-не. Мы считываем значение потенциометра. Чем дальше от середины шкалы повернут потенциометр, тем быстрее должен вращаться мотор. Чтобы реализовать такое поведение, мы движение мотора разбиваем на "циклы" длительностью MOTOR_CYCLE миллисекунд. В данном случае 128.
    От значения, прочитанного с потенциометра, отнимаем половину (как бы встаем в середину шкалы) и делим полученное на 4 - получаем в итоге длительность. Только в моем примере это длительность вращения, а на самом деле должна быть длительность остановки - иначе скорость мотора будет расти не в ту сторону, это я не подумал сразу :) Т.е. на самом деле должно быть:
    Код (Text):
    durationStop = (potValue - 511) / motorPotScale;
    durationMove = MOTOR_CYCLE - durationStop;
    Ну и в случае, если значение потенциометра <512, нужно изменить направление вращения мотора, прибавить 512 к значению потенциометра (чтобы не получить отрицательной величины), а потом все то же самое.
    Получается: чем дальше от середины повернут потенциометр, тем дольше становятся длительности вращения мотора и короче остановки - в итоге средняя скорость вращения повышается.
    А функцией millis() мы как раз замеряем время, прошедшее с начала вращения или стояния мотора - это чтобы не использовать delay().
     
  17. Megakoteyka

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

    Поскольку millis() возвращает количество миллисекунд, прошедшее с момента ресета контроллера, то все длительности мы тоже измеряем в мс.
     
  18. sanik

    sanik Гик

    Так значит у вас перекур завтра с работы приду попробую реализовать в коде с руганью я его укротил не надо было = ставить Я в курсе что delay() в таком коде навредит так как нам надо будет еще отщеты времени запускать просто я millis() совсем не понимаю читал а толку мало как его использовать
     
  19. sanik

    sanik Гик

    Тогда с MAX_PAUSE_VALUE засада значение большое иногда приходиться ставить до 1 минуты.:)
     
  20. Megakoteyka

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

    Попробуйте для примера повесить потенциометр на ногу А0 и погоняйте этот код:
    Код (Text):
    #define LED_ON 0
    #define LED_OFF 1

    // длительность цикла светодиода "вкл+выкл" - 1024 мс
    #define LED_CYCLE 1024

    #define LED_PIN 13
    #define POT_PIN A0

    int potValue = 0;
    int durationOn = 0;            // длительность вкл
    int durationOff = LED_CYCLE;  // длительность выкл
    int ledState = LED_ON;        // текущее состояние
    long startTime = 0;            // время начала очередного полуцикла

    void setup()
    {
      pinMode(LED_PIN, OUTPUT);
      startTime = millis();
      Serial.begin(9600);
    }

    void loop()
    {
      potValue = analogRead(POT_PIN);  // читаем потенциометр
      long currentTime = millis();    // берем текущее время
     
      switch(ledState)
      {
        // полуцикл "ВКЛ"
        case LED_ON:
          if(startTime + durationOn <= currentTime)
          {      
            digitalWrite(LED_PIN, LOW);
            startTime = currentTime;
            ledState = LED_OFF;
          }
          break;

        // полуцикл "ВЫКЛ"
        case LED_OFF:
          if(startTime + durationOff <= currentTime)
          {
            digitalWrite(LED_PIN, HIGH);
            startTime = currentTime;
            ledState = LED_ON;

            durationOff = potValue;
            durationOn = LED_CYCLE - durationOff;
            Serial.print("durationOn:  ");
            Serial.println(durationOn);
            Serial.print("durationOff: ");
            Serial.println(durationOff);
          }
          break;
      }
    }
    В зависимости от положения потенциометра будет менять длительность вспышек и пауз светодиода.
    С мотором почти то же самое :)