SPI arduino to arduino communication sending int values

Hi all

So as an extension of some of my other posts, i am now trying to understand SPI communication, to transfer data from one arduino to another. The final idea is to have two Teensy's sending data to a Pi for the user interface.

I've been reading Nick Gammon's tutorial and i have the examples all working. My only issue is i've been trying to work out how to send integer values, or loop over an array of integer values (think sending MPU6050 data from one arduino to another). I tried using his "convert anything to a stream of bytes" example, but it only gave me zeroes.

Can someone point me in the right direction, as finding tutorials for sending int's is harder than finding I2C tutorials

Thanks

Ross

Can someone point me in the right direction, as finding tutorials for sending int's is harder than finding I2C tutorials

An int (on some Arduinos) is just two bytes. Not rocket science to send the highByte() and then send the lowByte().

On others, an int is 4 bytes, and a union between an int and a 4 byte array becomes useful.

If only you had posted some code...

My apologies for no code.

below is the code for the master, slave, and the SPI_anything.h file Nick Gammon made. I haven't yet tried changing this code, as i was playing with the hello world example yesterday trying to get it to send int values. I understand an int is just two bytes, so i have to send it separately (high byte, low byte).

unfortunately i look really stupid now as i only just realised that highByte and lowByte are arduino functions, not just names for variables people were using. :confused: :blush:

so say i had the integer 10,000 to send, in binary that would be 0010011100010000. So i need to send it in byte format. So i need to send 00100111 as high byte, and 00010000 as low byte.

However, while trying to visualise what highByte and lowByte do via using Serial.print, it removes the first two zeros of 10,000, then when printing highByte and lowByte, it removes the first 3 zeros of lowByte? why is that?

Sorry for my stupidity

// master

#include <SPI.h>
#include "SPI_anything.h"

// create a structure to store the different data values:
typedef struct myStruct
{
  byte a;
  int b;
  long c;
};

myStruct foo;

void setup ()
  {
  SPI.begin ();
  // Slow down the master a bit
 // SPI.setClockDivider(SPI_CLOCK_DIV8);

  foo.a = 42;
  foo.b = 32000;
  foo.c = 100000;
  }  // end of setup

void loop () 
  { 
  digitalWrite(SS, LOW);    // SS is pin 10
  SPI_writeAnything (foo);
  digitalWrite(SS, HIGH);
  delay (1000);  // for testing  
  
  foo.c++;
  }  // end of loop
// slave

#include <SPI.h>
#include "SPI_anything.h"

// create a structure to store the different data values:
typedef struct myStruct
{
  byte a;
  int b;
  long c;
};

volatile myStruct foo;
volatile bool haveData = false;

void setup ()
  {
  Serial.begin (115200);   // debugging

  // have to send on master in, *slave out*
  pinMode(MISO, OUTPUT);
  
  // turn on SPI in slave mode
  SPCR |= _BV(SPE);

  // now turn on interrupts
  //SPI.attachInterrupt();
  
  }  // end of setup

void loop () 
  { 
  if (haveData)
     {
     Serial.println ((int) foo.a);
     Serial.println (foo.b);
     Serial.println (foo.c);
     Serial.println ();
     haveData = false;
     }
  }  // end of loop

// SPI interrupt routine
ISR (SPI_STC_vect)
  {
  SPI_readAnything_ISR (foo);
  haveData = true;
  }  // end of interrupt routine SPI_STC_vect
#include <Arduino.h>

template <typename T> unsigned int SPI_writeAnything (const T& value)
  {
    const byte * p = (const byte*) &value;
    unsigned int i;
    for (i = 0; i < sizeof value; i++)
          SPI.transfer(*p++);
    return i;
  }  // end of SPI_writeAnything

template <typename T> unsigned int SPI_readAnything(T& value)
  {
    byte * p = (byte*) &value;
    unsigned int i;
    for (i = 0; i < sizeof value; i++)
          *p++ = SPI.transfer (0);
    return i;
  }  // end of SPI_readAnything
  
  
template <typename T> unsigned int SPI_readAnything_ISR(T& value)
  {
    byte * p = (byte*) &value;
    unsigned int i;
    *p++ = SPDR;  // get first byte
    for (i = 1; i < sizeof value; i++)
          *p++ = SPI.transfer (0);
    return i;
  }  // end of SPI_readAnything_ISR

