How to Send Float/Double over SPI Arduino (SAMD21 Based Board) - arduino

I am trying to send a double/float over SPI from my SAMD21 based board, with chip select on pin A1/A2. I have copied some code from the internet, but I don't really understand it, plus it only works for sending data between two Arduino Unos. Here is my master:
#include <SPI.h>
float a = 3.14159;
float b = 2.252332;
uint8_t storage [12];
float buff[2] = {a, b};
void setup()
{
digitalWrite(SS, HIGH);
SPI.begin();
Serial.begin(9600);
SPI.setClockDivider(SPI_CLOCK_DIV8);
}
void loop()
{
digitalWrite(SS, LOW);
memcpy(storage, &buff, 8);
SPI.transfer(storage, sizeof storage ); //SPI library allows a user to
//transfer a whole array of bytes and you need to include the size of the
//array.
digitalWrite(SS, HIGH);
delay(1000);
}
And here is my slave:
#include <SPI.h>
byte storage [8];
volatile byte pos;
volatile boolean process;
float buff[2];
void setup()
{
pinMode(MISO,OUTPUT);
SPCR |= _BV(SPE);
SPCR |= _BV(SPIE);
pos = 0;
process = false;
Serial.begin(9600);
}
ISR(SPI_STC_vect)
{
byte gathered = SPDR;
if( pos < sizeof storage)
{
storage[pos++] = gathered;
}
else
process = true;
}
void loop()
{
if( process )
{
memcpy(buff,&storage,8);
Serial.print("This is val1:");Serial.println(buff[0], 5);
Serial.print("This is val2:");Serial.println(buff[1], 6);
storage[pos] = 0;
pos = 0;
process = false;
}
}
Any help would be aprreciated, and please understand that I am a newb in this subject.

Related

Master - Slave using SPI communication (Tinkercad)

Need your help again: I'm doing this time Master - Slave Using SPI communication, there is no error in the code when I simulate the code but the LED won't turn on.
The supposed outcome that should happen is that when I push the push button on master board the LED on the slave board will turn on.
Master code:
// Master Board
#include <SPI.h>
#define button1 4
#define SS 10
int buttonvalue;
int x;
void setup(void) {
Serial.begin(115200); //set baud rate to 115200 for usart
digitalWrite(SS, HIGH); // disable Slave Select
SPI.begin ();
SPI.setClockDivider(SPI_CLOCK_DIV8); //divide the clock by 8
}
void loop(void) {
digitalWrite(SS, LOW);
buttonvalue = digitalRead(button1);
if (buttonvalue == HIGH) {
x = 1;
} else {
x = 0;
}
digitalWrite(SS, HIGH);
delay(1000);
}
Slave code:
// Slave Board
#include <SPI.h>
#define led1 2
volatile byte Slavereceived;
volatile boolean received;
int x;
void setup(void) {
Serial.begin(115200);
pinMode(2, OUTPUT);
pinMode(MISO,OUTPUT);
SPCR |= _BV(SPE);
received = false;
SPI.attachInterrupt();
}
ISR (SPI_STC_vect) {
Slavereceived = SPDR;
received = true;
}
void loop() {
if (received) {
if (Slavereceived == 1) {
digitalWrite(led1, HIGH);
} else {
digitalWrite(led1, LOW);
}
delay(1000);
}
}
I too was stuck in the same situation, there is no support for the SPI library in tinkercad, you can include it without errors, and even use it, but any useful command will let the code stuck at that command
Sorry, but there no much you can do
this link if for a tinkercad forum, where one of the people said SPI library amoung two others are not supported
Add SPI.transfer(x); below the if else to your master code.
The master code will look somewhat like this:
// Master Board
#include <SPI.h>
#define button1 4
#define SS 10
int buttonvalue;
int x;
void setup(void) {
Serial.begin(115200); //set baud rate to 115200 for usart
digitalWrite(SS, HIGH); // disable Slave Select
SPI.begin ();
SPI.setClockDivider(SPI_CLOCK_DIV8); //divide the clock by 8
}
void loop(void) {
digitalWrite(SS, LOW);
buttonvalue = digitalRead(button1);
if (buttonvalue == HIGH) {
x = 1;
} else {
x = 0;
}
SPI.transfer(x);
digitalWrite(SS, HIGH);
delay(1000);
}

Can I temporarily disable Arduino Serial data receive?

