Arduino застрял в PT_WAIT_UNTIL
Я использую библиотеку Protothread от Адама Данкелса. Предполагается, что он подождет 1 секунду, а затем продолжит работу. Но вместо этого он застревает там, и все, что происходит после этой строки, не выполняется.
lastTimeBlink = millis();
PT_WAIT_UNTIL(pt, millis() - lastTimeBlink > 1000);
Почему он там застревает? Весь код загружается сюда: https://pastebin.com/jRsuvn54
(Комментарии на немецком языке)
@hypertext, 👍0
Обсуждение1 ответ
Лучший ответ:
Изо всех сил старайтесь дать что-то вроде ответа.
Вы сказали:
PT_WAIT_UNTIL(pt, millis() - lastTimeBlink> 1000);
Это не буквально представлено в вашем коде, поэтому я беру ваш вопрос для ссылки :
int dist2 = dist1.toInt();
...
PT_WAIT_UNTIL(pt, millis() - lastTimeBlink > (dist2 * 1710));
или аналогичный раздел.
Когда вы выполняете этот PT_WAIT_UNTIL
, dist2
содержит любое значение, которое вы инициализировали в int dist2 = dist1.toInt() ;
Предполагая, что условие не выполнено, вы выходите из runCommand()
с помощью PT_WAIT_UNTIL,
возвращающего PT_WAITING ;
#define PT_WAIT_UNTIL(pt, condition) \
do { \
LC_SET((pt)->lc); \
if(!(condition)) { \
return PT_WAITING; \
} \
} while(0)
LC_SET
здесь, в PT_WAIT_UNTIL
, используется для создания метки, к которой можно перейти позже:
#define LC_SET(s) \
do { \
LC_CONCAT(LC_LABEL, __LINE__): \
(s) = &&LC_CONCAT(LC_LABEL, __LINE__); \
} while(0)
Позже, когда вы позже вызываете runCommand для возобновления потока, вы выполняете LC_RESUME
через PT_BEGIN(pt);
#define PT_BEGIN(pt) { char PT_YIELD_FLAG = 1; LC_RESUME((pt)->lc)
...
#define LC_RESUME(s) \
do { \
if(s != NULL) { \
goto *s; \
} \
} while(0)
goto *s
здесь в конечном счете переходит к метке, созданной с помощью PT_WAIT_UNTIL
.
Теперь вы вернулись в PT_WAIT_UNTIL
, проверяя условие строкой if(!(condition))
. То есть вы проверяете millis() - lastTimeBlink> (dist2 * 1710)
Однако то, что вы, вероятно (подробнее об этом ниже) делаете здесь, - это чтение мусора из стека. dist2
был инициализирован при предыдущем выполнении runCommand
, и его эффективное время жизни закончилось, когда вы вернулись в PT_WAIT_UNTIL
при этом предыдущем выполнении. При этом новом выполнении dist2
неинициализируется, потому что вы перепрыгнули через его инициализацию. Если вы включите уровень предупреждения в файле / Настройках, вы должны увидеть что-то для этого.
В этот момент может произойти множество вещей, большинство из которых не очень хороши. Я не могу точно сказать, что оптимизатор компилятора сделает с этим кодом, но меня это не сильно удивило бы. Вполне вероятно, просто знакомясь с оптимизирующими компиляторами и тем, как выглядит ваш код, что он генерирует код для чтения dist2
. Это может звучать как данность, но это не так, когда вы делаете что-то неопределенное. Возможно,
dist2 имеет значение из предыдущего запуска, когда вы выполняете эту функцию в цикле. Но он также может иметь значение, которое заставляет dist2 * 1710
оценивать продолжительность почти до 50 дней, заставляет PT_WAIT_UNTIL
возвращаться из runCommand до тех пор, пока вы тестируете.
Как правило, если вы собираетесь использовать эти прото-потоки, вам придется быть очень осторожным, думая о том, что на самом деле инициализировано и что только выглядит. Если у вас есть PT_whatever
между инициализацией или назначением нестатической локальной переменной и кодом, в котором она используется, это нужно изучить.
Причина, по которой я поставил 1000 вместо (dist2* 1710) в вопросе, заключается просто в том, что это не работает в любом случае. Вычисление (dist2 * 1710) работает отлично. С этим нет никаких проблем., @hypertext
Но я думаю, что понял, в чем причина. По сути, функция запускается только один раз. Он не запускается при выполнении этого условия. Если функция будет находиться в цикле, то все будет работать, так как программа может перейти к метке и снова проверить, выполнено ли условие. Тогда это тоже могло бы продолжаться. Поток на самом деле не приостановлен, он остановлен, и есть метка, к которой нужно вернуться при повторном запуске. Поскольку функция больше не запускается, вы не можете вернуться к ярлыку., @hypertext
В любом случае спасибо, так как ваш ответ помог мне понять это., @hypertext
Я ценю, что это помогло, но если вы обнаружите, что проблема на самом деле заключается в чем-то другом, вы можете написать свой собственный ответ на вашу проблему и отметить * это * как принятое. Я думаю, что через два дня вы сможете сами отметить свои ответы как принятые. Вы можете проголосовать за то, чтобы этот вопрос был полезным, не объявляя его * ответом *., @timemage
- Как создать несколько запущенных потоков?
- Как подключить Wi-Fi Shield ESP-12E-ESP8266-UART-WIFI-Wireless-Shield к Arduino
- Глобальные переменные занимают много места в динамической памяти.
- Использовать timer0, не влияя на millis() и micros().
- Торговый автомат Arduino для мониторинга ввода монет в слот во время ожидания ввода пользователя
- Статус выхода 1 ожидаемое первичное выражение перед ']' Arduino
- Невозможно использовать библиотеку клавиатуры с Arduino UNO даже после смены прошивки.
- Ошибка: "'lcd' does not name a type" при использовании библиотеки LiquidCrystal.
На самом деле не так уж полезно включать только короткий фрагмент кода для решения подобной проблемы., @jwh20
Я добавил весь код целиком, @hypertext
Примеры библиотеки Protothread, похоже, используют для этого таймер., @Gerben