RS 485 Modbus Kommunikation

Hardware- und Elektronikbasteleien, Ansteuerung von Schnittstellen und Peripherie.
Fragen zu "Consumer"-Problemen kommen in Offtopic.
Benutzeravatar
heiße Luft
Beiträge: 45
Registriert: 21.04.2009 12:04
Computerausstattung: Ausreichend. 3 Pc, 1 Laptop
BS: Win 7 (zum spielen),XP (weils noch da ist), Win 2000(laptop) und Linux (Umbuntu und Mint)
Wohnort: NRW

RS 485 Modbus Kommunikation

Beitrag von heiße Luft »

Hallo Leute,

ich habe wieder ein Hardware-Projekt bei dem ich nicht so recht weiss wie ich anfangen soll.
Ich habe einen Regler der Firma Gefran ( Typ 600) mit RS485 Schnittstelle bekommen. Als Protokoll wird MODBUS verwendet.
In meiner Elektronik Grabbelkiste habe ich noch einen ADAM Schnittstellen Konverter (RS485/RS232) gefunden.
Im Netz habe ich ein Konfigurations- Tool von Gefran gefunden. Damit konnte über den ADAM auf den Regler zugreifen. Die Hardware funktioniert also.
In Netz bieten etliche Firmen DLLs für die Kommunikation über Modbus mit ihren Geräten an. Auch kommerzielle allgemeine DLLs für die Modbus- Kommunikation habe ich gefunden.
Auch eine freie DLL habe ich gefunden, jedoch keine gute Beschreibung bisher (rxmod.dll).
Jetzt bin ich ein wenig verwirrt.
Ich dachte Modbus ist lediglich die Art (Reihenfolge) wie ich Anfragen über die RS232 schicke um eine bestimmte Antwort zu bekommen.

Hat jemand damit schon Erfahrungen gemacht?

Grüße hL
Wissen ist das einzige Gut das sich vermehrt wenn man es teilt!
Benutzeravatar
helpy
Beiträge: 635
Registriert: 29.08.2004 13:29

Re: RS 485 Modbus Kommunikation

Beitrag von helpy »

Erfahrung: Nein

Infos:
==> http://de.wikipedia.org/wiki/Modbus
==> Modbus-Spezifikation über serielle Leitung (englisch), mit Data-Link Layer und physischem Layer (auch Steckerbelegung)
Windows 10
PB Last Final / (Sometimes testing Beta versions)
Benutzeravatar
heiße Luft
Beiträge: 45
Registriert: 21.04.2009 12:04
Computerausstattung: Ausreichend. 3 Pc, 1 Laptop
BS: Win 7 (zum spielen),XP (weils noch da ist), Win 2000(laptop) und Linux (Umbuntu und Mint)
Wohnort: NRW

Re: RS 485 Modbus Kommunikation

Beitrag von heiße Luft »

Hallo Helpy,

danke für die links. Habe ich natürlich selbst gefunden.
Mich verwunderte nur das viele Hersteller DLLs zur Kommunikation über Modbus für ihre Geräte anbieten.
Da es auch die erwähnte freie DLL gibt dachte ich, dass man das Ganze vereinfachen könnte und nicht alles „zu Fuß“ programmieren muß. Ich bin halt von Haus aus faul und möchte mir nicht mehr Arbeit machen als nötig. Für Tipps bin ich immer dankbar.

Viele Grüße hL
Wissen ist das einzige Gut das sich vermehrt wenn man es teilt!
Benutzeravatar
Kiffi
Beiträge: 10621
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Re: RS 485 Modbus Kommunikation

Beitrag von Kiffi »

@heiße Luft

vielleicht wirst du hier fündig:

http://www.codeproject.com/info/search. ... tkw=modbus

oder hier:

http://sourceforge.net/search/?type_of_ ... rds=modbus

Grüße ... Kiffi
Hygge
Benutzeravatar
mk-soft
Beiträge: 3701
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: RS 485 Modbus Kommunikation

Beitrag von mk-soft »

Das Modbus-Protokoll ist wirklich kein geheimnis. Sollte ohne probleme in PB Programmiert werden können.
Der einzige Unterschied zwischen Modus und Modus-TCP ist, das bei TCP noch ein Header von 3 Worter (16bit) hat und das CheckByte nicht mit übertragen wird. Habe den quatsch schon mit einer Siemens SPS (Step7) selber programmiert.
Mit einen PC sollte es noch leichter gehen.
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
BI2
Beiträge: 145
Registriert: 26.11.2006 19:07

Re: RS 485 Modbus Kommunikation

Beitrag von BI2 »

@heiße Luft

Das Modbus Protokoll ist wirklich kein Problem, habe das auch mal in einem Projekt von mir umgesetzt (auslesen der Messwerte aus einem SENTRON PAC 3000 von Siemens über Ethernet - MODBUS Protokoll). Wenn Du Interesse hast, kann ich Dir die Sourcen mal zukommen lassen.

Gruß, BI2

Edit: hier noch meine gesammelten Links zu dem Projekt (waren mir seinerzeit eine große Hilfe):

