Hat jemand von euch NRF24L01+ zum laufen gebracht?

Hallo zusammen,
ich hatte leider keinen Erfolg. Ich habe folgendes mit einem Duemillenova328p probiert:

/*
Arduino Software reset
*/

#include <avr/wdt.h>

#define soft_reset() 

int led = 13;

void wdt_init(void) __attribute__((naked)) __attribute__((section(".init3")));

//void wdt_init(void) {
//    MCUSR = 0;
//    wdt_disable();
//    return;
//}

void reboot() {
  wdt_disable();  
  wdt_enable(WDTO_15MS);
  while (1) {}
}

void setup() {                
  pinMode(led, OUTPUT);     
  Serial.begin(115200);
  Serial.println("Start reset test");
}

void loop() {
  digitalWrite(led, HIGH);   
  Serial.println("on");
  delay(1000);               
  digitalWrite(led, LOW);    
  Serial.println("off");
  delay(1000);            
}

void serialEvent() {

byte key = 0;

	if(Serial.available() > 0) {

		key = Serial.read();

			switch (key) {
			case 'b':			
				 reboot();
//				 soft_reset();
				 Serial.println("Now reset");
				 
			default:
				break;
			}
		}
	}
//--------------------------- end of serialEvent --------------------------------------------------

Ich habe verschiedene Versionen getestet, deshalb die Auskommentierungen. Erfolg war lediglich, das ich den Arduino neu starten musste. Ich ging davon aus, dass das kleine Programm mit setup wieder startet. Ich muss dazu sagen, das dieses kleine "Projekt" als Unterstützung für mein Hauptprojekt dienen soll.

Gruß Willi

Der jetzige Code ist Murks

Das #define macht gar nichts. Da fehlt der Teil des Makros den er eigentlich statt soft_reset() einsetzen soll.

Und der Funktions-Prototyp für den init Code ist so alleine auch überflüssig.

Der Code nach reboot() wird nie erreicht.

Das geht bei mir:

#include <avr/wdt.h>

void wdt_init(void) __attribute__((naked)) __attribute__((section(".init3")));
void wdt_init(void)
{
    MCUSR = 0;
    wdt_disable();

    return;
}

#define soft_reset()        \
do                          \
{                           \
    wdt_enable(WDTO_15MS);  \
    for(;;)                 \
    {                       \
    }                       \
} while(0)

void setup() 
{
  Serial.begin(115200);
  Serial.println("START");  
}

void loop() 
{
  char c = Serial.read();
  
  if(c == 'r')
  {
    soft_reset();
  }
  
  Serial.println("running");
  delay(1000);
}

Da siehst du "START" wenn du 'r' eingibst

Danke für die Hilfe zu dieser Uhrzeit :). Ich habe das Programm 1 zu 1 kopiert. Kein Neustart, aber der Arduino muss neu gestartet werde. Diese Funktionen:

wdt_disable();
soft_reset();

sind unterstrichen mit einer Meldung, ".....es wird ein ")" erwartet". Ist das normal?

Keine Ahnung was da los ist. Ich habe es auf einem ganz normalen UNO getestet.

Statt dem Makro eine Funktion draus zu machen geht bei mir auch:

void soft_reset()        
{
    wdt_enable(WDTO_15MS);
    for(;;){}                       
}

Ich habe leider keinen Due. Mit dem Nano hat es auch nicht funktioniert. Ich habe es sogar mit der Arduino IDE probiert. Trotzdem danke für die Geguld. Gute Nacht. 8)

Gruß Willi

Dass du Neustarten musst deutet darauf hin dass der WDT nicht ausgelöst wird. Er wird dann in der Endlosschleife hängen.

Ob das auf dem Due so geht würde ich erst bezweifeln. Das ist für AVR Prozessoren gedacht.

