【问题标题】:Arduino I²C freezes after startupArduino I²C 启动后冻结
【发布时间】:2025-12-18 01:55:01
【问题描述】:

我正在尝试I²C 设置,其中一个主 Arduino 控制两个从属。

我为 I²C 使用了两个 2000 欧姆的上拉电阻,所有电路板都是 Arduino Duemilanoves。 I²C 设置和控制设置在彼此断开连接时都能正常运行,但在连接后,只要调用第一个 wire.write 函数,Arduino 就会变得无响应。我停止接收串行消息,从 Arduinos 停止接收来自主机的消息,并且我失去了使用按钮打开和关闭系统的能力。

我尝试在每个wire.write 函数之后添加短暂的延迟,并使用了各种上拉电阻来尝试解决问题,但似乎没有任何效果。我该如何解决这个问题?

主密码:

#include <Wire.h>

int potPin1 = 0;    // Select the input pin for the potentiometer
int potPin2 = 1;
int potVal1;       // Variable to store the value coming from the sensor
int potVal2;
int times=0;   // All the below variables are used to control an on-off button
int state=0;
int lastState=0;
boolean pot=false;

void setup()
{
    pinMode(13, OUTPUT);  //LED that turns on when system is activated
    pinMode(3, INPUT);    //Button that turns on system
    Serial.begin(9600);
    Wire.begin();
}

void loop(){
    state=digitalRead(3);
    if(state != lastState){
        if(state==HIGH){
            times++;
            Serial.println(times);
        }
        else{
            Serial.println("off");
        }
    }

    lastState=state;

    if(times%2 ==1)
    {
        turnPotOn();
    }
    else
    {
        turnPotOff();
    }

//到目前为止,循环中的所有代码都会在按下按钮时打开和关闭系统。 //以下代码对应于基于电位器读数的I²C。

    if(pot==true)
    {
        potVal1 = analogRead(potPin1);    // Read the value from the sensor
        potVal2 = analogRead(potPin2);

        if((potVal1>700) && (300<potVal2) && (potVal2<700))
        {
            arduino1_motor1();
        }
        else if ((potVal1<330) && (336<potVal2) && (potVal2<683))
        {
            arduino1_motor2();
        }
        else if ((potVal2>683) && (330<potVal1) && (potVal1<640))
        {
            arduino2_motor3();
        }
        else if ((potVal2<336) && (330<potVal1) && (potVal1<640))
        {
            arduino2_motor4();
        }
        else if ((potVal2<336) && (potVal1<330))
        {
            arduino12_motor24();
        }
        else if ((potVal2>683) && (potVal1>640))
        {
            arduino12_motor23();
        }
        else if ((potVal2>683) && (potVal1<640))
        {
            arduino11_motor23();
        }
        else if ((potVal2<336) && (potVal1>330))
        {
            arduino11_motor24();
        }
        else
        {
            arduino12_still();
        }
    }
    else
    {
        // arduino1_still();
        // arduino2_still();
        Serial.println("OFF");
    }
}

void turnPotOff()
{
    digitalWrite(13, LOW);
    pot=false;
}

void turnPotOn()
{
    digitalWrite(13, HIGH);
    pot=true;
}

void arduino1_motor1()
{
    Wire.beginTransmission(5);
    Wire.write('A');
    Wire.endTransmission();
    arduino2_still();
    Serial.println("A1 in M1 d");
}

void arduino1_motor2()
{
    Wire.beginTransmission(5);
    Wire.write('B');
    Wire.endTransmission();
    arduino2_still();
    Serial.println("A1 in m2 d");
}

void arduino12_still()
{
    arduino1_still();
    arduino2_still();
    Serial.println("A1 & A2 stl");
}

void arduino2_motor3()
{
    arduino1_still();
    Wire.beginTransmission(10);
    Wire.write('M3');
    Wire.endTransmission();
    Serial.println("A2 in M3 d");
}

void arduino2_motor4()
{
    arduino1_still();
    Wire.beginTransmission(10);
    Wire.write('D');
    Wire.endTransmission();
    Serial.println("A2 in M4 d");
}

void arduino12_motor24()
{
    Wire.beginTransmission(5);
    Wire.write('B');
    Wire.endTransmission();
    Wire.beginTransmission(10);
    Wire.write('D');
    Wire.endTransmission();
    Serial.println("A1 & A2 in M2 and M4 d");
}

void arduino12_motor23()
{
    Wire.beginTransmission(5);
    Wire.write('B');
    Wire.endTransmission();
    Wire.beginTransmission(10);
    Wire.write('C');
    Wire.endTransmission();
    Serial.println("A1 & A2 in M2 and M3 d");
}

void arduino11_motor24()
{
    Wire.beginTransmission(5);
    Wire.write('A');
    Wire.endTransmission();
    Wire.beginTransmission(10);
    Wire.write('D');
    Wire.endTransmission();
    Serial.println("A1 & A2 in M1 and M4 d");
}

void arduino11_motor23()
{
    Wire.beginTransmission(5);
    Wire.write('A');
    Wire.endTransmission();
    Wire.beginTransmission(5);
    Wire.write('C');
    Wire.endTransmission();
    Serial.println("A1 & A2 in M1 and M3 d");
}

