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

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

  1. Faig

    Faig Нерд

    Нет, ответ слишком большой, в ACK не помещается.
     
  2. Faig

    Faig Нерд

    Скажите пожалста, а я даташит нашел правильный? Если да, то может уважаемый автор в шапку его добавит ?
    https://www.digchip.com/datasheets/download_datasheet.php?id=1106247&part-number=nRF24L01
    Update. На сайте производителя этого чипа уже нет, но я нашел более новую версию даташита:
    https://eu.mouser.com/datasheet/2/297/nRF24L01_Product_Specification_v2_0-9199.pdf
     
    Последнее редактирование: 9 фев 2019
  3. Faig

    Faig Нерд

    Странно, в даташите говорят что все возможно:
     
  4. parovoZZ

    parovoZZ Гуру

    Нет. Искать надо на сайте производителя микросхем.
     
  5. parovoZZ

    parovoZZ Гуру

    Там можно поместить 3 по 32 байта. Но забираться будет только один за раз.
     
  6. Faig

    Faig Нерд

    Для не любителей библиотеки "RF24" вот ссылка на код умельца который выковырял все нужное и привел это в форме открытых и (надеюсь) понятных функций:
    https://forum.arduino.cc/index.php?topic=352534.0
    Есть минус в его коде, он не установил задержки при переключении, так что добавляйте их сами в соответствии с таблицей в даташите по ссылке в моеем предыдущем сообщении.
    parovoZZ Вы меня простите, но я не могу сдержаться и не пошутить:)) Вы мне напомнили одного классного авто-мастера. Рассказывал знакомый: Отличный мастер, толковый, но вот когда звонишь ему и говоришь: "мастер у меня проблема, колеса направо не поворачивают!" - а он в ответ "А ты не поворачивай на право и нет проблемы..." ))
     
    Последнее редактирование: 9 фев 2019
  7. parovoZZ

    parovoZZ Гуру

    Если честно, то сплошная ерунда. csnHi, csnLow - кто это будет запоминать? У меня гораздо лаконичнее - nRF_Select, nRF_Deselect. Просто когда в проекте очень много периферии, то что такое csnLow - да херего поймёшь.
     
  8. Faig

    Faig Нерд

    Согласен, но я думал это подойдет для ознакомления с прямыми командами модуля.
    Да, но я бы уже тогда прописал nRF_Csn_Hi, nRF_Csn_Low (или же nRF_Csn_Select, nRF_Csn_Deselect) чтобы былмаксимально "self explanatory".
    Кстати насчет вашего кода инициализации, спасибо вам огромное. Правда если бы в нем еще и коментарии были абсолютно на каждый шаг (для новичков), то ему бы цены не было! Вот например вы все в закидываете в массив buf, а потом отправляете его модулю. Это красиво и аккуратно, но новичку что китайский язык что этот код... одинаково не понятно, думаю.
     
    Последнее редактирование: 10 фев 2019
  9. parovoZZ

    parovoZZ Гуру

    csn лишнее.

    В даташите все регистры и команды перечислены в
    и
    Также я здесь выкладывал заголовочный файл. Также по-русски есть хорошая статья с примерами кода
    http://aterlux.ru/article/nrf24l01p
     
  10. Faig

    Faig Нерд

    parovoZZ Вам отдельное огромное спасибо!

    Вобщем работающий код с переключением режимов модулей с приемника на передатчик и обратно:
    Нашел причину проблемы с переключением режимов модуля, оказывается это из за delay()
    Код сварганил на скорую руку, сильно не бейте. Дополнительно, в коментах, осветил некототорые нюансы работы с радио-модулями.
    Описание: Передатчик посылает сообщение. Приемник принимает его, ждет 2 сек, переходит в режим передатчика отправляет ответное сообщение. Передатчик перешедший в режим приемника принимает сообщение и подтверждает прием автоответом. Приемник в свою очередь принимает автоответ. Все сообщения печатаются по серийному порту.
    Update: Поправил номер трубы на сендере.

    Код (C++):
    //Sender
    #include <RF24.h>
    #include <RF24_config.h>
    #include <SPI.h>
    #include "printf.h"
    const uint64_t pipe01_ = 0xE8E8F0F0A1LL; //Writing pipe must be full address if acknowledges will be used
    const uint64_t pipe02_ = 0xE8E8F0F0A2LL; //At least one of reading pipes must be full adress
    const uint64_t pipe03_ = 0xA3LL;
    const uint64_t pipe04_ = 0xA4LL;
    const uint64_t pipe05_ = 0xA5LL;
    const uint64_t pipe06_ = 0xA6LL;
    RF24 radio(9, 53);

    void setup()
    {
        Serial.begin(115200);
        delay(250);
        radio.begin();
        radio.setChannel(0x57); //not necessary. But must be equal at both sides
        radio.setPALevel(RF24_PA_LOW); //not necessary. But must be equal at both sides
        radio.enableAckPayload(); //For ability to change the Ack Payload with writeAckPayload()
        radio.openReadingPipe(1, pipe02_); //First pipe must be full address
        radio.openWritingPipe(pipe01_); //Writing pipe must be full address if acknowledges will be used
        radio.enableDynamicPayloads(); //If not set, size will be of fixed length. Default fixed length is 32 bytes

        /*Must run this if  "startListening()" will be used anywhere in the code below.
        nRF24L01 remembers it's state even if Arduino was restarted*/

        radio.stopListening();
        Serial.println("Sending the message...");
        char message[32] = "qwertyuiopasdfghjklzxc1234567890"; //some test message
        radio.write(message, 32); //Send message over the predefined "writing pipe"

        Serial.println("Waiting for response...");
        radio.startListening(); //Resets TX buffer and switches radio module's mode to "receiver"

        uint16_t ack = 123;
        radio.writeAckPayload(2, &ack, sizeof(ack)); //Custom ACK payload must be set after "startListening()". Because "startListening()"
    resets TX buffer
    }

    void loop()
    {
        if (radio.available())
        {
            char respMessage[33];
            memset(respMessage, 0, sizeof(byte) * 33);
            while (radio.available())
            {radio.read(respMessage, 32);}

            Serial.println("respMessage: " + String((const char*)respMessage));
        }
    }
    Код (C++):
    //Receiver
    #include <RF24.h>
    #include <RF24_config.h>
    #include <SPI.h>
    #include "printf.h"

    #define period_  2000

    // Set pipes
    const uint64_t pipe01_ = 0xE8E8F0F0A1LL; //At least one of reading pipes must be full adress
    const uint64_t pipe02_ = 0xE8E8F0F0A2LL; //Writing pipe must be full address if acknowledges will be used
    const uint64_t pipe03_ = 0xA3LL;
    const uint64_t pipe04_ = 0xA4LL;
    const uint64_t pipe05_ = 0xA5LL;
    const uint64_t pipe06_ = 0xA6LL;

    unsigned long checkPoint = 0;
    bool messageReceived = false;
    RF24 radio(9, 53);

    void setup()
    {
        Serial.begin(115200);
        delay(250);
        radio.begin();
        radio.setChannel(0x57); //not necessary. But must be equal at both sides
        radio.setPALevel(RF24_PA_LOW); //not necessary. But must be equal at both sides
        radio.enableAckPayload(); //For ability to change the Ack Payload with writeAckPayload()
        radio.openReadingPipe(1, pipe01_); //At least one of reading pipes must be full adress
        radio.openWritingPipe(pipe02_); //Writing pipe must be full address if acknowledges will be used
        radio.enableDynamicPayloads(); //Writing pipe must be full address if acknowledges will be used
        radio.startListening(); //If not set, size will be of fixed length. Default fixed length is 32 bytes
    }

    void loop()
    {
        if (radio.available())
        {
            char newMessage[33];
            memset(newMessage, 0, sizeof(byte) * 33);
            while (radio.available())
            {radio.read(newMessage, 32);}

            Serial.println("newMessage: " + String((const char*)newMessage));
            checkPoint = millis();
            messageReceived = true;
        }

        unsigned long timePassed = millis() - checkPoint;

        //When it receives, controller waits for 2 seconds then sends the response just one time
        if (messageReceived && timePassed > period_)
        {
            messageReceived = false;
            checkPoint = millis();
            Serial.println("sending response...");

            //This must be called before sending anything (except acknowledges)
            radio.stopListening(); //Resets TX buffer and switches radio module's mode to transmitter

            char response[32] = "1234567890qwertyuiopasdfghjklzxc";
            radio.write(response, 32);

            unsigned long ack = 0;
            if (radio.isAckPayloadAvailable())
            {
                radio.read(&ack, sizeof(ack));
                Serial.println("ack received: " + String(ack));
            }

            radio.startListening(); //Resets TX buffer and switches radio module's mode to "receiver"
        }
    }
     
    Последнее редактирование: 14 фев 2019 в 10:09
  11. Faig

    Faig Нерд

    Вот нашел еще интересные заметки про эти модули: http://forum.arduino.cc/index.php?topic=272143.0
    Пост номер #3
    Кратко:
    -Как я понял, если выполнить "writeAckPayload()" более трех раз не использовав их, то уже после четвертого раза модуль перестанет отправлять автоответы.
    -Регистр радио-модуля "FEATURE" не очищается при рестарте ардуины - это не правда, по крайней мере в обновленной версии RF24 очищается.
    -Но утверждение parovoZZ - а о том что надо инициализироовать абсолютно все параметры верно и верно не только для китайских но и для оригинальных модулей, так как вы можете изменить какой-то регистр где-нибудь в коде и он так и останется в том состоянии пока полностью не выключите питание радио-модуля (причем у некот-х на неск секунд).
     
    Последнее редактирование: 11 фев 2019
  12. Miller_VA

    Miller_VA Нерд

    Ну наконец-то Вы прислушались к paravoZZ, он же Вас плохому не научит, всё очень просто, книжки нужно читать, а потом уже библиотекарям верить.
     
  13. Faig

    Faig Нерд

    Зачем же мне тогда его благодарить если я не прислушивался? )
    А на счет доверия, знаете, иногда просто человеческая наивность берет верх, хочется иногда поверить что кто-то зделал все как надо.
     
  14. parovoZZ

    parovoZZ Гуру

    Надо регистр observe проверять, точнее флаги в нем.
     
  15. Faig

    Faig Нерд

    Дорогие форумчане, помогите пожалуйста в очередной раз :(
    Вчера лег спать с хорошим настроением и уверенностью что модули работают... Утром проснулся, а проблема с переключением режимов вернулась, причем ничего в коде не менял, просто выключил ночью и включил утром. Не работают и автоподтверждения. Думал контакты, припоял все напрямую к ардуино, питание вообще от повербанка (5 с лишним вольт, у меня базовый модуль для радио на 5в работает) протянул. Принимать принимает, а вот уже в обратном порядке глухо. Если поменять роли наоборот (изначально конечноже) то опять все работает в одну (теперь уже в противоположную сторону). Пробовал инициализировать как показано в рускоязычной статье, которой поделился provoZZ(спасибо ему), без изменений вообще, ни лучше ни хуже.
    Кто-то сталкивался с таким поведением модулей? Помогите пожалуйста, у меня проект висит в воздухе изза этой гадости, зря я понадеялся на эти радио модули...
     
  16. ImrDuke

    ImrDuke Гик

    Надо бы на код глянуть...
     
  17. parovoZZ

    parovoZZ Гуру

    Флаги в FIFO_STATUS какие?
    И обязательно значение регистра STATUS. Он первым вылезает из модуля при начале общения с ним. Наверняка флаг MAX_RT взведен, который не проверяешь и не сбрасываешь. Скорее всего, замута с синхронизацией - оба модуля или в стандбай ушли или оба слушают. И не раз слышал, что модули с алика иногда живут своей жизнью - хотят работают, хотят нет. У меня на балконе пролежал полтора года и под снегом, и под дождем, и на морозе - ни разу проблем не было.
     
    Последнее редактирование: 13 фев 2019 в 10:48
  18. Faig

    Faig Нерд

    Код приведен выше вот тут
     
  19. ImrDuke

    ImrDuke Гик

    Надо попробовать, если нет ответа через определенный промежуток времени, заново инициализировать модуль. Где то тут встречал такой способ.

    Вот нашел.
     
    Последнее редактирование: 13 фев 2019 в 11:11
  20. Faig

    Faig Нерд

    Код (C++):
    status after init: 10001
    status after writing ack payload: 1
    status before read: 0
    status after read: 1
    newMessage: qwertyuiopasdfghjklzxc1234567890
    sending response...
    status after stop listening: 10001
    status after write: 10001
    status after start listening: 10001
    В коде то же самое только другой регистр вывожу:
    Крайний правый бит пустой . На сколько я знаю он бывает "1" если переполнен буфер автоответа, тобишь три и более раза написать writeAckPayload().
    Код (C++):
    status after init: 1110
    status after writing ack payload: 1110
    status before read: 1000010
    status after read: 1110
    newMessage: qwertyuiopasdfghjklzxc1234567890
    sending response...
    status after stop listening: 1110
    status after write: 1110
    status after start listening: 1110
    Так у меня две разных пары проверены(одна с антенной другая пара без). И так и этак, и накрест ничего не меняется, все одно.

    Так они общаются без проблем, только вот как инициализируешь так и работают, поменять роли модулей (приемник, передатчик) не получается.
     
    Последнее редактирование: 13 фев 2019 в 12:00