Нужна маленькая помощь (NRF24L01)

Glacion
Offline
Зарегистрирован: 19.02.2017
       Есть скетч для пульта управления, не важно чего. Он рабочий, но есть недостаток. Пока кнопка зажата на передатчике , реле на приемнике работает. При отпускании кнопки выключается реле. Но если при зажатой кнопке на передатчике вдруг пропадает связь с приемником (например села батарейка или отошел на расстояние вне зоны радиомодуля), то реле остается включенным. 
       Что можно дописать, чтобы  при пропадании сигнала реле автоматически отключался... 
 
**СКЕТЧ передатчика:** 
 
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
 
RF24 radio(9, 10); // "создать" модуль на пинах 9 и 10 Для Уно
 
byte address[][6] = {"1Node", "2Node", "3Node", "4Node", "5Node", "6Node"}; //возможные номера труб
 
byte button = 2;  // кнопка на 2 цифровом
byte button1 = 3;
byte button2 = 4;
byte button3 = 5;
byte slider = 1; // движковый потенциометр на 1 аналоговом пине
 
byte transmit_data[5]; // массив, хранящий передаваемые данные
byte latest_data[5]; // массив, хранящий последние переданные данные
boolean flag; // флажок отправки данных
 
void setup() {
  Serial.begin(9600); //открываем порт для связи с ПК
 
  pinMode(button, INPUT_PULLUP); // настроить пин кнопки
  pinMode(button1, INPUT_PULLUP);
  pinMode(button2, INPUT_PULLUP);
  pinMode(button3, INPUT_PULLUP);
  radio.begin(); //активировать модуль
  radio.setAutoAck(1);         //режим подтверждения приёма, 1 вкл 0 выкл
  radio.setRetries(0, 15);    //(время между попыткой достучаться, число попыток)
  radio.enableAckPayload();    //разрешить отсылку данных в ответ на входящий сигнал
  radio.setPayloadSize(32);     //размер пакета, в байтах
 
  radio.openWritingPipe(address[0]);   //мы - труба 0, открываем канал для передачи данных
  radio.setChannel(0x60);  //выбираем канал (в котором нет шумов!)
 
  radio.setPALevel (RF24_PA_MAX); //уровень мощности передатчика. На выбор 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.stopListening();  //не слушаем радиоэфир, мы передатчик
}
 
void loop() {
 
  transmit_data[0] = !digitalRead(button); // инвертированный (!) сигнал с кнопки
  transmit_data[1] = !digitalRead(button1);
  transmit_data[3] = !digitalRead(button2);
  transmit_data[4] = !digitalRead(button3);
   transmit_data[2] = map(analogRead(slider), 0, 1023, 0, 255);
 
  for (int i = 0; i < 4; i++) { // в цикле от 0 до числа каналов
    if (transmit_data[i] != latest_data[i]) { // если есть изменения в transmit_data
      flag = 1; // поднять флаг отправки по радио
      latest_data[i] = transmit_data[i]; // запомнить последнее изменение
    }
  }
 
  if (flag == 1) {
    radio.powerUp(); // включить передатчик
    radio.write(&transmit_data, sizeof(transmit_data)); // отправить по радио
    flag = 0; //опустить флаг
    radio.powerDown(); // выключить передатчик
  }
 
}
 
 
**СКЕТЧ** приемника:100: 
 
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include <Servo.h>
 
RF24 radio(9, 10); // "создать" модуль на пинах 9 и 10 Для Уно
 
byte recieved_data[5]; // массив принятых данных
byte relay = 2; // реле на 2 цифровом
byte relay1 = 3;
byte relay2 = 4;
byte relay3 = 5;
byte mosfet = 1; 
 
Servo myservo;
 
byte address[][6] = {"1Node", "2Node", "3Node", "4Node", "5Node", "6Node"}; //возможные номера труб
 