Nicht der DUE, das ist ein ARM-Processor. Ich hatte den Duemilenove(2009) gemeint:
http://arduino.cc/en/pmwiki.php?n=Main/ArduinoBoardDuemilanove.
Und das ist ein AVR.

Woran kann es den liegen, dass WDT nicht ausgelöst wird? Bei Dir funktioniert es ja. Wie gesagt, ich hatte es auch mit der Arduino IDE 1.0.5 versucht. Ansonsten nutze ich VS2012 mit Visualmicro.

Nach Deinem Hinweis, habe gerade das gefunden:

Der WDT läßt sich auch softwaremäßig durch Setzen des WDE-Bits im WDTCR Register aktivieren.

WDT_on:

in Temp1, WDTCR ; Write logical one to WDE
ori Temp1, (1<<WDE)
out WDTCR, Temp1
ret

Dieses hat den Vorteil, dass man den WDT auch softwaremäßig wieder deaktivieren kann.

AVR-Tutorial: Watchdog – Mikrocontroller.net.

Könnte das die Lösung sein? Wenn ja, wie geht das?

Probieren kannst du es mal. Das ist aber Assembler Code. Du braucht nur WDTCR = (1<<WDE)

Das ist aber eigentlich auch nix anderes als was das wdt_enable() Makro macht:
http://www.nongnu.org/avr-libc/user-manual/group__avr__watchdog.html#gaf6cfea2a1b61e2530ea0c4ef8fc572b3
Wobei da noch etwas mehr drin steckt

Auf der Seite wird auch das mit "neueren" AVRs besser erklärt:

Note that for newer devices (ATmega88 and newer, effectively any AVR that has the option to also generate interrupts), the watchdog timer remains active even after a system reset (except a power-on condition), using the fastest prescaler value (approximately 15 ms).

Geht also bis zum Atmega88 zurück! Was ich schon als alt bezeichnen würde :slight_smile:

Nee nee, das lasse ich die Finger von. Ich werde mein Prototyp-Platine mit einem Resetknopf versehen. Wie gesagt, das ist "nur" ein Nebenprojekt.
Trotzdem vielen lieben Dank für die Unterstützung, aber ich weiss genau, wo derzeit meine Grenzen sind.

Gruß Willi

Ich bin nun dahinter gekommen, warum der NRF24 manchmal den Geist aufgibt. Es lag an der Stromversorgung. Obwohl er lt. Datenblatt nur max 15mA benötigt, muss die Stromversorgung etwas mehr bereithalten. Mit einen extern 3.3V Supply und einem zusätzlich 10uF ist das Problem behoben.
Nun habe ich aber ein anderes Problem. Lt Datenblatt kann ich bis zu 32Byte übertragen. Wenn ich mein Datenarray auf 4 int Values (8Byte) beschränke, ist alles OK. Ab 5 streikt der Empfänger. D.h. es wird kein Interrupt, bzw. gerade noch einer ausgelöst. Ich habe es auch mit einer Struktur versucht, was viel besser wäre, aber auch kein Erfolg.

typedef struct __attribute__((__packed__)) {	Sender und Empfänger
uint16_t throttle;
int8_t yaw;
int8_t pitch;
int8_t roll;
int16_t checkSum;
} rx_values_t;

rxvalues_t rxValues;

----------------------------------------------------------------

Sender

rxValues.throttle = analogread(A0);
rxValues.yaw = analogread(A1);
rxValues.pitch = analogread(A2);
rxValues.roll = analogread(A3);

rxValues.checkSum = (rxValues.throttle*2) + (rxValues.yaw*3) + (rxValues.pitch*4) + (rxValues.roll*5);

....

  if (role == role_sender)
  {
        radio.powerUp() ;
    radio.startWrite( &rxValues, sizeof(rxValues_t) );

  }


----------------------------------------------------------------

