Доброго времени суток. Имеется: один мастер мк четыре слэйв мк четыре 16-битных АЦП (ads1115). Все сидят на одной I2C шине. Проблема заключается в том, что когда слэйвы опрашивают АЦП, часть данных теряется с определенной периодичностью (даже когда обмена данных с мастером нет, просто сидят на одной шине). Подскажите, что может быть не так и как это можно исправить. P.S. Либа под ADS (АЦП опрашиваю в дифференциальном режиме) Все слэйвы arduino nano (у них один I2C порт, было бы два подключал бы АЦП и мастера к разным, но что есть, то есть) Мастер NodeMCU ESP8266 (но это, как мне кажется не имеет значения) Без I2C шины все МК работают прекрасно
Попробуйте сделать одинаковым, хотя бы эксперементально. Также не плохо бы проверить номиналы подтягивающих резисторов шины i2c.
Есть возможность помониторить шину I2C? В своё время игрался с УНО и двумя гироскопами на одной шине I2C. Так Арудуино время от времени зависала, спасала только перезагрузка платы. Зависала абсолютно рандомно. Анализ показал, что на шине происходил сбой -- кто-то в не нужное время прижимал шину данных, из-за чего Ардуина теряла арбитраж шины и зависала (но зависание скорее следствие кривой библиотеки работы с гироскопами). Может тоже есть какие проблемы с распределением доступа к шине?
Кажется я понял в чем была проблема. Скорее всего у меня requestEvent наслаивается на опрос АЦП. То бишь, когда я делаю опрос АЦП и он отвечает на запрос, срабатывает requestEvent который отправляет данные мастеру, из-за этого происходит потеря данных. Как думаете, такое возможно?
Slave: Код (C++): #include <Wire.h> #include <Adafruit_ADS1015.h> Adafruit_ADS1115 ads(0x48); float voltage = 0.0F; char buff[7]; void setup() { ads.begin(); Wire.begin(8); Wire.onRequest(requestEvent); } void loop() { voltage = abs(ads.readADC_Differential_2_3() * 0.1875F / 1000.); } void requestEvent() { dtostrf(voltage,7,2, buff); Wire.write(buff); } Master: Код (C++): #include <Wire.h> void setup() { Wire.begin(D1, D2); Serial.begin(9600); } void loop() { String dataString = ""; float voltage = 0.0F; Wire.requestFrom(8, 7); while (Wire.available()) { char c = Wire.read(); dataString = dataString + c; } voltage = dataString.toFloat(); Serial.println(voltage); }
По логике, нужно поменять их ролями, тогда будет четыре мастера, и один слэйв в виде ESP, но тут возникает проблема - я нигде не могу найти как задать ESP i2c адрес или хотя бы, использовать его как ведомое устройство.
Целиком проект гораздо сложнее, я описал упрощенную версию тех частей, которые нужны для понимания проблемы. Один МК там точно не потянет.
Конечно возможно. По сути у Вас два потока: первый -- loop(), который читает данные из ADC; второй -- requestEvent(), который данные ADC отправляет по запросу. Переменная 'voltage' типа float, которая занимает 4-е байта. Пока эти четыре байта заполняются может прийти запрос и заполнение этих данных прервётся для их отправки через I2C, что приведёт к отправке частично новых заполненных и частично старых данных. Так что добавляйте блоки синхронизации -- как минимум запрещайте прерывание в loop() на время чтения данных из ADC: ads.readADC_Differential_2_3(). Но именно только на время вызова этой функции, а не все остальные операции с данными. Но это может не сработать (точнее подвесит контроллер), если функция ads.readADC_Differential_2_3() зависит от прерываний или, если она выполняется долго, то это грозит пропуском запросов по шине I2C (что может быть очень критичным для работы слейвов). Я бы взглянул на библиотеку 'Adafruit_ADS1015' и поправил её для поддержки многопоточности, если потребуется.