【问题标题】:How to write messages over the I2C bus on two different addresses using Arduino IDE?如何使用 Arduino IDE 通过 I2C 总线在两个不同的地址上写入消息?
【发布时间】:2021-01-26 00:57:01
【问题描述】:

我有一个由 nodeMCU(主)和 arduino nano(从)组成的主从设置。我想在两个不同的 I2C 地址上发送两种不同类型的数据。数据类型 1 是整数,数据类型 2 是字符。

我已经写了这两个代码,它们在某种程度上符合我的预期,但结果并不一致。

主控(nodeMCU):

#include <Wire.h>

void setup() {
 Serial.begin(9600); /* begin serial for debug */
 Wire.begin(5, 4); /* join i2c bus with SDA=D1 and SCL=D2 of NodeMCU */
}

void loop() {

 int r =5;
 Wire.beginTransmission(8); /* begin with device address 8 */
 Wire.write(r);  
 Wire.endTransmission();
  delay(100);
 String bod = "message";
 Wire.beginTransmission(9);
 Wire.write(bod.c_str());  
 Wire.endTransmission();
  delay(100);

}

奴隶(arduino nano)

#include <Wire.h>


void setup() {
  
 /* register request event */
 Serial.begin(9600);           /* start serial for debug */
}

void loop() {
 Wire.begin(8);                /* join i2c bus with address 8 */
 Wire.onReceive(receiveEvent1); /* register receive event */
 Wire.begin(9);                /* join i2c bus with address 9 */
 Wire.onReceive(receiveEvent2); 

 
}

// function that executes whenever data is received from master

void receiveEvent1(int howMany) {
 while (0 <Wire.available()) {
    int c = Wire.read();   
    /* receive byte as int */
    Serial.print(c);           /* print the int */
  }
 Serial.println();             /* to newline */
}

void receiveEvent2(char howMany) {
 while (0 <Wire.available()) {
   char d = Wire.read();   
    /* receive byte as a character */
    Serial.print(d);           /* print the character */
  }
 Serial.println();             /* to newline */
}

我得到的输出也会在短时间内停止:

5
message

5
5
5
10910111511597103101

5
10910111511597103101

message
5
message
5
10910111511597103101
10910111511597103101
10910111511597103101
5
message
message


message
5
message
message


message
5

预期的输出在那里,但不是以一致的方式,例如:

5
message
5
message
5
message

有没有办法得到这样的输出?有没有办法修复输出在短时间内停止?

【问题讨论】:

  • 不知道发生了什么(它似乎由于某种原因不同步 - 尝试发送相同类型的消息以确认?),但你在做什么? i2c slave 在每条消息后更改地址是非常奇怪的。
  • 我试图向从站获取两种不同类型的数据。我已经设法将它们分开发送。我在想我可以通过使用不同地址发送消息来做到这一点,就像某些传感器在 I2C 总线上使用不同地址一样。

标签: arduino i2c nodemcu master-slave arduino-c++


【解决方案1】:

您不应使用 2 个地址与单个从设备进行通信。相反,您应该使用一个地址,并指定您要发送的数据类型。

如何指定要发送的数据类型?

就像 Ben T 所说,您可以为此使用 JSON,但我认为这对您的应用程序来说有点矫枉过正。

需要更少字节来选择您正在传输的数据类型的更简单的实现是在软件方面定义 2 个不同的地址;一种用于接收整数,一种用于接收字符。

在您的主设备中,您将拥有如下内容:

// First sending the integer
Wire.beginTransmission(8); //slave address is 0x08
Wire.write(0); // this is your "propriatary" address for sending integers!
Wire.write(r); // write your integer
Wire.endTransmission();

// Then sending the characters
Wire.beginTransmission(8);
Wire.write(1); // this is the address for sending characters!
Wire.write(bod.c_str());
Wire.endTransmission();

在你的奴隶的setup() 函数中,你应该有类似的东西:

Wire.begin(8); // slave address
Wire.onReceive(dataReceived);

这就是回调dataReceived 的样子:

void dataReceived() {
    char address = Wire.read(); // get the "propriatary" address
    switch(address) {
        case 0: // receiving integers
            receiveEvent1();
            break;
        case 1: // receiving characters
            receiveEvent2();
            break;
        default:
            break; // if we received an invalid address, do nothing
    }
}

【讨论】:

    【解决方案2】:

    如果阅读在结束之前被切断,是不是意味着你不期待它? 确保主代码全部传输! 以后在slav中读取数据的时候确定全部拿到吗?

    while (Serial.available() > 0) { //Seri porttan gönderilmiş ama; henüz okunmamış tampon bellekte duran byte sayısını verir.
        // get the new byte:
        char inChar = (char)Serial.read();
        // add it to the inputString:
        inputString += inChar;
        // if the incoming character is a newline, set a flag so the main loop can
        // do something about it:
        if (inChar == '\n') {
          Serial.println(inputString);
          stringComplete = true;
        }
    

    您可以尝试像这样读取终止符和字符串!

    【讨论】:

      【解决方案3】:

      我想在两个不同的 I2C 地址上发送两种不同类型的数据。

      Arduino 的 Wire 库旨在为每个设备提供一个 I2C 地址。它的实现使用一组全局资源。这意味着如果您动态更改接收 Arduino 设备的地址,那么您还需要同步主设备以了解要使用的地址。

      将单个地址分配给从设备并让主设备指示正在发送的数据类型会更简单。这可以通过发送 JSON 或键/值对来完成。例如主机可以在任何整数之前发送前缀int:,在任何字符串之前发送str:。从机可以使用前缀来解释传输方式。

      解释输出

      10910111511597103101

      这是整数字符串message 的ASCII 字符。即 109、101、115、115、97、103、101

      这里receiveEvent1() 正在处理通过 I2C 总线发送的数据并将每个字节作为整数输出。

      loop() 中调用Wire.begin()Wire.onReceive() 将更改全局TwoWire singleton 中的设置。底层twi library 也有一组资源。

      更改地址和接收处理程序(在loop() 中重复)的结果是一组竞争条件和两个接收处理程序的未定义使用。

      这似乎包括receiveEvent1() 处理“5”和receiveEvent2() 按您的意图处理“消息”。它还包括receiveEvent1() 处理“消息”,从而产生数字序列。

      明显的空行可能是receiveEvent2() 处理“5”,因此可能输出了一个不可打印的 ASCII ENQ(查询)字符。也可能有一段时间没有正确配置处理程序,并且某些消息被丢弃或忽略。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-09-05
        • 2021-01-01
        • 2018-08-22
        • 1970-01-01
        • 1970-01-01
        • 2015-08-14
        • 1970-01-01
        相关资源
        最近更新 更多