I2C Communication blocks code?

Hello guys,

im new in the field of programming and just started my second project.
I want to read a dial gauge, compile the reading and then send it to another arduino.
The sketch did work perfectly fine and i had tested the communication with an arduino nano as slave and a mega as master. The mega received the Measured value from the nano.

Now i added another nano as slave aswell as a display. Everything communicates and works, but now my measurement sketch from the first nano is doing some weird thing wich i do not understand yet.

First problem:
The whole structure works without the mesurement nano, when i plug it into the ic2 the orther slaves start doing weird stuff and nothing works anyore.
When i comment out the whole nano code (wich i provide futher down) and just set a value, the whole system works perfectly finde and everythig communicates. So my conclusion is that is has something to do with my code.
I tried different things and found that it has something to do with the code between line 44 and 60. But i do not know why this part of the code, wich previously worked and didnt affect the i2c, is doing problems now.

Second Problem:
If i write a serial print in line 42 the mesurement is beeing printed, and it has the right value.
If i write the same print command in line 61 or futher down it does not print any. And i have no cunclusion why this happens.

Can somebody here give me a few hints what i am missing or how i can track down the root cause for my problems ?

Thanks in advance if somebody is willing the take his time and energy to take a look into this code

/*
 Name:    Messuhr.ino
 Created: 05.02.2022 12:45:12
 Author:  Marvin Poetter
*/

/*
 Dieser Scetch ist für das Auslesen der Messuhr, das Wandeln in das richtige Format und die 
 übertragung des Messwertes an den Master 
*/

#include <Wire.h>

/*Pin deklaration input & output */
int dialgauge_o_request = 4;    // Request pin (D4) (weiß)
int dialgauge_i_data = 3;       // Data pin (D3) (schwarz)
int dialgauge_i_clock = 2;      // Clock pin (D2) (rot)

/* deklaration interne Variablen */
boolean dialgauge_gv_raw_data[51];           // Array Buffer zum einlesen der Rohdaten 
int dialgauge_gv_tenthousand;                // Hilfsvariable 10 mm Wertigkeit
int dialgauge_gv_thousand;                   // Hilfsvaribale 1 mm Wertigkeit
int dialgauge_gv_hundred;                    // Hilfsvariable 0,1 mm Wertigkeit
int dialgauge_gv_ten;                        // Hilfsvariable 0,01 mm Wertigkeit
int dialgauge_gv_one;                        // Hilfsvariable 0,001 mm Wertigkeit
int dialgauge_gv_value;                      // Variable fertiger Messwert (Achtung int / Kommastelle um 3 nach rechts verschoben)

void setup() {

    Wire.begin(20);                             // Starten der I2C Kommunikation 
    Wire.onRequest(requestEvent);               // ruft bei eingehendem reqest des Masters die Funktion auf
    Serial.begin(9600);                         // nur zum debuggen benötigt

    pinMode(dialgauge_o_request, OUTPUT);       // Pin als output definieren
    pinMode(dialgauge_i_clock, INPUT_PULLUP);   // Pin als input definieren und internen Pullup zuschalten
    pinMode(dialgauge_i_data, INPUT_PULLUP);    // Pin als input definieren und internen Pullup zuschalten
    digitalWrite(dialgauge_o_request, LOW);     // initial output mit low beschalten (definierten Zustand herstellen)
}

