如何使用Arduino IDE在两个不同的地址上通过I2C总线写消息?

问题描述

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

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

Master(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地址上发送两种不同类型的数据。

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

将单个地址分配给从设备并让主设备指示要发送的数据类型会更简单。这可以通过发送JSON或键/值对来完成。例如主机可以在任何整数之前发送前缀on_hand_qty=fields.Float(related='qty_available',string="Your Field") ,在任何字符串之前发送int:。从站可以使用前缀来解释传输模式。

解释输出

10910111511597103101

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

message正在处理通过I2C总线发送的数据,并将每个字节输出为整数。

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

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

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

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

,

您不应使用 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
    }
}
,

如果阅读还没结束就被截断了,是不是就意味着你不期待了? 确保主代码传输所有! 确定以后在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;
    }

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

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...