Почему не работает код?

Тема в разделе "Arduino & Shields", создана пользователем Vittorio, 28 май 2016.

  1. Tomasina

    Tomasina Сушитель лампочек Модератор

    а в языке Си вычитание беззнаковых чисел по определению не может дать отрицательное число.
     
  2. joman

    joman Гик

    Вспомнил.
    Там была такая конструкция:
    Код (C++):
    #define x 100
    unsigned long LastWork;
    bool v = 0;

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

    void loop() {
      if (millis() > LastWork + x) {
        LastWork = millis();
        // тут ещё какие то вычисления
      }
    }
    может случиться так, что LastWork + x - не переполнится, а millis() - переполнится на следующей итерации loop, и тогда программа в условие никогда не попадёт.

    Про отрицательность я не говорил. Речь о переполнении.

    P.S. стоит заметить, что и при вычитании такая же ситуация может произойти, так что одно другого не краше..
     
    Последнее редактирование: 30 май 2016
  3. Tomasina

    Tomasina Сушитель лампочек Модератор

    вот именно, что если числа беззнакового типа, то коду millis() - prevMillis) >= period абсолютно пофиг на переполнения, оно просто не изменит результат.
     
  4. joman

    joman Гик

    Хорошо, Какой результат будет при
    millis() = 10, prevMillis = 2^32 - 5, period = 3?
    P.S. Надо подумать варианты, а т.к. с вычитанием всё не так очевидно, как со сложением, вероятно там тоже есть проблема.
     
  5. Tomasina

    Tomasina Сушитель лампочек Модератор

    это ж очевидно, результат будет true, так как 10 - 4294967296 - 5 схлопнется до 4294967281, что однозначно больше чем 3.
    Если бы тип числа был еще более многоразрядным (т.е. нет переполнения в таком примере), то результат будет точно такой же.
     
  6. Tomasina

    Tomasina Сушитель лампочек Модератор

    ostrov, переделка твоего скетча из поста #9 (по-моему, так более изящно, т.к. не используем глобалы):
    Код (C++):
    unsigned long x = 1000;  // интервал между вспышками, мс
    unsigned long y =  300;  // длительность вспышки, мс

    void setup()
    {
      pinMode(LED_BUILTIN, OUTPUT);
    }

    void loop()
    {
      static unsigned long period = x;
      static unsigned long prevMillis = 0;
      if ( (millis() - prevMillis) >= period)
      {
        prevMillis = millis();
        digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
        period = period == x ? y : x; // чередуем интервал через сколько нужно сработать в следующий раз
      }
    }
    Код компактный и лаконичный, переполнения не волнуют.
    Ну разве я не няшка? :D
     
    Последнее редактирование: 30 май 2016
  7. joman

    joman Гик

    Да, согласен. С разностью лучше.
    Правда с глобальными переменными, я все равно не согласен. Ясно, что за ними нужно следить и аккуратнее использовать, но и возможности становятся шире. К примеру, как я уже сказал, изменение периода в другой части программы.
     
    ostrov нравится это.
  8. ZAZ-965

    ZAZ-965 Гуру

    Tomasina, а digitalRead(LED_BUILTIN) для пина настроенного на выход отработает корректно?
    Попытался найти ответ в исходном коде ардуиновских библиотек, макрос на макросе дефайном погоняет, запнулся на макросе g_APinDescription (что это и где определено?)
    Приятнее прострелить себе ногу, чем запутаться в лапше :)
     
    Последнее редактирование: 30 май 2016
  9. Tomasina

    Tomasina Сушитель лампочек Модератор

    LED_BUILTIN рекомендован к использованию разработчиками Arduino, думаю, они это предусмотрели.
     
  10. ZAZ-965

    ZAZ-965 Гуру

    Полистал datasheet, да операция корректна
    Reading the Pin Value
    Independent of the setting of data direction bit DDxn, the port pin can be read through the PINxn register bit.
    Код (C++):
    unsigned char i;
    ...
    /* Define pull-ups and set outputs high */
    /* Define directions for port pins */
    PORTB = (1<<PB7)|(1<<PB6)|(1<<PB1)|(1<<PB0);
    DDRB = (1<<DDB3)|(1<<DDB2)|(1<<DDB1)|(1<<DDB0);
    /* Insert nop for synchronization*/
    __no_operation();
    /* Read port pins */
    i = PINB
     
  11. ostrov

    ostrov Гуру

    Я хотел так, но период вкл-выкл не привязано ни к чему, может случиться что вкл будет 10 сек, а выкл 3. Поэтому лучше связать время периода с состоянием светодиода.

    И еще, я все же люблю глобальные переменные. Не все, конечно, но некоторые. С ними и без того непростая жизнь становится немного проще. )
     
  12. Tomasina

    Tomasina Сушитель лампочек Модератор

    Как такое возможно? При первом попадании в цикл четко сравнивается: period == x ? и четко всегда попадаем на y, далее просто чередуется автоматом.

    Наоборот, с локальными проще - не надо помнить как переменная называется и где ее искать в начале скетча, можно не заморачиваться с совпадением имен переменных в разных циклах - они не пересекаются, удобно переносить код в другие проекты - цап всю функцию и она за собой ничего не тянет.
    Впрочем, каждый любит вкус своих фломастеров ;)
     
  13. ostrov

    ostrov Гуру

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