Зависает arduino nano

MocArt
Offline
Зарегистрирован: 15.12.2014

Доброго времени суток!

используя nrf24l01 отправляю запросы о состоянии "ножки" на МК arduino nano, каждые 3 секунды. примерно после 20 минут, 2-ой МК зависает и престает отвечать на запросы, думал с переполнение serial, отключил, но все равно зависает, подскажите пожалуйста, в чем может быть дело:

/*

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 version 2 as published by the Free Software Foundation.
 */
 /*
  Hack.lenotta.com
  Modified code of Getting Started RF24 Library
  It will switch a relay on if receive a message with text 1, 
  turn it off otherwise.
  Edo
 */

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

int relay1 = 8;
int relay2 = 7;

//
// Hardware conf
//

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

RF24 radio(9,10);

//
// Topology
//

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


char * convertNumberIntoArray(unsigned short number, unsigned short length) {
    
    char * arr = (char *) malloc(length * sizeof(char)), * curr = arr;
    do {
        *curr++ = number % 10;
      number /= 10;
    } while (number != 0);
    return arr;
}

unsigned short getId(char * rawMessage, unsigned short length){
    unsigned short i = 0;
    unsigned short id = 0;
    for( i=1; i< length; i++){
        id += rawMessage[i]*pow( 10, i-1 );
    }
    return id;
}

unsigned short getMessage( char * rawMessage){
    unsigned short message = rawMessage[0];
    return (unsigned short)message;
}
unsigned short getLength( unsigned int rudeMessage){
    unsigned short length = (unsigned short)(log10((float)rudeMessage)) + 1;
    return length;
}

void setup(void)
{
  //
  // Print preamble
  //

  //Serial.begin(57600);
  pinMode(relay1, OUTPUT);
  digitalWrite(relay1, HIGH);
  pinMode(relay2, OUTPUT);
  digitalWrite(relay2, HIGH);
  //printf_begin();
  //printf("\nRemote Switch Arduino\n\r");

  //
  // Setup and configure rf radio
  //

  radio.begin();
//  radio.setAutoAck(1);                    // Ensure autoACK is enabled
  radio.setRetries(15,15);
  radio.setDataRate(RF24_2MBPS);

  radio.openWritingPipe(pipes[1]);
  radio.openReadingPipe(1,pipes[0]);
  radio.startListening();
  //radio.printDetails();
}

int getState(unsigned short pin){
  boolean state = digitalRead(pin);
  return state == true ? 0 : 1;
}

void doAction(unsigned short id, unsigned short action){

    
    if( action == 0 ){
        digitalWrite(id, HIGH);
    }else{
        digitalWrite(id, LOW);
    }
  


}
void sendCallback(unsigned short callback){
   // First, stop listening so we can talk
      radio.stopListening();

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

      // Now, resume listening so we catch the next packets.
      radio.startListening();
}

void performAction(unsigned short rawMessage){
  unsigned short action, id, length, callback;
  char * castedMessage;
  
  length = getLength(rawMessage);
  castedMessage = convertNumberIntoArray(rawMessage, length);
  action = getMessage(castedMessage);
  id = getId(castedMessage, length);

  if (action == 0 || action ==1){
      callback = action;
      doAction(id, action);
  }else if(action == 2){
      callback = getState(id);
  }
  sendCallback(callback);


 
}
void loop(void)
{

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

        // Spew it
        //printf("Got message %d...",rawMessage); 

        performAction(rawMessage);

        //delay(2);
        Serial.flush();
      }

     
    }

}

 

std
Offline
Зарегистрирован: 05.01.2012

1. Кросспост это нехорошо.

2. Может поможет, если перевести на библиотеку MIRF.

Из любопытства: а что оно посылает назад? И как в посылке обозначены включения релюх? Другими словами - протокол в студию.

IMNSHO, стримы, трубы, callback какой-то... По-мне, этот скетч слишком прост, чтобы устраивать себе такой ад.

MocArt
Offline
Зарегистрирован: 15.12.2014

с первого  МК отправляется "2", запрашивая состояние пина, второй МК в свою очередь посылает исключительно либо "0" либо "1" этим и обозначены включения релюх, если 0 значит выключено, если 1 включено соответственно

std
Offline
Зарегистрирован: 05.01.2012

