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

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

  1. Oleg_7

    Oleg_7 Гик

    Удалось подружить
    nRF24LE1 с nrf24L01+ ???...
     
  2. Удалось, верно, но есть вопросы по подтверждению, а так же дальности работы, вот выдержки из кода:
    Код передатчика, ATmega168(328) Arduino Pro Mini + nRF24L01+
    Код (C++):
    //Инициализация:
      radio.begin();                              // начало работы с NRF24l01
      radio.setDataRate(RF24_250KBPS);            // установка скорости
      radio.setChannel(100);                      // выбор канала
      radio.setRetries(0,15);                     // 15 попыток приёма/передачи с задержкой между ними в 250µs
      radio.setDataRate(RF24_250KBPS);            // скорость передачи
      radio.setChannel(CHANNEL);                  // номер канала от 0 до 125
      radio.setPALevel(RF24_PA_HIGH);             // мощность передатчика (RF24_PA_MIN=-18dBm, RF24_PA_LOW=-12dBm, RF24_PA_HIGH=-6dBm, RF24_PA_MAX=0dBm)
      radio.setAutoAck(false);                    // автоподтверждение выключено
      radio.setCRCLength(RF24_CRC_16);            // crc 16 бит
      radio.setPayloadSize(1);                    // размер данных 1 байт
      radio.openWritingPipe(pipes[1]);            // открываем канал передачи
      radio.openReadingPipe(1, pipes[0]);         // открываем один из 6-ти каналов приема

    //ну а так же сама передача и проверка ошибки, если таковая была:
    // передача нажатой кнопки приёмнику с проверкой
    bool sendCommand(void){
        unsigned char cheakCommand = 0;         // проверочная команда
        radio.flush_tx();                       // очистка буфера передачи
        radio.stopListening();                  // переходим на передачу данных
        radio.write(&command, sizeof(command)); // отправляем команду
        radio.startListening();                 // начинаем слушать эфир
        if(radio.available()){                  // проверяем не пришло ли чего в буфер
          radio.read(&cheakCommand, sizeof(cheakCommand));  // принимаем команду
        }
      if(command == cheakCommand) return true;  // передача завершилась удачей
      else return false;                        // иначе нет
    }
    Для приёмника писал всё в CodeBlocks+SDCC:
    Код (C++):
    //Инициализация:
        rf_configure_debug_lite(true, 1); /// инициализация приёмника в режиме приёма одного байта с выключенной проверкой
        setRetries(); /// установка количества попыток приёма-передач сигнала, и промежутка между ними
        setCRCLength(2);
        setChannel(CHANNEL); /// установка канала приёма-передачи сигнала
        setDataRate(DATA_RATE); /// установка скорости приёма-передачи сигнала
        setPALevel(PA_LEVEL); /// установка мощности приёма-передачи сигнала (PA_MAX)/

    ///Приём/передача ответа:
    /// получение команды и отправка её в ответ
    unsigned char getCommand(void){
        unsigned int counter; /// счётчик попыток чтения
        for(counter = 0; counter < 15000; counter++){ /// устраиваем цикл для приёма команды
            if(rf_irq_pin_active() && rf_irq_rx_dr_active()){ /// если есть что-то в канале для чтения, то читаем
                rf_read_rx_payload(&command, 1); /// чтение команды от передатчика
                break; /// выход из цикла
            }
        }
        rf_irq_clear_all(); /// сбрасываем все значения прерываний в rf
        rf_set_as_tx(); /// перевод rf в режим TX для передачи
        rf_write_tx_payload(&command, 1, true); /// передача команды передатчику
        while(!(rf_irq_pin_active() && rf_irq_tx_ds_active())); /// ожидаем, пока пакет будет отправлен или достигнуто максимальное число попыток передачи
        rf_irq_clear_all(); /// сбрасываем все значения прерываний в rf опять
        rf_set_as_rx(true); /// перевод rf в режим RX для чтения
        return command; /// возвращаем полученную команду
    }
    Вот и вопрос, как сделать обратную связь между Л0 и ЛЕ нормально, с помощью ACK?
    И ещё, если кто знает, как будить ЛЕ1 по прерыванию, к примеру, в эфире появилось что-то для неё, она просыпается из сна, делает своё дело, и засыпает?
    Заранее спасибо!
    P.S.
    Если есть и по дальности работы предположения - очень буду рад!
    А так же подтверждение получения команды....
     
    Последнее редактирование: 21 ноя 2018
  3. Добавлю к своему посту, там номер канала сами понимаете одинаков между приёмником и передатчиком.
    Индикаторы труб используются заводские, как помню 0xE7E7E7E7E7, что для приёма, что для передачи.
    Мощности разные, Л01 у меня с усилителем и антенной, и более чем HIGH уже она не работает, а вот приёмник (LE1), имеет лишь керамическую антенну, (тут мне важен размер и энергопотребление) вполне восприимчив и на MAX.
     
  4. Oleg_7

    Oleg_7 Гик

  5. Oleg_7

    Oleg_7 Гик

    У меня были проблемы с подтверждением между (Pro Mini + nRF24L01+) и (nano + nRF24L01+). Хотя везде были напаяны конденсаторы. Проблема была именно с (Pro Mini + nRF24L01+), и решилась только напайкой более мощного конд на 4,7 или 10 вроде + керамика 103, параллельно.
     
  6. Oleg_7

    Oleg_7 Гик

    Еще именно с вариантом (Pro Mini + nRF24L01+) были большие наводки, я провода экранировал на nRF24L01+ на тестовой сборке. На плате уже такого не было.
     
  7. ImrDuke

    ImrDuke Гик

    Подскажите пожалуйста, где я мог накосячить.
    Задача: по аппаратному прерыванию (геркон), нужно сразу же отправить сообщение что сработала тревога.
    Проблема в том, что идет отправка с опозданием на один пакет.
    Код (C++):

    #include <LowPower.h>
    #include <nRF24L01.h>
    #include <avr/wdt.h>
    #include <RF24.h>
    #include <SPI.h>
    #include <DHT.h>

    //--------------------- НАСТРОЙКИ -------------------------------
    byte WaitCount = 0;             // Количество циклов сна по 8 сек.
    #define DeviceID 5              // Номер устройства
    #define btnAlarm 2              // Вход датчика охраны (геркон)
    #define dhtPIN 5                // Вход датчика температуры
    #define CH_NUM 0x44             // Номер канала (должен совпадать с приёмником)
    #define SIG_POWER RF24_PA_LOW   // УРОВЕНЬ МОЩНОСТИ RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH, RF24_PA_MAX
    #define SIG_SPEED RF24_1MBPS    // СКОРОСТЬ ОБМЕНА RF24_2MBPS, RF24_1MBPS, RF24_250KBPS
    //--------------------- НАСТРОЙКИ -------------------------------

    DHT dht(dhtPIN, DHT21);    // Инициируем DHT21
    RF24 radio(9, 10);         // "Создать" модуль на пинах 9 и 10
    byte address[][6] = {"1Node", "2Node", "3Node", "4Node", "5Node", "6Node"}; //возможные номера труб

    void setup() {
      wdt_disable();
      byte pin;
      switch (btnAlarm) {
        case 2: pin = 0;
          break;
        case 3: pin = 1;
          break;
      }
      pinMode(btnAlarm, INPUT_PULLUP);     // пин D2/D3 подтянут к Vcc
      attachInterrupt(pin, Alarm, RISING); //Arduino Uno цифровые пины 2 (int 0) и 3 (int 1)
      dht.begin();
      radioSetup();
      wdt_enable (WDTO_8S);
    }

    void loop() {
      Transmit(digitalRead(btnAlarm));
      for (int i = 0; i <= WaitCount; i++) { // засыпает на WaitCount * 8c
        wdt_reset();
        LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_OFF);
      }
    }

    void Transmit(boolean _Flag) {
      noInterrupts();
      dht.begin();
      radio.powerUp();                                       //Включить передатчик
      uint32_t transmit_data[5];                             //Массив, хранящий передаваемые данные;
      transmit_data[0] = DeviceID;                           //Номер устройства
      transmit_data[1] = dht.readTemperature() * 100;        //Температура
      transmit_data[2] = dht.readHumidity() * 100;           //Влажность
      transmit_data[3] = (float)(1.1 * 16368) / Vbg() * 100; //Напряжение аккум.
      transmit_data[4] = _Flag;                              //Геркон
      radio.write(&transmit_data, sizeof(transmit_data));    //Отправить по радио
      radio.powerDown();                                     //Выключить передатчик
      interrupts();
    }

    void Alarm() {
      static unsigned long millis_prev;
      if (millis() - 1000 > millis_prev)
        Transmit(1);
      millis_prev = millis();
    }

    void radioSetup() {
      radio.begin();                     // активировать модуль
      radio.setAutoAck(1);               // режим подтверждения приёма, 1 вкл 0 выкл
      radio.setRetries(0, 15);           // (время между попыткой достучаться, число попыток)
      radio.enableAckPayload();          // разрешить отсылку данных в ответ на входящий сигнал
      radio.setPayloadSize(32);          // размер пакета, в байтах
      radio.openWritingPipe(address[0]); // мы - труба 0, открываем канал для передачи данных
      radio.setChannel(CH_NUM);          // выбираем канал (в котором нет шумов!)
      radio.setPALevel(SIG_POWER);       // УРОВЕНЬ МОЩНОСТИ RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH, RF24_PA_MAX
      radio.setDataRate(SIG_SPEED);      // СКОРОСТЬ ОБМЕНА RF24_2MBPS, RF24_1MBPS, RF24_250KBPS
      radio.powerUp();                   // начать работу
      radio.stopListening();             // не слушаем радиоэфир, мы передатчик
    }

    int Vbg() {
      ADMUX = (1 << REFS0) | (0 << REFS1) | (1 << MUX3) | (1 << MUX2) | (1 << MUX1) | (0 << MUX0);
      long buffersamp = 0;
      for (int n = 0x0; n <= 0xff; n++ ) {
        ADCSRA |= (1 << ADSC) | (1 << ADEN); //Starts a new conversion
        while (bit_is_set(ADCSRA, ADSC));
        buffersamp += ADC;
      }
      buffersamp >>= 4; //16368 full scale 14bit
      ADCSRA &= ~(1 << ADEN);  // отключаем АЦП
      return buffersamp;
    }
    [​IMG]
     
    Последнее редактирование: 1 дек 2018
  8. parovoZZ

    parovoZZ Гуру

    А точно отправка? Обычно трабла на приеме из-за неправильного обслуживания входного буфера.
     
  9. ImrDuke

    ImrDuke Гик

    Скрин порта это приемник.

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

    RF24 radio(D4, D8); // CE, CSN
    byte address[][6] = {"1Node", "2Node", "3Node", "4Node", "5Node", "6Node"};
    float Temp;            //Температура
    float Hum;             //Влажность
    float Vop;
    byte  Id;
    boolean Alarm;
    uint32_t recieved_data[5]; // массив принятых данных;

    void setup() {
      Serial.begin(9600);                  //открываем порт для связи с ПК
      Serial.println("--- START!!! ---");
      radio.begin();                       // активировать модуль
      radio.setAutoAck(1);                 // режим подтверждения приёма, 1 вкл 0 выкл
      radio.setRetries(0, 15);             // (время между попыткой достучаться, число попыток)
      radio.enableAckPayload();            // разрешить отсылку данных в ответ на входящий сигнал
      radio.setPayloadSize(32);            // размер пакета, в байтах
      radio.openReadingPipe(1, address[0]); //хотим слушать трубу 0
      radio.setChannel(0x44);              // выбираем канал (в котором нет шумов!)
      radio.setPALevel(RF24_PA_LOW);       // УРОВЕНЬ МОЩНОСТИ RF24_PA_MIN, RF24_PA_LOW, RF24_PA_HIGH, RF24_PA_MAX
      radio.setDataRate(RF24_1MBPS);     // СКОРОСТЬ ОБМЕНА RF24_2MBPS, RF24_1MBPS, RF24_250KBPS
      radio.powerUp();                     // начать работу
      radio.startListening();              //начинаем слушать эфир, мы приёмный модуль
    }

    void loop() {
      Id    = recieved_data[0];
      Temp  = (float)recieved_data[1] / 100;            //Температура
      Hum   = (float)recieved_data[2] / 100;             //Влажность
      Vop   = (float)recieved_data[3] / 100;
      Alarm = recieved_data[4];
      byte  pipeNo;
      while ( radio.available(&pipeNo)) {  // слушаем эфир со всех труб
        radio.read( &recieved_data, sizeof(recieved_data) );         // чиатем входящий сигнал
        Serial.print("Recieved: ");
        Serial.println("Id=" + String(Id) + " Temp=" + String(Temp) + " Hum=" + String(Hum) + " Vop=" + String(Vop) + " Alarm=" + String(Alarm));
      }
    }
     
  10. parovoZZ

    parovoZZ Гуру

    там есть буфер 3х32 байта. Каждая посылка занимает один буфер. Итого, если мы не успеваем с чтением принятых данных, то nRF может принять 3 посылки и после замрет ожидая действия. Чтобы очистить буфер, его необходимо прочитать. Читаем до тех пор, пока биты RX_P_NO в регистре статуса не будут равны 111. Очистить буфер можно командой FLUSH_RX. У передатчика тоже есть буфер. Его полное заполнение сигнализируется установленным флагом TX_FULL все в том же регистре STATUS и дальнейшая работа с nRF также невозможна - трансивер ожидает команды от управляющего МК. Чтобы не заморачиваться с этим регистром (подробностей не помню - надо читать дашик), следующие данные отправляем только после уведомления о том, что предыдущий пакет успешно убежал. Это флаг TX_DS. Очищается этот буфер командой FLUSH_TX.
     
  11. ImrDuke

    ImrDuke Гик

    Я сам накосячил жестко... :oops:
    Читаю переменные ДО того как их получил.
    Код (C++):
    void loop() {
      Id    = recieved_data[0];
      Temp  = (float)recieved_data[1] / 100;            //Температура
      Hum   = (float)recieved_data[2] / 100;             //Влажность
      Vop   = (float)recieved_data[3] / 100;
      Alarm = recieved_data[4];
      byte  pipeNo;
      while ( radio.available(&pipeNo)) {  // слушаем эфир со всех труб
        radio.read( &recieved_data, sizeof(recieved_data) );         // чиатем входящий сигнал
        Serial.print("Recieved: ");
        Serial.println("Id=" + String(Id) + " Temp=" + String(Temp) + " Hum=" + String(Hum) + " Vop=" + String(Vop) + " Alarm=" + String(Alarm));
      }
    }
    А правильно
    Код (C++):
    void loop() {
      byte  pipeNo;
      while ( radio.available(&pipeNo)) {  // слушаем эфир со всех труб
        radio.read( &recieved_data, sizeof(recieved_data) );         // чиатем входящий сигнал
        Id    = recieved_data[0];
        Temp  = (float)recieved_data[1] / 100;            //Температура
        Hum   = (float)recieved_data[2] / 100;             //Влажность
        Vop   = (float)recieved_data[3] / 100;
        Alarm = recieved_data[4];
        Serial.print("Recieved: ");
        Serial.println("Id=" + String(Id) + " Temp=" + String(Temp) + " Hum=" + String(Hum) + " Vop=" + String(Vop) + " Alarm=" + String(Alarm));
      }
    }
     
  12. Ivanii

    Ivanii Нуб

    Кто нибудь победил ПЕРЕДАТЧИК NRF24L01+PA+LNA?
    Долго возился и понял, что она сама себя глушит передаваемым сигналом - контакт по оплетке и центральной жиле хороший, при установке большой металлической пластины на SMA или при охвате рукой корпуса разъема двухсторонняя связь 100%, а если прикоснуться к центральной жиле антенны то 0%, прием всегда 100%.
    Пробовал на уже 10 трансиверах из 4х партий разных месяцев, ведут себя чуть по разному но зависимость от прикосновений одинаковая.
    Такое ощущение что не согласована антенна и до входа усилителя доходит отраженный сигнал.
    Тему просмотрел мельком но про свою проблему ничего не нашел.
     
  13. parovoZZ

    parovoZZ Гуру

    У меня работает. Усилитель будет принимать - вход и выход объединены.
    Сама себя глушить передаваемым сигналом она не может - она или передает, или принимает. Прием или передачу задает программист - сама она может только уйти в сон в ожидании действий пользователя.
     
  14. Ivanii

    Ivanii Нуб

    С антенной на самом модуле и без потерь?
    Если объединить вход и выход усилителя то получится генератор.
    RFX2401C который добавляет PA+LNA содержит 2 переключаемых усилителя, усилитель передачи имеет усиление по напряжению 17 раз по мощности 300 раз, он подключается входом к nRF24L01 и выходом к антенне, если не правильно сконструирована плата или антенна то выходной сигнал усилителя может наводиться с выходного фильтра или антенны на точку соединения nRF24L01 и RFX2401C что похоже и происходит.

    Платы очень похожи но при ближайшем рассмотрении 3х типов, а поведение похожее, возможно я упустил какой-то параметр необходимый усилителю?
    nrf.jpg

    "бусина" на провода от ардуинки к nRF не помогает, антенна от Wi-Fi не помогает, также ошибки при передаче и реагирует на плотное прикосновение к земле модуля и антенны...
     
    Последнее редактирование: 8 дек 2018
  15. parovoZZ

    parovoZZ Гуру

    Образование какое? Не рановато ли анализировать АФО?
    у меня нет оборудования для измерения потерь. Априори известно, что на китайских модулях с алика всё очень плохо.
     
  16. Ivanii

    Ivanii Нуб

    Потерь пакетов, у меня тоже нет оборудования на 2,4 ГГц.
    Ну у кого-то они(NRF24L01+PA+LNA) китайские работают?
     
  17. ImrDuke

    ImrDuke Гик

     
  18. parovoZZ

    parovoZZ Гуру

    У меня работает. У меня два варианта - с экраном и без. Оба передают, оба принимают. Тут надо искать причину в другом - во внешних условиях и в программе.
     
  19. Ivanii

    Ivanii Нуб

    Скетчи тестовые GettingStarted от RF24.h.
    Без усилителя и внешней антенны вроде работают нормально а вот с усилителем колбасит все.
    Методом перестановок выяснил, что глючит модуль ответчик(R) и только если с усилителем...

    Пошел либы и тесты из под видео смотреть.
     
    Последнее редактирование: 8 дек 2018