Как подключить несколько последовательных портов arduino вместе
Идея состоит в том, чтобы подключить более 1 подчиненного устройства arduino к ведущему, как показано в schamatic
Проблема в том, что TX slave не может просто объединиться с master RX. Ему нужно сделать какой-то трюк, например, буфер с тремя состояниями, чтобы сделать подчиненный TX по одному за раз. В любом случае, порт avr можно настроить как буфер tristate. (Q1) Существует ли какое-либо программное решение для этого? Во-вторых, если я подключу TX к RX для полудуплексной связи (используя 1 линию передачи данных). Как заставить Rx перестать прослушивать себя во время передачи данных?
@M lab, 👍1
Обсуждение4 ответа
Лучший ответ:
Вы можете сделать это с помощью двух диодов и резистора:
Вам все равно придется внедрить какую-то систему для предотвращения столкновений, но электрически это будет надежно.
Есть ли у него решение для программирования?, @M lab
Совет волшебным образом превратите бритвенные устройства в открытый слив? Нет. Нет, если только у вас нет возможности перепрограммировать подчиненные устройства и написать свою собственную реализацию последовательного программного обеспечения, эмулирующего open drain., @Majenko
Сработает ли что-то вроде трюка Serial.end() и oinMode(x,INPUT)? или мне нужно написать свою собственную последовательную библиотеку?, @M lab
На подчиненных устройствах, да, это сработало бы, но также отключило бы последовательный прием. Чтобы предотвратить коллизии, вам нужно, чтобы ведущий сообщал ведомому устройству, которое он может отправлять, что означает, что прием должен работать, или вам нужно реализовать какую-то другую форму архитектуры сигнализации (и это, скорее всего, потребует дополнительных изменений в вашем оборудовании). Проще всего просто добавить эти диоды и резистор и сделать это правильно - или вообще не использовать Serial и использовать правильную шинную систему, такую как I2C., @Majenko
Без диодов или какой-либо формы прямого контроля над тем, когда каждый подчиненный может посылать сообщение, столкновение может быть фатальным для одного или обоих подчиненных устройств. Это может привести к короткому замыканию (один посылает 1, а другой 0 одновременно), что может привести к перегоранию контактов ввода-вывода., @Majenko
При таком подходе линия Rx всегда подключается к 5 В, за исключением случаев, когда линия Tx от ведомого устройства становится НИЗКОЙ. Мне пришлось посмотреть, чтобы убедиться, что холостой ход на самом деле ВЫСОКИЙ, а не НИЗКИЙ, и да, это так: https://learn.sparkfun.com/tutorials/serial-communication/all#wiring-and-hardware -- см. диаграмму в разделе "Аппаратная реализация", а также: Сигнал на уровне VCC (3,3 В, 5 В и т.д.) указывает либо ** на холостой ход строка**, бит значения 1 или стоповый бит
. Так что, да, это решение определенно сработает, хотя я думаю, что предпочитаю свое решение с 2 резисторами, которое я опубликовал здесь, этому решению., @Gabriel Staples
Объяснения Спаркфана превосходны. Я благодарен, что они и Adafruit, в дополнение к Arduino, конечно, существуют., @Gabriel Staples
Вы можете использовать однополюсный переключатель с двойным переключением. простой переключатель, который может переключать линии между несколькими подчиненными устройствами.
Ограничение: Salve не сможет создать запрос, если мастер не выбрал соответствующие строки. Ведущий должен активно запрашивать данные или посылать команды подчиненным устройствам. Подчиненные устройства могут быть не в состоянии инициировать обмен данными (если не выбрано).
Благодарю за ваше участие, но я предпочитаю сначала программное решение., @M lab
Обновление ноябрь 2020: мой ответ ниже, хотя и немного проницательный и со многими правильными утверждениями, неверен. Моя схема ниже действительно предотвратит повреждение Arduino друг друга, но это не позволит наладить надлежащую связь. Ответ Маенко здесь правильный. Используйте его схему, но также прочтите мой ответ ниже, чтобы получить дополнительную информацию и идеи.
ОРИГИНАЛЬНЫЙ ОТВЕТ:
Вы можете сделать это с помощью 2 резисторов, как показано ниже. Вот именно! Очень просто!
Электрическое объяснение:
Цель состоит просто в том, чтобы защитить два контакта Tx от уничтожения друг друга. Без резисторов одно ведомое устройство может записывать низкий выходной сигнал, в то время как другое ведомое устройство записывает высокий выходной сигнал, что является смертельным короткимзамыканием и приводит к повреждению обоих устройств. Простое подключение резистора 1 ком последовательно с каждым выводом Tx подобным образом предотвращает это короткое замыкание. Теперь, если один вывод Tx ВЫСОКИЙ, а другой НИЗКИЙ, вы получаете ток от одного к другому в общей сложности через 2 Ком, что означает, что ток будет только I = V / R = 5 В / 2000 Ом = 2,5 мА
, что не является проблемой, поскольку каждый вывод может безопасно обрабатывайте 40 мА максимум и 20 мА ~ 30 мА непрерывно. Кроме того, резистор 1 Ком не является большой нагрузкой, поэтому вы все равно должны получить хорошую последовательную пропускную способность даже при довольно высоких скоростях передачи данных.
Код:
Код связи будет выполнен в обычном режиме с помощью Serial.print()
или Serial.write()
, Serial.read() и т.д.
В коде нет ничего особенного, за исключением того, что вы должны приложить усилия, чтобы подчиненные устройства не разговаривали одновременно, чтобы предотвратить повреждение данных от подчиненного устройства к ведущему. Итак, у вас должен быть главный запрос данных от ведомого устройства, и ведомое устройство должно разговаривать только тогда, когда оно знает, что другое ведомое устройство не разговаривает (например: оно должно разговаривать только тогда, когда с ним разговаривают). Мастер координирует коммуникацию. Таким образом, это похоже на SPI: главный отвечает и сообщает каждому Ведомому, когда говорить. Поскольку оба подчиненных устройства всегда слушают, просто используйте "идентификатор", чтобы указать, с каким подчиненным устройством разговаривают. Если подчиненное устройство не видит свой идентификатор, оно должно проигнорировать сообщение.
Пример:
Запросите новое значение температуры у ведомого устройства 1:
Serial.println("1:T");
Теперь подождите, пока не получите полный ответ от ведомого устройства 1, затем отправьте запрос на ... скажем, некоторое текущее чтение от ведомого устройства 2:
Serial.println("2:C");
Точные коммуникационные коды зависят от вас - предел вашего воображения.
Опять же, оба подчиненных устройства видят оба сообщения, но они смотрят на номер в начале и отвечают только в том случае, если это их номер. Используя эту технику, вы могли бы подключить почти бесконечное количество подчиненных устройств к одной и той же линии, просто добавив резистор 1 ком к линии Tx каждого подчиненного устройства перед соединением, где все они подключаются обратно к линии Rx ведущего устройства.
Довольно круто. Я никогда не думал об этом раньше, пока вы не задали этот вопрос. Хороший вопрос.
Ваша аппаратная настройка может привести к повреждению, но мне интересно, если один подчиненный не отправит никаких данных (при высоком сигнале), будут ли данные получать эффект делителя напряжения, который делит амплитуду сигнала вдвое?, @M lab
@Mlab: Действительно. “Бесшумный” TX активно вытягивает линию ВЫСОКО. Вот почему вам нужны диоды., @Edgar Bonet
@EdgarBonet вот почему я ищу решение, чтобы “бесшумный” TX стал высокоимпедансным. каким-то образом это должно быть возможно с помощью программного обеспечения., @M lab
Я думаю, что мой ответ неверен и нуждается в диодах из-за активного холостого хода Tx (низкий импеданс). Я обновлю свой ответ, как только смогу. Сегодня рано утром я измерил импеданс высокочастотной линии передачи данных примерно на уровне 26 Ом., @Gabriel Staples
26 Ом - ожидаемое сопротивление вывода ATmega, настроенного как ВЫХОДНОЙ сигнал. C.f. раздел спецификации на [драйвер вывода strength](http://ww1.microchip.com/downloads/en/DeviceDoc/ATmega48A-PA-88A-PA-168A-PA-328-P-DS-DS40002061A.pdf#G3.2900717)., @Edgar Bonet
Чтобы эта схема работала, вам нужно убедиться, что не более одного ведомого устройства управляет своим TX в любой момент времени. Вам нужно будет разработать какой-то протокол , с помощью которого ведущий обращается к одному ведомому устройству, а затем отвечает только это ведомое устройство. Проблема заключается в следующем:
- оба подчиненных устройства должны иметь включенные последовательные порты, чтобы заметить , когда к ним обращается ведущий
- активный последовательный порт поддерживает свой вывод TX в состоянии низкого импеданса, активно повышая его, когда данные не передаются.
Лучший выход из этой дилеммы - модифицировать аппаратное обеспечение в соответствии с Ответ Маенко. Если по какой-либо причине вы не можете выполнить эту модификацию, может существовать программное решение, но только в том случае, если базовое оборудование позволяет вам отключать последовательные передатчики ведомых устройств, сохраняя при этом последовательные приемники активными.
API-интерфейс Arduino не позволяет вам поддерживать последовательный передатчик активным
, пока приемник отключен: функции Serial.begin()
и
Serial.end()
управляют передатчиком и приемником в целом.
Возможно, вы сможете сделать это, получив доступ к оборудованию на более низком уровне. Вы
не указали, какой тип Arduino вы используете. Предполагая, что у вас есть
что-то похожее на Uno, вы можете отключить передатчик с помощью:
UCSR0B &= ~_BV(TXEN0);
и включите его снова с помощью:
UCSR0B |= _BV(TXEN0);
Если вы хотите использовать Arduino API для последовательной связи, вам
придется отключить передатчик сразу после Serial.begin()
:
const uint8_t TX_PIN = 1;
void setup() {
pinMode(TX_PIN, INPUT_PULLUP); // действителен, когда передатчик выключен
Serial.begin(9600); // включить последовательный порт
UCSR0B &= ~_BV(TXEN0); // отключить передатчик
}
Но имейте в виду, что тогда он будет включен на время сортировки (не более нескольких микросекунд), непосредственно перед тем, как вы его отключите. Это может привести к короткому замыканию, если один подчиненный загрузится, в то время как другой передает данные.
Одна из проблем с такого рода программными решениями заключается в том, что ошибки действительно случаются, и в вашей схеме ошибка в обработке протокола может привести к сбою вашего оборудования. Если вам удастся хотя бы добавить несколько защитных резисторов, как в ответе Габриэля Стейплза, это должно обезопасить вас.
- Как разделить входящую строку?
- Как вывести несколько переменных в строке?
- В чем разница между Serial.write и Serial.print? И когда они используются?
- Загрузка Arduino Nano дает ошибку: avrdude: stk500_recv(): programmer is not responding
- Программы построения последовательных данных
- Как узнать частоту дискретизации?
- Что такое Serial.begin(9600)?
- Очистить существующий массив при получении новой последовательной команды
Диоды и резистор., @Majenko
Два резистора - вот и все! Я просто добавил свой ответ., @Gabriel Staples