RS485 master multi-slave

Arduino RS485 master multislave

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

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

Използвали сме програмата Fritzing, за начертаване на платката.

Кратък клип как работи:

Заключение

В бъдеще ще се опитаме да доразработим тази платформа до завършен продукт, който ще може да комуникира с Linux и Windows сървъри. Тя ще остане с RS485 master multi-slave комуникация, но ще се постараем да напишем библиотеки за Shell и Python за улеснение на процеса. Освен това, ще включим поддръжка за по-широк кръг от сензори и устройства, което ще увеличи гъвкавостта и приложимостта на системата. Ще осигурим и обширна документация и примери, които ще помогнат на разработчиците бързо и лесно да се интегрират и да използват платформата.