void loop()
{
    
    digitalWrite(dialgauge_o_request, HIGH);        // durch nachgeschalteten Transistor den request pin der Uhr auf Masse ziehen um Übertragung zu starten
    for (int i = 0; i < 52; i++)                    // Schleife um nacheinander alle 52 Bit der Messuhr einzulesen
    {
        while (digitalRead(dialgauge_i_clock) == LOW) {}    // leere schleife um low zustand der Clock abzuwarten

        while (digitalRead(dialgauge_i_clock) == HIGH) {}   // leere Schleife um high Zustand abzuwarten

                                                            // Sobald Signalwechsel von high auf low wird einmalig der Zustand auf Data eingelesen
        if (digitalRead(dialgauge_i_data) == HIGH)
        {
            dialgauge_gv_raw_data[i] = 1;
        }

        if (digitalRead(dialgauge_i_data) == LOW)
        {
            dialgauge_gv_raw_data[i] = 0;
        }
    }
    
    /*
     Auswerten der eben eingelesenen Rohdaten
     Die Wertigkeit der einzelnen bits werden hier auf Hilfsvarablen zusammengerechnet.
     Am Ende alle Hilfsvariablen zu fertigem Messwert zusammensetzen. 
     Zum einfacheren Übertragen wird der Wert nicht als Float dagestellt sondern als Integer 
     mit einer Kommaverschiebung um 3 Stellen nach rechts, dies muss auf dem Pully spaeter 
     beruecksichtigt werden
    */

    dialgauge_gv_tenthousand = 0;
    dialgauge_gv_tenthousand = dialgauge_gv_raw_data[24] * 1 * 10000;
    dialgauge_gv_tenthousand = dialgauge_gv_tenthousand + dialgauge_gv_raw_data[25] * 2 * 10000;
    dialgauge_gv_tenthousand = dialgauge_gv_tenthousand + dialgauge_gv_raw_data[26] * 4 * 10000;
    dialgauge_gv_tenthousand = dialgauge_gv_tenthousand + dialgauge_gv_raw_data[27] * 8 * 10000;

    dialgauge_gv_thousand = 0;
    dialgauge_gv_thousand = dialgauge_gv_raw_data[28] * 1 * 1000;
    dialgauge_gv_thousand = dialgauge_gv_thousand + dialgauge_gv_raw_data[29] * 2 * 1000;
    dialgauge_gv_thousand = dialgauge_gv_thousand + dialgauge_gv_raw_data[30] * 4 * 1000;
    dialgauge_gv_thousand = dialgauge_gv_thousand + dialgauge_gv_raw_data[31] * 8 * 1000;

    dialgauge_gv_hundred = 0;
    dialgauge_gv_hundred = dialgauge_gv_raw_data[32] * 1 * 100;
    dialgauge_gv_hundred = dialgauge_gv_hundred + dialgauge_gv_raw_data[33] * 2 * 100;
    dialgauge_gv_hundred = dialgauge_gv_hundred + dialgauge_gv_raw_data[34] * 4 * 100;
    dialgauge_gv_hundred = dialgauge_gv_hundred + dialgauge_gv_raw_data[35] * 8 * 100;

    dialgauge_gv_ten = 0;
    dialgauge_gv_ten = dialgauge_gv_raw_data[36] * 1 * 10;
    dialgauge_gv_ten = dialgauge_gv_ten + dialgauge_gv_raw_data[37] * 2 * 10;
    dialgauge_gv_ten = dialgauge_gv_ten + dialgauge_gv_raw_data[38] * 4 * 10;
    dialgauge_gv_ten = dialgauge_gv_ten + dialgauge_gv_raw_data[39] * 8 * 10;

    dialgauge_gv_one = 0;
    dialgauge_gv_one = dialgauge_gv_raw_data[40] * 1 * 1;
    dialgauge_gv_one = dialgauge_gv_one + dialgauge_gv_raw_data[41] * 2 * 1;
    dialgauge_gv_one = dialgauge_gv_one + dialgauge_gv_raw_data[42] * 4 * 1;
    dialgauge_gv_one = dialgauge_gv_one + dialgauge_gv_raw_data[43] * 8 * 1;

    dialgauge_gv_value = 0;
    dialgauge_gv_value = dialgauge_gv_tenthousand + dialgauge_gv_thousand + dialgauge_gv_hundred + dialgauge_gv_ten + dialgauge_gv_one;
    dialgauge_gv_value=500;
    Serial.println(dialgauge_gv_value);

  
}



void requestEvent()
{
    byte buffer[2];                         //teilt das int in 2x8bit
    buffer[0] = lowByte(dialgauge_gv_value);        //da per i2c immer nur 8bit gesendet werden können
    buffer[1] = highByte(dialgauge_gv_value);

    Wire.write(buffer, 2);
}

[quote="mpoetter, post:1, topic:991980"]
Now i added another nano as slave aswell as a display.[/quote]

