Проблема с плохой пропускной способностью при 50 Arduino, подключенных по I2C
У меня есть проблема, и я надеюсь, что кто-нибудь здесь сможет мне помочь.
Я хочу измерить изменения в емкости с течением времени. На каждый датчик емкости используется один Arduino. На Arduino приходится один анод и в общей сложности один общий каход. (См. Рисунок)
С помощью четырех Arduino, соединенных последовательно через соединение I2C master-slave, были получены успешные результаты. При использовании более четырех Arduino все результаты измерений были равны 0, поскольку напряжение на входном выводе больше не измеряется. Затем я понизил опорное напряжение для analogRead. Таким образом, было возможно 10 Ардуино в серии. Однако измеренные значения явно ниже. Тем не менее, абсолютные значения не подлежат измерению, но разницы в мощности достаточно. Наконец, следует использовать 50 Ардуино. Я подумал о следующих возможностях
- уменьшите опорное напряжение еще больше, но это может еще больше ухудшить результаты измерений, так что отклонение не будет измерено.
- увеличьте выходное напряжение на Arduino с помощью операционного усилителя, чтобы компенсировать падение напряжения.
Есть ли у кого-нибудь другая идея, как я мог бы продолжить, чтобы получить полезный результат со всеми 50 Arduino? Код, который я использовал, можно найти ниже.
Заранее большое спасибо
Приветствую , Имоджия
Мастер
const int OUT_PIN = A0;
const int IN_PIN = A2;
//Емкость между IN_PIN и Землей
// Паразитная емкость присутствует всегда. Дополнительная емкость может быть добавлена в
// позволяет измерять более высокую емкость.
const float IN_STRAY_CAP_TO_GND = 30.00;
const float IN_EXTRA_CAP_TO_GND = 0.0;
const float IN_CAP_TO_GND = IN_STRAY_CAP_TO_GND + IN_EXTRA_CAP_TO_GND;
const int MAX_ADC_VALUE = 1023;
#include <Wire.h>
#define nodeMax 10
#define nodeStart 2
union u_capacitance
{
struct
{
float capa_slave;
};
byte bytes[10];
};
u_capacitance capacitanceSlave;
void setup()
{
analogReference(EXTERNAL);
Wire.begin(); // присоединиться к шине i2c (адрес необязателен для master)
pinMode(OUT_PIN, OUTPUT);
pinMode(IN_PIN, OUTPUT);
Serial.begin(9600);
}
void loop() {
//Тестируемый конденсатор между OUT_PIN и IN_PIN
// Увеличение верхнего края в режиме вывода
pinMode(IN_PIN, INPUT);
digitalWrite(OUT_PIN, HIGH);
int val = analogRead(IN_PIN);
//Очистить все для следующего измерения
digitalWrite(OUT_PIN, LOW);
pinMode(IN_PIN, OUTPUT);
//digitalWrite(IN_PIN, НИЗКИЙ);
// Вычислить и распечатать результат
float capacitance = (float)val * IN_CAP_TO_GND / (float)(MAX_ADC_VALUE - val);
Serial.print(capacitance, 2);
Serial.print(",");
Serial.print(val);
Serial.print(",");
delay(10);
for( int node = nodeStart; node <= nodeMax; node++){
Wire.requestFrom(node, sizeof(capacitanceSlave));
for (unsigned int i = 0; i < sizeof(capacitanceSlave); i++){
capacitanceSlave.bytes[i] = Wire.read();
}
Serial.print(capacitanceSlave.capa_slave);
Serial.print(",");
delay(10);
}
Serial.println();
delay(50);
}
Подчинение
const int OUT_PIN = A0;
const int IN_PIN = A2;
//Емкость между IN_PIN и Землей
// Паразитная емкость присутствует всегда. Дополнительная емкость может быть добавлена в
// позволяет измерять более высокую емкость.
const float IN_STRAY_CAP_TO_GND = 30.00;
const float IN_EXTRA_CAP_TO_GND = 0.0;
const float IN_CAP_TO_GND = IN_STRAY_CAP_TO_GND + IN_EXTRA_CAP_TO_GND;
const int MAX_ADC_VALUE = 1023;
#include <Wire.h>
#define node 10
union u_capacitance
{
struct
{
float capa_slave;
};
byte bytes[10];
};
u_capacitance capacitanceSlave;
void setup()
{
analogReference(EXTERNAL);
Wire.begin(node); // соединение шины i2c с адресным узлом
Wire.onRequest(requestEvent); // зарегистрировать событие
Serial.begin(9600); // запустить последовательный для вывода
pinMode(OUT_PIN, OUTPUT);
pinMode(IN_PIN, OUTPUT);
}
void loop()
{
}
// функция, которая выполняется всякий раз, когда данные поступают от ведущего
// эта функция зарегистрирована как событие, см. раздел setup()
void requestEvent()
{
//Тестируемый конденсатор между OUT_PIN и IN_PIN
// Увеличение верхнего края в режиме вывода
pinMode(IN_PIN, INPUT);
digitalWrite(OUT_PIN, HIGH);
int val = analogRead(IN_PIN);
//Очистить все для следующего измерения
digitalWrite(OUT_PIN, LOW);
pinMode(IN_PIN, OUTPUT);
//digitalWrite(IN_PIN, НИЗКИЙ);
// Вычислить и распечатать результат
float capacitance = (float)val * IN_CAP_TO_GND / (float)(MAX_ADC_VALUE - val);
capacitanceSlave.capa_slave = capacitance;
Wire.write(capacitanceSlave.bytes, sizeof(capacitanceSlave));
//Serial.println(емкость, 3);
}
@Imogdia, 👍2
Обсуждение3 ответа
Катодная линия используется совместно всеми выводами ардуино.
Когда
один из них пытается установить вывод ВЫСОКО
, все остальные пытаются
держать ее НИЗКО
. Это состояние короткого замыкания, которое может повредить
выходы Arduino. Даже если они выживут, напряжение на линии будет
значительно ниже 5 В из-за того, что эти Arduino тянут
линию НИЗКО
. Чем больше из них тянут линию НИЗКО
, тем ниже будет напряжение
.
Простым решением было бы изменить протокол таким образом, чтобы только
Arduino, который в данный момент производит измерение, мог использовать эту линию, в то время
как другие сохраняют свой OUT_PIN
в режиме высокого импеданса (т. Е. Ввода
).
Это хрупко, потому что ... случаются ошибки, и вы все еще можете допустить
короткое замыкание. Более надежным решением было бы подключить
к катоду только главный источник питания и возложить на него ответственность за управление линией
ВЫСОКИЙ
и НИЗКИЙ
.
Теперь несколько несвязанных комментариев:
Число с
плавающей
запятой равно четырем байтам: нет смысла передавать десять байтов.Вы можете измерить до четырех конденсаторов с каждым Arduino (контакты
от A0
доA3
, вы можете использовать цифровой вывод дляOUT_PIN
), расточительно использовать один Arduino на конденсатор.
В конфигурации I2C никто не устанавливает высокий уровень выходного сигнала. Это делают подтягивающие резисторы., @Nick Gammon
@NickGammon: я говорю о линии с надписью «катод» на рисунке, а не о I2C SDA., @Edgar Bonet
ХОРОШО. «Контурная схема» была не так уж и ясна., @Nick Gammon
@Eggar Bonet: Прежде всего спасибо за ответы, Я попробовал ваше предложение, только подключив мастер к катоду и изменив код, но это не сработало. датчик, подключенный к ведущему, дает лучшую выходную емкость, но выход ведомого - «нан». Я должен использовать один Arduino для каждого датчика, потому что в предыдущих научных работах два датчика мешали одному Arduino, и результаты были плохими., @Imogdia
@Imogdia: Должно быть что-то не так либо с вашей обновленной схемой, либо с вашим обновленным кодом. Возможно, вы захотите обновить вопрос, чтобы он отражал текущую схему и код., @Edgar Bonet
@Imogdia: с обновленным кодом ведомые устройства все еще получают OUT_PIN. И они освобождают «IN_PIN» _после_ того, как мастер установил «OUT_PIN» в «HIGH», что уже слишком поздно. Вам нужен более сложный коммуникационный протокол, в котором мастер сообщает ведомому, когда освободить IN_PIN., @Edgar Bonet
И как я могу это сделать? Я совершенно новичок в ардуино и у меня нет опыта программирования, @Imogdia
@Imogdia: см. расширенный ответ., @Edgar Bonet
Я протестировал ваш код (см. обновленную угрозу), но результат остался прежним. я протестировал ваш код на 10 arduinos и получил следующие результаты: только мастер получает измерение 12:22:21.472 -> 1.38,45,в,в,в,в,в,в,в,в,в,в 12:22:21.710 -> 1.38,45,в,в,в,в,в,в,в,в,в,в 12:22:21.947 -> 1.41,46,в,в,в,в,в,в,в,в,в,в 12:22:22.186 -> 1.38,45,в,в,в,в,в,в,в,в,в,в 12:22:22.426 -> 1.38,45,в,в,в,в,в,в,в,в,в,в 12:22:22.700 -> 1.38,45, нан, нан, нан, нан, нан, нан, нан, нан, нан,, @Imogdia
@Tizian: 1. Ваши рабы все еще управляют OUT_PIN. 2. Они ничего не отправляют (мой комментарий // передаем результат...
должен был быть заменен вашим кодом, передающим результат). 3. Зачем дважды вызывать Wire.onRequest()
? 4. Попробуйте отправить фиксированное значение (например, 12.34
), чтобы исключить проблему со связью. 5. Почему бы не отправить необработанные показания АЦП вместо вычисленной емкости?, @Edgar Bonet
@EdgarBonet Я снова обновил свой код. Спасибо за вашу помощь! Завтра проверю и скажу, получилось ли., @Imogdia
@EdgarBonet Сработало отлично, спасибо за помощь!, @Imogdia
Шина I2C никогда не предназначалась в качестве распределительной шины между многими компьютерами. Выходы не предназначены для подключения длинных проводов. С большим трудом вы можете заставить это работать, но определенно не повторяемо и не доступно повторно. Подумайте о чем-нибудь другом. Может, может сделать, может быть, 60 узлов в зависимости от выбранного приемопередатчика. Это относительно недорого.
Возможно, вы захотите использовать протокол RS485. В отличие от I2C, здесь используется «сбалансированный» проводка, поэтому больше подходит для более длинных кабелей.
Я описал способ кодирования нескольких Arduino с помощью "Rolling Master" протокол здесь — это позволяет подключить значительное количество Arduino к двум проводам, и они по очереди будут отправлять данные.
Однако в вашем случае, поскольку вы измеряете емкость (а не емкость?), то каждый из ваших Arduino может измерять 6 (или, возможно, больше) аналоговых показаний, поэтому вам не нужно 50, вам нужно 50/6 = 8,33 Arduino. (ОК, девять).
Например, Arduino Micro имеет 12 аналоговых входных каналов, поэтому потребуется только 4 (чтобы получить 48 входов) или 5 (чтобы получить 60 входов). Тогда вы можете придерживаться I2C.
Я рекомендовал CAN из-за 50 узлов, RS485 имеет ограничение в 32. Чтобы выйти за эти пределы, необходимы повторители., @Gil
- Считывание значений с емкостного сенсорного датчика TTP229 на arduino
- Отправка и получение различных типов данных через I2C в Arduino
- Как работают функции вне цикла void?
- Как отображать переменные на 0,96-дюймовом OLED-дисплее с библиотекой u8glib?
- Как отправить строку на мастер с помощью i2c
- Как выбрать альтернативные контакты I2C на ESP32?
- Что означает в I2C «NACK получен»?
- NodeMCU с RFID RC522 и LCD-модулем интерфейса I2C вместе
Вам нужно будет значительно уменьшить подтягивающие резисторы на вашей шине I2C, чтобы противодействовать увеличению емкости затвора из-за количества устройств. Чем больше у вас устройств, тем ниже подтягивающие резисторы. Через некоторое время становится непрактичным больше уменьшать подтягивающие резисторы, и вы достигаете предела количества устройств, которые вы можете иметь на шине. Я бы сказал, что 50 устройств - это гораздо больше, чем может выдержать любая разумная шина., @Majenko
Есть ли причина, по которой вы используете 50 Arduino, а не 4 Arduino, подключенных к 8-портовым мультиплексорам? Это уменьшит затраты, а также позволит избежать вашей проблемы., @Nick Gammon
«Наконец-то нужно использовать 50 Arduino» — почему? Не создает ли это проблему, которую вы пытаетесь решить?, @Nick Gammon