Emfänger

    if ( role == role_receiver )
    {
      radio.read( &rxValues, sizeof(rxValues_t) );		Geht nur mit "&" Opperator
      
      // Add an ack packet for the next time around.  This is a simple
      // packet counter
      radio.writeAckPayload( 1, &message_count, sizeof(message_count) );
      ++message_count;
    }
	
	if(((rxValues.throttle*2) + (rxValues.yaw*3) + (rxValues.pitch*4) + (rxValues.roll*5)) == rxValues.ceckSum) {
	   received = OK;
	}

Gruß Kucky

Leider sieht man nicht, was du da einstellst......

Meine Glaskugel sagt:

radio.setRetries(15,15);

könnte dein Problem beheben.

Aber wie gesagt, alles im Glaskugelmodus.
:wink:

Danke für die Antwort,
aber sind diese Werte nicht optional?
Ich hätte eher gedacht "radio.setPayloadSize-8". Aber den habe ich auch nicht gesetzt. Aber hier mal mein Code, der funktioniert:

Sender

/*
Transmitter for Quadrocopter
based on Arduino Mini Pro (328p 5v 16MHz)

write to an 9 channel RC

*/

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

#define NANO328

// sets the role of this unit in hardware.  Connect to GND to be the 'pong' receiver
//											Leave open to be the 'ping' transmitter

#ifdef NANO328
// Nano 328
RF24 radio(9,10);
const short role_pin = 9;
#else
//MEGA2560
RF24 radio(46, 53);
const short role_pin = 41;
#endif

const uint64_t pipe = 0xE8E8F0F0E1LL;

typedef enum { role_sender = 1, role_receiver } role_e;

const char* role_friendly_name[] = { "invalid", "Sender", "Empfaenger" };

role_e role;
static uint32_t message_count = 0;

#define NUM_TXDATA 4
int tx_data[NUM_TXDATA];
const uint8_t readPin[NUM_TXDATA] = {A0, A1, A2, A3};   /// Yaw, Pitch, Roll, Throttle

//--------------------------- end of declration and initialisations--------------------------------

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

  if ( digitalRead(role_pin) )
    role = role_sender;
  else
    role = role_receiver;

  Serial.begin(115200);
  printf_begin();
  printf("\n\rQuad_Transmitter/\n\r");
  printf("ROLE: %s\n\r",role_friendly_name[role]);

  radio.begin();

  radio.enableAckPayload();

  if ( role == role_sender ) {
    radio.openWritingPipe(pipe);
  }
  else {
    radio.openReadingPipe(1,pipe);
  }

  if ( role == role_receiver )
    radio.startListening();

  radio.printDetails();

  attachInterrupt(1, check_radio, FALLING);
}
//--------------------------- end of setup ------------------------------------

void loop(void)  {

	tx_data[0] = map(analogRead(readPin[0]), 189, 898, -600, 600);		///< 1/10°  to set setpoint Yaw
	tx_data[1] = map(analogRead(readPin[1]), 141, 839, -600, 600);		///< Pitch
	tx_data[2] = map(analogRead(readPin[2]), 141, 866, -600, 600);		///< Roll

	tx_data[3] = map(analogRead(readPin[3]), 176, 872, 1000 , 2000);	///< Throttle

  if (role == role_sender)
  {
    printf("Now sending data  %i %i %i %i \n\r",tx_data[0], tx_data[1], tx_data[2], tx_data[3]);
    radio.powerUp() ;
    radio.startWrite( tx_data, sizeof(tx_data) );

    delay(100);
  }
  // Receiver role: Does nothing!  All the work is in IR
}
//--------------------------- end of mainloop -----------------------------------------------------