void setup() {
  Serial.begin(9600); //открываем порт для связи с ПК
 
  pinMode(relay, OUTPUT); // настроить пин реле как выход
  pinMode(relay1, OUTPUT);
  pinMode(relay2, OUTPUT);
  pinMode(relay3, OUTPUT);
 
  radio.begin(); //активировать модуль
  radio.setAutoAck(1);         //режим подтверждения приёма, 1 вкл 0 выкл
  radio.setRetries(0, 15);    //(время между попыткой достучаться, число попыток)
  radio.enableAckPayload();    //разрешить отсылку данных в ответ на входящий сигнал
  radio.setPayloadSize(32);     //размер пакета, в байтах
 
  radio.openReadingPipe(1, address[0]);     //хотим слушать трубу 0
  radio.setChannel(0x60);  //выбираем канал (в котором нет шумов!)
 
  radio.setPALevel (RF24_PA_MAX); //уровень мощности передатчика. На выбор 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() {
  byte pipeNo;
  while ( radio.available(&pipeNo)) {  // слушаем эфир со всех труб
    radio.read( &recieved_data, sizeof(recieved_data) );         // читаем входящий сигнал
    digitalWrite(relay, recieved_data[0]); // подать на реле сигнал с 0 места массива
    digitalWrite(relay1, recieved_data[1]); 
    digitalWrite(relay2, recieved_data[3]);
    digitalWrite(relay3, recieved_data[4]);
    myservo.write(recieved_data[2]); // повернуть серво на угол 0..180
    // значение получено с 1 элемента массива
    analogWrite(mosfet, recieved_data[3]); // подать на мосфет ШИМ сигнал
    // в соответствии с принятыми данными со 2 места массива, диапазон 0...255
  }
}
Megawollt
Offline
Зарегистрирован: 06.12.2015

Там есть функция отлова пакетов и связи. Если до завтра никто не ответит, покопаю свои старые коды с радиомодулем

Voodoo Doll
Voodoo Doll аватар
Offline
Зарегистрирован: 18.09.2016

Простой принцип, делается метка времени (переменная типа unsigned long), в которую в момент приёма сигнала складывается время из millis(). Потом условие, если millis минус метка больше чем некий порог, то отключать.

byte rfdata; //payload=1
unsigned long lastcmd=millis();

void loop(){
  bool done=0;
  if(radio.available()){
    while(!done) done=radio.read(&rfdata,1);
    lastcmd=millis();
    // custom code here...
    if(rfdata==7) PORTD&=B10011111; //stop
  }
  if(millis()-lastcmd>=3000) PORTD&=B10011111; //auto stop if no radio data
}

По такой схеме делают обнаружение отсутствия связи в DMX приёмниках.

Glacion
Offline
Зарегистрирован: 19.02.2017

PORTD&=B10011111; это команда? И что означает?

Voodoo Doll
Voodoo Doll аватар
Offline
Зарегистрирован: 18.09.2016

Это моя команда, выключает D5, D6, на неё вообще смотреть не надо. Вместо этого куска ваш код который отключает. Всё же в комментариях написано.

А, ну да... англ. Ну сорян, привычка - у меня IDE русские буквы покзывает как попало.

Glacion
Offline
Зарегистрирован: 19.02.2017

Я вписал ваш код со своими изменениями, и случилось вот что: я зажал кнопку и реле отключился, связь не терялась, просто отключает реле спустя 3 секунды хотя кнопка зажата. Есть подозрение, что скетч при зажатой кнопке отправляет сигнал одинажды, и ваша команда думает, что связи больше нет с пультом. Так как наш скетч при зажатой кнопке отсылает сигнал не постоянно. Знаний не хватает переделать этот не достаток.

Glacion
Offline
Зарегистрирован: 19.02.2017

Если есть и у других тоже идеи поделитесь пожалуйста. И еще. Этот скетч я скачал из интернета и подстроил под себя. И если я удаляю мосфет, ползунки или сервоприводы то пульт уже не работает, можно ли как-то избавиться?

Voodoo Doll
Voodoo Doll аватар
Offline
Зарегистрирован: 18.09.2016

Glacion пишет:
Так как наш скетч при зажатой кнопке отсылает сигнал не постоянно.

Да, надо повторять.

unsigned long timestamp=millis();
//............
loop(){
  //............
  if(кнопка && millis()-timestamp>=2500){
    //............
    послать();
    timestamp=millis();
  }
}

 

Glacion
Offline
Зарегистрирован: 19.02.2017

Вот эта команда вообще царский подгон. Большое спасибо. 

а с первым еще бы чуток разъяснений