OK, so i am really stuck and won't have much hair left soon! I am no longer trying to make the code in the above post work (using the SPI_anything.h header file). Instead i am focusing on the first example.

MASTER_ORIGINAL

// Written by Nick Gammon
// February 2011


#include <SPI.h>

void setup (void)
{

  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 c;

  // enable Slave Select
  digitalWrite(SS, LOW);    // SS is pin 10

  // send test string
  for (const char * p = "Hello, world!\n" ; c = *p; p++)
    SPI.transfer (c);

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

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

SLAVE_ORIGINAL

// Written by Nick Gammon
// February 2011


#include <SPI.h>

char buf [100];
volatile byte pos;
volatile boolean process_it;

void setup (void)
{
  Serial.begin (115200);   // debugging
  
  // turn on SPI in slave mode
  SPCR |= bit (SPE);

  // have to send on master in, *slave out*
  pinMode(MISO, OUTPUT);
  
  // get ready for an interrupt 
  pos = 0;   // buffer empty
  process_it = false;

  // now turn on interrupts
  SPI.attachInterrupt();

}  // end of setup


// SPI interrupt routine
ISR (SPI_STC_vect)
{
byte c = SPDR;  // grab byte from SPI Data Register
  
  // add to buffer if room
  if (pos < (sizeof (buf) - 1))
    buf [pos++] = c;
    
  // example: newline means time to process buffer
  if (c == '\n')
    process_it = true;
      
}  // end of interrupt routine SPI_STC_vect

// main loop - wait for flag set in interrupt routine
void loop (void)
{
  if (process_it)
    {
    buf [pos] = 0;  
    Serial.println (buf);
    pos = 0;
    process_it = false;
    }  // end of flag set
    
}  // end of loop

From the sound of it i am not alone where i am struggling with the pointers aspect. I have been going through pointer tutorials but i still can not make sense of it. At the moment my understanding is that the declaration of the pointer and the dereferencing is done in one statement i.e.

const char * p = "Hello, world!\n" ;

so the const char *p on the left hand side of the '=' sign is setting aside the amount of memory of size char at a location. then the actual string is assigned to that memory location. Then i get stuck with

c = *p; p++

i know that 'p++' is moving the memory location that the pointer is pointing at by 1, nut i don't understand the 'c = *p' part as when reading it said that this is illegal so i'm obviously missing something.

As i intend to send integers i have broken down three data values of 10,000, 20,000 and 30,000 into high bytes and low bytes as recommended and put them in an array. do i need to use pointers or can i just use a for loop? My non working attempt to send 3 integers broken down is below but isn't working.

MASTER

// Written by Nick Gammon
// February 2011


#include <SPI.h>

void setup (void)
{



  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)
{
  // break down data into high and low bytes
  //=======================================
  int data_x = 10000;
  byte high_byte_x = highByte(data_x);
  byte low_byte_x = lowByte(data_x);
  int data_y = 20000;
  byte high_byte_y = highByte(data_y);
  byte low_byte_y = lowByte(data_y);
  int data_z = 30000;
  byte high_byte_z = highByte(data_z);
  byte low_byte_z = lowByte(data_z);
  byte Stop = 0;
  //=======================================

  //declare c[] array
  byte c[7] = {high_byte_x, low_byte_x, high_byte_y, low_byte_y, high_byte_z, low_byte_z, Stop};

  // enable Slave Select
  digitalWrite(SS, LOW);    // SS is pin 10

  // send test bytes one by one
 for (int i = 0; i < 7; i++){
    SPI.transfer(c[i]);
    delay(1000);
 }

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

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

SLAVE

// Written by Nick Gammon
// February 2011


#include <SPI.h>

char buf [100];
volatile byte pos;
volatile boolean process_it;

void setup (void)
{
  Serial.begin (115200);   // debugging
  
  // turn on SPI in slave mode
  SPCR |= bit (SPE);

  // have to send on master in, *slave out*
  pinMode(MISO, OUTPUT);
  
  // get ready for an interrupt 
  pos = 0;   // buffer empty
  process_it = false;

  // now turn on interrupts
  SPI.attachInterrupt();

}  // end of setup


// SPI interrupt routine
ISR (SPI_STC_vect)
{

  byte high_byte_x;
  byte low_byte_x;
  byte high_byte_y;
  byte low_byte_y;
  byte high_byte_z;
  byte low_byte_z;
  byte Stop;
  
  byte c[7] = {high_byte_x, low_byte_x, high_byte_y, low_byte_y, high_byte_z, low_byte_z, Stop};

for(int i = 0; i < 7; i++){
   c[i] = SPDR;  // grab byte from SPI Data Register
  
  // add to buffer if room
  if (pos < (sizeof (buf) - 1)){
    buf [pos++] = c[i];
  {
  // example: newline means time to process buffer
  if (c[i] == 0)
    process_it = true;
      
}  // end of interrupt routine SPI_STC_vect
  }
}
}
// main loop - wait for flag set in interrupt routine
void loop (void)
{
  if (process_it)
    {
    buf [pos] = 0;  
    for(int j = 0; j < 100; j++){
    Serial.println (buf[j], BIN);
    }
    pos = 0;
    process_it = false;
    }  // end of flag set
    
}  // end of loop

Thanks

Ross

Hi there

I've been having some trouble lately regarding SPI transmission (see post below for history). But it is now a different issue so created a new post, hopefully that's the right thing?

SPI arduino to arduino communication sending int values - Networking, Protocols, and Devices - Arduino Forum.

Due to some help i have now managed to get the high and low bytes of the data sent through. However, unless i declare the first byte i want to transfer twice in my array, it is not sent. example output below

0
16
78
32
117
48
0
0

Whereas it should be sending the number 39 first, which can only be accomplished by declaring the first two elements of my array to the same value.

 myArray[0] = High_x;
 myArray[1] = High_x;
 myArray[2] = Low_x; 
 myArray[3] = High_y;
 myArray[4] = Low_y;
 myArray[5] = High_z;
 myArray[6] = Low_z;
 myArray[7] = Stop;

MASTER

#include <SPI.h>

int x = 10000;
int y = 20000;
int z = 30000;
byte High_x = highByte(x);
byte Low_x = lowByte(x);
byte High_y = highByte(y);
byte Low_y = lowByte(y);
byte High_z = highByte(z);
byte Low_z = lowByte(z);
byte Stop = 0b00000000;

  byte myArray[7];
  


void setup (void)
{

  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);
  

 myArray[0] = High_x;
 myArray[1] = Low_x; 
 myArray[2] = High_y;
 myArray[3] = Low_y;
 myArray[4] = High_z;
 myArray[5] = Low_z;
 myArray[6] = Stop;

  delay(2000);
}

void loop (void)
{

  byte data;
  
  // enable Slave Select
  digitalWrite(SS, LOW);    // SS is pin 10

  
  for (byte * p =  myArray; data = *p; p++){
    SPI.transfer (data);
  }
  // disable Slave Select
  digitalWrite(SS, HIGH);

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

SLAVE

byte buf [100];
volatile byte pos;
// what to do with incoming data
byte command = 0;

// start of transaction, no command yet
void ss_falling ()
{
  command = 0;
}  // end of interrupt service routine (ISR) ss_falling

void setup (void)
{

  Serial.begin(9600);

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

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

  // turn on interrupts
  SPCR |= _BV(SPIE);

  // interrupt for SS falling edge
  attachInterrupt (0, ss_falling, FALLING);
  
}  // end of setup


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

  // add to buffer if room
  if (pos < (sizeof (buf) - 1))
    buf [pos++] = data;
 
}  // end of interrupt service routine (ISR) SPI_STC_vect


void loop (void)
{
  
  for(int i = 0; i < 100; i++){


    Serial.println (buf[i]);
    pos = 0;
    delay(1000);
  }
}  // end of loop

Any help would be greatly appreciated.

Thanks

Ross

There is absolutely NO need to create yet another thread!
You are still not able to do what you want to do!

I have asked the moderator to merge the two threads.

if you think that's best. my intention was not to annoy people etc. On previous forums i've been on the etiquette was not to put subsequent/ follow-up questions (albeit on similar/ related issues sometimes) in the same thread as it meant people had to read through sometimes irrelevant posts to get what can sometimes be a short answer.

I was trying to avoid a massive amount of variants of the same code being put in the same thread, when my original problem had been answered and a different although related problem had arisen. the other thread had been posted with the intention of clarity, not annoyance.

my apologies