Оба? Всмысле 00 обе выкл, 10 первая вкл вторая выкл, или тупо 0 1?

И что вызывает doAction? Первый МК может прислать команду, типа включи вторую релюху, или он только посылает цифру 2, спрашивая состояние?

MocArt
Offline
Зарегистрирован: 15.12.2014

С первого МК можно включить и выключить оба канала релюхи и запросить состояния обоих (по отдельности):

команда remote -m 71 включает на втором МК канал реле №1 (пин 7)

команда remote -m 81 включает на втором МК канал реле №1 (пин 8)

команда remote -m 72 получает со второго МК состояние канала реле №1 (1 - если включен, 0 - если выключен)

команда remote -m 82 получает со второго МК состояние канала реле №2 (1 - если включен, 0 - если выключен)

Далее код с первого МК:

#include <string>
#include <getopt.h>
#include <cstdlib>
#include <sstream>
#include <iostream>
#include <RF24/RF24.h>

using namespace std;
//RF24 radio("/dev/spidev0.0",8000000 , 25);
//RF24 radio(RPI_V2_GPIO_P1_15, RPI_V2_GPIO_P1_24, BCM2835_SPI_SPEED_8MHZ);

RF24 radio(RPI_V2_GPIO_P1_22, RPI_V2_GPIO_P1_24, BCM2835_SPI_SPEED_8MHZ);
//const int role_pin = 7;
const uint64_t pipes[2] = { 0xF0F0F0F0E1LL, 0xF0F0F0F0D2LL };
//const uint8_t pipes[][6] = {"1Node","2Node"};

// hack to avoid SEG FAULT, issue #46 on RF24 github https://github.com/TMRh20/R                                                                                        F24.git
unsigned long  got_message;

void setup(void){
        //Prepare the radio module
//      printf("\nPreparing interface\n");
        radio.begin();
        radio.setRetries( 15, 15);
        radio.setDataRate(RF24_2MBPS);
        //      radio.setChannel(0x4c);
        radio.setPALevel(RF24_PA_MAX);


        //radio.printDetails();
        radio.openWritingPipe(pipes[0]);
        radio.openReadingPipe(1,pipes[1]);
        //      radio.startListening();

}

bool sendMessage(int action){
        //This function send a message, the 'action', to the arduino and wait fo                                                                                        r answer
        //Returns true if ACK package is received
        //Stop listening
        radio.stopListening();
        unsigned long message = action;
        //printf("Now sending  %lu...", message);

        //Send the message
        bool ok = radio.write( &message, sizeof(unsigned long) );
        if (!ok){
                printf("failed...\n\r");
        }else{
                printf("");
        }
        //Listen for ACK
        radio.startListening();
        //Let's take the time while we listen
        unsigned long started_waiting_at = millis();
        bool timeout = false;
        while ( ! radio.available() && ! timeout ) {
                //printf("%d", !radio.available());
                if (millis() - started_waiting_at > 1000 ){
                        timeout = true;
                }
        }

        if( timeout ){
                //If we waited too long the transmission failed
                printf("0");
                return false;
        }else{
                //If we received the message in time, let's read it and print it
                radio.read( &got_message, sizeof(unsigned long) );
                printf("%lu",got_message);
                return true;
        }

}

int main( int argc, char ** argv){

        char choice;
        setup();
        bool switched = false;
        int counter = 0;

        //Define the options

        while(( choice = getopt( argc, argv, "m:")) != -1){

                if (choice == 'm'){


//                      printf("\n Talking with my NRF24l01+ friends out there..                                                                                        ..\n");

                        while(switched == false && counter < 1){

                                switched = sendMessage(atoi(optarg));

                                counter ++;

                                sleep(1);
                        }


                }else{
                        // A little help:
                        printf("\n\rIt's time to make some choices...\n");
                        printf("\n\rTIP: Use -m idAction for the message to send                                                                                        . ");


                        printf("\n\rExample (id number 12, action number 1): ");
                        printf("\nsudo ./remote -m 121\n");
                }

                //return 0 if everything went good, 2 otherwise
                if (counter < 5)
                        return 0;
                else
                        return 2;
        }
}

 

std
Offline
Зарегистрирован: 05.01.2012

Предлагаю так:

Передатчик (тот кто спрашивает и включает/выключает):