void check_radio(void)  { 

  bool tx,fail,rx;
  radio.whatHappened(tx,fail,rx);

  if ( tx )  {
    if ( role == role_sender )
      printf("Send: OK\n\r");

    if ( role == role_receiver )
      printf("Ack Payload: Sent\n\r");
  }

  if ( fail )  {
    if ( role == role_sender )
      printf("Send: Failed\n\r");

    if ( role == role_receiver )
      printf("Ack Payload: Failed\n\r");
  }

  if ( ( tx || fail ) && ( role == role_sender ) )
    radio.powerDown();

  if ( rx )  {
    if ( role == role_sender )  {
      radio.read(&message_count,sizeof(message_count));
      printf("Ack: %lu\n\r",message_count);
    }

    if ( role == role_receiver )  {
      radio.read( tx_data, sizeof(tx_data) );
      printf("Got payload %i %i %i %i n\r",tx_data[0], tx_data[1], tx_data[2], tx_data[3]);

      radio.writeAckPayload( 1, &message_count, sizeof(message_count) );
      ++message_count;
    }
  }
}
//--------------------------- end of check_radio --------------------------------------------------

/*-------------------------------- end of Quad_Transmitter --------------------------------------*/

Empfänger

// 
// 
// 

#include "RC.h"
#include "RF24.h"

#ifdef NANO328
// Nano 328
RF24 radio(9,10);
const short role_pin = 9;
#else
//MEGA2560
RF24 radio(46, 53);

#endif

role_e role;

//--------------------------- end of initialation ans declaration ---------------------------------
void RCClass::init() {

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

  uint64_t pipe = PIPE;
  const char* role_friendly_name[] = { "invalid", "Sender", "Empfaenger" };

  int tx_data[NUM_TXDATA];
  const uint8_t readPin[] = {A0, A1, A2, A3};   /// Yaw, Pitch, Roll, Throttle
  static uint32_t message_count = 0;

  if ( digitalRead(role_pin) )
    role = role_transmitter;
  else
    role = role_receiver;

    printf("\n\rQuad_Receiver /\n\r");
    printf("ROLE: %s\n\r",role_friendly_name[role]);

    radio.begin();
    radio.enableAckPayload();

	  if ( role == role_transmitter )  
		radio.openWritingPipe(pipe);
	  else
		radio.openReadingPipe(1,pipe); 

	  if ( role == role_receiver )
		radio.startListening();

  radio.printDetails();
}
//--------------------------- end of init ---------------------------------------------------------

void RCClass::check_radio(void)  {     /// Wird vom Interrupt aus Startprogramm aufgerufen

  bool tx,fail,rx;
  radio.whatHappened(tx,fail,rx);

  if ( tx )  {
    if ( role == role_transmitter )
      printf("Send: OK\n\r");

    if ( role == role_receiver )
      printf("Ack Payload: Sent\n\r");
  }

  if ( fail )  {
    if ( role == role_transmitter )
      printf("Send: Failed\n\r");

    if ( role == role_receiver )
      printf("Ack Payload: Failed\n\r");
  }

  if ( ( tx || fail ) && ( role == role_transmitter ) )
    radio.powerDown();

  if ( rx )  {
    if ( role == role_transmitter )  {
      radio.read(&message_count,sizeof(message_count));
      printf("Ack: %lu\n\r",message_count);
    }

    if ( role == role_receiver )  {
      radio.read( tx_data, sizeof(tx_data) );
      printf("Got payload %i %i %i %i ",tx_data[0], tx_data[1], tx_data[2], tx_data[3]);
 	  printf("  Ack send %i \n\r",message_count);
      radio.writeAckPayload( 1, &message_count, sizeof(message_count) );
      ++message_count;
    }
  }
}
//--------------------------- end of check_radio --------------------------------------------------
RCClass RC;
/*--------------------------- end of RCclass ----------------------------------------------------*/

Main Empfänger

/*
Receiver modul for Quadrocopter
based on Arduino Mini Pro (328p 5v 16MHz)

read an 9 channel RC

*/

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

#include "RC.h"

//-----------------------------------------------------------------------------

void read_RC(void);
//-----------------------------------------------------------------------------

void setup(void)  {

  Serial.begin(115200);
  printf_begin();

  RC.init();

  attachInterrupt(1, read_RC, FALLING);
}
//--------------------------- end of setup --------------------------------------------------------

