Arduino und der Sparkfun Transceiver nRF2401A ???

Das

while(!Radio.available());

Radio.read();

steht ja im loop(), richtig?

somit wird die Hauptschleife aufgehalten, solange das radio nicht verfügbar ist. Sobald es jedoch verfügbar ist (etwa weil Daten angekommen sind), dann geht es weiter im Programm und es wird Radio.read() aufgerufen.

Das blockiert also die komplette CPU vom atmega. Die meiste Zeit verschwendet er mit warten.

Du kannst nun den DR Pin an einen interruptfähigen Arduino Pin anschließen und einen hardware interrupt auslösen lassen. Die Empfangsarbeit kannst Du dann in eine ISR auslagern. Ich denke aber mal, das alles sagt Dir nicht viel, oder?
Diese Schritte sind auch nicht unbedingt notwendig, denn wenn es in der loop() so funktioniert wie es jetzt ist, dann ist es ja gut. Ich bin leider nicht ganz auf dem Stand der Dinge, was Dir noch fehlt und was aktuell der Code ist...

und nochmal zu der while Schleife:

while(!erloesendesEvent);

ist das gleiche wie

while(!erloesendesEvent)
{
//tue garnix
}

die Klammern können dann also weggelassen werden und die while Schleife blockiert einfach nur bis die Abbruchbedingung (erloesendesEvent) eintritt.

Hallo Bohne,

ich möchte aber ein paar Dinge erldigen während ich auf Signale warte !

NOchmal zu der while.. das ! bedeutet doch in diesem Falle, dass das Event bei "false" stattfindet oder? Also wenn Radio.availabe = false gehe auf Empfang oder? Das wundert mich ein wenig.

Besitzt dr Arduino überhaupt einen Hardware Interrupt? Und ist das nicht gleichbedeutend mit einem Reset? Kann cih festlegen wo er im Programm nach einem Hardware INterrput weitermacht?

So jetzt auch zum Senden von Sensorwerten:

// Arduinos senden sich Sensorwerte zu und blinken dann die Zahl-mal //
// Peter sein Dank... der Rest ist von Martin //

#include "Nrf2401.h"

Nrf2401 Radio;


void setup () // Geht auch OHNE ADRESSIERUNG //

{
   pinMode(13, OUTPUT);
  
  int value = 0;                            // variable to keep the actual value 
 
  int wertHELL = 0;
  
  }




void loop( void )
{
   int no;
   sendNumber();
   no = receiveNumber();
   blink( no );
} 

void sendNumber( void )
{
  delay (600); // warte vor dem senden falls der andere noch am blinken ist und noch nicht auf Empfang //
  int wertHELL = 0;
   Radio.txMode(1);
   wertHELL = analogRead (0) / 20;
   Radio.data[0] = wertHELL;
   Radio.write();
} 

int receiveNumber( void )
{
   Radio.rxMode(1);
   while(!Radio.available());
   Radio.read();
   return Radio.data[0];
} 

void blink( int forMax )
{
int forZaehler;

  for( forZaehler=0; forZaehler<forMax; forZaehler++)
  {
     digitalWrite(13,HIGH);
     delay(100);
     digitalWrite(13,LOW);
     delay(100);
  }
  


}

Sensorwerte hab ich auf ein Zehntel runtergerechnet um sie in einem byte unterzugringen.

Weiß jemand ob ich auch mehr als ein byte senden kann oder andersherum gefragt, wenn ich Werte über 256 senden möchte, wie mach ich dass dann? Ich kann ja pro Radio.data (x) nur ein byte senden.

#
Radio.txMode(3);
#
  Radio.data[0] = 22;
#
  Radio.data[1] = 33;
#
  Radio.data[2] = 44;

Ich kann so zwar mehrere bytes hintereinander schicken aber wie mach stelle ich da zum Beispiel 467 dar?

Wie es scheint bleibt der Transceiver hängen wenn er im Supershockburst-Mode mit 1mbit betrieben wird, nachdem ich ihn in den lahmen 25kbit Shockburst-Mode versetzt habe läuft er durch.

Bisherige Fakten:

  • Anschluß und Library aus Playground benutzen, funktioniert gut

  • Reichweite in Räumen nur Sichtlinie und durch Glas, keine Wände
    (gilt für Keramikantenne)

  • der Transceiver sendet im Shock-Burst Modus aber nur der 250kbit Modus ist zuverlässig - muss man in Nrf2401.cpp ändern

