![Arduino RS485 master multislave](http://ardudevelop.eu/wp-content/uploads/2022/10/Arduino-RS485.jpg)
RS485 master multi-slave комуникация
базиранa на Orange Pi Zero и Atmega328p.
В тази статия ще разгледаме “RS485_Shell master – AVR multi-slave” комуникация, базирана на Orange Pi Linux платформа ( която ще използваме за “master” устройство ) и две AVR ( Atmega328p ) платформи ( които ще използваме за “slave” устройства ).AVR платформите ще разпознаваме по “id” идентификатор, съответно “id=4000” и “id=4001”. По този начин ще се опитаме да направим прототип на RS485 master multi-slave платформа.
Orange_Pi-Zero: Linux платформата ще използвам за “maser” устройство което чрез shell скрипт ще комуникира с две AVR платформи. Към него може да се прибавиви и “предпочитаня от мен” WEB интерфейс за комуникация, както могат да се пишат и логове на данни подадени “slave” от устройствата.
AVR_ id=4000: Базирана на контролера Atmega328p, платформата ще е с идентификатор за разпознаване “4000”. На нея ще има три изходни релета които ще подават 12v, едно комутиращо реле, вход до 50v, вход до 20v, ROW вход който връща резултат 0-1023, дигитален вход от датчик I/O както и температурен сензор “ds18b20”.
AVR_ id=4001: Базирана на контролера Atmega328p, платформата ще е с идентификатор за разпознаване “4001”. На нея ще има три изходни релета които ще подават 12v, едно комутиращо реле, вход до 50v, вход до 20v, ROW вход който връща резултат 0-1023, дигитален вход от датчик I/O както и температурен сензор “ds18b20”.
![Arduino RS485 slave platform](http://ardudevelop.eu/wp-content/uploads/2022/10/Arduino-RS485-platform_3.jpg)
Shell script
В “Shell” скрипта не съм използвал функции като “cut” с цел подобряване на бързината. Може да разгледате кратки уроци в този сайт. По начина който е написан софтуера на AVR_платформите, изтичането на двете платформите става в порядъка на 0.3 секунди а сетването на релетата е от порядъка на 0.02 секунди. Проверката е направена с функцията “time” в “shell” средата. За по бърза работа може да се използвата портокол за комуникация като “ModBus”.
#!/bin/bash
RS485=/dev/ttyUSB0
chmod 777 $RS485;
stty -F $RS485 9600 -echo
function readControllers() {
# ----------- Controler 1 -----------------
echo "4000,101" > $RS485;
read -r -t 0.3 digitalRead_4000 < $RS485;
# echo "digital-4000 = " $digitalRead_4000;
echo "4000,102" > $RS485;
read -t 0.3 -r analogRead_4000 < $RS485;
# echo "analog-4000 = " $analogRead_4000;
# ----------- Controler 2 ------------------
echo "4001,101" > $RS485;
read -t 0.3 -r digitalRead_4001 < $RS485;
# echo "digital-4001 = " $digitalRead_4001;
echo "4001,102" > $RS485;
read -t 0.3 -r analogRead_4001 < $RS485;
# echo "analog-4001 = " $analogRead_4001;
}
function parceDigitalController_4000() {
D6_4000="${digitalRead_4000%%,*}"; digitalRead_4000="${digitalRead_4000#*,}"
D7_4000="${digitalRead_4000%%,*}"; digitalRead_4000="${digitalRead_4000#*,}"
D8_4000="${digitalRead_4000%%,*}"; digitalRead_4000="${digitalRead_4000#*,}"
D9_4000="${digitalRead_4000%%,*}"; digitalRead_4000="${digitalRead_4000#*,}"
D10_4000="${digitalRead_4000%%,*}"; digitalRead_4000="${digitalRead_4000#*,}"
}
function parceAnalogController_4000() {
A1_4000="${analogRead_4000%%,*}"; analogRead_4000="${analogRead_4000#*,}"
A2_4000="${analogRead_4000%%,*}"; analogRead_4000="${analogRead_4000#*,}"
A3_4000="${analogRead_4000%%,*}"; analogRead_4000="${analogRead_4000#*,}"
}
function parceDigitalController_4001() {
D6_4001="${digitalRead_4001%%,*}"; digitalRead_4001="${digitalRead_4001#*,}"
D7_4001="${digitalRead_4001%%,*}"; digitalRead_4001="${digitalRead_4001#*,}"
D8_4001="${digitalRead_4001%%,*}"; digitalRead_4001="${digitalRead_4001#*,}"
D9_4001="${digitalRead_4001%%,*}"; digitalRead_4001="${digitalRead_4001#*,}"
D10_4001="${digitalRead_4001%%,*}"; digitalRead_4001="${digitalRead_4001#*,}"
}
function parceAnalogController_4001() {
A1_4001="${analogRead_4001%%,*}"; analogRead_4001="${analogRead_4001#*,}"
A2_4001="${analogRead_4001%%,*}"; analogRead_4001="${analogRead_4001#*,}"
A3_4001="${analogRead_4001%%,*}"; analogRead_4001="${analogRead_4001#*,}"
}
function printValues() {
echo "4000_Digital_Read >>> " $D6_4000 "|" $D7_4000 "|" $D8_4000 "|" $D9_4000 "|" $D10_4000;
echo "4000_Analog_Read >>> " $A1_4000 "|" $A2_4000 "|" $A3_4000;
echo "4001_Digital_Read >>> " $D6_4001 "|" $D7_4001 "|" $D8_4001 "|" $D9_4001 "|" $D10_4001;
echo "4001_Analog_Read >>> " $A1_4001 "|" $A2_4001 "|" $A3_4001;
}
function PIR() {
if (( $D6_4000 == 1 ))
then
echo "4001,100,7,255" > $RS485;
else
echo "4001,100,7,0" > $RS485;
fi
}
function battery() {
battVolt=14.4;
if (( $(bc <<< "$A3_4001<$battVolt") > 0 ))
then
echo "4000,100,9,255" > $RS485;
else
echo "4000,100,9,0" > $RS485;
fi
}
temp=22.5;
while true
do
((count++));
readControllers;
parceDigitalController_4000;
parceAnalogController_4000;
parceDigitalController_4001;
parceAnalogController_4001;
printValues;
PIR;
battery;
if (( $count == 10 ))
then
echo "4000,103" > $RS485;
read -r -t 1 ds18b20 < $RS485;
echo $ds18b20;
count=0;
if (( $(bc <<< "$ds18b20>$temp") > 0 ))
then
echo "4001,100,8,255" > $RS485;
else
echo "4001,100,8,0" > $RS485;
fi
fi
echo "Count = " $count;
done
AVR платформа с “id=4000”
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 5 // arduino Pin
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
int sendPin = 2;
int sleep = 0;
int sleepSend = 15;
const int ledPin = 4;
int ledState = LOW;
unsigned long previousMillis = 0;
unsigned long interval = 500;
float R1_50v = 197000;
float R2_50v = 21400;
float Vin_50v = 0.0;
float Vout_50v = 0.0;
float Vprint_50v = 0.0;
float R1_20v = 98300;
float R2_20v = 33100;
float Vin_20v = 0.0;
float Vout_20v = 0.0;
float Vprint_20v = 0.0;
long ROW = 0.0;
void setup() {
Serial.begin(9600);
sensors.begin();
pinMode(sendPin , OUTPUT);
digitalWrite(sendPin , LOW);
pinMode(ledPin , OUTPUT);
digitalWrite(ledPin , HIGH);
pinMode(5 , INPUT);
}
float ds18b20() {
sensors.requestTemperatures();
float tempC = sensors.getTempCByIndex(0);
return tempC;
}
void loop() {
int pinFunction = 0;
int pinNumber = 0;
int pinSet = 0;
if (Serial.find("4000")) {
pinFunction = Serial.parseInt(); // parse first character
// ------- // analogWrite Pins \\ --------
if (pinFunction == 100) {
pinNumber = Serial.parseInt();
if ( pinNumber == 7 || pinNumber == 8 || pinNumber == 9 || pinNumber == 10 ) {
pinSet = Serial.parseInt();
analogWrite(pinNumber , pinSet);
}
delay(sleep);
}
// ------- // digitalRead Pins ALL \\ --------
if ( pinFunction == 101) {
digitalWrite(sendPin , HIGH);
delay(sleepSend);
for (int i = 6 ; i < 11 ; i++) {
Serial.print(digitalRead(i));
Serial.print(",");
}
Serial.println();
delay(sleepSend);
digitalWrite(sendPin , LOW);
}
delay(sleep);
// ------- // analogRead Pins ALL \\ --------
if ( pinFunction == 102) {
for (int i = 0 ; i < 100 ; i++) {
Vin_50v = Vin_50v + analogRead(A1);
Vin_20v = Vin_20v + analogRead(A2);
ROW = ROW + analogRead(A3);
}
Vin_50v = Vin_50v / 100;
Vin_20v = Vin_20v / 100;
ROW = ROW / 100;
Vout_50v = (Vin_50v * 5.0) / 1023;
Vout_20v = (Vin_20v * 5.0) / 1023;
Vprint_50v = (Vout_50v / (R2_50v / (R1_50v+R2_50v)));
Vprint_20v = (Vout_20v / (R2_20v / (R1_20v+R2_20v)));
digitalWrite(sendPin , HIGH);
delay(sleepSend);
Serial.print(ROW);
Serial.print(",");
Serial.print(Vprint_20v);
Serial.print(",");
Serial.print(Vprint_50v);
Serial.println();
delay(sleepSend);
digitalWrite(sendPin , LOW);
delay(sleep);
}
if ( pinFunction == 103 ) {
digitalWrite(sendPin , HIGH);
delay(sleepSend);
Serial.println(ds18b20());
delay(sleepSend);
digitalWrite(sendPin , LOW);
}
}
unsigned long currentMillis = millis();
if (currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
if (ledState == LOW)
ledState = HIGH;
else
ledState = LOW;
digitalWrite(ledPin, ledState);
}
}
AVR платформа с “id=4001”
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 5 // arduino Pin
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
int sendPin = 2;
int sleep = 0;
int sleepSend = 15;
const int ledPin = 4;
int ledState = LOW;
unsigned long previousMillis = 0;
unsigned long interval = 500;
float R1_50v = 196000;
float R2_50v = 21500;
float Vin_50v = 0.0;
float Vout_50v = 0.0;
float Vprint_50v = 0.0;
float R1_20v = 99500;
float R2_20v = 32300;
float Vin_20v = 0.0;
float Vout_20v = 0.0;
float Vprint_20v = 0.0;
long ROW = 0.0;
void setup() {
Serial.begin(9600);
sensors.begin();
pinMode(sendPin , OUTPUT);
digitalWrite(sendPin , LOW);
pinMode(ledPin , OUTPUT);
digitalWrite(ledPin , HIGH);
pinMode(5 , INPUT);
}
float ds18b20() {
sensors.requestTemperatures();
float tempC = sensors.getTempCByIndex(0);
return tempC;
}
void loop() {
int pinFunction = 0;
int pinNumber = 0;
int pinSet = 0;
if (Serial.find("4001")) {
pinFunction = Serial.parseInt(); // parse first character
// ------- // analogWrite Pins \\ --------
if (pinFunction == 100) {
pinNumber = Serial.parseInt();
if ( pinNumber == 7 || pinNumber == 8 || pinNumber == 9 || pinNumber == 10 ) {
pinSet = Serial.parseInt();
analogWrite(pinNumber , pinSet);
}
delay(sleep);
}
// ------- // digitalRead Pins ALL \\ --------
if ( pinFunction == 101) {
digitalWrite(sendPin , HIGH);
delay(sleepSend);
for (int i = 6 ; i < 11 ; i++) {
Serial.print(digitalRead(i));
Serial.print(",");
}
Serial.println();
delay(sleepSend);
digitalWrite(sendPin , LOW);
}
delay(sleep);
// ------- // analogRead Pins ALL \\ --------
if ( pinFunction == 102) {
for (int i = 0 ; i < 100 ; i++) {
Vin_50v = Vin_50v + analogRead(A1);
Vin_20v = Vin_20v + analogRead(A2);
ROW = ROW + analogRead(A3);
}
Vin_50v = Vin_50v / 100;
Vin_20v = Vin_20v / 100;
ROW = ROW / 100;
Vout_50v = (Vin_50v * 5.0) / 1023;
Vout_20v = (Vin_20v * 5.0) / 1023;
Vprint_50v = (Vout_50v / (R2_50v / (R1_50v+R2_50v)));
Vprint_20v = (Vout_20v / (R2_20v / (R1_20v+R2_20v)));
digitalWrite(sendPin , HIGH);
delay(sleepSend);
Serial.print(ROW);
Serial.print(",");
Serial.print(Vprint_20v);
Serial.print(",");
Serial.print(Vprint_50v);
Serial.println();
delay(sleepSend);
digitalWrite(sendPin , LOW);
delay(sleep);
}
if ( pinFunction == 103 ) {
digitalWrite(sendPin , HIGH);
delay(sleepSend);
Serial.println(ds18b20());
delay(sleepSend);
digitalWrite(sendPin , LOW);
}
}
unsigned long currentMillis = millis();
if (currentMillis - previousMillis > interval) {
previousMillis = currentMillis;
if (ledState == LOW)
ledState = HIGH;
else
ledState = LOW;
digitalWrite(ledPin, ledState);
}
}
Схема и печатна платка няма да публикувам. Ще оставя на вас свободно да интерпретирате хардуерната платформа. Не се изискват голям набор от части и не е много сложна за изпълнение. Оставил съм “I2C” порта свободен за бъдещи доработки.
Ето моята интерпретация на платформата:
![Arduino RS485 slave platform PCB](http://ardudevelop.eu/wp-content/uploads/2022/10/Arduino-RS485-platform_2.jpg)
![Arduino RS485 slave platform PCB](http://ardudevelop.eu/wp-content/uploads/2022/10/Arduino-RS485-platform_1.jpg)
![Arduino RS485 slave platform proto](http://ardudevelop.eu/wp-content/uploads/2022/10/Arduino-RS485-platform_3.jpg)
![Arduino RS485 slave platform PCB Fritzing](http://ardudevelop.eu/wp-content/uploads/2022/10/Arduino-RS485-platform_4.jpg)
Използвали сме програмата Fritzing, за начертаване на платката.
Кратък клип как работи:
Заключение
В бъдеще ще се опитаме да доразработим тази платформа до завършен продукт, който ще може да комуникира с Linux и Windows сървъри. Тя ще остане с RS485 master multi-slave комуникация, но ще се постараем да напишем библиотеки за Shell и Python за улеснение на процеса. Освен това, ще включим поддръжка за по-широк кръг от сензори и устройства, което ще увеличи гъвкавостта и приложимостта на системата. Ще осигурим и обширна документация и примери, които ще помогнат на разработчиците бързо и лесно да се интегрират и да използват платформата.