http://www.anybus.de/technologie/modbustcp.shtml
http://www.google.com/codesearch/p?hl=d ... dbus%20tcp
http://mbserver.tripod.com/
http://sites.google.com/site/plcsimulator/
http://www.modbus.org/
http://www.industry.siemens.com/industr ... us_tcp.htm
http://www.buildingtechnologies.siemens ... c3200.aspx
http://www.simplymodbus.ca/TCP.htm
http://www.ipsta.de/seiten_html/technologie_modbus.html
http://de.wikipedia.org/wiki/Modbus
PB 5.7x (x64), LinuxMint 18.3 - Xfce (x64)

Einsteigerbuch: PureBasic - Eine Einführung in die Computer Programmierung
Benutzeravatar
heiße Luft
Beiträge: 45
Registriert: 21.04.2009 12:04
Computerausstattung: Ausreichend. 3 Pc, 1 Laptop
BS: Win 7 (zum spielen),XP (weils noch da ist), Win 2000(laptop) und Linux (Umbuntu und Mint)
Wohnort: NRW

Re: RS 485 Modbus Kommunikation

Beitrag von heiße Luft »

Hallo Leute,

sorry, das ich mich erst jetzt melde, aber ich war im Urlaub.
Jetzt geht es weiter.
@B12
oh ja, an Beispiel- Code bin ich sehr interessiert!

Ich habe auch noch eine schöne Website zum Thema gefunden.

http://pvbrowser.org/pvbrowser/sf/manua ... odbus.html

Grüße hL
Wissen ist das einzige Gut das sich vermehrt wenn man es teilt!
Benutzeravatar
BI2
Beiträge: 145
Registriert: 26.11.2006 19:07

Re: RS 485 Modbus Kommunikation

Beitrag von BI2 »

Da ich jetzt schon ein paar Anfragen hatte Poste ich das ganze einfach mal hier:

Code: Alles auswählen

;/ SENTRON PAC3200 Viewer
;/ 13.09.2009 PureBasic 4.31

EnableExplicit

Global PRGName$   = "SENTRON PAC3200 Viewer"
Global Version$   = "1.0"
Global Copyright$ = "© 2009 ASW"

Enumeration ;Konstanten
	#frmHaupt
	#ListIcon_0
	#ToolBar_0
	#tlbInfo
	#tlbResetMin
	#tlbResetMax
	#StatusBar_0
EndEnumeration
;==================================================================================================

Global *Anfrage = AllocateMemory(12)
Global *Antwort = AllocateMemory(300)
Global Abfragecode
Global NewList Messgroessen.s()
Global NewList IPListe.s()
Global Dim Messwerte.f(0,0)
Global Leseintervall
Global Programmende

;- Images
Global ImgInfo   = CatchImage(1, ?info)
Global ImgRed    = CatchImage(3, ?red)
Global ImgGreen  = CatchImage(4, ?green)
Global ImgYellow = CatchImage(5, ?yellow)
Global ImgRmin   = CatchImage(6, ?rmin)
Global ImgRmax   = CatchImage(7, ?rmax)

DataSection ;info.ico   hat eine Länge von 318 Bytes
	info:
	Data.b $00, $00, $01, $00, $01, $00, $10, $10, $00, $00, $01, $00, $04, $00, $28, $01
	Data.b $00, $00, $16, $00, $00, $00, $28, $00, $00, $00, $10, $00, $00, $00, $20, $00
	Data.b $00, $00, $01, $00, $04, $00, $00, $00, $00, $00, $80, $00, $00, $00, $00, $00
	Data.b $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
	Data.b $00, $00, $80, $00, $00, $00, $00, $80, $00, $00, $80, $80, $00, $00, $00, $00
	Data.b $80, $00, $80, $00, $80, $00, $00, $80, $80, $00, $C0, $C0, $C0, $00, $80, $80
	Data.b $80, $00, $FF, $00, $00, $00, $00, $FF, $00, $00, $FF, $FF, $00, $00, $00, $00
	Data.b $FF, $00, $FF, $00, $FF, $00, $00, $FF, $FF, $00, $FF, $FF, $FF, $00, $00, $00
	Data.b $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
	Data.b $00, $0E, $60, $00, $00, $00, $00, $00, $00, $0E, $60, $00, $00, $00, $00, $00
	Data.b $00, $00, $00, $00, $00, $00, $00, $00, $00, $0E, $60, $00, $00, $00, $00, $00
	Data.b $00, $0E, $60, $00, $00, $00, $00, $00, $00, $0E, $60, $00, $00, $00, $00, $00
	Data.b $00, $0E, $E6, $00, $00, $00, $00, $00, $00, $00, $EE, $60, $00, $00, $00, $00
	Data.b $E6, $00, $0E, $E6, $00, $00, $00, $00, $E6, $00, $00, $E6, $00, $00, $00, $00
	Data.b $EE, $60, $0E, $E6, $00, $00, $00, $00, $0E, $EE, $EE, $60, $00, $00, $00, $00
	Data.b $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $FF, $FF
	Data.b $00, $00, $FE, $7F, $00, $00, $FC, $3F, $00, $00, $FC, $3F, $00, $00, $FE, $7F
	Data.b $00, $00, $FC, $3F, $00, $00, $FC, $3F, $00, $00, $FC, $3F, $00, $00, $FC, $1F
	Data.b $00, $00, $F2, $0F, $00, $00, $E1, $07, $00, $00, $E1, $87, $00, $00, $E0, $07
	Data.b $00, $00, $F0, $0F, $00, $00, $F8, $1F, $00, $00, $FF, $FF, $00, $00
EndDataSection
DataSection ;green.ico  hat eine Länge von 318 Bytes
	green:
	Data.b $00, $00, $01, $00, $01, $00, $10, $10, $10, $00, $00, $00, $00, $00, $28, $01
	Data.b $00, $00, $16, $00, $00, $00, $28, $00, $00, $00, $10, $00, $00, $00, $20, $00
	Data.b $00, $00, $01, $00, $04, $00, $00, $00, $00, $00, $C0, $00, $00, $00, $00, $00
	Data.b $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
	Data.b $00, $00, $00, $00, $80, $00, $00, $80, $00, $00, $00, $80, $80, $00, $80, $00
	Data.b $00, $00, $80, $00, $80, $00, $80, $80, $00, $00, $80, $80, $80, $00, $C0, $C0
	Data.b $C0, $00, $00, $00, $FF, $00, $00, $FF, $00, $00, $00, $FF, $FF, $00, $FF, $00
	Data.b $00, $00, $FF, $00, $FF, $00, $FF, $FF, $00, $00, $FF, $FF, $FF, $00, $00, $00
	Data.b $00, $00, $00, $00, $00, $00, $AA, $AA, $AA, $AA, $AA, $AA, $AA, $00, $AA, $AA
	Data.b $AA, $AA, $AA, $AA, $AA, $00, $AA, $AA, $AA, $AA, $AA, $AA, $AA, $00, $AA, $AA
	Data.b $AA, $AA, $AA, $AA, $AA, $00, $AA, $AA, $AA, $AA, $AA, $AA, $AA, $00, $AA, $AA
	Data.b $AA, $AA, $AA, $AA, $AA, $00, $AA, $AA, $AA, $AA, $AA, $AA, $AA, $00, $AA, $AA
	Data.b $AA, $AA, $AA, $AA, $AA, $00, $AA, $AA, $AA, $AA, $AA, $AA, $AA, $00, $AA, $AA
	Data.b $AA, $AA, $AA, $AA, $AA, $00, $AA, $AA, $AA, $AA, $AA, $AA, $AA, $00, $AA, $AA
	Data.b $AA, $AA, $AA, $AA, $AA, $00, $AA, $AA, $AA, $AA, $AA, $AA, $AA, $00, $AA, $AA
	Data.b $AA, $AA, $AA, $AA, $AA, $00, $00, $00, $00, $00, $00, $00, $00, $00, $FF, $FF
	Data.b $00, $00, $00, $03, $00, $00, $00, $03, $00, $00, $00, $03, $00, $00, $00, $03
	Data.b $00, $00, $00, $03, $00, $00, $00, $03, $00, $00, $00, $03, $00, $00, $00, $03
	Data.b $00, $00, $00, $03, $00, $00, $00, $03, $00, $00, $00, $03, $00, $00, $00, $03
	Data.b $00, $00, $00, $03, $00, $00, $00, $03, $00, $00, $FF, $FF, $00, $00
EndDataSection
DataSection ;red.ico    hat eine Länge von 318 Bytes
	red:
	Data.b $00, $00, $01, $00, $01, $00, $10, $10, $10, $00, $00, $00, $00, $00, $28, $01
	Data.b $00, $00, $16, $00, $00, $00, $28, $00, $00, $00, $10, $00, $00, $00, $20, $00
	Data.b $00, $00, $01, $00, $04, $00, $00, $00, $00, $00, $C0, $00, $00, $00, $00, $00
	Data.b $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
	Data.b $00, $00, $00, $00, $80, $00, $00, $80, $00, $00, $00, $80, $80, $00, $80, $00
	Data.b $00, $00, $80, $00, $80, $00, $80, $80, $00, $00, $80, $80, $80, $00, $C0, $C0
	Data.b $C0, $00, $00, $00, $FF, $00, $00, $FF, $00, $00, $00, $FF, $FF, $00, $FF, $00
	Data.b $00, $00, $FF, $00, $FF, $00, $FF, $FF, $00, $00, $FF, $FF, $FF, $00, $00, $00
	Data.b $00, $00, $00, $00, $00, $00, $99, $99, $99, $99, $99, $99, $99, $00, $99, $99
	Data.b $99, $99, $99, $99, $99, $00, $99, $99, $99, $99, $99, $99, $99, $00, $99, $99
	Data.b $99, $99, $99, $99, $99, $00, $99, $99, $99, $99, $99, $99, $99, $00, $99, $99
	Data.b $99, $99, $99, $99, $99, $00, $99, $99, $99, $99, $99, $99, $99, $00, $99, $99
	Data.b $99, $99, $99, $99, $99, $00, $99, $99, $99, $99, $99, $99, $99, $00, $99, $99
	Data.b $99, $99, $99, $99, $99, $00, $99, $99, $99, $99, $99, $99, $99, $00, $99, $99
	Data.b $99, $99, $99, $99, $99, $00, $99, $99, $99, $99, $99, $99, $99, $00, $99, $99
	Data.b $99, $99, $99, $99, $99, $00, $00, $00, $00, $00, $00, $00, $00, $00, $FF, $FF
	Data.b $00, $00, $00, $03, $00, $00, $00, $03, $00, $00, $00, $03, $00, $00, $00, $03
	Data.b $00, $00, $00, $03, $00, $00, $00, $03, $00, $00, $00, $03, $00, $00, $00, $03
	Data.b $00, $00, $00, $03, $00, $00, $00, $03, $00, $00, $00, $03, $00, $00, $00, $03
	Data.b $00, $00, $00, $03, $00, $00, $00, $03, $00, $00, $FF, $FF, $00, $00
