Arduino to arduino i2c code - arduino

I have an OPT101 connected to a slave arduino to measure light intensity. I want to send the data received from the OPT101 circuit to a master arduino that will print the data on the serial monitor. When I test my code, nothing shows up on the screen. (I know it's not my i2c connection cause I tested it by sending "hello"). I am using an arduino leonardo as the slave and the arduino uno as the master.
The code for the OPT101 circuit is:
#define inPin0 0
void setup() {
Serial.begin(9600);
Serial.println();
}
void loop() {
int pinRead0 = analogRead(inPin0);
double pVolt0 = pinRead0 / 1024.00 * 5.0;
Serial.print(pVolt0, 4 );
Serial.println();
delay(100);
}
I tired to combine the slave code and my OPT101 code to get this:
#include
#define inPin0 0
void setup() {
Wire.begin(2);
}
void loop() {
Wire.beginTransmission(2);
Wire.onRequest(requestEvent);
Wire.endTransmission();
}
void requestEvent()
{
int pinRead0 = analogRead(inPin0);
int pVolt0 = pinRead0 / 1024.0 * 5.0;
Wire.write((byte)pVolt0);
}
And this is my master code:
#include <Wire.h>
void setup()
{
Wire.begin();
Serial.begin(14400);
Wire.requestFrom(2, 8);
while(Wire.available())
{
char c = Wire.read();
Serial.print(c);
}
}
void loop()
{
}

You must follow steps described below to communicate between master and slave I2C devices:
Only master can initiate read or write request.
Read or write requests must be synchronous. It means, slave can only return data after master requests for them and vice versa for write.
Do not use slave address from 0 - 7. They are reserved. Use slave address that ranges between 8 to 127.
On Arduino I2C, you can only send and receive a byte. To send or receive integer, double that have multiple bytes, you need to split them first and on other side, you have to combine them into its equivalent datatype. (Correct me, if I'm wrong.)
Your code should be like this:
Master Sketch:
#include <Wire.h>
#define SLAVE_ADDRESS 0x40
// This macro reads two byte from I2C slave and converts into equivalent int
#define I2C_ReadInteger(buf,dataInteger) \
buf[0] = Wire.read(); \
buf[1] = Wire.read(); \
dataInteger = *((int *)buf);
// Returns light intensity measured by 'SLAVE_ADDRESS' device
int GetLightIntensity()
{
byte Temp[2];
int Result;
// To get integer value from slave, two are required
int NumberOfBytes = 2;
// Request 'NumberOfBytes' from 'SLAVE_ADDRESS'
Wire.requestFrom(SLAVE_ADDRESS, NumberOfBytes);
// Call macro to read and convert bytes (Temp) to int (Result)
I2C_ReadInteger(Temp, Result);
return Result;
}
void setup()
{
// Initiate I2C Master
Wire.begin();
// Initiate Serial communication # 9600 baud or of your choice
Serial.begin(9600);
}
void loop()
{
// Print light intensity at defined interval
Serial.print("Light Intensity = ");
Serial.println(GetLightIntensity());
delay(1000);
}
Slave Sketch:
#include <Wire.h>
#define SLAVE_ADDRESS 0x40
#define inPin0 0
// Preapres 2-bytes equivalent to its int
#define IntegerToByte(buf,intData) \
*((int *)buf) = intData;
// Sends int to Master
void I2C_SendInteger(int Data)
{
byte Temp[2];
// I2C can only send a byte at a time.
// Int is of 2bytes and we need to split them into bytes
// in order to send it to Master.
// On Master side, it receives 2bytes and parses into
// equvivalent int.
IntegerToByte(Temp, Data);
// Write 2bytes to Master
Wire.write(Temp, 2);
}
void setup()
{
// Initiate I2C Slave # 'SLAVE_ADDRESS'
Wire.begin(SLAVE_ADDRESS);
// Register callback on request by Master
Wire.onRequest(requestEvent);
}
void loop()
{
}
//
void requestEvent()
{
// Read sensor
int pinRead0 = analogRead(inPin0);
int pVolt0 = pinRead0 / 1024.0 * 5.0;
// Send int to Master
I2C_SendInteger(pVolt0);
}
This code is tested on Arduino Version: 1.6.7.
For more information regarding I2C communication, refer Arduino
Example: Master Reader

Why are you putting the while loop in the setup() function instead of using the loop() function ?
But more confusing is this line int pVolt0 = pinRead0 / 1024.0 * 5.0;. In the initial code the variable is not int but double. I suggest you try to recode using the original line:
double pVolt0 = pinRead0 / 1024.00 * 5.0;
And only then reduce to int.

In Arduino I2C, you can only send and receive one byte, and it is necessary to combine them in their equivalent data type.

Related

arduino as modbus RS485 slave sending message to master

I am French speaking, excuse my poor English. I am working on a rs485 modbus communication between 2 arduino megas. I would like the slave to send for example the value "10" to the master.
On the slave I use the example of the library https://github.com/yaacov/ArduinoModbusSlave :
#include <ModbusSlave.h>
// explicitly set stream to use the Serial serialport
Modbus slave(Serial, 1); // stream = Serial, slave id = 1, rs485 control-pin = 8
void setup() {
// register handler functions
slave.cbVector[CB_READ_INPUT_REGISTERS] = ReadAnalogIn;
// slave.cbVector[CB_READ_HOLDING_REGISTERS] = readMemory;
// start slave at baud 9600 on Serial
Serial.begin( 9600 ); // baud = 9600
slave.begin( 9600 );
}
void loop() {
// listen for modbus commands con serial port
slave.poll();
}
// Handel Read Input Registers (FC=04)
uint8_t ReadAnalogIn(uint8_t fc, uint16_t address, uint16_t length) {
// write registers into the answer buffer
for (int i = 0; i < length; i++) {
uint16_t res;
res = 221;
//slave.writeRegisterToBuffer(i, analogRead(address + i));
slave.writeRegisterToBuffer(i,10);
}
return STATUS_OK;
}
on the master I use an example from the librabry https://github.com/4-20ma/ModbusMaster
´´´
#include <ModbusMaster.h>
// instantiate ModbusMaster object
ModbusMaster node;
void setup()
{
// use Serial (port 0); initialize Modbus communication baud rate
Serial.begin(9600);
// communicate with Modbus slave ID 1 over Serial (port 0)
node.begin(1, Serial);
}
void loop()
{
static uint32_t i;
uint8_t j, result;
uint16_t data[6];
i++;
// set word 0 of TX buffer to least-significant word of counter (bits 15..0)
// node.setTransmitBuffer(0, lowWord(i));
// set word 1 of TX buffer to most-significant word of counter (bits 31..16)
// node.setTransmitBuffer(1, highWord(i));
// slave: write TX buffer to (2) 16-bit registers starting at register 0
// result = node.writeMultipleRegisters(0, 2);
// slave: read (6) 16-bit registers starting at register 2 to RX buffer
result = node.readHoldingRegisters(2, 6);
// do something with data if read is successful
if (result == node.ku8MBSuccess)
{
Serial.println(result);
}
}
´´´
but it does not work, it seems that there is no communication between the arduino. does anyone have a solution?

Is it possible not to use onReceive command when receiving data through i2c?

I understand that when trying to receive data through i2c I can use the following code in arduino :
#include <Wire.h>
void setup() {
Wire.begin(0x04); // join i2c bus with address #8
Wire.onReceive(receiveEvent); // register event
Serial.begin(9600); // start serial for output
}
void loop() {
delay(100);
}
void receiveEvent(int howMany) {
while (1 < Wire.available()) { // loop through all but the last
char c = Wire.read(); // receive byte as a character
Serial.print(c); // print the character
}
int x = Wire.read(); // receive byte as an integer
Serial.println(x); // print the integer
}
But what if I don't want to use the onReceive command at void.setup and receive using a function like the following code:
void receiveData() {
Wire.begin(0x04);
while(Wire.available()) {
if(x==4) { x=0;}
data[x]=Wire.read();
x++;
}
}
I want to do this because I have to read a sensor and simultaneously receive an array from a raspberry pi.
Is this doable?
BTW I am using an arduino nano and raspberry pi 3 and the sensor is MPU6050.

Parameter int howmany in Arduino i2C slave receiver

I have the following example code of a Arduino Slave i2C. Taken from https://www.arduino.cc/en/Tutorial/MasterWriter
#include <Wire.h>
void setup() {
Wire.begin(8); // join i2c bus with address #8
Wire.onReceive(receiveEvent); // register event
Serial.begin(9600); // start serial for output
}
void loop() {
delay(100);
}
// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany) {
while (1 < Wire.available()) { // loop through all but the last
char c = Wire.read(); // receive byte as a character
Serial.print(c); // print the character
}
int x = Wire.read(); // receive byte as an integer
Serial.println(x); // print the integer
}
In the method void receiveEvent(int howMany), what exactly is the functionality of the parameter int howMany?
The function receiveEvent is provided as an event handler to Wire.onReceive().
So, from the documentation of Wire.onReceive
handler: the function to be called when the slave receives data; this should take a single int parameter (the number of bytes read from the master) and return nothing, e.g.: void myHandler(int numBytes)
It contains the amount of bytes of the received data.

Global variable arduino

I'm using I2C to communicate a Master Arduino to 4 Slaves Arduinos, and an Shield (OULIMEX Shield LCD 16x2) on every Arduino slave.
I send Data from the master to slaves using I2C. So I use this code in the master :
#include <Wire.h>
#include <math.h>
#include <floatToString.h>
double incomingData;
void setup()
{
Wire.begin();
Serial.begin(9600);
incomingData = Serial.parseFloat(); //read incoming data
}
void loop()
{
delay (1000);
if (Serial.available())
{
incomingData = Serial.parseFloat(); //read incoming data
Wire.beginTransmission(8); // transmit to device #8
if ((M==0) || (M==1) || (M==2))
Wire.beginTransmission(8); // transmit to device #8 *****************************************************************
else
Wire.beginTransmission(7); // transmit to device #7 *****************************************************************
M++;
if (M==5)
M=0;
String a = "";
a = floatToString(test,incomingData,3,5,true);
for(i=0; a[i]!='\0'; ++i); // length of the string
Wire.write(i);
Wire.write(floatToString(test,incomingData,3,5,true)); // sends one byte
Wire.endTransmission(); // stop transmitting
}
}
I wanted the Data to be printed on the Shield, but I'm connecting all slaves with the same way with the master. For that I have two problems :
1- The global data I'm using to print value is always printed as 0, and not giving the real value;
2- All Shields print the same thing : For exemple, I print "hello" in the first Shield, and I print "hi" in the second Shield, but bouth are printing the same thing (hello or hi).
The code using for the first slave is :
#include <LCD16x2.h>
#include <Wire.h>
LCD16x2 lcd;
int buttons;
int sensorPin = A0; // select the input pin for the potentiometer
int sensorValue = 0; // variable to store the value coming from the sensor
float numOut;
int comp=1 ;
String wordd = "";
int M =0;
void setup()
{
Wire.begin(8); // join i2c bus with address #8
Wire.onReceive(receiveEvent); // register event
Serial.begin(9600); // start serial for output
}
void loop()
{
delay(500);
}
// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany) {
wordd = "";
int x = Wire.read();
for (int i=0; i<=x; i++)
{
char c = Wire.read();
wordd += c;
}
numOut = wordd.toFloat();
Serial.println(numOut,3); // print the integer
}
Thank you in advance !!
I think it's due to a poor program structure in master shield.
This block selects the slave but on the first line you already select #8
I think this is confusing for the slaves.
Wire.beginTransmission(8); // transmit to device #8
if ((M==0) || (M==1) || (M==2))
Wire.beginTransmission(8); // transmit to device #8
else
Wire.beginTransmission(7); // transmit to device #7
This block should be at the end of the function
M++;
if (M==5)
M=0;
Then you parse the value in a string.
But leave out the first char because you write ++i instead of i++
Moreover you close the loop with ; so it does nothing
String a = "";
a = floatToString(test,incomingData,3,5,true);
for(i=0; a[i]!='\0'; ++i); // length of the string
Finally you write the ordinal number of the byte
And then again the Whole string
So you should get "0" (or "1" because of ++i)
followed by your number if Wire.write() supports it
Wire.write(i);
Wire.write(floatToString(test,incomingData,3,5,true)); // sends one byte
Wire.endTransmission(); // stop transmitting
}
Your sketch should be:
if (Serial.available())
{
incomingData = Serial.parseFloat(); //read incoming data
String a = "";
a = floatToString(test,incomingData,3,5,true);
if ((M==0) || (M==1) || (M==2))
Wire.beginTransmission(8); // transmit to device #8
else
Wire.beginTransmission(7); // transmit to device #7
for(i=0; a[i]!='\0'; ++i) // length of the string
Wire.write(a[i]); // write one byte
Wire.endTransmission(); // stop transmitting
M++;
if (M==5) M=0;
}
Let me know if this works.
I already ask this question but I think I have the answer of it. A global variable have to be diclared befor the void setup, and the void loop too, like that :
type YourGlobalVariable;
void setup()
{
}
void loop()
{
}
So, it is exactly how I did already. The reason it didn't work for me, it was cause of I used this function :
void receiveEvent(int howMany) {}
I don't really know what are the properties of it that let it not work for a global variables, but It works like I sayd already.
Thank you all