so you have the MEGA as master (controller ) and two Nanos as slaves?
did you provide different I2C addresses for the nanos? that's the parameter you pass in
Wire.begin(20); // <=== 7-bit slave address is 20

yes

Mega as Master
2 Nanos
1 Disyplay

everyone has an unique adresse and the communication between all works, when i do not use the code from above or respectively comment out the for and while loops

with such a definition,

index goes from 0 to 50 (which is 51 elements)

but you use

    for (int i = 0; i < 52; i++)                    // Schleife um nacheinander alle 52 Bit der Messuhr einzulesen

so i will go to 51 and so will overwrite some memory when you modify

dialgauge_gv_raw_data[i]

I can't speak on whether it'll solve your current problems, but I do immediately see some issues with your code.

The onRequest callback is executed in an interrupt context so you should observe proper care. Variables accessed from within the ISR (interrupt service routine) should be declared as volatile, to instruct the compiler to not optimize them away even though they do not appear in the regular call tree. Like this:

volatile int dialgauge_gv_value= 4;

Furthermore the code being executed outside the ISR can be interrupted at any time, even when modifying variables, so you should make sure to disable interrupts when modifying variables accessed from within the ISR context. You can do this by using the noInterrupts() and interrupts() functions. Like this:

noInterrupts();
dialgauge_gv_value = 0;
dialgauge_gv_value = dialgauge_gv_tenthousand + dialgauge_gv_thousand + dialgauge_gv_hundred + dialgauge_gv_ten + dialgauge_gv_one;
dialgauge_gv_value=500;
interrupts();

Can you please give a link to your dial gauge?

thank you, i will test if the other problems resolve when i get this done

thank you, makes sense to disable the interupts in certain moments. I will test this and read into "volatile" because i do not really know anything about this.

sure
https://shop.mitutoyo.de/web/mitutoyo/de_DE/mitutoyo/1300442458734/ID-C112XB%20DIGIMATIC%20Messuhr/$catalogue/mitutoyoData/PR/543-390/index.xhtml

Its this one wich i pluged the connection wire into, used a small transistor to get it working on the arduino. If you like i can provide a simple fritzing circuit diagram how i wired it, and a diagram how the dial gauge protocol is build up

Please, provide. That's the thing I need.

Don't bother with the Fritzing diagram. 99% of the time, it's an unreadable mess. Make a pen and paper or computer art sketch.

hold on i thing i might have an idea what the root cause is.
On the mega (master) i only send data to the slaves when the data changes, so its not that ofen (>1s) .
But i do not have a routine to request the data vom the measurent nano, so the request is just in the loop.
Could it be that the mega sends so much requests, that the code on the measurement nano has not enough time for beein executed, because its gets so much interupted from the requests ?

its in german but the pictures should be explaination enough.

https://fablab-wiki.fsg-preetz.de/index.php?title=Digitale_Messuhren_mit_dem_PC_auslesen

https://fablab-wiki.fsg-preetz.de/index.php?title=Digitale_Messuhren_mit_dem_PC_auslesen

it is in german but the pictures should explain everything

@mpoetter
I would use the following codes to convert the Timing Chart of Fig-1 of the dial gauge.


#define CK 2
#define DATA 3
#define REQ 4

byte dialgauge_gv_raw_data[52] = {0};
long long myData = 0;  //64-bit
int i = 0;

void setup()
{
  pinMode(CK, INPUT);
  pinMode(DATA, INPUT_PULLUP);
  digitalWrite(REQ, OUTPUT);
  digitalWrite(REQ, HIGH);
  delay(10);
  //---------------------------
  digitalWrite(REQ, LOW);
  delayMicroseconds(400);
  digitalWrite(REQ, HIGH);
  //---------------------------
  for (int i = 0; i < 52; i++)
  {
    while (digitalRead(CK) != LOW)
    {
      ;
    }
    delayMicroseconds(100);
    bitWrite(myData, i, digitalRead(DATA)); //myData holds 52-bits (myData51 - myData0)
    while (digitalRead(CK) != HIGH)
    {
      ;
    }
  }
}

void loop() 
{

}

Figure-1:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.