EndDataSection
DataSection ;yellow.ico hat eine Länge von 318 Bytes
	yellow:
	Data.b $00, $00, $01, $00, $01, $00, $10, $10, $10, $00, $00, $00, $00, $00, $28, $01
	Data.b $00, $00, $16, $00, $00, $00, $28, $00, $00, $00, $10, $00, $00, $00, $20, $00
	Data.b $00, $00, $01, $00, $04, $00, $00, $00, $00, $00, $C0, $00, $00, $00, $00, $00
	Data.b $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
	Data.b $00, $00, $00, $00, $80, $00, $00, $80, $00, $00, $00, $80, $80, $00, $80, $00
	Data.b $00, $00, $80, $00, $80, $00, $80, $80, $00, $00, $80, $80, $80, $00, $C0, $C0
	Data.b $C0, $00, $00, $00, $FF, $00, $00, $FF, $00, $00, $00, $FF, $FF, $00, $FF, $00
	Data.b $00, $00, $FF, $00, $FF, $00, $FF, $FF, $00, $00, $FF, $FF, $FF, $00, $00, $00
	Data.b $00, $00, $00, $00, $00, $00, $BB, $BB, $BB, $BB, $BB, $BB, $BB, $00, $BB, $BB
	Data.b $BB, $BB, $BB, $BB, $BB, $00, $BB, $BB, $BB, $BB, $BB, $BB, $BB, $00, $BB, $BB
	Data.b $BB, $BB, $BB, $BB, $BB, $00, $BB, $BB, $BB, $BB, $BB, $BB, $BB, $00, $BB, $BB
	Data.b $BB, $BB, $BB, $BB, $BB, $00, $BB, $BB, $BB, $BB, $BB, $BB, $BB, $00, $BB, $BB
	Data.b $BB, $BB, $BB, $BB, $BB, $00, $BB, $BB, $BB, $BB, $BB, $BB, $BB, $00, $BB, $BB
	Data.b $BB, $BB, $BB, $BB, $BB, $00, $BB, $BB, $BB, $BB, $BB, $BB, $BB, $00, $BB, $BB
	Data.b $BB, $BB, $BB, $BB, $BB, $00, $BB, $BB, $BB, $BB, $BB, $BB, $BB, $00, $BB, $BB
	Data.b $BB, $BB, $BB, $BB, $BB, $00, $00, $00, $00, $00, $00, $00, $00, $00, $FF, $FF
	Data.b $00, $00, $00, $03, $00, $00, $00, $03, $00, $00, $00, $03, $00, $00, $00, $03
	Data.b $00, $00, $00, $03, $00, $00, $00, $03, $00, $00, $00, $03, $00, $00, $00, $03
	Data.b $00, $00, $00, $03, $00, $00, $00, $03, $00, $00, $00, $03, $00, $00, $00, $03
	Data.b $00, $00, $00, $03, $00, $00, $00, $03, $00, $00, $FF, $FF, $00, $00
EndDataSection
DataSection ;rmin.ico   hat eine Länge von 318 Bytes
	rmin:
	Data.b $00, $00, $01, $00, $01, $00, $10, $10, $10, $00, $00, $00, $00, $00, $28, $01
	Data.b $00, $00, $16, $00, $00, $00, $28, $00, $00, $00, $10, $00, $00, $00, $20, $00
	Data.b $00, $00, $01, $00, $04, $00, $00, $00, $00, $00, $C0, $00, $00, $00, $00, $00
	Data.b $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
	Data.b $00, $00, $00, $00, $80, $00, $00, $80, $00, $00, $00, $80, $80, $00, $80, $00
	Data.b $00, $00, $80, $00, $80, $00, $80, $80, $00, $00, $80, $80, $80, $00, $C0, $C0
	Data.b $C0, $00, $00, $00, $FF, $00, $00, $FF, $00, $00, $00, $FF, $FF, $00, $FF, $00
	Data.b $00, $00, $FF, $00, $FF, $00, $FF, $FF, $00, $00, $FF, $FF, $FF, $00, $00, $00
	Data.b $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
	Data.b $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
	Data.b $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
	Data.b $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
	Data.b $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
	Data.b $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
	Data.b $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
	Data.b $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $FF, $FF
	Data.b $00, $00, $FF, $FF, $00, $00, $9E, $77, $00, $00, $9C, $63, $00, $00, $9C, $C1
	Data.b $00, $00, $98, $F7, $00, $00, $91, $F7, $00, $00, $83, $F7, $00, $00, $80, $F7
	Data.b $00, $00, $9C, $77, $00, $00, $9E, $77, $00, $00, $9C, $77, $00, $00, $80, $F7
	Data.b $00, $00, $81, $F7, $00, $00, $FF, $FF, $00, $00, $FF, $FF, $00, $00