Unable to receive correct data using i2c serial communication between two Arduino

I'm using an i2c serial bus for communication between two Arduino (Uno = Master, Due = Slave) and I'm currently experiencing problems while reading data received by the slave.
The master sends some data using Wire.write(command). The slave receives it and the handler function receiveEvent(int howMany) is called thanks the instruction Wire.onReceive(receiveEvent).
Here is the simplified code for the serial communication:
Master's Sketch
#include <Wire.h>
void setup() {
Wire.begin();
Serial.begin(9600);
}
void loop() {
Wire.beginTransmission(8);
byte command[] = {2, 5, 3};
Wire.write(command, 3);
Wire.endTransmission();
Serial.println("command sent...");
delay(1000);
}
Slave's Sketch
#include <Wire.h>
int c = 0;
void setup() {
Serial.begin(9600);
Wire.begin(8);
Wire.onReceive(receiveEvent);
}
void loop() {
delay(1000);
}
void receiveEvent(int howManyBytes){
for(int iter=0; iter<howMany; iter++){
c = Serial.read();
Serial.print("c : ");
Serial.println(c);
}
}
Slave's Output
c : -1
c : -1
c : -1
It appears that three bytes are received but the data are not transmitted correctly. Any idea were there could be a mistake or a bug? Thanks!
Since you expect the data from the Wire, I think your slave should receive the data via Wire.read() instead of Serial.read().

Resources