nRF24L01+ : побеждаем модуль.

Тема в разделе "Проводная и беспроводная связь", создана пользователем ИгорьК, 19 июн 2014.

  1. ИгорьК

    ИгорьК Гуру

    Не помню. Приведите, пожалуйста, код ка Вы это делали для своего случая.
     
  2. tgwt

    tgwt Нерд

    Приблизительно так.

    Код для передатчика:

    Код (C++):
    /* В дефайнах */
    #include <SPI.h>
    #include "nRF24L01.h"
    #include "RF24.h"
    RF24 radio(9, 10);
    const uint64_t pipe = 0xE8E8F0F0E1LL;
    uint32_t message;  // Эта переменная для сбора обратного сообщения от приемника;
    int command = 555;// Не суть - приемнику надо что-то передать, но это может быть и полезная информация;
    void setup()
    {
      radio.begin();
      radio.enableAckPayload();
      radio.openWritingPipe(pipe);
    }
    void loop()
    {

      radio.write( &command, sizeof(command) );  //Отправляем команду;
      if ( radio.isAckPayloadAvailable() )
      {  // Ждем получения...
        radio.read(&message, sizeof(message)); //... и имеем переменную message с числом 111 от приемника.
        Serial.println(message);
      }
      command++;
    }
    Код для приемника:

    Код (C++):
    /* В дефайнах */
    #include <SPI.h>
    #include "nRF24L01.h"
    #include "RF24.h"
    RF24 radio(9, 10); // Определяем рабочие ножки;
    const uint64_t pipe = 0xE8E8F0F0E1LL; // Определяем адрес рабочей трубы;

    void setup()
    {
      radio.begin(); // Старт работы;
      radio.enableAckPayload();  // Разрешение отправки нетипового ответа передатчику;
      radio.openReadingPipe(1, pipe); // Открываем трубу и
      radio.startListening();  //начинаем слушать;
    }

    void loop()
    {
      uint32_t message = 111;  //Вот какой потенциальной длины сообщение - uint32_t!
      //туда можно затолкать значение температуры от датчика или еще что-то полезное.
      radio.writeAckPayload( 1, &message, sizeof(message) ); // Грузим сообщение для автоотправки;
      if ( radio.available() )
      { //Просто читаем и очищаем буфер - при подтверждении приема
        int dataIn;  //передатчику приемник протолкнет ему в обратку наше сообщение;
        bool done = false;
        while (!done)
        {
          done = radio.read( &dataIn, sizeof(dataIn)); // Значение dataIn в данном случае
          //не важно. Но его можно использовать и как управляющую команду.
          Serial.println(dataIn);
        }
      }
    }
     
  3. ИгорьК

    ИгорьК Гуру

    Зто не работает? Подумайте, в чем принципиальное отличие ранее приведенных кодов и этого.
     
  4. tgwt

    tgwt Нерд

    Я свой код переписывал под ваш пример. Сейчас напишу его и выложу.

    Еще делал как здесь описано: http://fartunamis.ru/?p=182
     
  5. tgwt

    tgwt Нерд

    Код для приемника:

    Код (C++):
    #include <SPI.h>
    #include <RF24.h>
    // Настройка пинов для CE, CSN
    const uint64_t pipe = 0xF0F1F2F3F4LL; // идентификатор передачи, "труба"
    const uint64_t pipe1 = 0xF0F1F2F3F5LL;
    bool done;
    RF24 radio(40, 53); // CE, CSN

    void setup() {
      Serial.begin(57600);
      pinMode(2, OUTPUT);
      radio.begin();
      delay(2);
      radio.setChannel(9); // канал (0-127)
      radio.enableAckPayload();
      radio.setDataRate(RF24_250KBPS);
      radio.setPALevel(RF24_PA_HIGH);
      radio.openReadingPipe(1, pipe); // открываем первую трубу с идентификатором "pipe"
      radio.startListening(); // включаем приемник, начинаем слушать трубу
    }

    // radio.stopListening(); // останавливает приём (нужно перед началом передачи)

    void loop()
    {
      uint32_t data;
      uint32_t message = 111;
      radio.writeAckPayload(1, &message, sizeof(message));
      if (radio.available()) // проверяем не пришло ли чего в буфер.
      {
        done = false;
        while (!done)
        {
          done = radio.read(&data, sizeof(data)); // читаем данные, указываем сколько байт читать
          Serial.print("data: ");
          Serial.println(data);
        }
        digitalWrite(2, HIGH);
      }
      else
      {
        digitalWrite(2, LOW);
      }
    }
     
    Код для передатчика:

    Код (C++):
    #include <SPI.h>
    #include <RF24.h>

    const uint64_t pipe = 0xF0F1F2F3F4LL; // идентификатор передачи, "труба"
    const uint64_t pipe1 = 0xF0F1F2F3F5LL;

    RF24 radio(40, 53); // CE, CSN
    bool done = false;
    uint32_t message;
    uint32_t data = 1;
    void setup()
    {
      Serial.begin(57600);

      radio.begin();
      delay(2);
      radio.setChannel(9); // канал (0-127)
      radio.enableAckPayload();
      radio.setDataRate(RF24_250KBPS);
      radio.setPALevel(RF24_PA_HIGH);
      radio.openWritingPipe(pipe); // открываем трубу на передачу.
    }

    void loop()
    {
      radio.write(&data, sizeof(data));
      if (radio.isAckPayloadAvailable())
      {
        radio.read(&message, sizeof(message));
        Serial.println(message);
      }
      if (message == 111)
      {
        data++;
      }
    }
     
    Вроде все верно.
     
  6. sergey-fedor

    sergey-fedor Нерд

    Вот пример одного из модулей, я так понимаю вполне рабочий он, если что то не так можете подсказать?
     

    Вложения:

  7. sergey-fedor

    sergey-fedor Нерд

    а вот скриншот со второго модуля , один в один только каналы чуть подзабиты потому как домочадцы все по ви фи сидят на гаджетах своих :)
    p/s закажу ка я еще штуки 4 чую что с этими чо то не так ...
     

    Вложения:

    • snapshot1.png
      snapshot1.png
      Размер файла:
      45,2 КБ
      Просмотров:
      767
    Последнее редактирование: 7 май 2016
  8. sergey-fedor

    sergey-fedor Нерд

    вставил строчки для проверки, оба модуля в норме но обмен не происходит
     

    Вложения:

  9. tgwt

    tgwt Нерд

    Код (C++):
    bool RF24::write( const void* buf, uint8_t len )
    {
      bool result = false;

      // Begin the write
      startWrite(buf,len);

      // ------------
      // At this point we could return from a non-blocking write, and then call
      // the rest after an interrupt

      // Instead, we are going to block here until we get TX_DS (transmission completed and ack'd)
      // or MAX_RT (maximum retries, transmission failed).  Also, we'll timeout in case the radio
      // is flaky and we get neither.

      // IN the end, the send should be blocking.  It comes back in 60ms worst case, or much faster
      // if I tighted up the retry logic.  (Default settings will be 1500us.
      // Monitor the send
      uint8_t observe_tx;
      uint8_t status;
      uint32_t sent_at = millis();
      const uint32_t timeout = 500; //ms to wait for timeout
      do
      {
        status = read_register(OBSERVE_TX,&observe_tx,1);
        IF_SERIAL_DEBUG(Serial.print(observe_tx,HEX));
      }
      while( ! ( status & ( _BV(TX_DS) | _BV(MAX_RT) ) ) && ( millis() - sent_at < timeout ) );

      // The part above is what you could recreate with your own interrupt handler,
      // and then call this when you got an interrupt
      // ------------

      // Call this when you get an interrupt
      // The status tells us three things
      // * The send was successful (TX_DS)
      // * The send failed, too many retries (MAX_RT)
      // * There is an ack packet waiting (RX_DR)
      bool tx_ok, tx_fail;
      whatHappened(tx_ok,tx_fail,ack_payload_available);
     
      //printf("%u%u%u\r\n",tx_ok,tx_fail,ack_payload_available);

      result = tx_ok;
      IF_SERIAL_DEBUG(Serial.print(result?"...OK.":"...Failed"));

      // Handle the ack packet
      if ( ack_payload_available )
      {
        ack_payload_length = getDynamicPayloadSize();
        IF_SERIAL_DEBUG(Serial.print("[AckPacket]/"));
        IF_SERIAL_DEBUG(Serial.println(ack_payload_length,DEC));
      }

      // Yay, we are done.

      // Power down
      powerDown();

      // Flush buffers (Is this a relic of past experimentation, and not needed anymore??)
      flush_tx();

      return result;
    }
    Покопался немного в библиотеке, в методе write есть строчки, содержащие (?)метод(?) IF_SERIAL_DEBUG. Может кто знает как заставить выводить на экран то, что в скобках без изменения библиотеки?
     
  10. AlexVS

    AlexVS Гик

    Очень просто: раскомментить строчку //#define SERIAL_DEBUG в rf24_config.h
     
  11. tgwt

    tgwt Нерд

    Она не закомменчена.
     
  12. AlexVS

    AlexVS Гик

    А Serial инициализирован?
     
  13. tgwt

    tgwt Нерд

    В скетче да.
     
  14. AlexVS

    AlexVS Гик

    Тогда добавьте в код #include "printf.h" и в setup() добавьте printf_begin();
     
  15. tgwt

    tgwt Нерд

    Я изменил все-таки немного библиотеку. Теперь он у меня выводит все, что мне нужно. И нашлась проблема. Данные передатчик отправляет, они доходят до приемника, приемник их выводит, но в консоли передатчика пишет все время "...Failed", поэтому я и не мог сделать writeAckPayload и т.д. Не подскажете, в чем может быть проблема в данной ситуации? А то в гугле все ссылки вплоть до 3 страницы фиолетовые(все обшарил) при разных запросах, и информацию найти не могу(да я и гуглить то особо и не умею).
     
  16. Syberon

    Syberon Нерд

    Прошу помощи.

    Есть два устройства - приемник и передатчик с NRF24L01+. На NRF по питанию напаяны конденсаторы 10uF, по рекомендации из первого поста. Передатчик раз в 8 секунд отправляет информацию. На приемнике подключен пин прерывания (d2) при получении пакета и назначен обработчик. И всё вроде как работает замечательно, но спустя какое-то время (не засекал точно сколько раз за это время успевает отработать модуль, но похоже это величина не постоянная) модуль на приемнике перестает генерировать прерывания и, соответственно, прием данных не идет. Само устройство-приемник при этом не зависает и функционирует без проблем, и даже реагирует на прерывание, если коснуться щупом мультиметра до пина прерывания. Сброс устройства позволяет снова отработать ему какое-то время.

    Приведу часть кода приемника:

    Код (C++):
    void setup(void) {
      attachInterrupt(0, receiveInterrupt, FALLING);
      ....
    }

    void receiveInterrupt()
    {
      bool tx, fail, rx;
      radio.whatHappened(tx, fail, rx);
      Serial.println("interrupt");
      if (rx) {
        dataReceived = true;
      }
    }
    Если использовать вариант проверки поступившего сообщения в цикле loop без использования прерывания, то всё работает без проблем, но хочется разобраться с проблемой.
    Код (C++):
    void loop(void) {
      if (radio.available())
        receiveData();
    ...
    }
    Подскажите куда копать хоть?:) Мож кто сталкивался.
     
  17. joman

    joman Гик

    Судя по картинке - оба рабочие.
    Один передаёт, второй - видит, что что-то передано.
    Где-то выше писали, что есть кривые приёмники с "перевернутым" битом подтверждения. Может быть у Вас как раз такие и по-этому они не видят подтверждения.
    Попробуйте отключить подтверждение приёма (модулем) и реализовать его самому в скетче.
     
    tgwt нравится это.
  18. tgwt

    tgwt Нерд

    Реализовать через принял->отправил или через enableAckPayload?
     
  19. joman

    joman Гик

    Небольшой уточняющий вопрос:
    Если присоединить (и не отсоединять) мультиметр к пину, все работает хорошо?
     
  20. joman

    joman Гик

    Через принял - отправил:
    передатчик: отправляем сообщение, пока не получили подтверждение (вероятно тут еще надо добавить количество попыток отправки).
    приёмник: принял сообщение - отправил подтверждение.