EndDataSection
DataSection ;rmax.ico   hat eine Länge von 318 Bytes
	rmax:
	Data.b $00, $00, $01, $00, $01, $00, $10, $10, $10, $00, $00, $00, $00, $00, $28, $01
	Data.b $00, $00, $16, $00, $00, $00, $28, $00, $00, $00, $10, $00, $00, $00, $20, $00
	Data.b $00, $00, $01, $00, $04, $00, $00, $00, $00, $00, $C0, $00, $00, $00, $00, $00
	Data.b $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
	Data.b $00, $00, $00, $00, $80, $00, $00, $80, $00, $00, $00, $80, $80, $00, $80, $00
	Data.b $00, $00, $80, $00, $80, $00, $80, $80, $00, $00, $80, $80, $80, $00, $C0, $C0
	Data.b $C0, $00, $00, $00, $FF, $00, $00, $FF, $00, $00, $00, $FF, $FF, $00, $FF, $00
	Data.b $00, $00, $FF, $00, $FF, $00, $FF, $FF, $00, $00, $FF, $FF, $FF, $00, $00, $00
	Data.b $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
	Data.b $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
	Data.b $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
	Data.b $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
	Data.b $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
	Data.b $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
	Data.b $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00
	Data.b $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $FF, $FF
	Data.b $00, $00, $FF, $FF, $00, $00, $9E, $77, $00, $00, $9C, $77, $00, $00, $9C, $F7
	Data.b $00, $00, $98, $F7, $00, $00, $91, $F7, $00, $00, $83, $F7, $00, $00, $80, $F7
	Data.b $00, $00, $9C, $77, $00, $00, $9E, $77, $00, $00, $9C, $41, $00, $00, $80, $E3
	Data.b $00, $00, $81, $F7, $00, $00, $FF, $FF, $00, $00, $FF, $FF, $00, $00
EndDataSection


Procedure.w BLEconvW(WordWert.w)  ; Big-Little-Endian Konverter für Wordwerte

	Protected temp.w

	PokeB(@temp    , PeekB(@WordWert + 1))
	PokeB(@temp + 1, PeekB(@WordWert))

	ProcedureReturn temp

EndProcedure
;==================================================================================================
Procedure.l BLEconvL(LongWert.l)  ; Big-Little-Endian Konverter für Longwerte

	Protected temp.l

	PokeB(@temp    , PeekB(@LongWert + 3))
	PokeB(@temp + 1, PeekB(@LongWert + 2))
	PokeB(@temp + 2, PeekB(@LongWert + 1))
	PokeB(@temp + 3, PeekB(@LongWert))

	ProcedureReturn temp

EndProcedure
;==================================================================================================
Procedure.f BLEconvF(FloatWert.f) ; Big-Little-Endian Konverter für Floatwerte

	Protected temp.f

	PokeB(@temp    , PeekB(@FloatWert + 3))
	PokeB(@temp + 1, PeekB(@FloatWert + 2))
	PokeB(@temp + 2, PeekB(@FloatWert + 1))
	PokeB(@temp + 3, PeekB(@FloatWert))

	ProcedureReturn temp

EndProcedure
;==================================================================================================
Procedure.s ChgAddExtension(File.s, NewExtension.s) ; Ändert die Dateiendung einer Datei oder fügt sie bei fehlen hinzu

	If GetExtensionPart(File)
		File = GetPathPart(File) + ReplaceString(GetFilePart(File), "." + GetExtensionPart(File), "." + NewExtension)
	Else
		File + "." + NewExtension
	EndIf

	ProcedureReturn File

EndProcedure
;==================================================================================================

;- Konfigurationsdatei

Procedure ReadINI() ; Konfigurationsdatei lesen

	OpenPreferences(ChgAddExtension(ProgramFilename(), "ini")) ; INI-Datei öffnen

	PreferenceGroup("Programmkonfiguration")
	Leseintervall = ReadPreferenceLong("LeseintervallinSekunden", 15)

	PreferenceGroup("IPAdressen")
	ExaminePreferenceKeys()
	While NextPreferenceKey()
		AddElement(IPListe())
		IPListe() = PreferenceKeyValue()
	Wend

	ClosePreferences()

EndProcedure
;==================================================================================================
Procedure SaveINI() ; Konfigurationsdatei erstellen

	If CreatePreferences(ChgAddExtension(ProgramFilename(), "ini")) ; INI-Datei erstellen

		PreferenceGroup("Info")
		WritePreferenceString("Programmname", PRGName$)
		WritePreferenceString("Version", Version$)

		PreferenceComment("")

		PreferenceGroup("Programmkonfiguration")
		WritePreferenceLong("LeseintervallinSekunden", 15)

		PreferenceComment("")

		PreferenceGroup("IPAdressen")
		WritePreferenceString("IP1", "0.0.0.0")

		ClosePreferences()

	EndIf

