I2C wird durch Stepper-Signale gestört

Ich hab da ein lästiges Problem. Und zwar kämpfe ich mit Interferenzen zwischen I2C-Signalen, die zusammen mit Schrittmotorsignalen über ein geshieldetes Kabel laufen.
Ich steure einen Nema-Schrittmotor via einem TB6600-Driver an. Über dieselbe Leitung lese ich Daten eines Kompassmoduls (grove - 3-axis digital compass v2.0) und printe sie auf ein 4x16 Display. Die I2C-Strecke ist durch einen ADUM1250 galvanisch getrennt
Doch leider passen dem I2C die Pulse des Steppers nicht. Der uC freezt schon nach ca. 2 Sekunden. Ich lese I2C jetzt schon nur jede Sekunde, doch das nützt nichts.

Getrennt funktionieren sowohl der Steppermotor, als auch das Kompassmodul einwandfrei. Ich bräuchte wohl wie ein Timing zwischen den zwei Signalen, oder, dass I2C stummgeschaltet wird, wenn der Stepper dreht. Denn noch ein zusätzliches Kabel wäre overkill.
Kennt jemand dieses Problem?


#include <LiquidCrystal.h>
#include <AccelStepper.h>
#include <EEPROM.h>  // Add EEPROM library
#include <Arduino.h>
#include <Wire.h>
// libraries
#include "bmm150.h"
#include "bmm150_defs.h"

BMM150 bmm = BMM150();

LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

//AccelStepper stepper; // Defaults to AccelStepper::FULL4WIRE (4 pins) on 2, 3, 4, 5

const int dirPin = 2;
const int stepPin = 3;
#define motorInterfaceType 1

AccelStepper myStepper(motorInterfaceType, stepPin, dirPin);

long int Pot = A0;
long int Pot2 = A1;
long int PotVal;
long int PotVal2;
long int Val;
long int Val2;
long int TargetStep;
int EndSwitch = 13;
int enablePin = 10;
long NewPos;
long NewPos2;
long OldPos = 0;
long OldPos2 = 0;
char txtBuf[10];
char txtBuf2[10];
char txtBuf3[10];

void updateDisplay(long target, long current, float heading);

void setup() {

  pinMode(Pot, INPUT);
  pinMode(Pot2, INPUT);
  pinMode(enablePin, OUTPUT);
  pinMode(EndSwitch, INPUT_PULLUP);
  Serial.begin(9600);

  digitalWrite(enablePin, HIGH);

  if (bmm.initialize() == BMM150_E_ID_NOT_CONFORM) {
    Serial.println("Chip ID can not read!");
    while (1)
      ;
  } else {
    Serial.println("Initialize done!");
  }

  digitalWrite(enablePin, HIGH);

  lcd.begin(16, 4);

  lcd.setCursor(0, 0);

  // Retrieve last position from EEPROM (address 0-3)
  long savedPosition;
  EEPROM.get(0, savedPosition);

  myStepper.setCurrentPosition(savedPosition);

  myStepper.setMaxSpeed(1000);
  myStepper.setAcceleration(50);
  myStepper.setSpeed(700);



  delay(1000);
  lcd.clear();
}

void loop() {

  unsigned long currentMillis = millis();
  static unsigned long lastI2CUpdate = 0;
  static unsigned long lastDisplayUpdate = 0;
  static float headingDegrees = 0;

  NewPos = analogRead(Pot);  // read the Value of Potentiometer

  if ((NewPos - OldPos > 10) || (OldPos - NewPos > 10)) {  // only true if position of potentiometer has changed
    PotVal = (analogRead(Pot));
    OldPos = NewPos;
  }

  NewPos2 = analogRead(Pot2);                                // read the Value of Potentiometer2
  if ((NewPos2 - OldPos2 > 5) || (OldPos2 - NewPos2 > 5)) {  // only true if position of potentiometer has changed
    PotVal2 = (analogRead(Pot2));

    OldPos2 = NewPos2;
  }

  Val = (PotVal * 2);
  TargetStep = Val + PotVal2;

  // Get current position
  long int current = myStepper.currentPosition();



  // STEPPER MOVEMENT - non-blocking, only move a few steps per loop
  if (abs(TargetStep - myStepper.currentPosition()) > 0) {
    digitalWrite(enablePin, LOW);
    myStepper.moveTo(TargetStep);
    myStepper.run();  // Run only one step
  } else {
    EEPROM.put(0, myStepper.currentPosition());
    digitalWrite(enablePin, HIGH);
  }
  



// Only read compass every 1000ms, not every loop cycle
if (currentMillis - lastI2CUpdate >= 1000) {
  bmm150_mag_data value;
  bmm.read_mag_data();
  value.x = bmm.raw_mag_data.raw_datax;
  value.y = bmm.raw_mag_data.raw_datay;
  value.z = bmm.raw_mag_data.raw_dataz;
  
  // Calculate heading
  float xyHeading = atan2(value.x, value.y);
  float heading = xyHeading;
  if (heading < 0) heading += 2 * PI;
  if (heading > 2 * PI) heading -= 2 * PI;
  float headingDegrees = heading * 180 / M_PI;
  
      lastI2CUpdate = currentMillis;
  }
  
  // Update display - every 1000ms
  if (currentMillis - lastDisplayUpdate >= 1000) {
    updateDisplay(TargetStep, myStepper.currentPosition(), headingDegrees);
    lastDisplayUpdate = currentMillis;
  }
}

