Основы работы с nRF24l01
- Войдите на сайт для отправки комментариев
Добрый день, участники форума! Пытаюсь разобраться с радиомодулем nRF24l01. Запустил сканер. Запустил пример Getting Started. Пытаюсь понемногу менять уже работающий код, чтобы понять принципы работы. Хочу изменить скетч Getting Started так, чтобы передавать не число, а символ. Для этого изменил в передатчике код так, чтобы он всегда отсылал в ответ символ "W", а в приемнике изменил код так, чтобы он этот символ выводил:
unsigned long got_time; //Было char send_char = 0; //Стало
Все заработало, но обнаружился неожиданный эффект. Если при передаче числа в оригинальном скетче
выключить передатчик, то приемник соответствено отображает ответ "ноль" и показывает задержку ответа.
Now sending
Sent 6055876, Got response 6055876, Round-trip delay 1128 microseconds
Now sending
failed
Failed, response timed out.
Sent 7058768, Got response 0, Round-trip delay 268520 microseconds
А если передавать символ, то он вылезает в сериал в любом случае, даже после отключения передатчика. Вот, видно, что передатчик отключен, время ответа очень большое, но символ все равно вылезает.
Sent 8126712, Got response W, Round-trip delay 1080 microseconds
Now sending
failed
Failed, response timed out.
Sent 9129208, Got response W, Round-trip delay 268512 microseconds
Из-за чего это может быть? И как с этим бороться? На Амперке не ответили :(.
Очевидно какой-то переменной присваивается значение "W" и так и торчит в приемнике и не изменяется. Скорее всего после первого вывода на экран это значение сразу надо заменить на "", а уж после этого вновь считывать.
Что вы таким образом хотите выяснить? Скорее всего ситуация в выключением передатчика на ходу никак не обрабатывается в библиотеке и/или вышем коде. Соответственно, результат плохо предсказуем. Так можно дойти до экспериментов, навроде удара топором поперек ардуины, и тоже потом пытаться искать объяснения непонятному поведению программы.
Прошу прощения, конечно, надо было сразу приложить скетчи. Но к вечеру в голове образовалась каша. Выкладывю код приемника и передатчика. За основу взят пример Getting Started из библиотеки TMRh20. Обработки ситуации, когда приходит ноль в этом коде нет, но и вопрос то в том, что ноль не приходит.
Передатчик получает сигнал от приемника и отправляет ответ. Если этот ответ unsigned long, то все работает как надо. Передатчик отключен, передатчик выводит в сериал ноль. С char приемник выводит в сериал постоянное значение, хотя при его перезагрузке выводит снова ноль. Я так понимаю дело в каких-то буферах, где остется полученное значение, но я не могу понять где. И опять же, с unsigned long все работает как надо.
Передатчик
#include <SPI.h> #include "RF24.h" /* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */ RF24 radio(7, 8); /**********************************************************/ byte addresses[][6] = {"1Node", "2Node"}; void setup() { Serial.begin(115200); Serial.println(F("Transpoder")); radio.begin(); delay(2000); radio.enableDynamicPayloads(); radio.enableAckPayload(); radio.setDataRate(RF24_1MBPS); radio.setChannel(0); radio.setRetries(15, 15); radio.setAutoAck(true); radio.setCRCLength(RF24_CRC_16); radio.setPALevel(RF24_PA_MIN); radio.powerUp(); radio.openWritingPipe(addresses[1]); //Передача "1Node" radio.openReadingPipe(1, addresses[0]); //Прием "2Node" // Start the radio listening for data radio.startListening(); } // setup void loop() { /****************** Pong Back Role ***************************/ unsigned long got_time; // Было char send_char = 'W'; // Стало if ( radio.available()) { // Variable for the received timestamp while (radio.available()) { radio.read( &got_time, sizeof(got_time) ); } radio.stopListening(); // radio.write( &got_time, sizeof(got_time) ); // Было radio.write( &send_char, sizeof(send_char) ); // Стало radio.startListening(); Serial.print(F("Sent response ")); // Serial.println(got_time); // Было Serial.println(send_char); // Стало } } // LoopПриемник
#include <SPI.h> #include "RF24.h" /* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */ RF24 radio(7, 8); /**********************************************************/ byte addresses[][6] = {"1Node", "2Node"}; // Used to control whether this node is sending or receiving //bool role = 1; void setup() { Serial.begin(115200); // Serial.println(F("RF24/examples/GettingStarted")); // Serial.println(F("*** PRESS 'T' to begin transmitting to the other node")); // Serial.println(F("Reciver")); radio.begin(); delay(2000); radio.enableDynamicPayloads(); radio.enableAckPayload(); radio.setDataRate(RF24_1MBPS); radio.setChannel(0); radio.setRetries(15, 15); radio.setAutoAck(true); radio.setCRCLength(RF24_CRC_16); radio.setPALevel(RF24_PA_MIN); radio.powerUp(); radio.openWritingPipe(addresses[0]); radio.openReadingPipe(1, addresses[1]); // Start the radio listening for data radio.startListening(); } void loop() { /****************** Ping Out Role ***************************/ radio.stopListening(); Serial.println(F("Now sending")); unsigned long start_time = micros(); if (!radio.write( &start_time, sizeof(start_time) )) { Serial.println(F("failed")); } radio.startListening(); unsigned long started_waiting_at = micros(); boolean timeout = false; while ( ! radio.available() ) { if (micros() - started_waiting_at > 200000 ) { timeout = true; break; } } if ( timeout ) { Serial.println(F("Failed, response timed out.")); } unsigned long got_time; // Было char send_char; // Стало // radio.read( &got_time, sizeof(got_time) ); // Было radio.read( &send_char, sizeof(send_char) ); // Стало unsigned long end_time = micros(); // Spew it Serial.print(F("Sent ")); Serial.print(start_time); Serial.print(F(", Got response ")); // Serial.print(got_time); // Было Serial.print(send_char); // Стало Serial.print(F(", Round-trip delay ")); Serial.print(end_time - start_time); Serial.println(F(" microseconds")); // Try again 2s later delay(2000); } // LoopНу и сравнение с битьем топором я совершенно не понял. По моему вполне разумное желание понять, что происходит с приемником, если передатчик по какой-то причине выходит из строя.
Вы продолжаете упорствовать в бессмысленных действиях. Приемник у вас не сообщил о поступлении новых данных, из цикла ожидания вы вываливаетесь по таймауту, но при этом зачем-то лезете читать приемный буфер. Что вы там ожидаете обнаружить? Внеземное послание? Если не выполнялась команда FLUSH_RX (а у вас она не выполнялась), то в ответ на команду чтения приемного буфера, приемник будет всегда возвращать последние корректно принятые данные. Если компанда FLUSH_RX выполнялась, то возвращаемым значением будут нули.
Смысл в сравнимой пользе от такоего эксперимента. То есть полном отсутствии таковой.
В даташите на NRF24L01 подробно описано, как приемник производит декодирование эфирного сигнала. Уверяю, что своим могучим экспериментом вы ни на миллиметр не приблизились к пониманию логики работы приемника.
Если описать вкратце, то приемник работает так: слушает эфир на выбранном канале и при обнаружении данных на несущей чавтоте начинает побитово их запихивать в сдвиговый регистр входного буфера. После каждого бита приемник анализирует, находится ли в буфере корректный заголовок пакета, соответствует ли адрес получателя его собственному адресу, правильно ли указана длина принятых данных и совпадает ли контрольная сумма. Если хотя бы что-то в принятых данных не соответствует ожиданиями приемника (ваш случай с прерыванием передачи), то приемник не предпринимает никаких действий, а продолжает заниматься тем, чем и занимался -- слушать эфир, запихивать биты в регистр и анализировать принятое. Если приемник обнаруживает, что во входном буфере все данные корректны, он переносит их в приемный буфер, который доступен для чтения извне (в данном случае ардуиной) и сигнализирует в статусе, что принят пакет данных, попутно отправив подтверждение передатчику, если последний его запрашивал.
Используемая вами библиотека написана таким образом, что функция radio.available() запрашивает статус модуля и если там утстановлен бит наличия принятых данных, то она возвращает TRUE, иначе FALSE.
Внеся правку в исходный код примера, вы нарушили логику его работы. В примере чтение данных выполнялось так:
if ( timeout ){ // Describe the results Serial.println(F("Failed, response timed out.")); }else{ unsigned long got_time; // Grab the response, compare, and send to debugging spew radio.read( &got_time, sizeof(unsigned long) ); unsigned long end_time = micros(); // Spew it Serial.print(F("Sent ")); Serial.print(start_time); Serial.print(F(", Got response ")); Serial.print(got_time); Serial.print(F(", Round-trip delay ")); Serial.print(end_time-start_time); Serial.println(F(" microseconds")); }Т.е. чтение буфера приема осуществлялось только в случае, если выход из цикла ожидания происходил не по условию наступления таймаута. Вы вынесли весь блок else, который выполнялся только при условии успешного приема, в основной программный код и у вас чтение буфера производится всегда, вне зависимости от того, реально ли были приняты даннные или нет.
Ну и нечего тогда удивляться, что считываются старые данные, которые завалялись в буфере приема.
Логика программы была изменена специально, чтобы посмотреть, как реагирует приемник на, например такую ситуацию, когда передатчик доступен, но ничего не шлет. Про оставание в буфере последнего значения я знал, но я также и был абсолютно уверен, что функция очистки буфера FLUSH_RX вызывается внутри функций StartListening и StopListening. После Вашего ответа я в сотый раз открыл rf24.cpp, чтобы найти этот кусок и доказать Вам, что Вы неправы и проблема гораздо глубже и сложнее... и обнаружил, что FLUSH_RX закомменитрована. После того, как я ее раскомментил, все очищается как положено.
Большое спасибо за уделенное мне внимание. Надеюсь Вас это не сильно затруднило. Еще раз благодарю Вас за помощь,
У приемника нет никакой возможности судить о состоянии передатчика, если тот не передает данные. Передатчик включает радиотракт только на время передачи пакета и автоматически выключает его сразу же, как только передача данных завершилась и все три буфера передачи остаются пустыми. В паузах между передачами в эфир не выдается даже несущая. Работу передатчика можно сделать более продолжительной, если оперативно подбрасывать в буфера передачи свежие данные. Но даже так нельзя заставить работать передатчик постоянно. NRF24L01 имеет аппаратное ограничение времени одного сеанса передачи в 4 миллисекунды.