Arduino in ModBus preko RS485

Arduino je pojav za katerega bi težko rekli, da opisuje samo HW ali samo SW, zato mu tu namenajm poseben prostor.

Moderator: tilz0R

Arduino in ModBus preko RS485

OdgovorNapisal/-a Peter123 » 23 Okt 2018, 11:36

Živjo.
Tokrat želim prebirati vsebino/meritve merilca električne energije: Hiking DDS238-1ZN - http://domoticx.com/modbus-kwh-meter-dds238-1-zn/
Prebiram navodila za ModBus pa brez uspeha.
Da bi si olajšal zadevo uporabljam Arduino mega (ima več serijskih portov).
Skratka želim prebrati tok/moč in jo nato naprej obdelati (na koncu pisati na SD kartico).
Je kdo že to počel in mu je uspelo?
Informacije dobrodošle?
lp
Peter
Peter123
 
Prispevkov: 867
Pridružen: 09 Feb 2015, 13:20
Kraj: 1117 Lj.
Zahvalil se je: 18 krat
Prejel zahvalo: 113 krat
Uporabnika povabil: jmivsek
Število neizkoriščenih povabil: 23

Re: Arduino in ModBus preko RS485

OdgovorNapisal/-a igo » 23 Okt 2018, 15:34

V enem stroju z Arduinom vozim 4 frekvenčnike preko 485 ModBus-a.

https://s5tech.net/viewtopic.php?f=29&t ... crc#p79485

https://www.elektronik.si/phpBB2/viewto ... bus#530412

Na povezavi, ki si jo pripel, imaš primere paketov, ki jih Arduino pošlje števcu in paketov, ki jih števec odgovori Arduinotu.
Enostavno napolniš Array bytov in ga pošlješ na serijski buffer. Nato prebereš sprejete byte iz bufferja.
Teoretično je praksa posledica teorije, praktično je pa ravno obratno. (igo 2001)
LP, Igor
igo
 
Prispevkov: 1172
Pridružen: 11 Apr 2015, 12:38
Kraj: Krško
Zahvalil se je: 148 krat
Prejel zahvalo: 272 krat
Uporabnika povabil: DusanK
Število neizkoriščenih povabil: 26

Re: Arduino in ModBus preko RS485

OdgovorNapisal/-a LiPo » 23 Okt 2018, 17:03

Zadeve se loti najprej na PC,
kjer preko terminala pošiljaš in sprejemaš podatke.
Ko ti bo to delovalo, pa preidi na Arduino.

RS485 vmesnik dobiš za USB.

Kakšen vmesnik uporabljaš na Arduinotu?
Ali prekljapljaš RX/TX?

LpG
Uporabniški avatar
LiPo
 
Prispevkov: 707
Pridružen: 04 Apr 2015, 16:30
Kraj: LJUBLJANA
Zahvalil se je: 22 krat
Prejel zahvalo: 86 krat
Uporabnika povabil: cimabella
Število neizkoriščenih povabil: 17

Re: Arduino in ModBus preko RS485

OdgovorNapisal/-a Peter123 » 23 Okt 2018, 17:38

Bol ko brskam bol se bom moral zakopati v kodiranje samega protokola.
To je zadeva, ki je še nisem počel.
Vmesni je pač Arduino.
Tudi Rx in Tx preklaplam, ampak je že sestavljanje paketa precej obširna zadeva.
Hvala.
LP
Peter
Peter123
 
Prispevkov: 867
Pridružen: 09 Feb 2015, 13:20
Kraj: 1117 Lj.
Zahvalil se je: 18 krat
Prejel zahvalo: 113 krat
Uporabnika povabil: jmivsek
Število neizkoriščenih povabil: 23

Re: Arduino in ModBus preko RS485

OdgovorNapisal/-a igo » 23 Okt 2018, 19:31

Ne boj se, no.
Sestavljanje paketa je zelo enostavno, saj je struktura opisana v navodilih za števec.
Narediš si funkcije BeriNap(), BeriTok(), BeriMoc(), ... , v katerih napolniš Paket iz Arduinota v Stevec. Za CRC16 funkcijo glej moj prejšnji prispevek. Polinom za kodiranje je zelo verjetno 0xA001.

