Integer with I2C between arduinos?

Hello community of arduino, I am working on a project to measure voltage and frequency, I have 2 arduinos connected by I2C to each other, with one I control the screen and with the other measured frequency, at the moment I have only managed to measure frequency using a detector zero crossing "H11AA1", and I show it by the arduino ide serial monitor, the question is that I want to use that frequency value to show it on a Touch screen 320x240qvt, which I am controlling with another arduino MEGA that is the master of the system, and I send the data of the arduino SLAVE (with which I am measuring frequency) to the teacher, but I can not print the correct value on the screen, but I print values ​​between 0 and 255, I have been investigating how send whole data by I2C protocol between arduino, but I can not make it work and data appear as I see them on the serial monitor, in advance thank you very much for reading me and if anyone can help me I would be very grateful to that person.

I attach the image in which the code on the left is the mestro and the one on the right is the slave:

https://1drv.ms/u/s!AoWVYNNzZXkmtDsu3jJPqm3TvNj7

Master arduino code:

 #include <UTFT.h> // UTFT library to draw the screen
#include <URTouch.h> // Library for the Touch
#include <Wire.h> // Library for I2C Communication

extern uint8_t BigFont [];

UTFT myGLCD (ILI9341_16,38,39,40,41); // Declare the controller of our screen

int frequency = 0;

void setup () {
myGLCD.InitLCD ();
myGLCD.clrScr ();
myGLCD.setFont (BigFont);
myGLCD.fillScr (VGA_WHITE);
Wire.begin (1);
}

void loop () {
  Wire.requestFrom (1,2);
  while (Wire.available ()) {
    frequency = int (Wire.read ()); // We transform the byte type to int
    myGLCD.setColor (VGA_BLACK);
    myGLCD.setBackColor (VGA_WHITE);
    myGLCD.print ("FREQUENCY:", 10, 140, 0);
    myGLCD.setColor (VGA_RED);
    myGLCD.printNumF (frequency, 1, 190, 140);
    myGLCD.print ("Hz", 270, 140, 0);
  }
}

Code of the slave arduino the one that measures frequency:

 #include <Wire.h>
int counter = 0;


void setup () {
  Wire.begin (1);
  Serial.begin (9600); // we initiate serial communication
  pinMode (2, INPUT);
  attachInterrupt (0, period, RISING);
  Wire.onRequest (requestEvent);
}

void loop () {
 delay (480);
 Serial.println (counter);
 counter = 0;
}

void requestEvent () {
  Wire.write (counter);
  }

void period () {
  counter ++;
  }

link of the video of how the data appear on the Touch screen:

