Конфликт I2C с двумя ардуино
У меня возникли проблемы с подключением двух моих Arduino Nano к I2C. У меня есть эта конфигурация:
- ВЕДОМЫЙ ПРИЕМНИК Nano с DS1037 и LCD 16x02 на I2C.
- ГЛАВНЫЙ ОТПРАВИТЕЛЬ Nano.
Через некоторое время ведомый приемник печатает на ЖК-дисплее случайные символы. Если я удалю строку, включающую библиотеку RTCLIB.h, все работает, кроме часов. Спасибо за помощь :D
Код ведомого приемника:
#include <Wire.h> // включаем библиотеку
#include <LiquidCrystal_I2C.h>
#include "RTClib.h"
LiquidCrystal_I2C lcd(0x3E, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
RTC_DS1307 RTC; // орология
static int anno;
static int giorno;
static int mese;
static int ora;
static int secondo;
static int oldSecondo;
static int minuto;
static int oldMinuto;
static int annoGrezzo;
//------------------------------------------------ ------------
// объединение повторяется точно так же, как в мастере
union Scomp_float {
// используется объединение x число с плавающей запятой
float temp;
char byte_s[4];
} S_float;
//------------------------------------------------ ------------
// объединение повторяется точно так же, как в мастере
union Scomp_long {
// используется объединение x long
long int mioL;
char byte_sL[4];
} S_long;
//------------------------------------------------ ------------
//------------- временные байты
byte f0 = 0; // содержат полученные байты
byte f1 = 0;
byte f2 = 0;
byte f3 = 0;
byte a1 = 0;
//------------------------------------------------ -------------
// сюда будем вводить данные пересобранные после передачи
long int masterLong = 0;
float masterFloat = 0;
int masterInt = 0;
//------------------------------------------------ --------------
void setup() {
Wire.begin(80); // присоединяемся к шине i2c с адресом #4
Wire.onReceive(receiveEvent); // регистрируем событие
lcd.begin(16, 2);
Serial.begin(9600); // запускаем сериал для вывода
//-----------орологио-----------
RTC.begin();
// Проверяем, отсчитывает ли RTC время. Если это так, загрузите время с вашего компьютера.
if (! RTC.isrunning()) {
Serial.println("RTC is NOT running!");
// Это будет отражать время компиляции скетча
RTC.adjust(DateTime(__DATE__, __TIME__));
}
//-----------тонкая орология-----------
}
void loop() {
//------------------------------------------------ ------------
// полученные и собранные данные выводятся на печать
//------------------------------------------------ ------------
Serial.println(masterInt);
Serial.println(masterLong);
Serial.println(masterFloat);
DateTime now = RTC.now();
annoGrezzo = now.year();
anno = ( annoGrezzo % 100);
mese = now.month();
giorno = now.day();
ora = now.hour();
minuto = now.minute();
lcd.setCursor(0, 0);
lcd.print(masterInt);
lcd.setCursor(0, 1);
lcd.print(giorno);
lcd.print(" ");
lcd.print(mese);
lcd.print(" ");
lcd.print(anno);
lcd.print(" ");
lcd.print(ora);
lcd.print(":");
lcd.print(minuto);
delay (1000);
lcd.clear();
}
// функция, которая выполняется всякий раз, когда данные получены от мастера
// эта функция регистрируется как событие, см. setup()
void receiveEvent(int howMany) {
if (howMany == 2) {
// поступление данных из-за поступления
f0 = Wire.read(); // si leggono i byte
f1 = Wire.read();
masterInt = ((f1 << 8) | f0); // si ricopone l'intero
}
if (howMany == 4) {
// вводим 4 данных с плавающей запятой
f0 = Wire.read(); // si leggono i byte
f1 = Wire.read();
f2 = Wire.read();
f3 = Wire.read();
S_float.byte_s[0] = f0; // добавим значение с плавающей запятой
S_float.byte_s[1] = f1;
S_float.byte_s[2] = f2;
S_float.byte_s[3] = f3;
masterFloat = S_float.temp;
}
if (howMany == 5) {
// se in arrivo 5 dati è un long
f0 = Wire.read(); // si leggono i byte
f1 = Wire.read();
f2 = Wire.read();
f3 = Wire.read();
a1 = Wire.read();
S_long.byte_sL[0] = f0; // si ricompone il long
S_long.byte_sL[1] = f1;
S_long.byte_sL[2] = f2;
S_long.byte_sL[3] = f3;
masterLong = S_long.mioL;
}
}
Основной код отправителя:
#include <Wire.h> // si include la libreria
//------------------------------------------------ ---------
union Scomp_float {
// используем объединение x с плавающей запятой
float temp;
char byte_s[4];
} S_float;
//------------------------------------------------ ---------
union Scomp_long {
// используется объединение x long
long int mioL;
char byte_sL[4];
} S_long;
//------------------------------------------------ ----------
// это данные, которые мы хотим отправить
long int mioLong = 1234567801;
float mioFlo = 123456.29;
//------------------------------------------------ ----------
byte a1 = 0; // будет содержать первый байт int
byte a2 = 0; // будет содержать второй байт int
byte f0 = 0; // содержит байты с плавающей запятой и длинные байты
byte f1 = 0;
byte f2 = 0;
byte f3 = 0;
void setup() {
Wire.begin(); // подключение к шине i2c (адрес необязателен для мастера)
}
void loop() {
int mioInt = random(30000);
//------------------------------------------------ -----
// передать целое число ( 2 байта)
//------------------------------------------------ -----
a1 = byte(mioInt); // разбиваем целое на 2 байта
a2 = byte( mioInt >> 8);
Wire.beginTransmission(80); // начинаем передачу ведомому
Wire.write(a1); // отправить байт
Wire.write(a2); // отправляем второй байт
Wire.endTransmission(); // прекращаем передачу
//------------------------------------------------ ------
delay (2000);
//------------------------------------------------ ------
// передать целое число длиной 4 байта
//------------------------------------------------ ------
S_long.mioL = mioLong; // разбивается на 4 байта
f0 = S_long.byte_sL[0];
f1 = S_long.byte_sL[1];
f2 = S_long.byte_sL[2];
f3 = S_long.byte_sL[3];
a1 = 1; // этот байт отправляется только для сигнала ведомому
// что мы отправляем длинный
// после разложения передаются 4 байта
Wire.beginTransmission(80); // передать подчиненному
Wire.write(f0); // отправить байт
Wire.write(f1); //
Wire.write(f2); //
Wire.write(f3); // отправить байт
Wire.write(a1);
Wire.endTransmission(); // конец передачи
//------------------------------------------------ -------
delay (2000);
//------------------------------------------------ ------
// передача 4-байтового числа с плавающей запятой
//------------------------------------------------ ------
S_float.temp = mioFlo; // разбивается на 4 байта
f0 = S_float.byte_s[0];
f1 = S_float.byte_s[1];
f2 = S_float.byte_s[2];
f3 = S_float.byte_s[3];
// после разложения передаются 4 байта
Wire.beginTransmission(80); // передать подчиненному
Wire.write(f0); // через один байт
Wire.write(f1); //
Wire.write(f2); //
Wire.write(f3); // через один байт
Wire.endTransmission(); // точная передача
//------------------------------------------------ -------
delay (3000);
}
//------ конечный мастер ----------------------------------
@Francesco Valla, 👍-1
Обсуждение2 ответа
я частично решаю проблему следующим образом:
Код ГЛАВНОГО ПРИЕМНИКА:
#include <Wire.h> // включаем библиотеку
#include <LiquidCrystal_I2C.h>
#include "RTClib.h"
LiquidCrystal_I2C lcd(0x3E, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
RTC_DS1307 RTC; // орология
static int anno;
static int giorno;
static int mese;
static int ora;
static int secondo;
static int oldSecondo;
static int minuto;
static int oldMinuto;
static int annoGrezzo;
char t[10] = {};
char v[10] = {};
void setup()
{
Wire.begin(); // присоединяемся к шине i2c с адресом #4
lcd.begin(16, 2);
Serial.begin(9600); // запускаем сериал для вывода
//-----------орологио-----------
RTC.begin();
// Проверяем, отсчитывает ли RTC время. Если это так, загрузите время с вашего компьютера.
if (! RTC.isrunning())
{
Serial.println("RTC is NOT running!");
// Это будет отражать время компиляции вашего скетча
RTC.adjust(DateTime(__DATE__, __TIME__));
}
//-----------тонкая орология-----------
}
void loop()
{
//------------------------------------------------ ------------
// си штампано и данные рисовути и рикомпости
//------------------------------------------------ ------------
Wire.requestFrom(8, 3);
int i = 0;
while (Wire.available()) {
t[i] = Wire.read(); // каждый пришедший символ упорядочивает в пустом массиве "t"
i = i + 1;
}
Wire.requestFrom(8, 3);
i=0;
while (Wire.available()) {
v[i] = Wire.read(); // каждый пришедший символ упорядочивает в пустом массиве "v"
i = i + 1;
}
Serial.println(t);
DateTime now = RTC.now();
annoGrezzo = now.year();
anno = ( annoGrezzo % 100);
mese = now.month();
giorno = now.day();
ora = now.hour();
minuto = now.minute();
lcd.setCursor(0, 0);
lcd.print(t);
lcd.setCursor(5,0)
lcd.print(v);
lcd.setCursor(0, 1);
lcd.print(giorno);
lcd.print(" ");
lcd.print(mese);
lcd.print(" ");
lcd.print(anno);
lcd.print(" ");
lcd.print(ora);
lcd.print(":");
lcd.print(minuto);
delay (1000);
lcd.clear();
}
// функция, которая выполняется всякий раз, когда данные получены от мастера
// эта функция регистрируется как событие, см. setup()
КОД ПОДЧИНЕННОГО ОТПРАВИТЕЛЯ:
#include <Wire.h> // si include la libreria
//------------------------------------------------ ---------
char t[10];
char v[10];
void setup()
{
Wire.begin(8); // подключение к шине i2c (адрес необязателен для мастера)
Wire.onRequest(requestEvent);
}
void loop()
{
int mioInt = random(30000);
int mioInt2 = 1234;
dtostrf(mioInt, 3, 2, t); // преобразует число с плавающей запятой или целое число в строку. (floatVar, minStringWidthIncDecimalPoint, numVarsAfterDecimal, пустой массив);
dtostrf(mioInt2, 3, 2, v);
//------------------------------------------------ ------
delay (500);
}
void requestEvent() {
Wire.write(t);
Wire.write(v);
}
//------ конечный слейв ----------------------------------
Теперь моя проблема заключается во второй переменной T, которую я не могу получить на Master. Спасибо за помощь
Только Master теперь является Master, а RTC, дисплей I2C и Slave Nano — все Slave. Это хорошо, коллизий на шине I2C больше не будет. Вы должны знать, какие данные вы хотите передать. Строка с завершающим нулем — не лучший вариант. Вы можете отправить сразу два целых числа или структуру со значениями. Легче отправить один пакет данных. В ведомом устройстве requestEvent() запускается из прерывания. Поэтому переменные, которые вы отправляете, должны быть сделаны «изменчивыми», и если они используются в цикле(), прерывания должны быть временно отключены в цикле()., @Jot
как? Я немного запутался, с одним проблем нет, со вторым проблема.. я понимаю, как это работает с одним. Спасибо за ответ, @Francesco Valla
Например, с "int x[2];". Передайте их с помощью «Wire.write((char *)x, 4);». В Мастере запросите 4 байта, также используйте "int x[2];" и вы можете использовать «Wire.readBytes ((char *) x, 4);» для чтения данных в целые числа. Проблема у вас не во втором, а в том, как вы используете две строки. Поэтому один пакет будет лучше., @Jot
Если это решило вашу проблему, пожалуйста, примите свой собственный ответ, другой Stack Exchange считает, что на вопрос не дан правильный ответ., @Nick Gammon
Я не знаю, в чем ваша проблема, но у вас грубая ошибка в LiquidCrystal_I2C lcd(0x3E, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
. У вас есть ЖК-дисплей I2C, но вы используете его для инициализации ЖК-дисплея старого образца.
Правильная инициализация ЖК-дисплея и I2C
LiquidCrystal(0x2A, 16, 2);
Вы должны заменить 0x2A на правильный адрес I2C вашего ЖК-дисплея (для этого используйте скетч сканера I2C).
Сначала необходимо проверить API ваших библиотек (обычно файл .h):
/**
* Constructor
*
* @param lcd_addr I2C slave address of the LCD display. Most likely printed on the
* LCD circuit board, or look in the supplied LCD documentation.
* @param lcd_cols Number of columns your LCD display has.
* @param lcd_rows Number of rows your LCD display has.
* @param charsize The size in dots that the display has, use LCD_5x10DOTS or LCD_5x8DOTS.
*/
LiquidCrystal_I2C(uint8_t lcd_addr, uint8_t lcd_cols, uint8_t lcd_rows, uint8_t charsize = LCD_5x8DOTS);
- переменная 'LiquidCrystal_I2C lcd' имеет инициализатор, но неполный тип
- NodeMCU с RFID RC522 и LCD-модулем интерфейса I2C вместе
- ЖК-дисплей I2C отображает странные символы
- Экран LCD 16*02 I2C показывает только первый напечатанный символ
- Sainsmart LCD 2004 - проблема с библиотекой LiquidCrytal_I2C, не удается скомпилировать
- Что означают цифры позади lcd (0x27)?
- Как перевести Arduino Nano в спящий режим с низким энергопотреблением (<0,05 мА)
- ATtiny85 I2C ЖК
Насколько я знаю, вы не можете контролировать I2C, если вы раб. Ведомые только отвечают на запросы ведущего, но не могут начать связь (например, с ЖК-дисплеем). Если вы хотите, чтобы ведомое устройство управляло ЖК-экраном, создайте другую шину I2C, где ведомое устройство является ведущим, или сделайте так, чтобы ведущее устройство управляло ЖК-дисплеем напрямую. Или соедините ведущее и ведомое устройства через другую шину (SPI, последовательную и т. д.) и сделайте ведомое устройство новым ведущим..., @frarugi87
может помочь мне преобразовать это в основной считыватель / подчиненный приемник, я пытаюсь безрезультатно ... tnks за помощь, @Francesco Valla