byte rfdata; //payload=1

unsigned long lastcmd=millis();
byte rfdata; //payload=1
unsigned long lastcmd=millis();
 
void loop(){
  bool done=0;
  if(radio.available()){
    while(!done) done=radio.read(&rfdata,1);
    lastcmd=millis();
    // custom code here...
    if(rfdata==7) PORTD&=B10011111; //stop
  }
  if(millis()-lastcmd>=3000) PORTD&=B10011111; //auto stop if no radio data
}

 

вот эта часть
if(rfdata==7) PORTD&=B10011111; //stop
 
и 
 
 if(millis()-lastcmd>=3000) PORTD&=B10011111; //auto stop if no radio data
 
я просто ставлю команды на отключение реле? в обеих местах? Заранее извиняюсь за свою докучность.
Voodoo Doll
Voodoo Doll аватар
Offline
Зарегистрирован: 18.09.2016

Glacion, да. rfdata это моё, вместо 7 ваше значение на откл если оно есть, и команда откл, а так же через время. Короче суть такая, что приёмник постоянно пытается выключиться, а передатчик ему мешает. Поэтому и получается что надо периодически повторять.

Kislotik
Offline
Зарегистрирован: 05.01.2018

Voodoo Doll пишет:

Glacion, да. rfdata это моё, вместо 7 ваше значение на откл если оно есть, и команда откл, а так же через время. Короче суть такая, что приёмник постоянно пытается выключиться, а передатчик ему мешает. Поэтому и получается что надо периодически повторять.

Не получается у мкня повторить, ничего не происходит какие только изменения не вносил, мне необходимо что бы на D6-D8 в случаее потери сигнала стал 0. Как я ваш код только не переделывал, ничего не получается, можете тыкнуть меня носом как  это должно работать? 

 

 

#include <SPI.h>
#include <nRF24L01.h> 
#include <RF24.h> //Скачиваем и устанавливаем библиотеку RF24 для радио модуля!!!!!!!!!
#include <Servo.h>
Servo myservo1;
Servo myservo2;
Servo myservo3;
Servo myservo4;
#define CE_PIN   9
#define CSN_PIN 10
const uint64_t pipe = 0xB1E8F0F0E1LL;
RF24 radio(CE_PIN, CSN_PIN); 
int joystick[9];
 
 
void setup()   
{
  delay(50);
  radio.begin();
  radio.setChannel(9);
  radio.setDataRate(RF24_250KBPS);        // Установка минимальной скорости;
  radio.setPALevel(RF24_PA_HIGH);          // Установка максимальной мощности;
  radio.openReadingPipe(1,pipe);
  radio.startListening();
  //myservo1.attach(A0); // Пин сервопривода мотор
  myservo2.attach(A0); // Пин сервопривода поворот
  myservo3.attach(A1); // Пин сервопривода сброс
  myservo4.attach(A2); // Пин сервопривода правый-левый
  
  pinMode(A3, OUTPUT); //Пин выхода на светодиод для подсветки от джойстика
  pinMode(A4, OUTPUT); //Пин выхода на светодиод для фонаря
  pinMode(A5, OUTPUT); //Пин выхода на светодиод от джойстика
  }
 
 
void loop()  
{
  if ( radio.available() )
  {
    bool done = false;
    while (!done)
    {
      done = radio.read( joystick, sizeof(joystick) );        
      myservo1.write(joystick[0]); // Сервопривод мотор
      myservo2.write(joystick[1]); // Сервопривод поворот
      digitalWrite(A3, !joystick[2]); //кнопка подсветка
      digitalWrite(A4, !joystick[4]); //кнопка фонарь
      digitalWrite(A5, !joystick[3]); //кнопка джойстика
           
           
if(!joystick[5]==HIGH)
  {
    myservo3.write(178); 
    }
      if(!joystick[6]==HIGH)
        {
          myservo3.write(2); 
            }
            
if(!joystick[7]==HIGH)
  {
    myservo4.write(110); 
      }
        if(!joystick[8]==HIGH)
          {
            myservo4.write(60); 
              }    
else 
  if(!joystick[7]==LOW)  
  if(!joystick[8]==LOW) 
  myservo4.write(85);
    }
  }
}