[Microsoft OneDrive - Access files anywhere. Create docs with free Office Online.[/ url]](https://1drv.ms/v/s! AoWVYNNzZXkmtDzDD5raXg6nEY1n)

You will need to send the integer as two bytes, not as an int.

At the receiving end, read the two bytes and combine them in an int.

Can't help further as I would have to make a setup to test.

Please clarify the meanings of the following:

1. You have 2 arduinos. Are they UNOs or what?
2. You have a screen. Is it the screen of the of the Monitor with which one arduino (arduino-1) connected or arduino-2?

3. You have an ide serial monitor. Is it connected with arduino-1 or arduino-2. Is there any difference between this ide serial monitor and the screen of Step-2?

4. You have a Touch Screen. Is is connected with one of the arduinos? Which arduino is it?

5. You have an Arduino MEGA. Is it arduino-3? It is the Master of the 3-arduino system. Correct?

6. You have a teacher. who is this teacher arduino?

7. You have whole data. What is the data type of this whole data?

Please, be clear on your expression being careful about the correct usage of the punctuation marks of the English Language.

GolamMostafa:

Sorry, I really do not speak English very well, my native language is Spanish, I use the google translator to be able to communicate with you, since this same post I did in Spanish but apparently there are not many users who know about it, They have not answered me, that's why I resorted to posting it in English.

Answering your questions:

  • I have 2 MEGA arduinos, one Master and another Slave.
    -The UTFT 320X240QVT screen is connected to the Arduino Maestro, the arduino slave is responsible for measuring the frequency, and I can see that same in the Serial Monitor of the Arduino slave.
    -The frequency data of the slave arduino, are int type.
  • Both arduinos are MEGA 2560 R3.

sterretje:

Could you help me edit my code correctly?

Some like the I2C_Anything: Gammon Forum : Electronics : Microprocessors : I2C - Two-Wire Peripheral Interface - for Arduino.
Others use an array or a struct or a pointer to a variable.

Thanks Koepel, then with the Wire.h library, can not send and receive data of the whole type ?.

Now, how would it be to send the types of data in my code, using the library you mention, could you help me?

The Wire library can send and receive more than one byte with "an array or a struct or a pointer to a variable" as I wrote.
The I2C_Anything can make it easier.

Did you see the example of the Master and the Slave how the I2C_Anything is used ?

Koepel:

I am still reading about that library, I still do not make examples, thanks for your help, I would be grateful if you could help me modify mycode, I had not worked with I2C before.

You could add the "I2C_Anything.h" to your project or make a "I2C_Anything" folder in the user "libraries" folder and copy it into that folder.

To add it to your project, there is a drop down menu to add a new file in the Arduino IDE, in the upper right corner. Call it "I2C_Anything.h" and copy the contents into it.
I'm not sure if you have to add a include to your sketch, but I think you do:

#include "I2C_Anything.h"

In the Master read two bytes, and check if two bytes are received. Use I2C_Anything to read the integer 'frequency'.

  Wire.requestFrom (1,2);
  if( Wire.available() == 2)
  {
    I2C_readAnything( frequency);
    ...
    myGLCD.printNumF (frequency, 1, 190, 140);
    ...

  }
  else
  {
    Serial.println( "I2C request fail");
  }

In the Slave, do the same. Add the "I2C_Anything.h" and include it.
Write the data using I2C_Anything. Make the counter also 'volatile'.

volatile int counter;

...

void requestEvent() 
{
  I2C_writeAnything( counter);
}

@Campax2

Thank you for responding to my queries. You have acceptable access to communicative and written English. Therefore, from henceforth, please don't rely on Google to have your post translated into English. Just take sometimes to connect the language elements (subject, object, pronoun, ..) using few appropriate prepositions; read it loudly and be sure that you have understood what you have wanted to convey. Your post will be OK!

Now coming to your I2C issue:
1. The output of your zero-crossing detector must be connected with one of the following pins of MEGA-2 (the Slave) : 2(INT4), 3(INT5); and, certainly not Pin-0.

2 The recommended syntax of attachInterrupt(); function is:
attachInterrupt(digitalPinToInterrupt(Pin), ISR_Name, Trigger_Level);

3. In the Slave Codes, you may take care of the following instructions of the Wire.onRequest() ISR

void requestEvent () 
{
 Wire.write (highByte(counter)); //I2C is a byte oriented system; send upper 8-bit of counter value
 Wire.write(lowByte(counter));   //send lower 8-bit of the counter value

}

4. In the Master Codes, you may take care of the following instructions:

Wire.requestFrom (0b0000001,2);  //expecting 2-byte data from slave; I prefer to key 7-bit address
while (Wire.available () != 2)
   ;                                         //you must wait until 2-byte have arrived from Slave
 
frequency = Wire.read ();  // retrieving upper 8-bit 
frequency = (frequency <<8) + Wire.read();     //frequency contains 16-bit value

@GolamMostafa, there is no such thing as waiting after a Wire.requestFrom(). You should not do this:

while (Wire.available () != 2)
   ;                                         //you must wait until 2-byte have arrived from Slave

@Campax2, you can use the I2C_Anything or split the integer into two bytes as GolamMostafa shows. The Arduino has a number of small functions to split and combine bytes and bits.
highByte()
lowByte()
word()
For myself, I don't use I2C_Anything, and I don't use splitting the bytes, I transfer a 'struct'.

@GolamMostafa, there is no such thing as waiting after a Wire.requestFrom(). You should not do this:

I have the following reasons to say so:
1. The 2nd argument of Wire.requestFrom(deviceAddress, n) is a pre-negotiated value with the slave. The designer knows (must know) the number of data bytes the Slave will send to the Master after arriving at the Wire.onRequest() ISR. In the present case, it is one word (2-byte data).

2. In the Wire.onRequest() ISR, the Slave transmits data byte-by-byte, which is not an instant transmission.

3. At the Master side, the Master must receive data on polling (as it is not configured to work as Slave) just after the issuance of the command -- Wire.requestFrom(deviceAddress, 2).

4. Because the data are yet to arrive from the slave, I prefer to wait and let the buffer get filled up with the requested amount of data bytes.

5. In the command (while(Wire.available() != 2), I am testing a condition; so, I have preferred to wait until the condition is satisfied.

6. When someone using the command while(Wire.available()), he is checking the TRUE/FALSE condition of a boolean variable. One danger is here and it is that the condition will stand TRUE even when 1-byte data has arrived; whereas, the expected number of data byte are 2.

I hope you will give a thought on my reasoning; I could be incorrect and even wrong!

@GolamMostafa, I'm sorry, but I have to correct you, it is not like that.

When the Master requests data from a Slave, the Slave acknowledges to its address. After that, the Master gives the clock, the acknowledge after each databyte (but not the last one) and the stop. The Slave does not know how many bytes are being requested.

In the Wire.onRequest() in the Slave, data is written to a buffer. The actual transferring of the bytes in done in a interrupt after that.

The Wire.endTransmission() and Wire.requestFrom() wait until the complete I2C transaction has finished.

After a Wire.requestFrom(), the Wire.available() returns the number of the bytes in a buffer.

The while-loop to wait for two bytes is not needed. It does no good, but it can do harm.
When the Slave is not connected or when the Wire library is able to detect a problem then the Wire.available() might return zero. With that while-loop, the sketch will be halted.

Thank you @Koepel.

As design documentation (not the Wire.h, Wire.cpp) of the Wire.h library is not available to us, we make reasonable assumptions (based on our experiences and understanding) on the functional mechanics of the Arduino TWI Bus Commands.

To grasp the meaning of your post, I am planning to design an experimental study using Register Level Instructions for the Arduino commands -- Wire.requestFrom()arg1, arg2) and Wire.onRequest(). I will post the setup and result (once ready) in this thread for review.

BTW: I have made an experimental study (using Register Level Instructions) on the issue of the parameters based on which the Wire.onReceive() ISR is called upon. It can be viewed in this link. I would highly appreciate receiving review on it.

Understanding Master in Receive Mode and Slave in Transmit Mode using Wire.requestFrom() and Wire.onRequest Functions. (Slave sends 0x12, 0x56)

(1) Master acquires the TWI Bus and executes the Wire.requestFrom(slaveAddress, 2); instruction.

(2) The Control Byte (7-bit SLA + 1-bit Read (LH)) is transferred to Slave via TWDR Register for which the Master generates the 8 SCL pulses.

(3) The Slave recognizes its own address, and it generates 1-bit ACK signal which the master samples by generating one more clock pulse on the SCL line.

(4) Assume that TWI transaction is successful, appropriate status codes (0x40 at the Master, 0xA8 at the Slave) are generated to move with the next transaction.

(5) What is about second argument of Wire.requestFrom(slaveAddress, 2)? Is it transmitted to the Slave? The answer is 'no' from my understanding. I think that it is a pre-set value which has been negotiated at the 'program design time' relating to the number of data bytes the Slave will transmit to the Master in response to request command. It works as a counter for the Master in order to be sure that 2-byte data are received.

(6) After receiving the request command, the Slave immediately enters into Wire.onRequest() ISR, and it writes 2-byte data into buffer.

(7) The data of the buffer are transmitted to the Master by the Slave before leaving the ISR. (I could not conceive the mechanism of how it is done in the Wire.h library. I have got some understanding by playing with the Register Level Instructions -- given in the next post.)

(8) Master Codes:

#include <Wire.h>
#include<LiquidCrystal.h>
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);