EndProcedure
;==================================================================================================


Procedure Open_frmHaupt() ; Hauptfenster

	If OpenWindow(#frmHaupt, 216, 0, 640, 480, PRGName$,  #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget | #PB_Window_SizeGadget | #PB_Window_TitleBar | #PB_Window_ScreenCentered )

		WindowBounds(#frmHaupt, 640, 120, #PB_Ignore, #PB_Ignore)

		If CreateToolBar(#ToolBar_0, WindowID(#frmHaupt))
			ToolBarImageButton(#tlbResetMin, ImgRmin)
			ToolBarToolTip(#ToolBar_0, #tlbResetMin, "Reset Min-Werte")
			ToolBarImageButton(#tlbResetMax, ImgRmax)
			ToolBarToolTip(#ToolBar_0, #tlbResetMax, "Reset Max-Werte")
			ToolBarSeparator()
			ToolBarImageButton(#tlbInfo, ImgInfo)
			ToolBarToolTip(#ToolBar_0, #tlbInfo, "Info")
		EndIf

		If CreateStatusBar(#StatusBar_0, WindowID(#frmHaupt))
			AddStatusBarField(18)
			AddStatusBarField(170)
			AddStatusBarField(170)
			AddStatusBarField(#PB_Ignore)
		EndIf

		ListIconGadget(#ListIcon_0, 0, 0, 640, 480, "Messgrößen", 150, #PB_ListIcon_GridLines | #PB_ListIcon_FullRowSelect | #PB_ListIcon_AlwaysShowSelection | #PB_ListIcon_MultiSelect)
		ForEach IPListe()
			AddGadgetColumn(#ListIcon_0, ListIndex(IPListe()) + 1, IPListe(), 100)
		Next

	EndIf

EndProcedure
;==================================================================================================
Procedure Info()

	Protected Info$

	Info$ + PRGName$ + #TAB$ + #CRLF$
	Info$ + "Version: " + Version$ + "  -  (PB " +  Str(#PB_Compiler_Version) + ")" + #TAB$ + #CRLF$ + #CRLF$
	Info$ + "Erstellt am: " + FormatDate("%dd.%mm.%yyyy - %hh:%ii:%ss", #PB_Compiler_Date) + #TAB$ + #CRLF$ + #CRLF$
	Info$ + Copyright$ + #TAB$

	If MessageRequester("Über " + PRGName$, Info$ , #MB_ICONINFORMATION) : EndIf

EndProcedure
;==================================================================================================


Procedure FillList() ; Messgrössen Liste füllen
	AddElement(Messgroessen())
	Messgroessen() = "Spannung U L1-N"      ; Offset: 1
	AddElement(Messgroessen())
	Messgroessen() = "Spannung U L2-N"      ; Offset: 3
	AddElement(Messgroessen())
	Messgroessen() = "Spannung U L3-N"      ; Offset: 5
	AddElement(Messgroessen())
	Messgroessen() = "Strom L1"             ; Offset: 13
	AddElement(Messgroessen())
	Messgroessen() = "Strom L2"             ; Offset: 15
	AddElement(Messgroessen())
	Messgroessen() = "Strom L3"             ; Offset: 17
	AddElement(Messgroessen())
	Messgroessen() = "Scheinleistung L1"    ; Offset: 19
	AddElement(Messgroessen())
	Messgroessen() = "Scheinleistung L2"    ; Offset: 21
	AddElement(Messgroessen())
	Messgroessen() = "Scheinleistung L3"    ; Offset: 23
	AddElement(Messgroessen())
	Messgroessen() = "Wirkleistung L1"      ; Offset: 25
	AddElement(Messgroessen())
	Messgroessen() = "Wirkleistung L2"      ; Offset: 27
	AddElement(Messgroessen())
	Messgroessen() = "Wirkleistung L3"      ; Offset: 29
	AddElement(Messgroessen())
	Messgroessen() = "Blindleistung L1"     ; Offset: 31
	AddElement(Messgroessen())
	Messgroessen() = "Blindleistung L2"     ; Offset: 33
	AddElement(Messgroessen())
	Messgroessen() = "Blindleistung L3"     ; Offset: 35
	AddElement(Messgroessen())
	Messgroessen() = "Max. Strom L1"        ; Offset: 87
	AddElement(Messgroessen())
	Messgroessen() = "Max. Strom L2"        ; Offset: 89
	AddElement(Messgroessen())
	Messgroessen() = "Max. Strom L3"        ; Offset: 91
	AddElement(Messgroessen())
	Messgroessen() = "Min. Spannung U L1-N" ; Offset: 145
	AddElement(Messgroessen())
	Messgroessen() = "Min. Spannung U L2-N" ; Offset: 147
	AddElement(Messgroessen())
	Messgroessen() = "Min. Spannung U L3-N" ; Offset: 149
EndProcedure
;==================================================================================================
Procedure LeseRegister(ConnectionID, Funktionscode.b, Startregister.w, RegisterAnzahlWert.w)

	Protected i, Daten, TranferOK
	Protected Spalte = ListIndex(IPListe())
	Static TransactionIdentifier.w
	Static Zeile

	If Zeile > 20 : Zeile = 0 : EndIf

	While Not TranferOK

		TransactionIdentifier + 1

		; MBAP Header in Big-endian Format
		PokeW(*Anfrage + 0,  BLEconvW(TransactionIdentifier)) ;Transaction Identifier (wird mit der Antwort zurückgemeldet - Empfehlung: bei jedem Durchlauf inkrementieren)
		PokeW(*Anfrage + 2,  BLEconvW(0))                     ;Protocol Identifier (Modbus Protokoll => 0)
		PokeW(*Anfrage + 4,  BLEconvW(6))                     ;Length (Länge der Nachfolgenden Daten inkl. Unit Identifier)
		PokeB(*Anfrage + 6,  1)                               ;Unit Identifier (wird mit der Antwort zurückgemeldet)

		; PDU in Big-endian Format
		PokeB(*Anfrage + 7,  Funktionscode)                   ;Funktionscode
		PokeW(*Anfrage + 8,  BLEconvW(Startregister))         ;Startregister
		PokeW(*Anfrage + 10, BLEconvW(RegisterAnzahlWert))    ;Anzahl der zu lesenden Register

		If SendNetworkData(ConnectionID, *Anfrage, 12)

			While Not Daten

				If NetworkClientEvent(ConnectionID) = #PB_NetworkEvent_Data
					Daten = ReceiveNetworkData(ConnectionID, *Antwort, 300)
					If Daten And TransactionIdentifier = BLEconvW(PeekW(*Antwort))
						TranferOK = #True

						If Funktionscode = 4
							For i = 9 To Daten - 1 Step 4 ; ab dem zehnten Byte kommen die Werte
								Messwerte(Spalte, Zeile) = BLEconvF(PeekF(*Antwort + i))
								Zeile + 1
							Next
						EndIf

					EndIf
				EndIf

				Delay(1)
				
			Wend
			Daten = 0

		EndIf
	Wend

EndProcedure
;==================================================================================================
Procedure Lesen(z.i) ; alle Stationen abfragen (Hintergrundthread)

	Protected ConnectionID, i, Zeit, ZeitAkt, ZeitMax, Wartezeit
	Protected Temp$

	While Not Programmende

		Zeit = ElapsedMilliseconds()

		ForEach IPListe()

			StatusBarText(#StatusBar_0, 1, " Verbinden mit " + IPListe())
			StatusBarImage(#StatusBar_0, 0, ImgYellow)
			ConnectionID = OpenNetworkConnection(IPListe(), 502, #PB_Network_TCP)

			If ConnectionID

				Select Abfragecode

					Case 0 ; Auslesen der Messregister
						StatusBarText(#StatusBar_0, 1, " Lesen von " + IPListe())
						StatusBarImage(#StatusBar_0, 0, ImgYellow)
						LeseRegister(ConnectionID, 4,   1,  6)
						LeseRegister(ConnectionID, 4,  13, 24)
						LeseRegister(ConnectionID, 4,  87,  6)
						LeseRegister(ConnectionID, 4, 145,  6)

					Case 1 ; Reset Min-Werte
						StatusBarText(#StatusBar_0, 1, " Reset Min-Werte")
						StatusBarImage(#StatusBar_0, 0, ImgYellow)
						LeseRegister(ConnectionID, 6, 60003, 0)

					Case 2 ; Reset Max-Werte
						StatusBarText(#StatusBar_0, 1, " Reset Max-Werte")
						StatusBarImage(#StatusBar_0, 0, ImgYellow)
						LeseRegister(ConnectionID, 6, 60002, 0)

				EndSelect

				CloseNetworkConnection(ConnectionID)

			Else

				StatusBarText(#StatusBar_0, 1, " Server Fehler")
				StatusBarImage(#StatusBar_0, 0, ImgRed)
				ForEach Messgroessen()
					Messwerte(ListIndex(IPListe()), ListIndex(Messgroessen())) = 0
				Next
				Delay(500)

			EndIf

			Delay(10)

		Next

		Abfragecode = 0

		HideGadget(#ListIcon_0, #True)
		ClearGadgetItems(#ListIcon_0)
		ForEach Messgroessen()
			Temp$ = Messgroessen()
			ForEach IPListe()
				Temp$ + Chr(10) + StrF(Messwerte(ListIndex(IPListe()), ListIndex(Messgroessen())), 2)
			Next
			AddGadgetItem(#ListIcon_0, -1, Temp$)
		Next
		HideGadget(#ListIcon_0, #False)

		ZeitAkt = ElapsedMilliseconds() - Zeit
		If ZeitAkt > ZeitMax : ZeitMax = ZeitAkt : EndIf

		StatusBarText(#StatusBar_0, 2, " Aktuelle Lesezeit: " + Str(ZeitAkt) + " ms")
		StatusBarText(#StatusBar_0, 3, " Maximale Lesezeit: " + Str(ZeitMax) + " ms")

		StatusBarImage(#StatusBar_0, 0, ImgGreen)
		Wartezeit = (z - Date() % z) * 1000
		While Wartezeit
			If Programmende : Break : EndIf
			StatusBarText(#StatusBar_0, 1, " Neulesen in " + Str(Wartezeit / 1000) + " s")
			Delay(1000)
			Wartezeit - 1000
		Wend

	Wend

EndProcedure
;==================================================================================================





;- Hauptprogramm ----------------------------------------------------------------------------------

If FileSize(ChgAddExtension(ProgramFilename(), "ini")) = -1
	SaveINI()
	MessageRequester("Konfiguration erstellt.", "Das Programm hat keine gültige Konfigurationsdatei gefunden." + #CRLF$ + #CRLF$  + "Es wurde eine INI-Datei angelegt." + #CRLF$ + #CRLF$ + "Bitte überprüfen Sie die Einstellungen vor dem nächsten Programmstart." + #TAB$ + #CRLF$  + #CRLF$ + "Das Programm wird jetzt beendet.", #MB_ICONINFORMATION)
	End
EndIf

If Not InitNetwork()
	MessageRequester("Fehler", "Netzwerk kann nicht initialisiert werden!", #MB_ICONERROR)
	End
EndIf

ReadINI()

FillList()

Dim Messwerte.f(ListSize(IPListe()) - 1, ListSize(Messgroessen()) - 1)

Open_frmHaupt()

Define LeseThread.i = CreateThread(@Lesen(), Leseintervall)

Define.i Event, EventWindow, EventGadget, EventMenu, EventType ; Variablen Eventschleife
Define.i wb0, wh0, tb0, sb0, wb1, wh1, sb1 ; Variablen für SizeWindow

Repeat ;- Ereignisschleife des Programms

	Event       = WaitWindowEvent() ; Warten bis Ereignis im Fenster auftritt
	EventWindow = EventWindow()     ; ID des Fensters mit Ereignis
	EventGadget = EventGadget() 		; ID des Gadgetss mit Ereignis
	EventMenu   = EventMenu()       ; ID des Menüs/Toolbar/Shortcut mit Ereignis
	EventType   = EventType()       ; Ermitteln des Ereignistyps

	Select Event
		;==================================================================================================
		Case #PB_Event_Menu            ; ein Menü / Symbol wurde ausgewählt
			Select EventMenu

				Case #tlbResetMin
					If Not Abfragecode
						If MessageRequester(PRGName$, "Möchten Sie die Minimalwerte zurücksetzen?", #PB_MessageRequester_YesNo | #MB_ICONEXCLAMATION) = #PB_MessageRequester_Yes
							Abfragecode = 1
						EndIf
					EndIf

				Case #tlbResetMax
					If Not Abfragecode
						If MessageRequester(PRGName$, "Möchten Sie die Maximalwerte zurücksetzen?", #PB_MessageRequester_YesNo | #MB_ICONEXCLAMATION) = #PB_MessageRequester_Yes
							Abfragecode = 2
						EndIf
					EndIf

				Case #tlbInfo
					Info()

			EndSelect
			;==================================================================================================
		Case #PB_Event_CloseWindow    ; das Schließgadget vom Fenster wurde gedrückt
			Select EventWindow

				Case #frmHaupt
					If MessageRequester(PRGName$, "Möchten Sie " + PRGName$ + " beenden", #PB_MessageRequester_YesNo | #MB_ICONEXCLAMATION) = #PB_MessageRequester_Yes
						Programmende = #True
					EndIf

			EndSelect
			;==================================================================================================
		Case #PB_Event_SizeWindow     ; das Fenster wurde in der Größe verändert
			Select EventWindow

				Case #frmHaupt
					wb0 = WindowWidth(#frmHaupt)
					wh0 = WindowHeight(#frmHaupt)
					tb0 = ToolBarHeight(#ToolBar_0)
					sb0 = StatusBarHeight(#StatusBar_0)
					ResizeGadget(#ListIcon_0, #PB_Ignore, tb0 , wb0, wh0 - tb0 - sb0)

			EndSelect
			;==================================================================================================
		Case #PB_Event_ActivateWindow ; das Fenster wurde aktiviert (hat den Fokus erhalten)
			Select EventWindow

				Case #frmHaupt
					SetActiveGadget(#ListIcon_0)

			EndSelect
			;==================================================================================================
	EndSelect

Until Programmende

; Abschlussarbeiten
StatusBarText(#StatusBar_0, 1, " Beenden...")
StatusBarImage(#StatusBar_0, 0, ImgRed)
WaitThread(LeseThread, 10000)

End
;
Gruß, BI2
PB 5.7x (x64), LinuxMint 18.3 - Xfce (x64)

Einsteigerbuch: PureBasic - Eine Einführung in die Computer Programmierung
Benutzeravatar
Helmut
Beiträge: 162
Registriert: 20.09.2004 22:53

Re: RS 485 Modbus Kommunikation

Beitrag von Helmut »

Hi,
ist da keine Port Angabe nötig?

Edit ist Modbus TCP, damit immer 502, steht auch im Code, muß angegeben werden?
Gruß Helmut
Antworten