void updateDisplay(long target, long current, float heading) {
  // Clear the display first to avoid artifacts

  lcd.clear();
  // First row
  lcd.setCursor(0, 0);
  lcd.print("Target:");
  sprintf(txtBuf, "%5ld", target);
  lcd.setCursor(0, 1);
  lcd.print(txtBuf);
  
  // Second row
  lcd.setCursor(4, 2);
  lcd.print("Current:");
  sprintf(txtBuf2, "%5ld", current);
  lcd.setCursor(4, 3);
  lcd.print(txtBuf2);
  
  // Third row 
  lcd.setCursor(10, 0);
  lcd.print("Heading:");
  dtostrf(heading, 5, 1, txtBuf3);
  lcd.setCursor(10, 1);
  lcd.print(txtBuf3);
}

Im englischen Teil des Forum müssen die Beiträge und Diskussionen in englischer Sprache verfasst werden. Deswegen wurde diese Diskussion in den deutschen Teil des Forums verschoben.

mfg ein Moderator.

Wie lang ist diese Leitung?

Ca. 10 Meter

I2C ist für Distancen bis 50cm ausgelegt.

Schau mal hier: Verlängerung der I2C Leitung - #77 by fony damit könnte es gehen.

Aber wenn ich den Stepper wegnehme, kommen die I2C-Signale sauber durch

Das ist ausserhalb der Norm.
Es gibt auch Leute, die haben mit CAT5e 50 Mtr I2C überbrückt.

Die würden aber nicht auf die Idee kommen, da einen Stepper im gleichen Kabel zu steuern.

Dafür gibt es Extender!!!

In deinem Fall würde ich empfehlen auch mit den Extendern eine weitere Leitung zu verwenden. Alternativ den Versuch mit einem Netzwerkkabel durchführen, da hier jedes Kabel einzeln geschirmt ist.
Dabei wichtig, den Schirm nur einseitig auflegen.

10m, dann hast du verdammt viel glück, versuch Lotto spielen :wink:
Auch wenn du Extender willst nehmen, wurde ich nicht ein Kabel nutzen. Mit CAT8 könnte das funktionieren, die Abschirmung nur auf einer Seite erden == mit GND verbinden.

Wie meinst Du das?

Statt 2 Kabel zu nutzen, kann man ein Netzwerkkabel nutzen, da hier genug Adern vorhanden sind. Jede Ader für sich abgeschirmt, damit werden gegenseitige Störungen weitestgehend verhindert.

Er meint wohl Paarabschirmung. Denkt ihr ich könnte über ein Cat7 mit Paar-Schirmung und Gesamtschirm die Stepper-Signale und eine I2C-Leitung (inkl. Extender) zusammen übertragen?

Was hat Dir an #7 nicht gefallen?

Provokative Frage:

Warum wird in der Industrie eher RS485 genutzt als I2C?

(Und nein: Die Antwort kenne ich schon!)

Ich verstehs nur nicht ganz. Meint er partout kein I2C zusammen mit Steppersignalen durch ein Cat Kabel, oder wenn dann mit einem Extender?

Nein.
Partout kein I2C über mehr als das, was die Spec vorsieht!
Schau mal 7.5.
Was fällt Dir auf?

Also das heisst I2C möglich über ein pair geshieldetes CAT-Kabel sofern I2C mit Extender?

I2C nicht mehr als 50cm.
Alles darüber mit Extender.
Da ist dann auch egal, ob es sich um (s)ftp handelt.

Ja, das hab ich geckeckt. Aber sind Steppersignale zusammen mit I2C inkl Expander über ein CAT mit pair geshieldeten Adern, also I2C geshieldet und Stepper geshieldet möglich?

Versuche es doch mal.
Es ist nicht sicher ob es sauber funktioniert, da es verschiedene Probleme geben kann.
Es gibt aber deutlich mehr Wege, die besser funktionieren.

Warum überhaubt das Steppersignal über die 10m schicken ?