Зависают arduino при обмене данных по i2c

dxf

✩✩✩✩✩✩✩
17 Апр 2020
47
2
Подскажите в чём может быть причина зависания обоих МК при обмене данными по I2C? Резисторы подтяжки шины i2c на питание имеются. Питание обоих плат идет от usb портов компьютера. По истечение примерно минуты оба МК начинаю оправлять сообщения без задержки.
Тестовые скетчи:
master:
#include <Wire.h>
#include <Arduino.h>

byte address = 8; // адрес ведомого
byte masterReceive = 100;
byte masterSend;
uint16_t timer = 0;
bool flag = false;

void setup()
{
  Wire.begin();
  Serial.begin(9600);
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop()
{
  if (millis() - timer > 1000)
  {
    Wire.requestFrom(address, 1);
    masterReceive = Wire.read();
    Wire.beginTransmission(address);
    Wire.write(masterSend);
    Wire.endTransmission();
    timer = millis();
  }

  if (flag && masterReceive == 105)
  {
    digitalWrite(LED_BUILTIN, HIGH);
    Serial.println("Принято от slave - ");
    Serial.println(masterReceive);
    masterSend = 50;
    flag = !flag;
  }
  if (!flag && masterReceive == 100)
  {
    digitalWrite(LED_BUILTIN, LOW);
    Serial.println("Принято от slave - ");
    Serial.println(masterReceive);
    masterSend = 55;
    flag = !flag;
  }
}
slave:
#include <Wire.h>
#include <Arduino.h>

byte address = 8; // адрес ведомого
byte slaveReceived;
byte SlaveSend = 105;
uint16_t timer = 0;
bool flag = false;

void receiveEvent(int howMany) // эта функция вызывается когда ведомый принимает значение от ведущего
{
  slaveReceived = Wire.read();
}

void requestEvent() // эта функция вызывается когда ведущий запрашивает значение от ведомого
{
  Wire.write(SlaveSend);
}

void setup()
{
  Serial.begin(9600);
  Wire.begin(address);
  Wire.onReceive(receiveEvent);
  Wire.onRequest(requestEvent);
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop()
{

  if (!flag && slaveReceived == 55)
  {
    digitalWrite(LED_BUILTIN, HIGH);
    Serial.println("Принято от master - ");
    Serial.println(slaveReceived);
    SlaveSend = 105;
    flag = !flag;
  }

  if (flag && slaveReceived == 50)
  {
    digitalWrite(LED_BUILTIN, LOW);
    Serial.println("Принято от master - ");
    Serial.println(slaveReceived);
    SlaveSend = 100;
    flag = !flag;
  }
}
 

dxf

✩✩✩✩✩✩✩
17 Апр 2020
47
2
@bort707,
C++:
  if (millis() - timer >= 1000)
  {
    timer = millis();
    ...
  }
Немного по другому переделал, ничего в работе не поменялось. Пока не понимаю в чём ошибся.

@Bruzzer,
Получается даже uint64 то тоже через какое то время переполнится.
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
501
149
@dxf,
millis() выдает результат в uint32_t, значит и timer должен быть uint32_t
В этом случае все будет считаться верно за счет особенностей без знаковой арифметики. Подробности в гугле по "переполнение millis" В том числе должно быть и на сайте Гайвера.
 
  • Лойс +1
Реакции: dxf

dxf

✩✩✩✩✩✩✩
17 Апр 2020
47
2
Пробовал применить ATtiny85 (dispark) в качестве ведомого, код нормально компилируется и заливается, но судя по ардуинке (ведущий) и светодиоду ничего не передаётся. Может есть какие особенности?
 

Геннадий П

★★★★★★✩
14 Апр 2021
1,975
635
45

dxf

✩✩✩✩✩✩✩
17 Апр 2020
47
2
@Геннадий П, с tiny есть сложности в том, что монитора порта там нет, наблюдать за работой проблематично малость на стадии изучения. А с ардуинками все работает.
 

Nitrogenium

✩✩✩✩✩✩✩
25 Ноя 2022
33
3
dxf
Проблема обмена по протоколу I2C с помощью библиотеки Wire.h заключается в шляпоотвальной реализации этой самой библиотеки. Как впрочем и многих других решениях около Arduino IDE. А если быть точнее, ты её скорее всего завел её в не правильной форме. При том что я знаю, что нигде нет толкового объяснения как этой библой пользоваться. Я не могу сказать где именно ты ошибся, скажу честно, у меня даже не возникает желание разбираться в этой шляпе, после того как юзал её один раз.

Отправка данных по I2C заключается в записи передаваемого байта в один из регистров МК. Во втором регистре ожидаем изменение одного из бита, который сигнализирует о том что байт ушел. (Запускаем пустой цикл, на пару миллисекунд) Третий регистр - настройки скорости и то что сперва уходит старший бит, или младший, по переднему фронту или по заднему читаем данные. Как правило тут всё работает по умолчанию.

Вот и вся передача по I2C.

Байт уходит за три строчки кода. SPI работает примерно по такой же самой схеме.

Работа с Wire.h начинается с begin transmission, или я это с Serial.print путаю... Наверное такому подходу где-то учат... Я этой шляпе не учился. Работать напрямую с регистрами и проще и понятнее, чем разбираться в чужом говнокоде. Что там бегинить ??? Не очень понятно... Если это влезает в одну строчку.

Для другого примера, максимально четко в ArduinoIDE работает, AnalogRead(), без соплей и лишних настроек. Скажу даже что сложно написать код, с прямым обращением к регистрам, который окажется меньше чем AnalogRead.

Видимо разные люди пишут код
 
Изменено: