Усім користувачам контролерів Arduino відомо, що можна передавати дані через апаратний порт UART контролера, а також за допомогою вільних дискретних входів-виходів програмним UART портом. По суті для з'єднання двох контролерів між собою нам знадобляться 2 ... 3 дроти. По двох дротах буде односторонній зв'язок, а по трьох в обидва боки.
Так от, ми можемо в один контролер записати наприклад ось такий шматок програми
// Підключаємо бібліотеку Software Serial #include <SoftwareSerial.h> // Оголошуємо використані дискретні канали контролера для зв'язку SoftwareSerial outSerial(5, 6); // RX, TX float i1=40.04; float i2=5.08; float i3=-200.03; String str; unsigned long previousMillis = 0; const long interval =2000; //періодичність відправки даних в порт іншому контролеру void setup(){ Serial.begin(9600); //стандартна швидкість передачі даних апаратного UART порту (використовуємо для перевірки отримання даних від другого контролера) outSerial.begin(9600); //швидкість обміну програмного порту } void loop(){ unsigned long currentMillis = millis(); //із заданою періодичністю пишемо у програмний порт //іншому контролеру Arduino три постійно змінюваних числа float if (currentMillis - previousMillis >= interval) { previousMillis = currentMillis; str = "<"; i1 = i1+0.1; str += i1; str += ";"; i2 = i2+0.1; str += i2; str += ";"; i3 = i3+0.1; str += i3; str += ">"; outSerial.println(str); //тут відправлення типу <3.54;56.17;-140.34> } //тут віправляємо усі отримані від сусіднього контролера дані в апаратний UART у монітор порту if (outSerial.available()) { Serial.write(outSerial.read()); } }
З'єднаємо два контролери Arduino Nano R3 згідно наступної не хитрої схеми
У другий контролер запишемо програму з невеликими змінами. Ми в ній змінимо стартові величини флоатів, щоб вони явно відрізнялись від даних з першого Nano. А також переставимо місцями дискретні піни, до яких прив'язано програмний UART.
// Підключаємо бібліотеку Software Serial #include <SoftwareSerial.h> // Декларуємо використані дискретні канали контролера для зв'язку SoftwareSerial outSerial(6, 5); // RX, TX float i1=240.04; float i2=1005.08; float i3=-4200.03; String str; unsigned long previousMillis = 0; const long interval =2000; //періодичність відправлення даних в порт іншому контролеру void setup(){ Serial.begin(9600); // Звичайна швидкість передачі даних апаратного UART порту (використаємо для перевірки отримання даних від іншого контролера) outSerial.begin(9600); //швидкість обміну програмного порту } void loop(){ unsigned long currentMillis = millis(); //із заданою періодичністю пишемо в програмний порт //іншому контролеру Arduino три постійно змінюваних числа float if (currentMillis - previousMillis >= interval) { previousMillis = currentMillis; str = "<"; i1 = i1+0.1; str += i1; str += ";"; i2 = i2+0.1; str += i2; str += ";"; i3 = i3+0.1; str += i3; str += ">"; outSerial.println(str); //тут відправлення типу <3.54;56.17;-140.34> } //тут відправляємо усі отримані від сусіднього контролера дані в апаратний UART у монітор порту if (outSerial.available()) { Serial.write(outSerial.read()); } }
Тепер один Arduino потрібно буде живити окремо без нашого компа, а інший підключити до компа. Та в моніторі порта будемо отримувати наступні рядки з періодичністю в 2 секунди:
<240.64;1005.68;-4199.43>
<240.74;1005.78;-4199.33>
<240.84;1005.88;-4199.23>
const byte numChars = 32; char receivedChars[numChars]; char tempChars[numChars]; // тимчасовий масив використовується під час парсингу // змінні для зберігання отриманих даних char messageFromPC[numChars] = {0}; //текстові дані int integerFromPC = 0; //цілочисленні дані float floatFromPC = 0.0; //дійсні дані boolean newData = false; //============ void setup() { Serial.begin(9600); Serial.println("Цей приклад очікує три значення даних - текст, ціле число та число з плаваючою крапкою"); Serial.println("Передавайте дані з іншого контролера у такому вигляді <HelloWorld, 12, 24.7> "); Serial.println(); } //============ void loop() { recvWithStartEndMarkers(); if (newData == true) { strcpy(tempChars, receivedChars); parseData(); showParsedData(); newData = false; } } //============ void recvWithStartEndMarkers() { static boolean recvInProgress = false; static byte ndx = 0; char startMarker = '<'; char endMarker = '>'; char rc; while (Serial.available() > 0 && newData == false) { rc = Serial.read(); if (recvInProgress == true) { if (rc != endMarker) { receivedChars[ndx] = rc; ndx++; if (ndx >= numChars) { ndx = numChars - 1; } } else { receivedChars[ndx] = '\0'; // закінчуємо рядок recvInProgress = false; ndx = 0; newData = true; } } else if (rc == startMarker) { recvInProgress = true; } } } //============ void parseData() { // розділення даних на складові частини char * strtokIndx; // це використовується функцією strtok() як індекс strtokIndx = strtok(tempChars,","); // отримуємо значення першої змінної - рядок strcpy(messageFromPC, strtokIndx); //записуємо її в змінну messageFromPC strtokIndx = strtok(NULL, ","); // продовжуємо з останнього індексу integerFromPC = atoi(strtokIndx); // конвертуємо цю складову в integer strtokIndx = strtok(NULL, ","); floatFromPC = atof(strtokIndx); // перетворюємо цей шматок тексту у float } //============ void showParsedData() { Serial.print("Message "); Serial.println(messageFromPC); Serial.print("Integer "); Serial.println(integerFromPC); Serial.print("Float "); Serial.println(floatFromPC); }
Взагалі дуже рекомендую використовувати цей приклад скетчу у своїх проектах. Цей інструмент дозволяє нам з'єднувати два окремих контролера в одне ціле, що дає можливість збільшити кількість пінів пристрою або розподілити мізки Arduino на велику відстань. Також до Arduino Nano можна підключити другий контролер через апаратний порт UART, а програмний другий порт в мене запустити не вдалося (або я щось не правильно робив або бібліотека такого не дозволяє). Відпишіться, якщо у вас вдавалося запускати два програмних порти на одному контролері.
Піду штурмувати далі. Усім великий привіт від geekmatic!