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

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

  1. Coolblaster

    Coolblaster Нерд

    Почитал про прерывания... Это же то что доктор прописал, как раз необходимая вещь для отправки команды внутри цикла, сегодня вечером попробую дописать код с прерыванием. Спасибо за мыслишку в верном направлении.
     
  2. Art

    Art Нуб

    Здравствуйте, уважаемые форумчане! прошу помочь в нелегкой борьбе с модулями nrf24l01+, ибо уже не знаю как к ним подступиться. Модули китайского происхождения. Один из модулей подключен к arduino nano, второй к leonardo. библиотеку использую RF24 из нее же пример pingpair. на обоих узлах наблюдается одна и та же картина см. вложение. Пробовал запитать от отдельного стабилизированного источника 3,3В - все аналогично. Единственное, что не пробовал, так это установить конденсатор на на ножки питания. Код привожу ниже
    /**
    * Example RF Radio Ping Pair
    *
    * This is an example of how to use the RF24 class. Write this sketch to two different nodes,
    * connect the role_pin to ground on one. The ping node sends the current time to the pong node,
    * which responds by sending the value back. The ping node can then see how long the whole cycle
    * took.
    */

    #include <SPI.h>
    #include "nRF24L01.h"
    #include "RF24.h"
    #include "printf.h"

    //
    // Hardware configuration
    //

    // Set up nRF24L01 radio on SPI bus plus pins 9 & 10

    RF24 radio(9,10);

    // sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver
    // Leave open to be the 'ping' transmitter
    const int role_pin = 7;

    //
    // Topology
    //

    // Radio pipe addresses for the 2 nodes to communicate.
    const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };

    //
    // Role management
    //
    // Set up role. This sketch uses the same software for all the nodes
    // in this system. Doing so greatly simplifies testing. The hardware itself specifies
    // which node it is.
    //
    // This is done through the role_pin
    //

    // The various roles supported by this sketch
    typedef enum { role_ping_out = 1, role_pong_back } role_e;

    // The debug-friendly names of those roles
    const char* role_friendly_name[] = { "invalid", "Ping out", "Pong back"};

    // The role of the current running sketch
    role_e role;

    void setup(void)
    {
    //
    // Role
    //

    // set up the role pin
    pinMode(role_pin, INPUT);
    digitalWrite(role_pin,HIGH);
    delay(20); // Just to get a solid reading on the role pin

    // read the address pin, establish our role
    if ( ! digitalRead(role_pin) )
    role = role_ping_out;
    else
    role = role_pong_back;

    //
    // Print preamble
    //

    Serial.begin(57600);
    printf_begin();
    printf("\n\rRF24/examples/pingpair/\n\r");
    printf("ROLE: %s\n\r",role_friendly_name[role]);

    //
    // Setup and configure rf radio
    //

    radio.begin();

    // optionally, increase the delay between retries & # of retries
    radio.setRetries(15,15);

    // optionally, reduce the payload size. seems to
    // improve reliability
    radio.setPayloadSize(8);

    //
    // Open pipes to other nodes for communication
    //

    // This simple sketch opens two pipes for these two nodes to communicate
    // back and forth.
    // Open 'our' pipe for writing
    // Open the 'other' pipe for reading, in position #1 (we can have up to 5 pipes open for reading)

    if ( role == role_ping_out )
    {
    radio.openWritingPipe(pipes[0]);
    radio.openReadingPipe(1,pipes[1]);
    }
    else
    {
    radio.openWritingPipe(pipes[1]);
    radio.openReadingPipe(1,pipes[0]);
    }

    //
    // Start listening
    //

    radio.startListening();

    //
    // Dump the configuration of the rf unit for debugging
    //

    radio.printDetails();
    }

    void loop(void)
    {
    //
    // Ping out role. Repeatedly send the current time
    //

    if (role == role_ping_out)
    {
    // First, stop listening so we can talk.
    radio.stopListening();

    // Take the time, and send it. This will block until complete
    unsigned long time = millis();
    printf("Now sending %lu...",time);
    bool ok = radio.write( &time, sizeof(unsigned long) );

    if (ok)
    printf("ok...");
    else
    printf("failed.\n\r");

    // Now, continue listening
    radio.startListening();

    // Wait here until we get a response, or timeout (250ms)
    unsigned long started_waiting_at = millis();
    bool timeout = false;
    while ( ! radio.available() && ! timeout )
    if (millis() - started_waiting_at > 200 )
    timeout = true;

    // Describe the results
    if ( timeout )
    {
    printf("Failed, response timed out.\n\r");
    }
    else
    {
    // Grab the response, compare, and send to debugging spew
    unsigned long got_time;
    radio.read( &got_time, sizeof(unsigned long) );

    // Spew it
    printf("Got response %lu, round-trip delay: %lu\n\r",got_time,millis()-got_time);
    }

    // Try again 1s later
    delay(1000);
    }

    //
    // Pong back role. Receive each packet, dump it out, and send it back
    //

    if ( role == role_pong_back )
    {
    // if there is data ready
    if ( radio.available() )
    {
    // Dump the payloads until we've gotten everything
    unsigned long got_time;
    bool done = false;
    while (!done)
    {
    // Fetch the payload, and see if this was the last one.
    done = radio.read( &got_time, sizeof(unsigned long) );

    // Spew it
    printf("Got payload %lu...",got_time);

    // Delay just a little bit to let the other unit
    // make the transition to receiver
    delay(20);
    }

    // First, stop listening so we can talk
    radio.stopListening();

    // Send the final one back.
    radio.write( &got_time, sizeof(unsigned long) );
    printf("Sent response.\n\r");

    // Now, resume listening so we catch the next packets.
    radio.startListening();
    }
    }
    }
    может кто-то сталкивался с подобной проблемой.
     

    Вложения:

    • ошибка.jpg
      ошибка.jpg
      Размер файла:
      96,3 КБ
      Просмотров:
      1.128
  3. Coolblaster

    Coolblaster Нерд

    А правильно ли подключены приемник и передатчик, там же роли ставить надо
    // sets the role of this unit in hardware. Connect to GND to be the 'pong' receiver
    // Leave open to be the 'ping' transmitter

    В библиотеке есть первый пример GettingStart по моему, в нем просто в сериале пишешь роль приемника или передатчика T или R, пробуйте этот пример, должно заработать сразу же, даже без конденсаторов.
     
  4. Art

    Art Нуб

    да 7 нога подключена к земле. с первым примером аналогичная проблема. Т.е. в режиме приема тишина, а при передаче failed
     
  5. Coolblaster

    Coolblaster Нерд

    Тогда модуль походу не правильно подключен к Леонардо
     
  6. Art

    Art Нуб

    леонардо выступает в качестве приемника. передатчик на нано. проверял подключения несколько раз
     
  7. Coolblaster

    Coolblaster Нерд

    Может дело в библиотеке, попробуйте скачать другую https://github.com/maniacbug/RF24 например эту
    У меня проблема такая тоже была, пытался подключить на двух нано, крутил вертел, менял библиотеки
    Вот с леонардо проект http://infar.be/index.php?/archives/1005-Elinchrom-EL-Skyport-triggered-by-an-Arduino.html там ссылки на библиотеки есть
     
  8. Coolblaster

    Coolblaster Нерд

    Эксперимент с прерыванием не удался. Переписал коды для приемника и передатчика, заработало как и хотел. Передатчик Мега + Ethernet shield + nRF24l01+, приемники несколько Нано + nRF24l01+ Конденсаторы не паял, по всей квартире получилось словить сигнал. Продолжаю изучать ардуинку.
     
  9. ИгорьК

    ИгорьК Гуру

    Так удался или не удался? Удался - выкладывайте код. Туча народа убивается об этот модуль :)
     
  10. ИгорьК

    ИгорьК Гуру

    to Art
    Уважаемый! Пожалуйста, оформите код как положено. Но если это код из примеров - зачем его сюда постить? Он и так 100% рабочий.
    У Вас или не правильное соединение, или проблема с питанием, или неисправные модули. Других вариантов просто не может быть.


    А если у Вас Леонардо - три раза проверьте по мануалу как там подключается модуль. Это не Уно - там надо задействовать ISP разъем обязательно.
     
  11. Coolblaster

    Coolblaster Нерд

    Первоначально хотел все сделать без всякого прерывания, не получалось, из за того что алгоритм в коде плохо понимал, как что с чем взаимодействует, вчера разобрался и переписал как надо опять таки без прерывания. В коде первоначального варианта было все завязано на 2 сериале Меги, возникла путаница, я от этого ушёл. Написал для каждого события отправку команды по nRF. Вечером выложу часть рабочего кода передатчика и часть от приемника.
     
  12. Coolblaster

    Coolblaster Нерд

    Как и обещал, вот приемник nano + nRF24l01+ :

    Код (Text):
    #include <SPI.h>
    #include "RF24.h"

    //Контакты от радиомодуля NRF24L01 подключаем к пинамнам -> Arduino (nano)
    //SCK -> 13
    //MISO -> 12
    //MOSI -> 11
    //CSN -> 10
    //CE -> 9

    RF24 radio(9, 10);

    //пины куда подключены светодиоды или другая слаботочка

    int led = 2;
    int led1 = 4;

    const uint64_t pipes[2] = {
    0xF0F0F0F000LL, 0xF0F0F0F0FFLL};// адреса каналов приема и передачи

    void setup(){
    Serial.begin(9600);

    radio.begin();
    delay(2);
    radio.setDataRate(RF24_250KBPS); // Скорость передачи
    radio.setChannel(100); // Номер канала от 0 до 127
    radio.setRetries(15,15); // Кол-во попыток и время между попытками
    radio.openWritingPipe(pipes[0]); // Открываем канал передачи
    radio.openReadingPipe(1, pipes[1]); // Открываем один из 6-ти каналов приема
    radio.startListening(); // Начинаем слушать эфир

    pinMode(led1, OUTPUT);
    pinMode(led, OUTPUT);

    }

    void loop(){

    int data;
    if(radio.available()){
    radio.read(&data, sizeof(data)); //принимаем пакет с Arduino Mega

    Serial.print(data);

    if (data == 11) digitalWrite(led, HIGH);
    if (data == 12) digitalWrite(led, LOW);

    radio.stopListening();
    radio.write(&data, sizeof(data)); // и отправляет обратно в Arduino Mega
    radio.startListening();

    }

    }
    Передатчик Mega + Ethernet shield + nRF24l01+ :

    Код (Text):
    #include <SPI.h>
    #include <Ethernet.h>
    #include <SD.h>
    #include "RF24.h"

    //Контакты от радиомодуля NRF24L01 подключаем к пинамнам -> Arduino (Mega)
    //SCK -> 52
    //MISO -> 50
    //MOSI -> 51
    //CSN -> 53
    //CE -> 9

    RF24 radio(9, 53);
    const uint64_t pipes[2] = {
    0xF0F0F0F000LL, 0xF0F0F0F0FFLL};// адреса каналов приема и передачи

    // размер буфера для захвата HTTP запросов
    #define REQ_BUF_SZ  60

    // MAC адрес
    byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
    IPAddress ip(192, 168, 1, 80); // IP адрес
    EthernetServer server(80);  // создаем сервер на 80 порту
    File webFile;              // файл веб страницы на карте SD
    char HTTP_req[REQ_BUF_SZ] = {0}; // буферный запрос HTTP хранится как строка
    char req_index = 0;              // индекс в буфере HTTP_req
    boolean LED_state[30] = {0}; // хранит состояние светодиодов

    void setup()
    {

        // отключение Ethernet чипа
        pinMode(10, OUTPUT);
        digitalWrite(10, HIGH);

        Serial.begin(9600);      // для дебага

        // инициализация SD карты
        Serial.println("Initializing SD card...");
        if (!SD.begin(4)) {
            Serial.println("ERROR - SD card initialization failed!");
            return;    // ошибка карты
        }
        Serial.println("SUCCESS - SD card initialized.");
        // проверка index.htm файла
        if (!SD.exists("index.htm")) {
            Serial.println("ERROR - Can't find index.htm file!");
            return;  // файл не найден
        }
        Serial.println("SUCCESS - Found index.htm file.");

        Ethernet.begin(mac, ip);  // инициализация Ethernet
        server.begin();          // начинаем слушать

        radio.begin();
        delay(2);
        radio.setDataRate(RF24_250KBPS); // Скорость передачи
        radio.setChannel(100); // Номер канала от 0 до 127
        radio.setRetries(15,15); // Кол-во попыток и время между попытками
        radio.openWritingPipe(pipes[1]); // Открываем канал передачи
        radio.openReadingPipe(1, pipes[0]); // Открываем один из 6-ти каналов приема
        radio.startListening(); // Начинаем слушать эфир

    }

    void loop()
    {
        EthernetClient client = server.available();  // попытка получить клиента

        if (client) {  // получил клиента?
            boolean currentLineIsBlank = true;
            while (client.connected()) {
                if (client.available()) {  // данные клиента доступны для чтения
                    char c = client.read(); // читаем 1 байт (символ) от клиента
                    // ограничим размер хранения полученного запроса на HTTP
                    // первая часть буффера HTTP запроса в HTTP_req массив (string)
                    // оставим последний элемент массива 0 до нуля и прекращаем строку (REQ_BUF_SZ - 1)
                    if (req_index < (REQ_BUF_SZ - 1)) {
                        HTTP_req[req_index] = c;          // сохраняем HTTP запрос
                        req_index++;
                    }
                    // последняя строка запроса клиента является пустой и заканчивается на \n
                    // ответить клиенту только после последней строки, полученной
                    if (c == '\n' && currentLineIsBlank) {
                        // отправить стандартный заголовок ответа HTTP
                        client.println("HTTP/1.1 200 OK");
                        // Остальная часть заголовка следует ниже, в зависимости от того
                        // веб-страница или XML-запрос
                        // Ajax запрос - отправляем XML файл
                        if (StrContains(HTTP_req, "ajax_inputs")) {
                            // отправить остальное из HTTP заголовка
                            client.println("Content-Type: text/xml");
                            client.println("Connection: keep-alive");
                            client.println();
                            SetLEDs();
                            // отправляем XML файл с вводными состояниями
                            XML_response(client);
                        }
                        else {  // запрос веб страницы
                            // отправить остальное из HTTP заголовка
                            client.println("Content-Type: text/html");
                            client.println("Connection: keep-alive");
                            client.println();
                            // отправка веб страницы
                            webFile = SD.open("index.htm");        // открываем файл с веб страницей
                            if (webFile) {
                                while(webFile.available()) {
                                    client.write(webFile.read()); // отправляем веб страницу клиенту
                                }
                                webFile.close();
                            }
                        }
                        // дисплей получил HTTP запрос на последовательный порт
                        // Serial.print(HTTP_req);
                        // сбросить буфер и все буферные элементы в 0
                        req_index = 0;
                        StrClear(HTTP_req, REQ_BUF_SZ);
                        break;
                    }
                    // каждая строка текста, полученной от клиента заканчивается на \ r \ n
                    if (c == '\n') {
                        // последний символ строки полученного текста
                        // начиная с новой строки с чтения следующего символа
                        currentLineIsBlank = true;
                    }
                    else if (c != '\r') {
                        // текстовый символ был получен от клиента
                        currentLineIsBlank = false;
                    }
                } // конец if (client.available())
            } // конец while (client.connected())
            delay(1);      // дать время веб-браузеру, чтобы получить данные
            client.stop(); // закрыть соединение
        } // конец if (client)
    }


    // проверка принятых запросов HTTP
    // также сохраняет состояние светодиодов
    void SetLEDs(void)
    {
        // LED 1
        if (StrContains(HTTP_req, "LED1=1")) {
            LED_state[0] = 1;  // сохранение состояния
      int data = 11;
      radio.stopListening();
      radio.write(&data, sizeof(data)); //и отправляем их в Arduino Nano
      radio.startListening();
        }
        else if (StrContains(HTTP_req, "LED1=0")) {
            LED_state[0] = 0;
      int data = 12;
      radio.stopListening();
      radio.write(&data, sizeof(data));
      radio.startListening();
        }
        // Далее идет много однотипного кода для отправки команд с веб интерфейса
        }


    //  обратная связь, для нескольких устройств
    void XML_response(EthernetClient cl)
    {

        cl.print("<?xml version = \"1.0\" ?>");
        cl.print("<inputs>");
        // LED1
        cl.print("<LED>");
        if (LED_state[0]) {
            cl.print("checked");
        }
        else {
            cl.print("unchecked");
        }
        cl.println("</LED>");
        // Так же тут много кода для каждой команды с вебки
        cl.print("</inputs>");
    }

    // устанавливает каждый элемент str в 0 (очищает массив)
    void StrClear(char *str, char length)
    {
        for (int i = 0; i < length; i++) {
            str[i] = 0;
        }
    }

    // Поиск строки sfind в строке str
    // Возвращает 1, если строка найдена
    // Возвращает 0, если строка не найдена
    char StrContains(char *str, char *sfind)
    {
        char found = 0;
        char index = 0;
        char len;

        len = strlen(str);

        if (strlen(sfind) > len) {
            return 0;
        }
        while (index < len) {
            if (str[index] == sfind[found]) {
                found++;
                if (strlen(sfind) == found) {
                    return 1;
                }
            }
            else {
                found = 0;
            }
            index++;
        }

        return 0;
    }
    Кое что было переведено с буржуйского через google так что сильно не пинайте :)

    Upd : да забыл сказать, модули без кондеров, пробивает через 2 железобетонные стены отлично, дальше не проверял.
     
    ИгорьК нравится это.
  13. ИгорьК

    ИгорьК Гуру

    Отличная работа!
     
  14. Coolblaster

    Coolblaster Нерд

    Спасибо с nRF разобрался, осталось дело за малым, подключить к модулям реле, встроить в включатели, и управлять освещением по всей квартире.
     
  15. Art

    Art Нуб

    Доброго времени суток! Спасибо Coolblaster за советы и отдельно ИгорюК за написание данной темы! Связь наладил, модули заработали - запитал оба модуля от отдельного стабилизированного источника питания.
     

    Вложения:

  16. Coolblaster

    Coolblaster Нерд

    Подключил 4 канальное реле на пины приемника, как оказалось ему явно не хватает питания. После включения четвертого реле, nRF начинает сбоить, принимает команду со второго раза. После подключения единичных модулей реле, штуки по три на одну нано, передача сигнала работает без глюков. Видимо правильно сделать отдельное питание, чтобы не было просадок. Подключил через такие штуки, приемник заработал без ошибок.
     
  17. Snoop1991

    Snoop1991 Нерд

    Можно ли паять простым паяльником этот модуль nRF24L01 и nrf24l01+pa+lna ? не убьет ли его статика, или еще какаянибудь муть ?
     
  18. AlexVS

    AlexVS Гик

    Паяются без прпоблем, сам перепаял с десяток.
     
  19. Cerner

    Cerner Нуб

    Добрый день.
    Спасибо ИгорюК за тему. На макетке всё в итоге более-менее работало.

    Возник вопрос при подключению внешнего питания, когда спаял всё (и уже много раз перепаял. Первый раз паяя на макетной печатной плате).
    Источник питания на 12 вольт. К нему подключены параллельно ардуина, лента светодиодная и модуль nRF через линейный стабилизатор на 3.3 V (lt1084 ct-3.3). Стабилизатор с конденсаторами, модуль с конденсатором. Стабилизатор в корпусе ТО-220 с пластиной радиатором.
    Стабилизатор греется больше 100 градусов.
    И вот тут я никак не пойму почему и, соответсвенно, как исправить.

    Вроде модуль должен потреблять не больше 20мА в самом активном режиме. Тогда рассеиваемая мощность (12-3.3)*0,02=0,174 Вт. И не должно так греться.

    С другой стороны сопротивление выключенного модуля меньше 20Ом (так и должно быть?). В таком случае можно предположить что ток будет 3.3/20> 0,165 А (и куда они деваются? Греют модуль?). Зато тогда рассеиваемая мощность на стабилизаторе около 1.5 Вт, что и даёт такую температуру(хотя, на мой взгляд, всё равно не должно). Предположу, что в этом случае мне поможет резистор Ом так на 200 последовательно между стабилизатором и модулем.
     

    Вложения:

    • схема.png
      схема.png
      Размер файла:
      62,8 КБ
      Просмотров:
      1.295
  20. AlexVS

    AlexVS Гик

    Дык кто мешает воспользоваться амперметром и замерить токи в режиме покоя и передачи?