Primer funkcije za polnjenje Paketa:
void BeriNap(){ // BeriNapetost Arduino2Stevec
Odgovor=7; // To je pomembno kasneje pri branju
PaketA2S[0] = 0x01; // modbus Naslov stevca je 1
PaketA2S[1] = 0x03; // ukaz za Branje
PaketA2S[2] = 0x00; // zg. del naslova
PaketA2S[3] = 0x0c; // sp. del naslova, 0x 00 0c je register napetosti
PaketA2S[4] = 0x00; // zg.del števila registrov, ki jih želiš prebrati
PaketA2S[5] = 0x01; // želiš prebrati 0x 00 01 register (register za napetost vsebuje 2 byta)
RacunajCRC16(); // Funkcija za izračun CRC16 napolne PaketA2S[6] in PaketA2S[7]
} // void BeriNap()

Potem v programu lepo kličeš funkcijo za polnjenje Paketa in nato še za pisanje na 485.
..
BeriNap(); // Napolne Paket
PisiNa485(); // porine Paket v buffer in sproži pošiljanje
Ko konča pošiljanje, moraš pa še prebrati odgovor od števca.
BeriIz485();

Za Tok je register toka 0x000d (paket2=0x00, paket3=0x0d) in bereš 0x0001 (en)register (paket4=0x00, paket5=0x01).
void BeriTok(){
Odgovor=7;
....
RacunajCRC16();
}

Za branje glej prejšnji prispevek.
Struktura paketa je opisana v navodilih za števec. Pomembna razlika je le v tem, da pri se branju v Paket2 nahaja število bytov, ki jih bo števec poslal nazaj. Funkcija števila Odgovor je bolj varovalna, da pri branju bufferja počakaš na cel paket. Če se kak byte izgubi in ni sprejelo dovolj bytov, pa aktiviraš TimeOut in letiš iz zanke, da program ne obtiči v bralni zanki.
Pri branju napetosti bo torej odgovor dolg 7 bytov:
Paket0= naslov števca
Paket1= 0x03; // ukaz za branje
Paket2=0x02; // 0x0002 (dveh) bytov
Paket3= zgornji prebran byte
Paket4= spodnji prebran byte
Paket5= zgornji del crc16
Paket6= spodnji del crc16

Če so prvi trije byti enaki pričakovanim in zadnja dva prava (byte 0, 1, 2, 3 in 4 preveriš s Crc16 algoritmom, ki mora vrniti enak rezultat kot byta 5 in 6), sta tudi 3 in 4 veljavna.

V bistvu imaš ukaze A2S fiksne in lahko pri pošiljanju paketov uporabiš že izračunane vrednosti CRC16 (PaketA2S[6] in PaketA2S[7]), ki jih najdeš v tabeli. Za preverjanje prebranih vrednosti moraš pa vsakič izračunati crc16, saj je odvisen od vrnjenih vrednosti.
Teoretično je praksa posledica teorije, praktično je pa ravno obratno. (igo 2001)
LP, Igor
igo
 
Prispevkov: 1172
Pridružen: 11 Apr 2015, 12:38
Kraj: Krško
Zahvalil se je: 148 krat
Prejel zahvalo: 272 krat
Uporabnika povabil: DusanK
Število neizkoriščenih povabil: 26

Re: Arduino in ModBus preko RS485

OdgovorNapisal/-a igo » 23 Okt 2018, 20:04

Sem malo hitel s pisanjem ... in pisal kar paket3, paket4, ... , namesto dosledno polnih imen spremenljivk.
Pri spremenljivkah potrebuješ 2 Array-a:
PaketA2S[...] so byti v Array-u za pošiljanje iz Arduinota na Števec
PaketS2A[...] so byti v Array-u, ki so prebrani iz Stevca v Arduinota.