#define slaveAddress 0b0000111 //0x07

void setup() 
{
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("OK!");
  Wire.begin();
  pinMode(13, OUTPUT);

  Wire.requestFrom(slaveAddress, 2);  //2 is the pre-negotiated value with slave/slvw program
  while(Wire.available() != 2)
   ;                                        //wait until buffer is ready with 2-byte data
 byte x = Wire.read();            //getting data byte from implicitly defined buffer into user defined variable
 byte y = Wire.read();

  lcd.setCursor(0, 1);
  lcd.print(x, HEX);
  lcd.print(y, HEX);
}

void loop()
{
  digitalWrite(13, !digitalRead(13));
  delay(1000); 
}

(9) Slave Codes:

#include <Wire.h>
#include<LiquidCrystal.h>
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);

#define slaveAddress 0b0000111 //0x07
 
void setup() 
{
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("OK!");
  Wire.begin(0b0000111);
  pinMode(13, OUTPUT);

  Wire.onRequest(sendToMaster);
}

void loop() 
{
  digitalWrite(13, !digitalRead(13));
  delay(1000);
}

void sendToMaster()
{
  Wire.write (0x12);
  Wire.write (0x56);
}

Understanding Master in Receive Mode and Slave in Transmit Mode using Register Level Instruction (Polling Strategy). (Slave sends 0x12, 0x56)