void loop(void) {
  // loop is empty
}
//--------------------------- end of mainloop -----------------------------------------------------

void read_RC() {
	RC.check_radio();
}
//--------------------------- end of read_RC -----------------------------------------------------
/*--------------------------- end of Quad_Receiver ----------------------------------------------*/

Ich hoffe, ich habe nicht zu viel Mühe gemacht. Ich habe hier
http://www.daedalus.ei.tum.de/index.php/de/zeppelin/blimp/gamepad-dms2-funkverbindung

folgendes gelesen :
"
Der erste Modus ist der Normale-Modus indem die Stickwerte verschickt werden, in dem Normalen-Modus werden permanent Pakete mit den zugehörigen Stickwerten verschickt. Dazu werden die Stickwerte codiert, sodass pro Stickwert 2Bytes gebraucht werden. Im gesendeten Paket stehen die Stickwerte somit vom 1. bis 8. Byte. Der 9.Byte hat den Wert Null. Im empfänger werden die Stickwerte anschließend wieder decodiert.
"
Ist das richtig, dass ich nur Byte senden kann? Kann ich mir nicht vorstellen.

Gruß Kucky

aber sind diese Werte nicht optional?

Durchaus...
Aber da deine Verwendung des "Ack Payload" den üblichen (Zeit)Rahmen sprengt, könntest du es damit mal versuchen...

Ist das richtig, dass ich nur Byte senden kann? Kann ich mir nicht vorstellen.

Du kannst alles senden, Hauptsache es passt in deine PayloadSize!
Also
32 byte
12 int
usw....
Das Funkmodul kennt keine Datentypen.

Jau das war es. Vielen Dank. Auch der Hinweis zu Ack Payload. Ab 999 hing das Programm wieder.

Gruß Willi

Schön!
Dann kann ich ja mit mir und meiner Glaskugel recht zufrieden sein.

Hallo,
nun funktioniert (fast) alles.

Ich habe folgende Struktur auf beiden Seiten:

typedef struct __attribute__((__packed__)) {
  uint16_t throttle;
  int16_t yaw;
  int16_t pitch;
  int16_t roll;
  uint8_t switch1;
  uint8_t switch2;
  uint8_t switch3;
//  uint8_t switch4;
//  uint8_t switch5;
  uint16_t checksum;
} rxValues_t;

Paylodsize(13);

Übertragung wie auf Bild "OK" zu sehen.

Wenn ich aber einen Wert (switch4) hinzu nehme und die Payloadsize auf 14 erhöhe, stockt der Empfang (Bild "NichtOK"). Ich vermute, es liegt an der Payloadsize und speziell an der "checksum". Was mache ich falsch?

rxValues.checksum = (rxValues.yaw*2) + (rxValues.pitch*3) + (rxValues.roll*4) + (rxValues.throttle*5);

Gruß
Willi

Es liegt tatsälich an der checksum. Ist ein uint16_t mit 2 Byte. Habe ich so berechnet.

rxValues.checksum = (rxValues.yaw*2) + (rxValues.pitch*3) + (rxValues.roll*4) + (rxValues.throttle*5);

erledigt, es lag an dem typ. Mit int16_t ist alles in Butter. Hätte ich auch früher drauf kommen können. :cold_sweat:
Gruß
Willi

Ich habe noch 2 Fragen zu "Ack Payload" und "radio.setRetries(15,15)". Du sagst, das AckPayload zeitintensiv ist. Habe ich das richtig verstanden habe, und dies ist eine einfache Kontrolle über das was gesendet/empfangen wurde, und ich das mit einer Checksumme schneller prüfen kann?
Was macht eigentlich "radio.setRetries(15,15)" außer das mein Programm innerhalb von setup bzw. init einfriert? Gehören die 2 zusammen. Ich habe die Doku gelesen aber nicht verstanden.

Gruß Willi