dataRate = 0; // 1 für 1mbit, 0 für 25okbit - 0 ist zuverlässiger !!! //
  • der DR1 Pin des Transceiver (an Pin2 Arduino) zieht hoch wenn ein Signal eintrifft, der Transceiver muss dann voher schon auf Empfang sein, sonst verpasst er wahrscheinlich auch den Rest des Signals

Ungeklärt:

  • wie kann ich andere Dinge tun und gleichzitig auf Empfang bleiben ?

  • wie sende ich Zahlen, die größer 256 sind ?

  • wie viel besser sind die Module mit anderen Antennen ?

  • wie lange läuft das Ding mit Batterien

NOchmal zu der while.. das ! bedeutet doch in diesem Falle, dass das Event bei "false" stattfindet oder? Also wenn Radio.availabe = false gehe auf Empfang oder? Das wundert mich ein wenig.

es heist: warte solange NICHT Radio.available. Also tue nichts, solange Radio nicht verfuegbar ist. Das ist also von der Logik her richtig herum formuliert.
Die Schleife soll ja solange blockieren bis !Radio.available false wird.
Es gibt ja nur diese beiden Faelle:

  1. Radio.available = false bedeutet also: !Radio.available = true und somit wird die while Schleife NICHT verlassen, der Prozessor verbleibt in der Warteschleife. ( while(!Radio.available) ist ja in diesem Fall while(true))

  2. Radio.available = true bedeutet also: !Radio.available = false und somit wird die while Schleife verlassen, die Warterei hat ein Ende. ( while(!Radio.available) ist ja in diesem Fall while(false))

Besitzt dr Arduino überhaupt einen Hardware Interrupt? Und ist das nicht gleichbedeutend mit einem Reset? Kann cih festlegen wo er im Programm nach einem Hardware INterrput weitermacht?

Der Arduino hat so viele Interrupts wie der auf ihm verwendete Atmel ATMega 168 Chip. Dieser hat eine ganze Fuelle an Interrrupts. Interessant sind die hardware interrupts. Um das ganze in der Arduino Syntax zu implementieren kannst Du Dir diese Seite mal angucken:
http://arduino.cc/en/Reference/AttachInterrupt

Man kann das auch in der normalen AVR C Syntax machen, siehe etwa hier (handelt sich nicht um externen hardware interrupt, sondern um timer, aber immerhin):
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1236866849
und so machen es andere:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1241920539/2

Hallo Bohne

ich Martin mal ein Beispiel mit dieser Timer2 Bibliothek gepostet. Aber wie Martin schon schrieb, schwere Kost.

Viele Grüße
Peter

Diese while Logik war ein wenig evrwirrend, im ENdeffekt bedeutet das aber dann, dass ich einfach den DR1 Pin über "availabel" auf eingehnde Nachrichten hin überprüfen kann und dann erst auf Empfang gehe.

Da ein byte bei 1mbit ca 1 1/1000stel Sekunde lang ist un der Arduino mit 16.000 hz läuft müsste er genug durchgänge schaffen um jedes Signal zu erwischen.

Ich werde es ausprobiren und dann bescheid sagen.

Das ist gefährlich, Du wirst unter Garantie die entscheidenden Pin level changes verpassen, da der Prozessor gerade etwas anderes abarbeitet. Besser, Du bemühst die Hardware Interrupts...

Es gibt im Endeffekt zwei Arten von Interrupts, die Dich interessieren könnten:
Pin Change Interrupt Request und
External Interrupt Request
guck mal im Datenblatt vom ATmega168 nach, welchen Du verwenden magst und was das bedeutet, konkret wird es ab Seite 65 spannend.

Das Wesentliche für EXTERNE INTERRUPTS (davon hat der Chip nur zwei Stück) wurde schon für Dich implementiert, guck mal in diese Datei:
http://code.google.com/p/arduino/source/browse/tags/0015/hardware/cores/arduino/WInterrupts.c

Du musst also den DR1 Pin an den digitalen Pin 2 bzw. 3 des Arduino anschließen. Das sind die Pins PD2 und PD3 im ATMega168 Datenblatt (dort werden sie dann auch INT0 bzw. INT1 genannt).