Master Codes:

#include<LiquidCrystal.h>
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);

void setup() 
{
  cli();                    //all interrupts are disabled
  TWBR = 0x02;
  TWSR = 0x02;     //TWI Bus speed = 200 kHz
  
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  pinMode(13, OUTPUT);
 
  TWCR = 0b10100100; //no SCL is ON ; (TWCR = TWINT TWEA TWSTA TWSTO TWWC TWEN X TWIE)  
  while(bitRead(TWCR,7)!= HIGH)
      ;
  lcd.print((TWSR & 0b11111000),HEX); //START condition asserted on TWI Bus; sts code = 0x08
  //--------------------------------------

  TWDR = 0b00001111; //slaveAddress = SLA+W-bit = 0b0000111 + 0 
  TWCR = 0b10000100; //
  while(bitRead(TWCR,7)!= HIGH) //data moving to Slave; SCL is being genrated by master
      ;                       //wait unti ACK comes
  lcd.print((TWSR & 0b11111000),HEX); //Slave has sent ACK; sts code 0x40
//-------------------------------------------------------

  TWCR = 0b11000100; 
  while(bitRead(TWCR,7)!= HIGH)
      ;                          //wait until data byte has arrivd from Slave
  lcd.print((TWSR & 0b11111000),HEX); //received data byte; sts code = 0x50

  byte z = TWDR;     //collect data byte (0x12) from TWDR register
  lcd.print(z, HEX); //show data on LCD
//-------------------------------------

  TWCR = 0b11000100; //
  while(bitRead(TWCR,7)!= HIGH)
      ;
  lcd.print((TWSR & 0b11111000),HEX);  //second data byte has arrived from Slave; stst code = 0x50

  byte z1 = TWDR;      //collect data byte 0x56
  lcd.print(z1, HEX);
//-------------------------------------
  sei();         //enable interrupt
} 

void loop() 
{
  digitalWrite(13, !digitalRead(13));
  delay(1000);
}

Slave Codes:

#include<LiquidCrystal.h>
LiquidCrystal lcd(2, 3, 4, 5, 6, 7);

void setup() 
{
  cli();                     //all interrupts are disabled
  TWBR = 0x02;
  TWSR = 0x02;               //TWI Bus speed : 200 kHz
  
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  pinMode(13, OUTPUT);

  TWAR = 0b00001110;   //7-bit slaveAddress + TWGCE-bit 
  TWCR = 0b11000100;   //TWCR = TWINT TWEA TWSTA TWSTO TWWC TWEN X TWIE
 
  while(bitRead(TWCR,7)!= HIGH)   //checking if the slveAddress has arrived
      ;
  lcd.print((TWSR & 0b11111000),HEX); //slave Address has arrived; it is indicated by sts code 0xA8
//--------------------------------------------
  TWDR = 0x12;          //Slave will transmit data byte 0x12
  TWCR = 0b11000100;    //Necessary condition (pls see data sheet)
  while(bitRead(TWCR,7)!= HIGH) //data is movong to Master by the SCL of Slave
      ;                        //wait until ACK comes from Master
  lcd.print((TWSR & 0b11111000),HEX); //ACK has come from master; the sts code is 0xB8
//----------------------------------------------------- 
  TWDR = 0x56;          //the second data byte
  TWCR = 0b11000100;   //
  while(bitRead(TWCR,7)!= HIGH)
      ;
  lcd.print((TWSR & 0b11111000),HEX); //ACK has come from Master; the sts code 0xB8
  //----------------------------------------------------
  sei();                              //interrupt is enabled to let the LED (L) blink
}
 
