RaspberryとArduinoの無線通信(nRF24L01 その6)

前回、writeAckPayload()を使って、Arduino→(受 信)Raspberry(応答)→Arduinoの通信ができる様になりましたが
writeAckPayload()では不便なことが有ります。
それは、writeAckPayload()では受信する前に応答データを決めてしまうので、Arduinoから受信したデータに応じた
応答データを決められません。(2回の通信を行えばできないことはないですが、コードが複雑になります)
Arduino
Raspberry

radio.write()



radio.writeAckPayload() 受信する前に応答データが決まってしま う                           

radio.read()

radio.read()



無理やりやるとすればこんな感じになります。
Arduino
Raspberry

radio.write()



radio.writeAckPayload() とりあえずダミーで応答データを決める

radio.read()



受信データに応じて次の通信のための応答データを決めておく
radio.read()

ダミーの応答データを受信する
radio.write()



radio.writeAckPayload() 上で決めた応答データ

radio.read()

radio.read()



そこで、Arduinoからのデータ受信後に応答データを決めて、返信する動作を試して見ます。
Arduino
Raspberry

radio.write()



radio.read()                

radio.write()
受信した内容に応じて応答データを決めて返信する               
radio.read()



【Raspberry側】

Raspberry側のコード(RecvAndSend.cpp)は以下の通りです。
赤字の部分でArduinoから受信したデータに+1して応答します。
#include <cstdlib>
#include <iostream>
#include <sstream>
#include <string>
#include <RF24/RF24.h>


using namespace std;
//
// Hardware configuration
//

// CE Pin, CSN Pin, SPI Speed

// Setup for GPIO 22 CE and CE1 CSN with SPI Speed @ 4Mhz
//RF24 radio(RPI_V2_GPIO_P1_22, BCM2835_SPI_CS1, BCM2835_SPI_SPEED_4MHZ);

// Setup for GPIO 22 CE and CE0 CSN with SPI Speed @ 4Mhz
RF24 radio(RPI_V2_GPIO_P1_22, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_4MHZ);

// Setup for GPIO 22 CE and CE0 CSN with SPI Speed @ 8Mhz
//RF24 radio(RPI_V2_GPIO_P1_22, BCM2835_SPI_CS0, BCM2835_SPI_SPEED_8MHZ);

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

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

  uint8_t len;
  uint8_t data[32];                     // Receive Data
  uint8_t adata[32];                    // Response Data

  radio.begin();                        // Setup and configure rf radio
  radio.openWritingPipe(pipes[0]);
  radio.openReadingPipe(0,pipes[1]);
  radio.startListening();
  radio.printDetails();


  // forever loop
  while (1) {
    if(radio.available()){
      len = radio.getDynamicPayloadSize();
      radio.read(&data,len);
      printf("Recv data=%d\n",data[0]);

      // First, stop listening so we can talk
      radio.stopListening();

      // Send the final one back.
      adata[0]=data[0]+1;
      radio.write( &adata, sizeof(adata) );
      printf("Sent response=%d\n",adata[0]);

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


次にexamplesディレクトリにあるMakefileを修正します。
PROGRAMS = RecvSimple RecvMulti
の行を以下の様に変更します。
PROGRAMS = RecvSimple RecvMulti RecvSimpleAck RecvMultiAck RecvAndSend

# define all programs
#PROGRAMS = scanner pingtest gettingstarted
#PROGRAMS = gettingstarted gettingstarted_call_response transfer pingpair_dyn
PROGRAMS = RecvSimple RecvMulti RecvSimpleAck RecvMultiAck RecvAndSend

nRF24L01とRaspberryの結線は前回と同じです。

【Arduino側】

Arduino側のスケッチは以下の通りです。
/*
 * nRF24L01 Sample Program
 *
 * VCC  3.3V
 * MISO 12
 * MOSI 11
 * SCK  13
 * CE   8
 * CSN  7
 */
#include <SPI.h>
#include "nRF24L01.h"
//#include <DigitalIO.h>  // Use Software SPI
#include "RF24.h"
#include "printf.h"

// Set up nRF24L01 radio on SPI bus plus pins 9 & 10
//RF24 radio(9,10);
RF24 radio(8,7);

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


void setup(void)
{
  Serial.begin(9600);
  Serial.println("nTF24L01 Send and Recv Demo");
  printf_begin();
 
  //
  // Setup and configure rf radio
  //
  radio.begin();
  radio.openWritingPipe(pipes[1]);
  radio.openReadingPipe(1,pipes[0]);
  radio.printDetails();
}

void loop(void)
{
  static int value = 0;
  uint8_t sdata[32];
  uint8_t rdata[32];

  // Take the time, and send it.  This will block until complete
  sdata[0]=value;
  value++;
  Serial.print("Now sending ...");

  bool ok = false;
  while(!ok) {
    ok = radio.write( sdata, sizeof(sdata) );
    if (ok) {
      Serial.println("ok...");
    } else {
      Serial.println("failed.");
      delay(1000);
    }
  }

  // Now, continue listening
  radio.startListening();
  while ( ! radio.available() ) {
//    Serial.print("Waiting..");
  }
  radio.read( &rdata, sizeof(rdata) );
  Serial.print("sdata=");
  Serial.print(sdata[0]);
  Serial.print("--->rdata=");
  Serial.println(rdata[0]);
  radio.stopListening();

  delay(1000);
}


このスケッチをArduinoで実行するとArduino側の表示が以下のようになります。



ちなみにこれができるのはArduinoが1台の通信のときだけです。
送信用のパイプは1つしか使えないので、複数のArduinoと同時に通信したいときは、
送信用パイプが不要なwriteAckPayload()を使って応答する必要があります。

続く....