#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>

byte data[2];      // посылка

void setup(){
  Mirf.spi=&MirfHardwareSpi;
  Mirf.cePin=9;
  Mirf.csnPin=10;
  Mirf.init();
  Mirf.setRADDR((byte *)"clien");  // принимаем на адрес "clien" т. к. мы клиент
  Mirf.setTADDR((byte *)"servr");
  Mirf.payload=2;
  Mirf.channel=1;
  Mirf.config();
}

void setstate(boolean relay1, boolean relay2){
  data[0]=relay1;
  data[1]=relay2;
  Mirf.send(data);
  while(Mirf.isSending()){}
  delay(10);
} 

void ackstate(){
  data[0]=2;                   // первый байт - двойка, второй пох
  Mirf.send(data);
  while(Mirf.isSending()){}
  delay(10);
} 

void loop(){
  if(!Mirf.isSending() && Mirf.dataReady()){
    Mirf.getData(data);
    // data[0] - состояние relay1
    // data[1] - состояние relay2
  }

  // ackstate(); - послать запрос на состояние
  // setstate(0,1); - установить состояние

} 

Приёмник:

#include <SPI.h>
#include <Mirf.h>
#include <nRF24L01.h>
#include <MirfHardwareSpiDriver.h>

int relay1=8;
int relay2=7;
byte data[2];      // посылка

void setup(){
  Mirf.spi=&MirfHardwareSpi;
  Mirf.cePin=9;
  Mirf.csnPin=10;
  Mirf.init();
  Mirf.setRADDR((byte *)"servr");  // принимаем на адрес "servr" т. к. мы - сервер
  Mirf.setTADDR((byte *)"clien");
  Mirf.payload=2;                  // размер посылки, 2 байта
  Mirf.channel=1;
  Mirf.config();
}

void loop(){
  if(!Mirf.isSending() && Mirf.dataReady()){
    Mirf.getData(data);
    if(data[0]==2){                // есть двойка, посылаем состояние
      data[0]=digitalRead(relay1);
      data[2]=digitalRead(relay2);
      Mirf.send(data);             // отправка
      while(Mirf.isSending()){}    // ничё не делаем, пока отправляется
      delay(10);                   // на всякий пожарный
    }else{                         // не двойка
      if(data[0]<2)                // защита от дурака, вдруг отправят 3 или больше
        digitalWrite(relay1,data[0]);   // делаем что надо, ноль выключит, единица включит
      if(data[1]<2)                // то же самое для второй
        digitalWrite(relay2,data[1]);
    }
  }
}

Останется только прикрутить работу с командной строкой, т. к. я в этом не соображаю.

Библиотека

Чтобы трансивер передавал на максимальной мощности, с максимальной чувствительностью на 250 кбит/с, надо сделать Mirf.configRegister(0x06, 0b00100110); после Mirf.config();

MocArt
Offline
Зарегистрирован: 15.12.2014

Скажите, а это библиотека разве будет работать на Raspberry Pi, потомучто первый МК это это он, а второй МК Arduino Nano а общаются они через nrf24l01

std
Offline
Зарегистрирован: 05.01.2012

Версия для RPi.

Но вообще по-идее можно ничего там не менять, т. к. висла именно нано. Ей лишь нужно посылать то чего от неё ждут циклы клиента. Без разницы каким способом и какой библиотекой. Главное чтобы настройка совпадала - канал, адреса, скорость, размер посылки. Если длина посылки у Raspberry неизвестна - выяснить.

UPD

А, ну и фраза radio.read( &rawMessage, sizeof(unsigned long) ); какбе намекает на payload=4

MocArt
Offline
Зарегистрирован: 15.12.2014

Большое спасибо! значит, Вы думаете, что дело в библиотеке для arduino? что она зависает

std
Offline
Зарегистрирован: 05.01.2012

Как вариант. Гадаю т. к. не приходилось крутить. Мне понятнее Mirf.

Другие факторы - аппаратные. Типа нету диода поперёк обмотки реле. Но от таких вещей ардуина обычно сбрасывается. А у вас если не было такого что 10-20 секунд тупка а потом работа восстанавливается, значит проблема программная.

MocArt
Offline
Зарегистрирован: 15.12.2014

еще раз спасибо, попробую, отпишусь