void loop() 
{
  digitalWrite(13, !digitalRead(13));
  delay(1000);
}

Well, I want to thank you for your help, the truth is that I did not understand much about the theory of sending and receiving bytes, but I will continue to investigate and in the same way I will test the codes that they left me, I hope my program can work and after that I will I'll confirm if the codes work for me.

GolamMostafa:
@Campax2

Thank you for responding to my queries. You have acceptable access to communicative and written English. Therefore, from henceforth, please don't rely on Google to have your post translated into English. Just take sometimes to connect the language elements (subject, object, pronoun, ..) using few appropriate prepositions; read it loudly and be sure that you have understood what you have wanted to convey. Your post will be OK!

Now coming to your I2C issue:
1. The output of your zero-crossing detector must be connected with one of the following pins of MEGA-2 (the Slave) : 2(INT4), 3(INT5); and, certainly not Pin-0.

2 The recommended syntax of attachInterrupt(); function is:
attachInterrupt(digitalPinToInterrupt(Pin), ISR_Name, Trigger_Level);

3. In the Slave Codes, you may take care of the following instructions of the Wire.onRequest() ISR

void requestEvent () 

{
Wire.write (highByte(counter)); //I2C is a byte oriented system; send upper 8-bit of counter value
Wire.write(lowByte(counter));   //send lower 8-bit of the counter value

}




**4.** In the Master Codes, you may take care of the following instructions:


Wire.requestFrom (0b0000001,2);  //expecting 2-byte data from slave; I prefer to key 7-bit address
while (Wire.available () != 2)
  ;                                         //you must wait until 2-byte have arrived from Slave

frequency = Wire.read ();  // retrieving upper 8-bit
frequency = (frequency <<8) + Wire.read();     //frequency contains 16-bit value

I tried the code that you left me, but it does not work, just throws me the value of "-257" on the UTFT screen, here I leave my codes, how they were:

SLAVE:

#include <Wire.h>
int contador = 0;

void setup(){
  Wire.begin(9);
  Serial.begin(9600); //iniciamos comunicacion serial
  pinMode(2, INPUT);
  attachInterrupt(0, periodo, FALLING);
  Wire.onRequest(requestEvent);
}

void loop(){ 
 delay(480);
 Serial.println(contador);
 contador = 0;
}

void requestEvent(){
  Wire.write (highByte(contador)); //I2C is a byte oriented system; send upper 8-bit of counter value
  Wire.write(lowByte(contador));   //send lower 8-bit of the counter value
  }

void periodo(){
  contador++;
  }

MASTER:

#include <UTFT.h>  //Librería UTFT para dibujar la pantalla
#include <URTouch.h> //Librería par el Touch
#include <Wire.h>  //Librería para Comunicación I2C

extern uint8_t BigFont[];

UTFT myGLCD (ILI9341_16,38,39,40,41); //Declaramos el controlador de nuestra pantalla

int frecuencia ;

void setup() {
myGLCD.InitLCD();
myGLCD.clrScr();
myGLCD.setFont(BigFont);
myGLCD.fillScr(VGA_WHITE);
Wire.begin();
}

void loop() {
  Wire.requestFrom(9,2);
  while(Wire.available() != 2){
    frecuencia = (Wire.read()); //Transformamos el tipo byte a int
    frecuencia = (frecuencia <<8) + Wire.read();
    myGLCD.setColor(VGA_BLACK);
    myGLCD.setBackColor(VGA_WHITE);
    myGLCD.print("FRECUENCIA:", 10, 140, 0);
    myGLCD.setColor(VGA_RED);
    myGLCD.printNumF(frecuencia, 1, 190, 140);
    myGLCD.print("Hz", 270, 140, 0);
    delay(500);
  }
}

"myGLCD.printNumF" is for a 'float' number.