Pri nekaterih napravah (naprimer moji frekvenčniki) je treba paket z ukazom poslati 2 do 3-krat v sekundi, sicer modbus povezava pade. Potem pa se ene naprave same poberejo, ko dobijo veljaven paket na svoj naslov, ene je treba pa na tak ali drugačen način resetirati. Pri tem števcu ni videti nekih posebnih zahtev glede pogostosti komuniciranja.

Usposobi branje napetosti, vse ostalo je samo kopiranje.
Teoretično je praksa posledica teorije, praktično je pa ravno obratno. (igo 2001)
LP, Igor
igo
 
Prispevkov: 1172
Pridružen: 11 Apr 2015, 12:38
Kraj: Krško
Zahvalil se je: 148 krat
Prejel zahvalo: 272 krat
Uporabnika povabil: DusanK
Število neizkoriščenih povabil: 26

Re: Arduino in ModBus preko RS485

OdgovorNapisal/-a PeterV » 24 Okt 2018, 17:44

...tudi jaz imam podoben namen. sicer gledam Eastron SDM modele, ki ze imajo spisane knjiznice za arduino. mogoce ti pride bolj v postev.

I am crocodile Moto G (5) Plus using Tapatalk
PeterV
 
Prispevkov: 5
Pridružen: 17 Avg 2018, 16:33
Zahvalil se je: 0 krat
Prejel zahvalo: 0 krat
Uporabnika povabil: DusanK
Število neizkoriščenih povabil: 0

Re: Arduino in ModBus preko RS485

OdgovorNapisal/-a Peter123 » 25 Okt 2018, 08:47

Trenutno sem na tej stopnji:
Koda: Izberi vse
const int RS485ON =  21;  //Pin, ki je uporabljen za RE DE RS485 čipa.
String podatek = "a";     //Vpišem a da se razlikuje od prejetih podatkov

void setup()
{
  Serial.begin(9600); //Serijski na PC
  Serial1.begin(9600);  //Serijski na RS485
  pinMode(RS485ON, OUTPUT); //Definiramo pin kot izhod
  digitalWrite(RS485ON, HIGH);
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop()
{
  delay (1000);   //Zakasnitev za 1 s

  digitalWrite(RS485ON, LOW);  //Rs485 damo na oddajo
  digitalWrite(LED_BUILTIN, HIGH);
  delay (1);      //Zakasnitev propagacije iz Rx na Tx 1ms

  Serial1.write(0x01);  // Branje napetosti.
  Serial1.write(0x03);
  Serial1.write(0x00);
  Serial1.write(0x0c);
  Serial1.write(0x01);
  Serial1.write(0x44);
  Serial1.write(0x09);
 
  digitalWrite(RS485ON, HIGH);
  digitalWrite(LED_BUILTIN, LOW);
  //delay (1);

  int podatek = Serial1.read();
  Serial.println(podatek);
}

Odgovora ni .
Če s sniferjem poslušam na TTL Tx so naslednji podatki:
Koda: Izberi vse
01
03
00
0C
01
44
09

Torej iz MCU grejo podatki.
Z osciloskopom vidim da na A in B liniji 485 neki podatki šibajo.
Zakaj pa ni odgovora pa?
Ima kdo predlog kako naprej?
LP
Peter
Peter123
 
Prispevkov: 867
Pridružen: 09 Feb 2015, 13:20
Kraj: 1117 Lj.
Zahvalil se je: 18 krat
Prejel zahvalo: 113 krat
Uporabnika povabil: jmivsek
Število neizkoriščenih povabil: 23

Re: Arduino in ModBus preko RS485

OdgovorNapisal/-a igo » 25 Okt 2018, 09:39

Med 0x0c in 0x01 manjka byte 0x00.
Poslati moraš 8 bytov.
Potem bi moralo delati, saj vse ostalo izgleda v redu.
Teoretično je praksa posledica teorije, praktično je pa ravno obratno. (igo 2001)
LP, Igor
igo
 
Prispevkov: 1172
Pridružen: 11 Apr 2015, 12:38
Kraj: Krško
Zahvalil se je: 148 krat
Prejel zahvalo: 272 krat
Uporabnika povabil: DusanK
Število neizkoriščenih povabil: 26

Re: Arduino in ModBus preko RS485

OdgovorNapisal/-a Peter123 » 25 Okt 2018, 10:38

@igo
Ja si imel prav, ampak še ni rešilo zadeve.
Sedaj je odgovor "-1".
Adreso sem preveril in je 01.
Lp
Peter
Peter123
 
Prispevkov: 867
Pridružen: 09 Feb 2015, 13:20
Kraj: 1117 Lj.
Zahvalil se je: 18 krat
Prejel zahvalo: 113 krat
Uporabnika povabil: jmivsek
Število neizkoriščenih povabil: 23

Re: Arduino in ModBus preko RS485

OdgovorNapisal/-a igo » 25 Okt 2018, 11:12

Poglej, kako jaz v zanki napolnim array bytov. Nato tiste byte pošlji na PC. Ker ni nujno, da boš iz int string-a dobil ven 8-bitne byte, ki pašejo skupaj v paru. Beri posamezne byte in jih potem kombiniraj skupaj glede na lokacijo v paketu.

Pa pri modbus je treba počakati vsaj 1,5 bita dolgo, preden se preklopi na RX. Nekaj podobnega je na začetku pošiljanja.
Teoretično je praksa posledica teorije, praktično je pa ravno obratno. (igo 2001)
LP, Igor
igo
 
Prispevkov: 1172
Pridružen: 11 Apr 2015, 12:38
Kraj: Krško
Zahvalil se je: 148 krat
Prejel zahvalo: 272 krat
Uporabnika povabil: DusanK
Število neizkoriščenih povabil: 26

Re: Arduino in ModBus preko RS485

OdgovorNapisal/-a Peter123 » 29 Okt 2018, 12:54

Eno malenkost sem napredoval.
Očitno števec sprejme vprašanje in na njega tudi odgovori, ampak mi MAX485 podatka ne odkodira. Več na oscilogramu:
Osci 01.jpg

Še sama koda:
Koda: Izberi vse
const int RS485ON =  21;  //Pin, ki je uporabljen za RE DE RS485 čipa.
String podatek = "a";     //Vpišem a da se razlikuje od prejetih podatkov

void setup()
{
  Serial.begin(9600); //Serijski na PC
  Serial1.begin(9600);  //Serijski na RS485
  pinMode(RS485ON, OUTPUT); //Definiramo pin kot izhod
  digitalWrite(RS485ON, HIGH);
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop()
{
  delay (3000);   //Zakasnitev za 1 s

  digitalWrite(RS485ON, LOW);  //Rs485 damo na oddajo
  //digitalWrite(LED_BUILTIN, HIGH);
  delay (1);      //Zakasnitev propagacije iz Rx na Tx 1ms
//digitalWrite(RS485ON, LOW);
  Serial1.write(0x01);  // Branje napetosti.
  Serial1.write(0x03);
  Serial1.write(0x00);
  Serial1.write(0x0c);
  Serial1.write(0x00);
  Serial1.write(0x01);
  Serial1.write(0x44);
  Serial1.write(0x09);

  delay(10);   //Čas ki je potreben da se pošlje celi podatek / paket.
  digitalWrite(RS485ON, HIGH);

  int podatek = Serial1.read();
  Serial.println(podatek);
}

Ali kdo vidi razlog zakaj ne vidim ničesar na ttl strani?
LP
Peter
Peter123
 
Prispevkov: 867
Pridružen: 09 Feb 2015, 13:20
Kraj: 1117 Lj.
Zahvalil se je: 18 krat
Prejel zahvalo: 113 krat
Uporabnika povabil: jmivsek
Število neizkoriščenih povabil: 23

Re: Arduino in ModBus preko RS485

OdgovorNapisal/-a Peter123 » 30 Okt 2018, 12:25

Takole, branje napetosti uspešno:
Koda: Izberi vse
const int RS485ON =  21;  //Pin, ki je uporabljen za RE DE RS485 čipa.
char podatek = "a";     //Vpišem a da se razlikuje od prejetih podatkov
String vrednost ;
float vrednostp = 0;

void setup()
{
  Serial.begin(9600); //Serijski na PC
  Serial1.begin(9600);  //Serijski na RS485
  pinMode(RS485ON, OUTPUT); //Definiramo pin kot izhod
  digitalWrite(RS485ON, LOW); //Nekateri RS485 čipi imajo logiko obrnjeno!
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop()
{
 // int i = 3;
  delay (3000);   //Zakasnitev za 1 s

  digitalWrite(RS485ON, HIGH);  //Rs485 damo na oddajo
  delay (1);      //Zakasnitev propagacije iz Rx na Tx 1ms

  Serial1.write(0x01);  // Branje napetosti.
  Serial1.write(0x03);
  Serial1.write(0x00);
  Serial1.write(0x0c);
  Serial1.write(0x00);
  Serial1.write(0x01);
  Serial1.write(0x44);
  Serial1.write(0x09);

Serial1.flush();

  digitalWrite(RS485ON, LOW);

  if (Serial1.available())
  {
    vrednost = "";
    int i = 0;
    uint8_t a = 0;
    uint8_t b = 0;
    uint8_t c = 0;
   
      while (Serial1.available())
      {
        char podatek = Serial1.read();
        i++;
   
          if ( 4 == i )
          {
          //Serial.print(podatek);
          a = podatek;
          }
         
          if ( i == 5 )
          {
          //Serial.print(podatek);
          b =podatek;
          }
       
        vrednost = String( a + b);
      }
 
  Serial.print("Napetost= ");
  vrednost = a << 8 | b;
  vrednostp = vrednost.toInt() * 0.1;
  Serial.print(vrednostp, 1);
  Serial.println(" Vac");
  }
}
Peter123
 
Prispevkov: 867
Pridružen: 09 Feb 2015, 13:20
Kraj: 1117 Lj.
Zahvalil se je: 18 krat
Prejel zahvalo: 113 krat
Uporabnika povabil: jmivsek
Število neizkoriščenih povabil: 23

Re: Arduino in ModBus preko RS485

OdgovorNapisal/-a igo » 31 Okt 2018, 02:50

:_clap
Prejete byte je najlažje polniti v ArrayBytov[0 do Odgovor] in kasneje sestaviti skupaj 16-bitne vrednosti, saj izmerjene vrednosti niso vedno na isti poziciji.
Sprejemna funkcija je tako lahko univerzalna, razlika je le v izpisu enot.

Za ostale registre samo sestaviš skupaj pakete za pošiljanje in bo delovalo.
Teoretično je praksa posledica teorije, praktično je pa ravno obratno. (igo 2001)
LP, Igor
igo
 
Prispevkov: 1172
Pridružen: 11 Apr 2015, 12:38
Kraj: Krško
Zahvalil se je: 148 krat
Prejel zahvalo: 272 krat
Uporabnika povabil: DusanK
Število neizkoriščenih povabil: 26

Re: Arduino in ModBus preko RS485

OdgovorNapisal/-a Peter123 » 31 Okt 2018, 09:20

Nisem še na koncu.
Se dogajajo zanimive stvari. In sicer se prebrana vrednost izpiše šele 2 cikel.
Torej prižgeš MCU se izvede 1 cikel ter izpiše prebrano kako 0V. Nato se izvede drugo branje in verjetno dobim izpisano vrednost iz 1 branja.
Torej se nadaljuje.
Ja sestavljanje arayev lahko rešiš tudi na druge načine.
Peter123
 
Prispevkov: 867
Pridružen: 09 Feb 2015, 13:20
Kraj: 1117 Lj.
Zahvalil se je: 18 krat
Prejel zahvalo: 113 krat
Uporabnika povabil: jmivsek
Število neizkoriščenih povabil: 23


Vrni se na Arduino

Kdo je na strani

Po forumu brska: 0 registriranih uporabnikov in 1 gost