2

I have an Arduino Uno acting as a master with 3 Arduino Nano's acting as a slaves.

Looking at this example: http://www.gammon.com.au/forum/?id=10892, it tells me how to send a string from the master to the slave, but I didn't see any examples sending a string from the slave to the master device. I was able to successfully send and receive digits to/from the master and slave, but I couldn't figure out how to send strings from the slave to the master based on the example.

My understanding is that SPI communications can only send information byte by byte, so am I supposed to convert my string into a byte format before putting that into the SPDR variable so that it can be sent back to the master?

In any case, would I be able to get some pointers on how to send strings from the slave to the master?

Thanks in advance.

4 Answers 4

3

Remember the master controls the transmission (provides the clock), however it can be done. For example:


Master

// master

#include <SPI.h>

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

  digitalWrite(SS, HIGH);  // ensure SS stays high for now

  // Put SCK, MOSI, SS pins into output mode
  // also put SCK, MOSI into LOW state, and SS into HIGH state.
  // Then put SPI hardware into Master mode and turn SPI on
  SPI.begin ();

  // Slow down the master a bit
  SPI.setClockDivider(SPI_CLOCK_DIV8);

}  // end of setup

void loop (void)
{
  char buf [20];

  // enable Slave Select
  digitalWrite(SS, LOW);    
  SPI.transfer (1);   // initiate transmission
  for (int pos = 0; pos < sizeof (buf) - 1; pos++)
    {
    delayMicroseconds (15);
    buf [pos] = SPI.transfer (0);
    if (buf [pos] == 0)
      {
      break;
      }
    }

  buf [sizeof (buf) - 1] = 0;  // ensure terminating null

  // disable Slave Select
  digitalWrite(SS, HIGH);

  Serial.print ("We received: ");
  Serial.println (buf);

  delay (1000);  // 1 second delay 
}  // end of loop

In this example the master initiates a transmission by sending 0x01 to the slave. Then it gets bytes back until a 0x00 byte (signifying the end of the string). The delayMicroseconds is there to give the slave time to respond.


Slave

// Slave

void setup (void)
{

  // have to send on master in, *slave out*
  pinMode(MISO, OUTPUT);

  // turn on SPI in slave mode
  SPCR |= bit(SPE);

  // turn on interrupts
  SPCR |= bit(SPIE);
}  // end of setup

volatile char buf [20] = "Hello, world!";
volatile int pos;
volatile bool active;

// SPI interrupt routine
ISR (SPI_STC_vect)
{
  byte c = SPDR;

  if (c == 1)  // starting new sequence?
    {
    active = true;
    pos = 0;
    SPDR = buf [pos++];   // send first byte
    return;
    }

  if (!active)
    {
    SPDR = 0;
    return;
    }

  SPDR = buf [pos];
  if (buf [pos] == 0 || ++pos >= sizeof (buf))
    active = false;
}  // end of interrupt service routine (ISR) SPI_STC_vect

void loop (void)
{

}  // end of loop

The slave does everything inside the ISR. The arrival of the 0x01 byte makes it reset its "pointer" to the start of the buffer. After that it responds with another byte from the buffer until it has reached the terminating 0x00 byte.

1

In part of sender I'm use the convert String to char array method before sending to the receiver.

Master

#include <SPI.h>
const int size_arr = 50;  // define array size (must be less than size of slave)
char buf[size_arr]; // define char array, use for convert from string for send to slave
String main_dat = "jack,12,47,123,8888"; // real String data

void setup() {

pinMode(SS, OUTPUT);
digitalWrite(SS, HIGH);
SPI.begin();
SPI.setClockDivider(SPI_CLOCK_DIV4);

}
void loop() {
main_dat.toCharArray(buf, size_arr); // convert String data to char array
Spi_tranmis(buf); // send char array
delay(500);

}

void send_spi(byte pram) {

  digitalWrite(SS, LOW);
  SPI.transfer(pram);
  digitalWrite(SS, HIGH);
  delayMicroseconds(50);

}

void Spi_tranmis(char buf[]) {
for (int i = 0 ; i < size_arr ; i ++) {
  send_spi(buf[i]);
}

send_spi('\n');
}

And in part of receiver i'm use char array receive from master and convert to String leter.

Slave

#include <SPI.h>


const int size_arr = 51; // define array size (must be more than size of master)
char buf[size_arr]; // char array , use for recive from master

volatile byte pos = 0;
volatile boolean process = false;

String msg; // real data

void setup() {
   Serial.begin(9600);
   Serial.println("test");
   pinMode(MISO, OUTPUT);
   digitalWrite(MISO, LOW);
   SPCR |= _BV(SPE);
   SPCR |= _BV(SPIE);

 }

 ISR(SPI_STC_vect) {
  char c = SPDR;

  if (pos < sizeof buf) {
    if (c == '\n') {
      process = true;
    }
     else {
      buf[pos++] = c;
     }
   }
 }


void loop() {
  recvHandle();

}


void recvHandle() {
  if (process) {  // when SPI available
    msg = String(buf);   // convert char array to String
    Serial.println(msg);
    process = false;
    pos = 0;
  }

}

  • You must define size of char array in receiver more than sender *
0

String is only array of char ended by char \0. But you can also access it as array of bytes ended with 0. And send them by one byte until it reaches the 0 (send it too). On master you save it to long enough array of char (work with it as with bytes) including the final zero and bingo, you have char string transmitted :)

0

How do I send a string from the an Arduino Slave using SPI?

Depending on your definition of string it would look something like this (for master):

String message = "....";
SPI.transfer(message.c_str(), message.length() + 1);

or

char message[MESSAGE_MAX];
strcpy(message, ....);
SPI.transfer(message, strlen(message) + 1);

For the SPI slave this will need to be transformed to either an SPI ISR or busy-wait for chip-select and then the transfer.

Cheers!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.