void arduino1_still()
{
    Wire.beginTransmission(5);
    Wire.write('S');
    Wire.endTransmission();
}

void arduino2_still()
{
    Wire.beginTransmission(10);
    Wire.write('S');
    Wire.endTransmission();
}

从属 1 代码:

#include <Servo.h>
#include <Wire.h>

Servo myservo1;
Servo myservo2;

void setup()
{
    Serial.begin(9600);          //  setup serial
    myservo1.attach(2);
    myservo2.attach(3);
    Wire.begin(5);
    Wire.onReceive(receiveEvent);


}

void loop()
{
}

void receiveEvent(int howMany)
{
  while(Wire.available())
  {
    char v = Wire.read();

    if(v == 'A')
    {
      myservo1.write(0);
      myservo2.write(180);
      Serial.println("Arduino 1 in motor 1 direction");
    }
    else if(v == 'B')
    {
      myservo1.write(180);
      myservo2.write(0);
      Serial.println("Arduino 1 in motor 2 direction");
    }
    else
    {
      myservo1.write(90);
      myservo2.write(85);
      Serial.println("Arduino 1 still");
    }
  }
}

从站 2:

#include <Servo.h>
#include <Wire.h>

Servo myservo3;
Servo myservo4;

void setup()
{
    Serial.begin(9600);         // Setup serial
    myservo3.attach(2);
    myservo4.attach(3);
    Wire.begin(10);
    Wire.onReceive(receiveEvent);
}

void loop()
{
}

void receiveEvent(int howMany)
{
    while(Wire.available())
    {
        char v = Wire.read();

        if(v == 'C')
        {
            myservo3.write(0);
            myservo4.write(180);
            Serial.println("Arduino 2 in motor 3 direction");
        }
        else if(v == 'D')
        {
            myservo3.write(180);
            myservo4.write(0);
            Serial.println("Arduino 2 in motor 4 direction");
        }
        else
        {
            myservo3.write(90);
            myservo4.write(90);
            Serial.println("Arduino 2 still");
        }
    }
}

【问题讨论】:

  • 您是否可以使用示波器来确定电子信号完整性并排除硬件问题?
  • 我没有用示波器检查我的设置,但是我已经测试了没有附加组件(电位器、LED、按钮等)的 i2c 设置和没有 i2c 的附加组件,发现两者系统单独工作。
  • 你能说一下I2C从机地址是在哪里设置的吗?它们是否设置在硬件中?我会尝试删除其中一个 arduino 从站,并尝试让其中一个响应。
  • 我删除了一个从属服务器并运行了一个版本的主代码,可以在这里找到:Master Code With One Slave 我使用了与上面相同的从属 1 代码系统的问题是一样的,当wire.write函数被删除时它是有效的,当它们被包含时它是无效的。问题可能出在我使用的电线长度或电阻器的强度上吗?

标签: arduino


【解决方案1】:

“接收事件”在 ISR 中,在事件函数返回之前不会退出

顺便说一句,AVR 硬件将 I2C 总线保持在冻结状态,直到此事件退出,也称为时钟延长

哦,你猜怎么着,Wire 没有将 FIFO 变量声明为 volatile,所以即使他有 while (Wire.available()),这也会变成一个无限循环,因为 available() 永远不会改变,因为这一切都发生在中断和 rxBufferIndex 和 rxBufferLength 未声明为 volatile

http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_volatile

这是一种可能的原因

在这里插入对 Arduino 及其糟糕的库的愤怒咆哮

解决方案?用别的库,“Wire.h”借用的TWI实用程序,知道怎么用就可以直接用,很好用,一直在用。

【讨论】:

    【解决方案2】:

    这可能会对你有所帮助:

    好的,所以这将是一堵文字墙,我在发布之前已经意外关闭了一次标签,所以我可能听起来很生气,因为 Arduino 的这个“功能”真的很糟糕,如果它会花费你 $$您将 3.3v 设备插入其中。 您正在使用 Wire 库,它在 SDA 和 SCL 引脚上启用了非常糟糕的 20k 内部上拉。

    在每个 ARDUINO 上。您的情况是总上拉电阻现在被破坏(拧紧)。 您需要研究如何禁用内部上拉。我建议修改库。出于整体原因,这种控制永远不应该在软件中完成。 在所需的外部上拉上仔细检查他的数学。 Arduino上每个SCL/SDA管脚的电容应该是10pF。

    这是直接来自 ATMEGA 数据表的公式

    http://i.imgur.com/ZAByF.png

    这是 ATMEGA 数据表,请参阅第 21 节了解 I2C 部分

    http://www.atmel.com/Images/doc8161.pdf

    【讨论】:

    • 我不同意这一点。没有事实证据支持任何说法。
    【解决方案3】:

    不要尝试使用多个从属,而是首先使用单主和单从配置启动。并尽量保持程序简单。您创建诸如接收和发送到主/从的功能

    【讨论】:

      【解决方案4】:

      你不能在receiveEvent里面写

      receiveEvent 定义命令 那么master应该调用requestFrom并请求值,slave处理(requestEvent)并在那里使用write。

      即 1-主线。写入(命令名称)

      2- slave:处理(receiveEvent)并获取命令ID

      3- Master 发送 requestFrom

      4-slave 处理 (requestEvent) 并根据命令 ID 向 master 发送回复。

      【讨论】: