Конфликт 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);
}
//------ конечный мастер ----------------------------------

, 👍-1

Обсуждение

Насколько я знаю, вы не можете контролировать I2C, если вы раб. Ведомые только отвечают на запросы ведущего, но не могут начать связь (например, с ЖК-дисплеем). Если вы хотите, чтобы ведомое устройство управляло ЖК-экраном, создайте другую шину I2C, где ведомое устройство является ведущим, или сделайте так, чтобы ведущее устройство управляло ЖК-дисплеем напрямую. Или соедините ведущее и ведомое устройства через другую шину (SPI, последовательную и т. д.) и сделайте ведомое устройство новым ведущим..., @frarugi87

может помочь мне преобразовать это в основной считыватель / подчиненный приемник, я пытаюсь безрезультатно ... tnks за помощь, @Francesco Valla


2 ответа


0

я частично решаю проблему следующим образом:

Код ГЛАВНОГО ПРИЕМНИКА:

#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


1

Я не знаю, в чем ваша проблема, но у вас грубая ошибка в 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);
,