Любопытное столкновение между OneWire и RadioHead

Приведенный ниже код работает на Arduino Pro Mini (8 МГц, 328p), отправляя показания температуры с помощью недорогого передатчика ASK. Я использую OneWire для чтения DS18B20 и RadioHead для управления радио.

Первоначальная проблема заключалась в том, что вызовы send() в начале цикла всегда работали, а вызов send() в цикле считывания температуры никогда не работал.

Исправление заключалось в вставке вызова setModeTx() перед вызовом send(). Я рад, что это работает, но это пустая победа, потому что я не могу понять, почему это работает.

OneWire не использует таймеры и прерывания. Я жду преобразования температуры, используя _delay_ms(), который является задержкой вращения.

Я читал и перечитывал код OneWire и RH_ASK и все еще озадачен. Кто-нибудь может объяснить?

Большое спасибо

Вот суть кода…

RH_ASK radio(1024, 0, 10, 0, false);
OneWire ow(2);

void loop()
{
    radio.send(/* build info */);     // всегда работает
    radio.send(/* battery health */); // всегда работает
    ow.reset_search();
    while (ow.search(addr))
    {
        read_thermometer(addr);

        // следующий send() работает ТОЛЬКО
        // если ему предшествует setModeTx()
        // Он *никогда* не работает без него
        radio.setModeTx();
        radio.send(/* one temp reading */);
    } 
}

ОБНОВЛЕНИЕ

@timemage был прав в том, что есть также вкрапленные вызовы Serial (которые разрешаются в HardwareSerial). Я не приблизился к ее решению; однако, меняя порядок вызовов, я могу добиться более или менее частого сбоя.

В некотором смысле это подчеркивает различие между диагностикой и ремонтом. В конце концов я могу обнаружить такой порядок вызовов, который делает сбой чрезвычайно редким, и в этом случае проблема будет устранена; хотя и не диагностировано.

, 👍2

Обсуждение

Я бы ожидал, что RH_ASK radio(1024, 0, 10, 0, false)] будет мешать Serial, но у меня нет возможности это проверить. Но вы, похоже, не используете «Serial», но тогда вы указываете, что это не полный код. Но тогда... Я не знаю, почему .setModeTx()` может иметь такой эффект. В любом случае, мне не ясно, что «0» может означать «неиспользованный» и, возможно, что-то нужно исправить в любом случае., @timemage

@timemage ты что-то задумал. Раньше я отказывался от взаимодействия с Serial, который, как вы предполагаете, я использую. Все еще ищу…, @Eric Nelson

Я даже не уверен, что зайду так далеко. Я видел, как некоторые библиотеки используют -1 как индикатор «не используется» или «не применимо». Что я сделал, так это посмотрел библиотеку RadioHead, чтобы увидеть, как она это интерпретирует. Для всех, кто думает, что это «ответ», я чувствую необходимость разъяснить это: нет, это не так. Это наблюдение за чем-то, что, вероятно, должно быть исправлено в любом случае и может иметь или не иметь никакого отношения к реальной проблеме, как указано в вопросе. Я не собираюсь писать это как ответ, потому что нет особенно веских причин думать, что это ответ или даже ответ., @timemage

Если вы обнаружите, что это помогает и почему, вы можете написать свой собственный ответ, потому что вы на самом деле _знаете_, что это ответ и в идеале _почему._, @timemage

Я мог представить две вещи, которые могут произойти (или не произойти ;-)). Во-первых, где-то в вашем коде есть строка кода, которая настраивает драйвер ASk для RX. Во-вторых, первые два посыла заполняют буфер записи, а третий посыл не работает, потому что в буфере недостаточно места для добавления новых данных. setModeTx может очистить буфер или ему просто нужно некоторое время, необходимое драйверу ASK для отправки оставшихся данных. Разве нет метода waitPacketSent() для ожидания перед записью новых данных? Может стоит попробовать???, @Peter Paul Kiefer

Я думаю, @PeterPaulKiefer что-то задумал. setModeTx() очищает _txIndex, _txBit, _txSample. И у transmitTimer() есть проверка if (_txIndex >= _txBufLen). Я, конечно, плююсь. Но там стоит провести расследование., @Fahad

Что, если вы проделаете аналогичную трассировку еще раз, но на этот раз с вызовом setModeTx() перед фактической отправкой., @Bryan Sychingiok

Если я не ошибаюсь, Radiohead будет использовать манчестерскую кодировку. Это гарантирует, что переход всегда будет. 0 — от низкого к высокому, а 1 — от высокого к низкому. Неудачная серия единиц или нулей не создаст «плоскую» зону. Траектория вашего сигнала выглядит как правильный сигнал, закодированный в Манчестере. Извините, я не знаю причину вашей проблемы. Этот пакет длиннее двух других, которые обычно успешны? Иногда радиоприемники чувствительны к температуре. Попробуйте положить их в морозилку или рядом с духовкой и посмотреть, станут ли они лучше или хуже. Но это не объясняет, почему вызов setModeTx() может решить проблему., @Bryan Sychingiok


1 ответ


Лучший ответ:

1

Наконец-то появилось время вернуться к этому. Я подключил линию вывода данных от отправителя к линии ввода данных получателя и обнаружил, что она всегда работает. Так что это не какое-либо столкновение между OneWire и RadioHead, любопытство или что-то другое. Что-то не так с радиосвязью... но что?

Посмотрите на следующие осциллограммы. Линия пурпурного цвета — это вход передатчика. Голубой - это выходной сигнал приемника (SYN480R, если вам интересно). Желтый нужен только для того, чтобы активировать область действия (цифровая запись() непосредственно перед отправкой сообщения о проблеме).

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

Обратите внимание, как приемник (голубая линия) синхронизируется с тренировочными импульсами и синхронизируется с передатчиком... до тех пор, пока... ОН НЕ ПОТЕРЯЕТСЯ и какое-то время думает, что все равно нулю. В конце концов он повторно синхронизируется с передатчиком, но к этому моменту пакет поврежден, отклонен декодером, и поэтому я теряю пакет в приемнике.

Но, спрашивается, почему именно этот пакет, а не любой другой? Ответ на этот вопрос довольно необычен для форума по программному обеспечению, но вот. Давайте добавим трассировку в область отображения.

На следующем изображении порог демодулятора показан синим цветом. Это аналоговое значение, которое демодулятор использует, чтобы решить, смотрит ли он на единицу или на ноль. Для микросхемы SYN480R это выходные данные фильтра нижних частот, который производит усреднение по последним битам.

В этом случае обратите внимание, как пороговое значение повышается в начале пакета, а затем стабилизируется. Мое предположение состоит в том, что до сих пор в пакетном кодировании слишком много единиц (т. е. намного больше единиц, чем нулей), и это сдвигает порог достаточно высоко, чтобы демодулятор думал, что все, что он видит, является нулем. Это подтверждается на предыдущем изображении. Видя все нули, порог устанавливается, и демодулятор может снова синхронизироваться.

Интересно, что простое прикосновение зонда осциллографа к пороговому конденсатору (чтобы получить синюю кривую) нарушает порог в достаточной степени, чтобы замедлить нарастание и сохранить работу пакетов.

Таким образом, OneWire определенно не в курсе, как и любое взаимодействие с RadioHead. Двигаясь дальше, мне нужно либо внести некоторые изменения в кодировщик пакетов драйвера RadioHead RH_ASK, либо заменить пороговый конденсатор в приемнике. Это само по себе является балансом, потому что вы хотите, чтобы он мог отслеживать изменения в полученном сигнале, но не был так чувствителен к кодированию пакетов.

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

,