#arduino #i2c #nodemcu #master-slave #arduino-c
#arduino #i2c #nodemcu #ведущий-ведомый #arduino-c
Вопрос:
У меня есть настройка master-slave, состоящая из NodeMCU (master) и arduino nano (slave). Я хочу отправить два разных типа данных на два разных адреса 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
Есть ли способ получить такой результат? И есть ли способ исправить вывод после остановки через короткое время?
Комментарии:
1. Понятия не имею, что происходит (по какой-то причине, похоже, не синхронизировано — попробуйте отправить однотипные сообщения для подтверждения?), Но что вы делаете? Для i2c slave очень странно менять адрес после каждого сообщения.
2. Я пытался передать два разных типа данных на подчиненное устройство. Я уже успел отправить их по отдельности. Я думал, что мог бы сделать это, отправив сообщения с использованием разных адресов, точно так же, как некоторые датчики, которые используют разные адреса на шине I2C.
Ответ №1:
Я хочу отправить два разных типа данных на два разных адреса I2C.
Библиотека Wire от Arduino рассчитана на один адрес I2C для каждого устройства. В его реализации используется единый набор глобальных ресурсов. Это означает, что если вы динамически изменяете адрес принимающего устройства Arduino, вам также потребуется синхронизировать мастер, чтобы узнать, какой адрес использовать.
Было бы проще назначить подчиненному устройству один адрес, а ведущее устройство указать тип отправляемых данных. Это можно сделать, отправив JSON или пары ключ / значение. например, мастер может отправить префикс int:
перед любым целым числом и str:
перед любой строкой. Подчиненное устройство может использовать префикс для интерпретации режима передачи.
Объяснение вывода
10910111511597103101
Это символы ASCII для строки message
в целых числах. т.е. 109, 101, 115, 115, 97, 103, 101
Здесь receiveEvent1()
обрабатываются данные, отправляемые по шине I2C, и выводится каждый байт как целое число.
Вызов Wire.begin()
и Wire.onReceive()
in loop()
изменит настройки в глобальном TwoWire
синглтоне. Базовая twi
библиотека также имеет единый набор ресурсов.
Результатом изменения адресов и обработчика приема (многократного loop()
ввода) является набор условий гонки и неопределенное использование двух обработчиков приема.
Похоже, это включает receiveEvent1()
в себя обработку «5» и receiveEvent2()
обработку «сообщения», как вы и предполагали. Он также включает receiveEvent1()
в себя обработку «сообщения», приводящего к последовательности чисел.
Кажущаяся пустой строка, вероятно receiveEvent2()
, обрабатывает «5», поэтому, вероятно, выводится непечатаемый символ ASCII ENQ (запрос). Также вероятно, что бывают периоды, когда ни один обработчик не настроен должным образом, а некоторые сообщения отбрасываются или игнорируются.
Ответ №2:
Вы не должны использовать 2 адреса для связи с одним подчиненным устройством. Вместо этого вы должны использовать один адрес и указать, какой тип данных вы собираетесь отправлять.
Как вы указываете, какой тип данных вы собираетесь отправлять?
Как сказал Бен Т., для этого вы можете использовать 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
}
}