Нужен принцип проверки условия

Тема в разделе "Arduino & Shields", создана пользователем funakoshi, 13 апр 2015.

  1. funakoshi

    funakoshi Нуб

    Всем привет.
    Стандартно - нуб. Причем полный. Но есть желание учиться. Поэтому прошу не код написать, а так сказать в стиле "для чайника" объяснить принцип. Код я попытаюсь сам написать.
    Имеем числовой ряд, пусть будет от 0 до 255. В данном ряду имеем число А (0<=A<=255). К числу А можем подойти как приращением от нуля, так и уменьшением от 255. При достижении А снизу (т.е. от нуля к А) необходимо выполнить функцию 1, при достижении А сверху (т.е. от 255 к А) необходимо выполнить фунцкию 2. Надеюсь понятно написал.
    Собственно, как образом определить с какой стороны мы подошли к А?
     
  2. ИгорьК

    ИгорьК Гуру

    Иметь и изучать предыдущее значение А :

    если А == требуемому значению
    если А(старое) меньше чем А (новое)
    то выполняем функцию 1​
    иначе
    выполняем функцию 2​
    конец
     
  3. funakoshi

    funakoshi Нуб

    Я так понимаю, что старое значение для первой проверки надо заранее задать. А после функции 1 и функции 2 надо старому значению присвоить текущее значение А.
    Код (Text):
    int val = 0;
    int oldA = 0;
    int A = 58;
    if (val == A && oldA < A)
      {
        function 1; // здесь любой код
        val++;
        oldA = A;
      }
    else if (val == A && oldA > A)
      {
        function 2; // здесь любой код
        val++;
        oldA = A;
      }
    else {oldA=0};
    }
    Поправьте пожалуйста, если что-то не так.
    У меня большие сомнения по поводу else {oldA=0};
     
  4. ИгорьК

    ИгорьК Гуру

    Оно не может не быть известно, если у Вас А меняется. Это А откуда то же берется? Откуда?
    Первый раз, возможно, А не имеет истории, но в следующий и все последующие разы - имеет.
    Для первого раза, включения следует сделать отдельное решение. Но все зависит от конкретики.

    Код (C):
    #define CHECK 127 // Постоянное число, с которым нужно сравнивать
    byte oldA = 0;
    byte A;

    while (1) {
        A = ... получли данные;
        if ( A == CHECK ) {
            if (A > oldA) {
                function 1 ...
            }
            else {
                function 2 ...
            }
        }
        oldA = A;
    }
     
    Последнее редактирование: 13 апр 2015
  5. funakoshi

    funakoshi Нуб

    :) Ладно, открою карты.
    Числовой ряд - скорость авто. А - значение скорости, при подходе к которому снизу надо выполнить функцию 1. Есть еще значение В - при подходе к нему сверху надо выполнить функцию 2.
    Вот полный скетч. Там моего практически нет ничего, сплошной копипаст. Но вот блок обработки скорости хотел сам написать, да что-то застопорился. Если не сложно - посмотрите, пожалуйста.
    Код (Text):
    /*
    created Tomasina, forum.amperka.ru
    created Frud, drive2.ru
    modified Andrew 'funakoshi' Ryabov
    8 April 2015
    */
    #define BUTTON_PIN 7
    #define BUZZER_PIN 4
    #define RELAY_PIN 9
    #define DISPLAY_PIN 5

    int bounceTime = 10;          // задержка для подавления дребезга
    int holdTime = 500;          // время, в течение которого нажатие можно считать удержанием кнопки
    int doubleTime = 1000; // время, в течение которого нажатия можно считать двойным
    int frequency = 3500; //частота звука "пищалки"
    int speedMode = 0; //просто чтобы не ругался компилятор
    int previousSpeed = 0; //скорость в настоящий момент

    boolean lastReading = false;  // флаг предыдущего состояния кнопки
    boolean buttonSingle = false; // флаг состояния "краткое нажатие"
    boolean buttonDouble = false; // флаг состояния "двойное нажатие"
    boolean buttonHold = false;  // флаг состояния "долгое нажатие"
    boolean dispState = false; //флаг "включенности" дисплея парктроника

    long onTime = 0;              // переменная обработки временного интервала
    long lastSwitchTime = 0;      // переменная времени предыдущего переключения состояния

    volatile unsigned long micros_sp = 0;
    volatile byte sz = 0;                  //счетчик обнуления
    volatile unsigned int sp = 0;          //скорость
    int regim = 1; // текущий режим
    volatile unsigned int speedUp = 0;    //набор скорости
    volatile unsigned int speedDown = 0;  //снижение скорости
    volatile unsigned int speedLimit = 0; //предел превышения скорости
    volatile boolean st = false;

    void setup()
    {
      pinMode(BUTTON_PIN, INPUT); // INPUT_PULLUP подключит кнопку через внутренний резистор
      attachInterrupt(1, speedometr, RISING);
      pinMode(DISPLAY_PIN, INPUT); //подключаем дисплей парктроника к пину
    }

    void loop()
    {
      if (sz != 0) {
        sz--;
      } else {
        sp = 0;
      };

      // ================ обработчик состояния кнопки ====================
      boolean reading = digitalRead(BUTTON_PIN);  /* читаем состояние пина кнопки. Если подключен через внутренний резистор (см. pinMode(BUTTON_PIN, INPUT_PULLUP)),
                                                    перед digitalRead(BUTTON_PIN) нужен !. */
      // проверка первичного нажатия
      if (reading && !lastReading)
      {
        onTime = millis();
      }
      // проверка удержания
      if (reading && lastReading)
      {
        if ((millis() - onTime) > holdTime)
        {
          buttonHold = true;
        }
      }
      // проверка отпускания кнопки
      if (!reading && lastReading)
      {
        if (((millis() - onTime) > bounceTime) && !buttonHold)
        {
          if ((millis() - lastSwitchTime) >= doubleTime)
          {
            lastSwitchTime = millis();
            buttonSingle = true;
          }
          else
          {
            lastSwitchTime = millis();
            buttonDouble = true;
            buttonSingle = false;
            isButtonDouble();
            buttonDouble = false;  // сброс состояния после выполнения команды
          }
        }
        if (buttonHold)
        {
          buttonDouble = false;
          isButtonHold(speedMode);
          buttonHold = false;  // сброс состояния после выполнения команды
        }
      }
      lastReading = reading;
      if (buttonSingle && (millis() - lastSwitchTime) > doubleTime)
      {
        buttonDouble = false;
        isButtonSingle();
        buttonSingle = false;  // сброс состояния после выполнения команды
      }
      // ================ конец обработчика состояния кнопки ==================
      // ================ обработчик скорости =================================
      int val = 0;
      dispState = digitalRead(DISPLAY_PIN);
     
      // если экран включен и скорость поднялась до speedUP снизу, то вкл выкл реле
      if (sp == speedUp && (speedUp - previousSpeed) > 0 && dispState) {
        isButtonSingle();
        previousSpeed = sp;
        val++;
      }
      else {
        val = 0;
      }

      // если экран выключен и скорость упала до speedDown сверху, то вкл выкл реле
      if  (sp == speedDown && (speedDown - previousSpeed) < 0 && !dispState )
      {
        isButtonSingle();
        previousSpeed = sp;
        val++;
      }
      else {
        val = 0;
      }

      // если скорость поднялась до speedLimit снизу, то пробибикать несколько раз

    //================= конец обработки скорости =================
    } // конец loop


    void isButtonSingle() // действия после одиночного нажатия кнопки
    { //При однократном "коротком" нажатии кнопки реле замкнётся на 0,5 сек.
      digitalWrite(RELAY_PIN, HIGH);
      delay(500);
      digitalWrite(RELAY_PIN, LOW);
    }

    void isButtonDouble() // действия после двойного нажатия кнопки. Автор X-Dron arduino.ru
    { //Выбрать активный режим (всего 3 режима: speedUp, speedDown, speedLimit)
      //Просигнализировать о выбранном режиме n-ым количеством бипов (n зависит от активного режима)
      speedMode = (++speedMode) % 4;
      if (speedMode == 0) speedMode = 1;
      for (int i = 0; i < speedMode; i++) {
        tone(BUZZER_PIN, frequency, 50);
        delay(200);
      }
    }

    void isButtonHold(int x) // действия после удержания кнопки
    { //Запомнить значание активному режиму. Об запоминании сигнализировать звуком
      switch (x) {
        case 1: //speedUp
          speedUp = sp;
          tone(BUZZER_PIN, frequency, 150);
          break;
        case 2: //speedDown
          speedDown = sp;
          tone(BUZZER_PIN, frequency, 150);
          break;
        case 3: //speedLimit
          speedLimit = sp;
          tone(BUZZER_PIN, frequency, 150);
          break;
      }
    }

    void speedometr() { //измеряем частоту на входе спидометра по прерыванию
      if (!st) {
        micros_sp = micros();
      }
      else {
        sp = (1600000 / (micros() - micros_sp));
      }
      st = !st;
      sz = 30;
    }
     
  6. ИгорьК

    ИгорьК Гуру

    Не, подождите, может кто другой ответит... :) Я такие длинные не умею читать.
     
  7. iglooshtosser

    iglooshtosser Гик

    Ну во первых:
    if (sp == speedUp && (speedUp - previousSpeed)
    не совсем корректно. ведь sp может и проскочить speedUp.
    то есть на одной итерации sp<speedUp, а на следующей уже может быть sp>speedUp, то есть порог пройден, а условие не выполнилось :)
    думаю вернее так: if (sp >= speedUp && (speedUp - previousSpeed)

    Логика такая если скорость больше порога или равна ему, а раньше была меньше, значит она прошла порог снизу.
    С обратным проходом порога - тоже самое.
     
  8. funakoshi

    funakoshi Нуб

    В принципе, учитывая, что есть еще 2 доп проверки, наверное соглашусь. В идеале, конечно, надо sp == speedUp.
    P.S. Хотя нет, соглашусь с вами. Мне "==" не принципиально, было бы достаточно точности +- 5 км/ч от speedUp.
     
  9. iglooshtosser

    iglooshtosser Гик

    Идеал, на то и идеал, что он недостижим техническими средствами :)
    В данном случае, имхо лучше получить событие с небольшим опозданием, чем пропустить его совсем.