I am working on a project and I encountered some problems.
I am using a DHT11 temperature sensor, an Arduino Uno and a TFT LCD display 2.2-inch model ITDB02-2.2.
What I want my project to do is to use 2 functioning modes for the sensor that I can select from the keyboard at the beginning of the program(one which is normal and one which will be used on special occasions)(so I need serial communication).
I noticed that the screen does not function if I start a serial communication at any rate so I used Arduino Serial.begin(9600) and Serial.end() for the mode selecting part of the program.
THE PROBLEM: My Arduino is still sending data through serial port even if I ended the serial communication and is looking like this:
I found out that Serial.end() function does not shut off serial communication but just the rate of communication. I am curious if you have any idea that I can use in order to get rid of the extra data, to neglect it before the computer receives it.
I`m stuck. I thought that interruptions would be a solution but they are not as far as I researched on the internet.
My ARDUINO CODE:
#include <SimpleDHT.h>
#include <UTFT.h>
UTFT myGLCD(ITDB22,A5,A4,A3,A2);
SimpleDHT11 dht11;
// Declare which fonts we will be using
extern uint8_t BigFont[];
//dht sensor data pin
int dataPinSensor1 = 12;
char mode;
int del;
void setup()
{
Serial.begin(9600);
Serial.print("Select functioning mode");
mode=SensorModeSelect(mode);
Serial.end();
pinMode(12, INPUT);
}
void loop()
{
if(mode=='1') {
FirstFuncMode(dataPinSensor1);
}
if(mode=='2') {
SecondFuncMode(dataPinSensor1,del);
}
delay(10);
}
char SensorModeSelect(char in)
{
char mode='0';
while(mode=='0') {
if(Serial.available() > 0) {
mode=Serial.read();
}
}
if (mode == '1') {
Serial.print("\nMOD1 SELECTED: press t key to aquire data \n");
}
if (mode == '2') {
Serial.print("\nMOD2 SELECTED: press q if you want to quit auto mode \n");
Serial.print("Select the data aquisition period(not smaller than 1 second) \n");
}
return mode;
}
int DataAqPeriod()
{
int del=0;
while(del==0) {
while(Serial.available() > 0) {
//Get char and convert to int
char a = Serial.read();
int c = a-48;
del *= 10;
del += c;
delay(10);
}
}
del*=1000;
return del;
}
void FirstFuncMode(int dataPinSensor1)
{
byte temperature = 0;
byte humidity = 0;
int err = SimpleDHTErrSuccess;
bool DispCond=false;
Serial.begin(9600);
delay(1500);
if (Serial.read() == 't' ) {
DispCond=true;
//read temperature and compare it with an error value
if((err = dht11.read(dataPinSensor1, &temperature, &humidity, NULL)) != SimpleDHTErrSuccess) {
Serial.print("unreliable measurement or unselected functioning mode");
}
byte f = temperature * 1.8 + 32;
Serial.print((int)temperature);
Serial.print(" *C, ");
Serial.print((int)f);
Serial.print(" *F, ");
Serial.print((int)humidity);
Serial.println(" H humidity");
delay(1500);
}
Serial.end();
if(DispCond==true) {
//Setup the LCD
myGLCD.InitLCD();
myGLCD.setFont(BigFont);
//print value on LCD
displayNoInit((int)temperature,(int)humidity);
}
}
void SecondFuncMode(int dataPinSensor1,int del)
{
bool q=false;
byte temperature = 0;
byte humidity = 0;
int err = SimpleDHTErrSuccess;
Serial.begin(9600);
del=DataAqPeriod();
Serial.end();
//Setup the LCD
myGLCD.InitLCD();
myGLCD.setFont(BigFont);
while(q==false) {
Serial.begin(9600);
//read temperature and compare it with an error value
if((err = dht11.read(dataPinSensor1, &temperature, &humidity, NULL)) != SimpleDHTErrSuccess) {
Serial.print("unreliable measurement or unselected functioning mode \n");
}
float f = temperature * 1.8 + 32;
Serial.print((int)temperature);
Serial.print(" *C, ");
Serial.print((int)f);
Serial.print(" *F, ");
Serial.print((int)humidity);
Serial.println(" H humidity");
delay(del);
if(Serial.read() == 'q')
q=true;
Serial.end();
displayNoInit((int)temperature,(int)humidity);
delay(10);
}
}
void displayNoInit(int temperature,int humidity)
{
//effective data display
myGLCD.clrScr();
myGLCD.setColor(255, 255, 0);
myGLCD.setBackColor(10,10,10);
myGLCD.print(" Temperature ", CENTER, 10);
myGLCD.setColor(254, 254, 254);
myGLCD.printNumI(temperature, CENTER, 45);
myGLCD.setColor(255, 255, 0);
myGLCD.print("C ", RIGHT, 45);
myGLCD.print("Relative Hum.", CENTER, 90);
myGLCD.setColor(204, 245, 250);
myGLCD.printNumI(humidity, CENTER, 120);
myGLCD.print("%", RIGHT, 120);
}
You are correct in the definition that Serial.end() does not disable the serial monitor, only the interrupts. After calling Serial.end() you can disable the serial monitor like so.
#include <avr/io.h>
// Save status register, disable interrupts
uint8_t oldSREG = SREG;
cli();
// Disable TX and RX
cbi(UCSRB, RXEN);
cbi(UCSRB, TXEN);
// Disable RX ISR
cbi(UCSRB, RXCIE);
// Flush the internal buffer
Serial.flush();
// Restore status register
SREG = oldSREG;

Reading and transferring encoder data from slave Arduino to master Arduino over SPI

My goal is to transfer a speed value from an encoder from a slave Arduino to a master Arduino via SPI. I am currently getting zeros on the master side serial print and I'm not sure what I am doing wrong. I have increased the amount of time to wait several times to see if it was a processing time issue but I had it waiting for 100mS with still no change. I know an unsigned int is 4 bytes and I am unsure if a union is the best option in this case seeing I might be overwriting my data due to the separate interrupts but I am unsure. I thought to use a struct since I'll have to move to transferring an array of floats and ints over SPI from various sensors including this encoder later. Below is my code and thank you for any help received:
Slave
#include "math.h"
#define M_PI
byte command = 0;
const int encoder_a = 2; // Green - pin 2 - Digital
const int encoder_b = 3; // White - pin 3 - Digital
long encoder = 0;
int Diameter = 6; // inches
float previous_distance = 0;
unsigned long previous_time = 0;
void setup (void)
{
Serial.begin(115200);
pinMode(MOSI, INPUT);
pinMode(SCK, INPUT);
pinMode(SS, INPUT);
pinMode(MISO, OUTPUT);
// turn on SPI in slave mode
SPCR |= _BV(SPE);
// turn on interrupts
SPCR |= _BV(SPIE);
pinMode(encoder_a, INPUT_PULLUP);
pinMode(encoder_b, INPUT_PULLUP);
attachInterrupt(0, encoderPinChangeA, CHANGE);
attachInterrupt(1, encoderPinChangeB, CHANGE);
}
// SPI interrupt routine
ISR (SPI_STC_vect)
{
union Data{
float f;
byte buff[4];}
data;
byte c = SPDR;
data.f = assembly_speed();
command = c;
switch (command)
{
// no command? then this is the command
case 0:
SPDR = 0;
break;
// incoming byte, return byte result
case 'a':
SPDR = data.buff[0];
break;
// incoming byte, return byte result
case 'b':
SPDR = data.buff[1];
break;
// incoming byte, return byte result
case 'c':
SPDR = data.buff[2];
break;
// incoming byte, return byte result
case 'd':
SPDR = data.buff[3];
break;
}
}
void loop (void)
{
// if SPI not active, clear current command
if (digitalRead (SS) == HIGH)
command = 0;
}
void encoderPinChangeA()
{
encoder += digitalRead(encoder_a) == digitalRead(encoder_b) ? -1 : 1;
}
void encoderPinChangeB()
{
encoder += digitalRead(encoder_a) != digitalRead(encoder_b) ? -1 : 1;
}
float distance_rolled()
{
float distance_traveled = (float (rotation()) / 8) * PI * Diameter;
return distance_traveled;
}
int rotation()
{
float eigth_rotation = encoder / 300;
return eigth_rotation;
}
float assembly_speed()
{
float current_distance = (float (rotation()) / 8) * PI * Diameter;
unsigned long current_time = millis();
unsigned long assemblySpeed = (((current_distance - previous_distance) /
12) * 1000) / (current_time - previous_time); // gives ft/s
previous_distance = current_distance;
previous_time = current_time;
return assemblySpeed;
}
Master
#include <SPI.h>
void setup (void)
{
pinMode(MOSI, OUTPUT);
pinMode(MISO, INPUT);
pinMode(SCK, OUTPUT);
pinMode(SS, OUTPUT);
Serial.begin (115200);
Serial.println ();
digitalWrite(SS, HIGH);
SPI.begin ();
SPI.setClockDivider(SPI_CLOCK_DIV8);
}
byte transferAndWait (const byte what)
{
byte a = SPI.transfer (what);
delayMicroseconds(10000);
return a;
}
union Data
{
float f;
byte buff[4];
}
data;
void loop (void)
{
digitalWrite(SS, LOW);
transferAndWait ('a');
data.buff[0] = transferAndWait ('b');
data.buff[1] = transferAndWait ('c');
data.buff[2] = transferAndWait ('d');
data.buff[3] = transferAndWait (0);
digitalWrite(SS, HIGH);
Serial.print("data.f = ");Serial.print(data.f);Serial.println(" Ft/s");
delay(200);
}

Trying to send a float value over SPI between 2 Arduinos

I am currently trying to send a float value across two Arduinos via SPI. Currently I am working to send a static value of 2.25 across and then read it via the Serial.println() command. I would then want to pass a float value from a linear displacement sensor. My end goal is to be able to have the master ask for information, the slave gathers the appropriate data and packages it and then master receives said data and does what it needs with it.
Currently I am getting an error "call of overloaded 'println(byte [7])' is ambiguous" and I am not to sure why I am getting this error. I am currently a mechanical engineering student and I am crash-coursing myself through C/C++. I am not entirely positive about what I am doing. I know that a float is 4 bytes and I am attempting to create a buffer of 7 bytes to store the float and the '\n' char with room to spare. My current code is below.
Master:
#include <SPI.h>
void setup() {
pinMode(SS,OUTPUT);
digitalWrite(SS,HIGH);
SPI.begin();
SPI.setClockDivider(SPI_CLOCK_DIV4);
}
void loop() {
digitalWrite(SS,LOW);
float a = 2.25;
SPI.transfer(a);
SPI.transfer('\n');
digitalWrite(SS,HIGH);
}
My slave code is as follows:
#include <SPI.h>
byte buf[7];
volatile byte pos = 0;
volatile boolean process_it = false;
void setup() {
Serial.begin(9600);
pinMode(MISO,OUTPUT);
digitalWrite(MISO,LOW);
SPCR |= _BV(SPE); // SPI Enable, sets this Arduino to Slave
SPCR |= _BV(SPIE); // SPI interrupt enabled
}
ISR(SPI_STC_vect) {
// Interrupt Service Routine(SPI_(SPI Transfer Complete)_vector)
byte c = SPDR;
// SPDR = SPI Data Register, so you are saving the byte of information in that register to byte c
if (pos < sizeof buf) {
buf[pos++] = c;
if (c == '\n') {
process_it = true;
}
}
}
void loop() {
if (process_it = true) {
Serial.println(buf);
pos = 0;
process_it = false;
}
}
I figured out what I needed to do and I wanted to post my finished code. I also added an ability to transfer more than one float value.
Master:
#include <SPI.h>
float a = 3.14;
float b = 2.25;
uint8_t storage [12];
float buff[2] = {a, b};
void setup()
{
digitalWrite(SS, HIGH);
SPI.begin();
Serial.begin(9600);
SPI.setClockDivider(SPI_CLOCK_DIV8);
}
void loop()
{
digitalWrite(SS, LOW);
memcpy(storage, &buff, 8);
Serial.print("storage[0] = "); Serial.println(storage[0]); // the
following serial prints were to check i was getting the right decimal
numbers for the floats.
Serial.print("storage[1] = "); Serial.println(storage[1]);
Serial.print("storage[2] = "); Serial.println(storage[2]);
Serial.print("storage[3] = "); Serial.println(storage[3]);
Serial.print("storage[4] = "); Serial.println(storage[4]);
Serial.print("storage[5] = "); Serial.println(storage[5]);
Serial.print("storage[6] = "); Serial.println(storage[6]);
Serial.print("storage[7] = "); Serial.println(storage[7]);
SPI.transfer(storage, sizeof storage ); //SPI library allows a user to
transfer a whole array of bytes and you need to include the size of the
array.
digitalWrite(SS, HIGH);
delay(1000);
}
For my Slave code:
#include <SPI.h>
byte storage [8];
volatile byte pos;
volatile boolean process;
float buff[2];
void setup()
{
pinMode(MISO,OUTPUT);
SPCR |= _BV(SPE);
SPCR |= _BV(SPIE);
pos = 0;
process = false;
Serial.begin(9600);
}
ISR(SPI_STC_vect)
{
byte gathered = SPDR;
if( pos < sizeof storage)
{
storage[pos++] = gathered;
}
else
process = true;
}
void loop()
{
if( process )
{
Serial.print("storage[0] = "); Serial.println(storage[0]);
Serial.print("storage[1] = "); Serial.println(storage[1]);
Serial.print("storage[2] = "); Serial.println(storage[2]);
Serial.print("storage[3] = "); Serial.println(storage[3]);
Serial.print("storage[4] = "); Serial.println(storage[4]);
Serial.print("storage[5] = "); Serial.println(storage[5]);
Serial.print("storage[6] = "); Serial.println(storage[6]);
Serial.print("storage[7] = "); Serial.println(storage[7]);
memcpy(buff,&storage,8);
Serial.print("This is buff[0]");Serial.println(buff[0]);
Serial.print("This is buff[1]");Serial.println(buff[1]);
storage[pos] = 0;
pos = 0;
process = false;
}
}
The immediate problem is that Serial.print doesn't know what to do with a byte array. Either declare it as a char array or cast it in the print statement:
char buf[7];
OR
Serial.print((char*) buf);
Either way, though, it's not going to show up as a float like you want.
An easier way to do all this is to use memcpy or a union to go back and forth between float and bytes. On the master end:
uint8_t buf[4];
memcpy(buf, &a, 4);
Then use SPI to send 4 bytes. Reverse it on the peripheral end.
Note that sending '\n' as the termination byte is a bad idea because it can lead to weird behavior, since one of the bytes in the float could easily be 0x0a, the hexadecimal equivalent of '\n'.

XBee not communicating with Arduino connected

I have two XBee S2 modules. Both are communicating when I connect them directly to my computer and check via X-CTU terminal. The problem is when I try to send data wirelessly by connecting both of them with two Arduinos there is no communication at all. It doesn't send any value.
This is the code for the receiving side:
#include <SoftwareSerial.h>
SoftwareSerial XBSerial = SoftwareSerial(2, 3);
int BackMotorForward = 6;
int BackMotorReverse = 5;
int FrontMotorRight = 10;
int FrontMotorLeft = 9;
int sv1 = 0;
int sv2 = 0;
void setup ()
{
pinMode(BackMotorForward, OUTPUT); // Initialize the pin as an output.
pinMode(BackMotorReverse, OUTPUT); // Initialize the pin as an output.
pinMode(FrontMotorRight, OUTPUT); // Initialize the pin as an output.
pinMode(FrontMotorLeft, OUTPUT); // Initialize the pin as an output.
Serial.begin(9600);
// Set the data rate for the SoftwareSerial port
XBSerial.begin(9600);
// XBSerial.println(".");
}
void loop()
{
Serial.write(XBSerial.read());
if (XBSerial.available())
{
sv1 = XBSerial.read();
Serial.write(sv1);
}
if (XBSerial.available())
{
sv2 = XBSerial.read();
Serial.write(sv2);
}
if (sv1 < 280)
{
Serial.write("backward");
digitalWrite(BackMotorForward, HIGH);
digitalWrite(BackMotorReverse,LOW);
}
else if (sv1 > 380)
{
Serial.write("forward");
digitalWrite(BackMotorReverse,HIGH);
digitalWrite(BackMotorForward,LOW);
}
else
{
digitalWrite(BackMotorForward,LOW);
digitalWrite(BackMotorReverse,LOW);
}
if (sv2 > 380)
{
Serial.write("left");
digitalWrite(FrontMotorRight, HIGH);
digitalWrite(FrontMotorLeft,LOW);
}
else if (sv2 < 280)
{
Serial.write("right");
digitalWrite(FrontMotorLeft,HIGH);
digitalWrite(FrontMotorRight,LOW);
}
else
{
digitalWrite(FrontMotorRight,LOW);
digitalWrite(FrontMotorLeft,LOW);
}
}
This is the code for the sending side:
#include <SoftwareSerial.h>
SoftwareSerial XBSerial = SoftwareSerial(2, 3);
const int xpin = A0; // x-axis of the accelerometer
const int ypin = A1; // y-axis
void setup()
{
// Initialize the serial communications:
pinMode(xpin, INPUT); //x axis
pinMode(ypin, INPUT); //y axis
Serial.begin(9600);
Serial.println("testing");
// Set the data rate for the SoftwareSerial port
XBSerial.begin(9600);
XBSerial.println("testing!!!");
}
void loop()
{
// Print the sensor values:
Serial.print(analogRead(xpin));
Serial.print("\t");
Serial.print(analogRead(ypin));
// Print a tab between values:
Serial.print("\t");
Serial.println();
// Delay before next reading:
delay(100);
int val = analogRead(xpin);
int val2 = analogRead(ypin);
XBSerial.print(val); //Changed from write to print
XBSerial.print(val2);
}
Okay, it was a really stupid mistake. I was using softwareserial pins 2,3 for XBee, but instead I was connecting their pins directly to pin 0,1 (rx,tx) of the Arduino. That's the reason there was no communication.

Resources