Probier doch mal das Beispiel aus dem Playground aus (http://www.arduino.cc/en/Reference/AttachInterrupt), indem Du einen Taster an digital Pin 2 des Arduinos hängst... die LED sollte dann blinken wenn Du einen pinchange an diesem Schalter vornimmst. Eigentlich sehr einfach.

Wenn Du so weit bist musst Du die blink() Funktion austauschen gegen die Programmlogik, die Du eigentlich benötigst und dann muss eben der DR1 Pin vom Transceiver an den digital Pin 2 vom Arduino angeschlossen werden und es wird dann funktionieren :slight_smile:

Netterweise hängt der DR1 schon am Pin2,der Hardware Interrupt müsste sich also direkt einfügen lassen. Ich nehme an, der Interrupt setzt an der Stelle ein, wo er abgefragt wird? Der Interrupt bewirkt keinen Reset?

Der Interrupt ruft nur die Funktion auf, die Du angibst, im Beispielcode wäre das blink()... ein Reset wird nicht ausgeührt.

Ok, Danke, dass sollte dann funktionieren.

Wo wird den in dem Beipiel hier http://www.arduino.cc/en/Reference/AttachInterrupt spezifiziert welcher Interrupt Pin abgefragt wird? Es gibt ja zwei, Pin2 und Pin 3? Ich möchte ja vielleicht einen der beiden als normalen Pin fü anderes benutzen.

int pin = 13;
volatile int state = LOW;

void setup()
{
  pinMode(pin, OUTPUT);
  attachInterrupt(0, blink, CHANGE);
}

void loop()
{
  digitalWrite(pin, state);
}

void blink()
{
  state = !state;
}

Ohne groß Ahnung zu haben, deutlicher wirds wohl hier erklärt:
AVR-Tutorial:_Interrupts
INT0 reagiert auf Änderung an PD2
INT1 auf PD3

Danke aber.... die Erklärung im Link ist in Assembler.. in ASSEMBLER !!! Ich kann doch kaum Arduino !!!!

Ich frage mich vorallem wo die Pin auswahl in dem obenstehenden Arduino Programm zu finden ist und wo der Interrupt-Punkt.

Ich kann weder Assembler noch Arduino, trotzdem find ich es im o.g. Link gut erklärt.
Die Interrupt-Funktionen sind fest im Chip integriert, man muß nur wissen wie man drankommt.
Dein Prg.-Beispiel hab ich mal nachvollzogen,
einmal mit

attachInterrupt(0, blink, CHANGE);

und dann mit

attachInterrupt(1, blink, CHANGE);

Im ersten Fall wechselt der Zustand der LED bei Änderung an Pin 2,
im zweitem bei Änderung an Pin 3, deutlicher kann ichs leider nicht beschreiben... :-[

Hallo kimmi

ich habe so den Verdacht, dass Dir die Interruptsachen nicht ganz klar sind? Mir kommt es so vor, dass wir alle manchmal aneinander vorbei"schreiben"...

Ich beschreibe mal auf Verdacht etwas die Funktionsweise ja? Und wenn es allzu großer Unsinn sein sollte werden die Kollegen hier es sicher schnell korrigieren :sunglasses: Im wiki ist es zwar beschrieben, aber es tauchen doch viele wahrscheinlich verwirrende Begriffe auf...

Es gibt im wesentlichen zwei Möglichkeiten einen Controller auf Signale der realen physikalischen Welt reagieren zu lassen. Signale der Umwelt werden immer als Spannungspegel oder Spannungsänderung an einem Pin des Controllers angelegt.

Die erste Methode kennst Du ja schon. In einer while-Schleife einen Pin nach seinem Spannungspegel abfragen.

Im wesentlichen macht Radio.available() so etwas. Man läßt also sein Hauptprogramm so vor sich hinwerkeln und fragt dabei einen interessanten Pin nach seinem Pegel.

Je nachdem welcher Pegel anliegt macht dein Hauptprogramm wie gewohnt weiter oder behandelt das Eingangssignal. Dieses Verfahren nennt man auch polling.

Die andere Methode die Umwelt zu erfassen sind Interrupts!
Interrupt kann man ja als "unterbrechen" beschreiben/übersetzen. Genau das ist es auch.

Hier übernimmt die Hardware das Erkennen einer Änderung an einem Eingangspin des Controllers.
Du bastelst Dir eine Funktion, die nur dann ausgeführt werden soll, wenn sich an Pin 2 z.B. der Pegel ändert. In den Beispielen hier war es die Funktion void blink(void). Du sagst dem Controller ganz zu Anfang in deinem Programm

"Wenn an Pin 2 etwas wackelt, dann führe blink aus attachInterrupt(0,blink)

Nun fängt dein eigentliches Hauptprogramm an zu werkeln. Schön einen Befehl nach dem anderen.
Irgendwann, ganz plötzlich und unerwartet passiert an Pin2 etwas. Und jetzt das schöne! Ohne das Du noch etwas abfragen musst unterbricht der Controller dein normales Hauptprogramm. Irgendwo, wo es halt gerade war.

Zusätzlich merkt sich der Controller, wo er Dein Hauptprogramm unterbrochen hat.

Dann ab zu der vorher für diesen Fall bekannt gemachten Funktion blink (Du erinnerst Dich: attachInterrupt(0,blink) )

blink ist ein Beispiel für die von Bohne angesprochenen ISRs
(Interrupt Service Routine). Wenn blink jetzt abgearbeitet ist, erinnert sich die Hardware, wo sie dein Hauptprogramm unterbrochen hat und macht dann da weiter als wäre nix geschehen.

Der kleine Atmel kann Interrupts erzeugen, wenn außen etwas passiert (das kann er an Pin2 oder Pin3) oder Timer abgelaufen sind oder der A/D Wandler fertig ist usf.

Zusatz: (muss man nicht direkt verstehen, schadet aber auch nix :D)
Für jeden Interrupt gibt es einen Eintrag im RAM an einer speziellen, vom Hersteller festgelegten Adresse. Das ist die Interrupt Vektor Tabelle. Wenn nun an Pin 2 etwas passiert schaut die Hardware in dieser Tabelle nach, wohin verzweigt werden soll.

.org 0x000 ; kommt ganz an den Anfang des Speichers
rjmp RESET ; Interruptvektoren überspringen
; und zum Hauptprogramm
rjmp EXT_INT0 ; IRQ0 Handler <- Pin 2
rjmp EXT_INT1 ; IRQ1 Handler
rjmp TIM2_COMP
rjmp TIM2_OVF
rjmp TIM1_CAPT ; Timer1 Capture Handler
rjmp TIM1_COMPA ; Timer1 CompareA Handler
rjmp TIM1_COMPB ; Timer1 CompareB Handler
rjmp TIM1_OVF ; Timer1 Overflow Handler
rjmp TIM0_OVF ; Timer0 Overflow Handler
rjmp SPI_STC ; SPI Transfer Complete Handler
rjmp USART_RXC ; USART RX Complete Handler
rjmp USART_DRE ; UDR Empty Handler
rjmp USART_TXC ; USART TX Complete Handler
rjmp ADC ; ADC Conversion Complete Interrupthandler
rjmp EE_RDY ; EEPROM Ready Handler
rjmp ANA_COMP ; Analog Comparator Handler
rjmp TWSI ; Two-wire Serial Interface Handler
rjmp SPM_RDY ; Store Program Memory Ready Handler

Vorteil: Du verpasst kein Ereignis, weil die Hardware drauf achtet und Du verschwendest keine Rechenzeit durch pollen, wenn nix passiert.

Vielleicht ist der Unterschied Pollen und Interrupt etwas klarer geworden?

Und sorry für langen Text....

Die Funktionsweise eines Interrupts war mir schon klar aber ich konnte mit der Codezeile aus dem Beispielprogramm nicht richtig was anfangen, aber jetzt ist alles klar, danke schön!!!

Was ja jetzt noch richtig klasse ist, dass der Transceiver2 Kanäle hat und der Arduino 2 Interrupt Pins, man kann also sogar zwei unabhängige Interrupts anlegen jit zwei verschiedenen Funktionen, zum Beipiel einen für den normalen Datenverkehr und einen für den Notfall. Wunderbar, da hab ich alles was ich bracuhe zusammen!!

Vielen Dank allen die hier gepostet und geholfen haben!!

Ok. Hab ich alles verstanden.

Aber woher weiß ich, dass
"rjmp EXT_INT0 ; IRQ0 Handler" für Pin2 steht,
"rjmp EXT_INT1 ; IRQ1 Handler" für Pin 3 usw. ?

Ich hab das Arduino Mega Board, da stehen noch einige mehr drin.

Und kann ich auch aufgrund von Signalen an Analogeingängen Interrupts starten?

Vielen Dank im voraus.