Варіанти для спілкування між Arduinos

Я хочу спілкуватися між ~ 5-10 Arduinos для надсилання команд і даних між ними. Під "Arduino" я маю на увазі програмування ATmega328, використовуючи архітектуру програмування Arduino.

Кожен з пристроїв буде на тій же друкованій платі.

Я знаю, що I2C і SPI можуть до певної міри з'єднуватися, але вони дійсно призначені для периферійних пристроїв, підключених до мікро-контролера, а не для підключення декількох мікро-контролерів один до одного, і що вони зазвичай надсилають лише кілька байтів даних за один раз . З іншого боку, я знаю, що РК-дисплеї можна керувати за допомогою них, і я думаю, що в цих випадках велика кількість переданих даних.

Чи є щось на зразок I2C (багатомасштабний, багаторядковий, односекційний, послідовний комп'ютерний шина) для зв'язку між мікроконтролерами? Дозволити кожному пристрою надсилати дані один до одного на небажані пристрої. Наприклад, якщо на пристрої A було натиснуто перемикач, це означатиме, що пристрій B, без натискання кнопки B, запитає A завжди. і навпаки.

Edit: I found some libraries that may do what I want with RS-485. Is this the only viable option for ~1k bps transmission between 5-10 devices? I would imagine TCP/IP over Ethernet would work as well, but that seems like too much. Are there any I2C libraries that allow sending that amount of data between only master devices?

5
ти маєш на увазі RS-485?
додано Автор user7461, джерело
@ Паул Я хочу розділити концерни. Я знаю, що я міг би просто отримати більш великий контролер з більшою кількістю переривань і введення/виводу, але я вважаю за краще тримати все прості на рівні пристрою. Це також допомагає, коли співпрацює з іншими, так як кожна підсистема може бути спроектована і навіть побудована самостійно та з'єднана пізніше. Також може бути простіше провести тестування та замінити/оновити.
додано Автор user7461, джерело
@ frarugi87 Я думаю, що топологія шини буде працювати найкраще, при цьому будь-який пристрій зв'язується з будь-яким іншим пристроєм і ініціює з'єднання. Отже, ніяких рабів.
додано Автор user7461, джерело
Вам потрібен фізичний рівень (кабельне або платове), електронне "стандартне", як RS-485, але 5V TTL теж добре. Тоді вам доведеться вибирати, який тип автобусного арбітражу (round-robin, master-slave або broadcast messages) і, можливо, реалізувати деякі перевірки адреси або помилок.
додано Автор dotnetengineer, джерело
На макеті я б не користувався RS485, оскільки він потребує приймачі. Тільки 5в для логіки 1 та 0в для логіки 0. Але з цього моменту можливості безмежні. Це також буде залежати від вимог до швидкості тощо.
додано Автор dotnetengineer, джерело
Ви не вказали, чому ви хочете створити таку річ. Якщо у вас короткі шпильки IO, ви можете використовувати IO-розширювачі. Там можуть бути кращі рішення. Якщо це хоббі/доказ концепції, ви можете перевірити інші проекти, як це, і намагайтеся "покращити/налаштувати".
додано Автор dotnetengineer, джерело
Ви дивилися на послідовний зв'язок?
додано Автор user67244, джерело
Тут є дуже схожі питання: Як з'єднати декілька Arduinos з Rpi для керування домашніми ліхтарями/вимикачами - ігнорування частини Rpi (це насправді не стосується питання). Я вважаю це практично ідентичним тому, що ви хочете робити Я зробив тривалий відгук про те, як робити систему "рухомого майстра". Будь ласка, прочитайте інше питання/відповідь і подивіться, що ви думаєте.
додано Автор Nick Gammon, джерело
інший мікро, ви повинні зробити російські хміль, але це працює. Останнє рішення - те, що ви сказали, так що всі, хто виступає на одному автобусі, але вам знадобиться виявлення зіткнень. У цьому випадку я пропоную вам шину CAN, оскільки вона вже обробляє зіткнення (але вам доведеться реалізувати його у вашому коді).
додано Автор Tom Collins, джерело
Ну, добре для топології автобусів, але я дуже рекомендую вам зробити одного автобусного майстра та всіх інших рабів. Інакше ви зіткнетеся, і виявлення/запобігання зіткнень є "важким" завданням. Якщо у вас є тільки один майстер, ви можете уникнути цього, оскільки тільки він може дати дозвіл на розмову. Ви можете створити серійний (UART) шину, з одним провідником підключення магістра TX до кожного підпорядкованого RX, а також один провод, що з'єднує раби TX (можливо, з 3-штатним буфером) для майстрів RX. В іншому випадку ви можете зробити ланцюгові ланцюги: TX1 підключений до RX2, TX2 до RX3 ... TXn до RX1. Це трохи менш ефективно, оскільки для обговорення
додано Автор Tom Collins, джерело
Може, я не просто знайшов це, але я не читав основне питання, яке "що топологія вам потрібна"? Вам потрібно, щоб усі розмовляли з усіма? Централізований доступ (тобто кожен, хто спілкується з одним)? Змішане рішення?
додано Автор Tom Collins, джерело

4 Відповіді

Є цілий ряд концепцій, які допоможуть вам реалізувати вашу мрію. Я не можу, у відповідь на цю відповідь, точно сказати, як реалізувати те, що вам потрібно, але я можу показати вам концепції, які допоможуть вам реалізувати це.

По-перше, є концепція автобуса . Це не обов'язково являє собою пристрій, який створює зв'язок - замість цього це пристрій, який володіє та елементами керування шиною.

Коли пристрій, який не є автобусом, хоче спілкуватися на шині, він спочатку запитує дозвіл від головного оператора шини. Старий Z80 (ну, я кажу "старий", але вони все ще використовуються в багатьох формах сьогодні) використовували цю концепцію, щоб інші чіпи могли використовувати дані та адреси автобусів. Він складається з двох сигналів - BUSRQ і BUSACK. Спочатку пристрій спочатку дивиться, чи є активним BUSRQ або BUSACK, і якщо це не так, то активізує BUSRQ. Якщо майстер автобуса готовий відмовитися від шини до іншого пристрою (він не використовує його в той момент), він активує BUSACK, а інший пристрій знає, що він може використовувати шину. Ніщо інше не може використовувати його, поки BUSRQ і BUSACK обидва були звільнені. Приємно і просто і елегантно.

Але не досконалий. Якщо обидва пристрої обидва вирішили запитати про автобус в той же момент, ви отримаєте зіткнення . Це загальна проблема серед спільних шинних систем, як це, і викликає незрозумілі проблеми, якщо ви не знаєте, як правильно її обробляти.

Введіть поняття слухати в той час як ви говорите . Це включає в себе пристрій, який надсилає на шині, також прослуховуючи те, що відправляється на автобусі через окремий приймач. Це тоді може знати якщо що це послане на автобусі що фактично закінчилося на автобусі. Наприклад, якщо два пристрої розмовляють одночасно, а один надсилає 10011001 , а інший надсилає 11001100 , результат, який з'являється на шині, насправді може стати чимось іншим, наприклад 11011101 або, можливо, 10001000 залежно від того, як створюються сигнали шини. Отже, якщо ви знаєте, що ви надіслали пошкоджені, то можете зробити щось про це.

Наступна концепція: відключення . Тут і відправники чекають короткий період і спробують відправити ще раз. Поки вони обидва затримуються на інший проміжок часу, перший спробує отримати автобус і мати можливість спілкуватися. Але як ви гарантуєте, що вони будуть затримуватися на різні часи? Ви можете подумати, що відповідь проста: скористайтеся випадковим числом, наприклад, rand() або random() . Але це також проблематично:

Another concept: The pseudo random number generator

Arduino не генерує випадкових чисел. Він просто використовує складну математичну формулу для створення послідовності чисел, які нам виглядають випадковими. Але це не так. Напишіть невелику програму для друку 10 випадкових чисел за допомогою серійного та запустіть її кілька разів (натисніть кнопку скидання). Ви знайдете однакові "випадкові" номери в тому ж порядку щоразу. Спробуйте це на іншому Arduino, і ви отримаєте ті ж номери знову. Завжди однаковий.

Так що робити? Відповідь називається насінням генератора випадкових чисел. Наступне число, створене rand() та ін, залежить від останнього згенерованого числа. Тому змініть номер першого , і всі інші номери будуть змінюватися. Тим не менш, у вас ситуація catch-22. Вам потрібна випадкова цифра, щоб виділити генератор випадкових чисел, щоб воно було випадковим, щоб мати можливість генерувати випадкове число для нарізки генератора випадкових чисел ... inf infinitum. Ви бачите, куди це відбувається? rand() не можна насівати, оскільки rand() не є випадковим, доки ви не перейшли з випадкового джерела. Отже, вам потрібно знайти випадкове джерело.

І це нелегке завдання. Найкращим джерелом ентропії , як відомо, є білий шум . Це може бути згенеровано кількома способами з рядом різних схем - від розбиття діодного з'єднання до дуже високої коефіцієнта підсилення теплових коливань в резисторах.

Все це досить складно для того, чого ви дійсно хочете, але є більш простий, якщо трохи менш випадковий спосіб - читати аналоговий вхід, який не пов'язаний ні з чим. Вона не буде мати стільки діапазону, як правильний генератор ентропії, але воно повинно забезпечити достатню випадковість, щоб дати розумні шанси кожного пристрою отримувати інше насіння.

Ще однією корисною концепцією є переривання.

Це добре в ситуації, коли ви не хочете, щоб складність багатокористувацького автобусу з усіма зіткненнями тощо. У вас є єдиний майстер, який виконує всю роботу на шині, а при веденні пристрою є щось важливе це підштовхує майстра до переривання. Тоді майстер іде "Так, що ти хочеш?" до якого раб відповідає "хтось натиснув мою кнопку".

Таким чином майстер не постійно проводить опитування раба, щоб побачити, чи натиснута кнопка. Він часто використовується в автобусних пристроях, таких як SPI, і є багато чіпів, таких як чіпи розширювача IO, які можуть стверджувати переривання, коли один з їх вхідних штифтів змінює стан.

Але якщо у вас 20 пристроїв, це означає, що у вас є 20 переривань шпильки? Не обов'язково. Нова концепція: дротова АР .

Цілком цілком можливим мати декілька різних рабів, які використовують один і той же перфоратор. Шпилька зазвичай тримається високо з резистором (це може бути внутрішній резистори), і кожний підпорядкований з виходом відкритого стоку , підключений до цього штифта. Вихід з відкритого стоку, коли "вимкнено", не пов'язано ні з чим - це схоже на штифт у режимі введення (насправді його можна емулювати на чіпах, які не мають відкритого стоку, перемикаючись між режимами введення та виведення). Коли вихід "на", він з'єднує штифт з землею, потягнувши вниз штекер IO, як би кнопка.

Тоді майстер повинен обійти рабів, які, як він знає, прикріплені до цього переривання, щоб побачити, хто потребує уваги. Звичайно, ви можете застосувати декілька різних штифтів для переривання з різними групами рабів на кожному з них - можливо, високого пріоритету з одним пристроєм і менш пріоритетними, наприклад, з кількома пристроями.

Те ж саме поняття проводового OR та open drain можна використовувати для того, щоб дозволити всім пристроям використовувати всі ті самі фізичні дроти. Це саме те, як працює I2C - дві шини лінії витягуються з допомогою резисторів, а пристрої на ньому використовують вихідні дренажні отвору, щоб витягнути лінію низькою, щоб відновити його до високого, щоб створити різні логічні рівні. Якщо два пристрої обидва потягують його разом, це буде просто низьким. Без методу відкритого стоку, якщо у вас був один пристрій, який видає 1, а інший - 0, то ви, в основному, отримаєте коротке замикання між цими двома, і це може призвести до пошкодження чіпів.

І тоді, звичайно, у вас є поняття про синхронне проти асинхронного зв'язку, але це зовсім інший чайник риби. Однак, прості сказано, що протоколи з годинником, такі як SPI та I2C, мають майстер, який генерує ці годинники, є синхронними. Протоколи типу UART та RS-232, RS-485 тощо асинхронні - вони покладаються на обидва кінці, погоджуючись на те, як швидко передаються дані (швидкість передачі), щоб вони знали, як інтерпретувати сигнали, коли вони надходять.

2
додано
@EdgarBonet Ви знаєте, чи бібліотека дротів підтримує мультимайстер? Це так просто, як це michael.bouvy.net/blog/uk/2013/05/25/…
додано Автор user7461, джерело
@ Waspinator: я не можу сказати, як я ніколи не намагався. Здається, Бібліотека Wire обробляє автобусний арбітраж , але я не знаю, чи зможе він впоратися з проблемами, про які я вже згадував раніше.
додано Автор Sprogz, джерело
Я хотів би просто додати, що I2C, теоретично, здатний володіти декількома майстрами, і має арбітражну схему, яка не потребує випадкових чисел. Проте, існує проблема з реалізацією Atmel. C.f. наприклад TWI модуль, здається, є помилковим в багатомасштабних комунікаціях та Кілька основних проблем з мікроконтролерами Atmel AVR . Єдиний майстер + переривання мені здається найпростішим рішенням.
додано Автор Sprogz, джерело
@EdgarBonet Практично всі протоколи можуть бути створені як багатопрофесійні, якщо реалізується деяка форма автобусної арбітражної системи. Деякі з них більше підходять для цього, ніж інші, і деякі, такі як I2C, мають "офіційні" способи зробити це, деякі з яких працюють краще, ніж інші. Найбільш надійним способом, звичайно, є відсутність мульти-майстер-системи взагалі :)
додано Автор Majenko, джерело

Ознайомтеся з PJON - https://github.com/gioblu/PJON . Це одна дротова альтернатива.

1
додано
Будь ласка, додайте деяку інформацію про те, чому це краще, ніж альтернативи/що виділяють його. Дякую!
додано Автор hintbw, джерело
PJON було доступно для декількох платформ, а не тільки для Arduino. Це простіше, ніж I2C/один провод. Він покращує шум. Він має мульти-майстер-підтримку. Прочитайте вікі з посиланням.
додано Автор Peter Green, джерело
Будь-ласка, ви можете розповісти про вашу відповідь на прикладі використання або плюсів і мінусів, оскільки це дійсно є відповіддю на посилання лише на даний момент.
додано Автор RSM, джерело

Крім відмінної відповіді @ Майенка, вам потрібно подумати про те, про що ви спілкуєтесь.

Схоже, ви хочете спілкуватися одним біт - можливо, ви можете піти з окремими контактами? Якщо у вас є майстер, і до 13 рабів, ви можете мати один штифт на майстер, підключений до одного штифта на кожному з рабів (через резистор). Якщо раб А хотів би сигналізувати, що це сигнал, він підніме штифт; майстер потім зможе опитати кожен штифт у свою чергу, щоб розібратися, хто сказав що.

0
додано
вибачте, що останній біт був лише прикладом того, як я хочу, щоб пристрої могли "штовхати" дані один одному, а не проводити опитування. Фактично, я хочу надіслати більше даних. ~ 100 байт 10 разів у секунду.
додано Автор user7461, джерело

Інший варіант - SPI.

SPI можна використовувати з будь-якою кількістю пристроїв у кільці. Мені пояснили так: будь-який учасник може перемикати лінію часу 8 разів, переміщати байт у власному буфері, в буфер нового пристрою, на кільці; пристрій отримує байт від попереднього пристрою. Якщо хтось ще 8 разів перемикає годинник, ви отримуєте повідомлення про те, що новий байт готовий (це робиться за допомогою апаратного забезпечення).

Вам потрібно уважно подумати про протокол для цього - "адреса", "довжина", "команда", а потім будь-яке число параметрів. Відправник надсилає байт "адреса", встановлює в буфері байт "length" і залишає готовий відпочинок. Наступне пристрій отримав байт "адреса" і бачить, чи він є призначеним одержувачем. Якщо це не так, він помічає це вниз і натискає ланцюг навколо, відзначає довжину і чекає, поки хтось ELSE не підштовхнув це багато байтів навколо. Якщо це ваш, прочитайте решту даних, натискайте дані навколо та видаляйте їх, коли ви йдете (щоб зупинити його повернення). Бланкова адреса (наприклад, 0) буде зарезервована, тобто "не робити нічого з цим, зачекайте, поки хтось ще натисне його, і прочитайте наступний байт як наступну адресу". Усі пристрої повинні буде ініціалізуватись до 0 при запуску.

Якщо вам потрібно динамічно встановлювати адреси, встановіть спеціальний байт "всі станції", з командою, яка означає "ваш номер пристрою X, і повідомити наступному пристрою, що номер пристрою - X + 1". Звичайно, хтось повинен це ініціювати.

Ви також ризикуєте зіткнення, якщо два пристрої починають надсилати одночасно, або якщо щось не ретранслює те, що передбачається (наприклад, чіп вимкнений). Вам потрібно подумати про те, як ви збираєтеся виявити/відновити це.

0
додано