pythonシリアルポートModbusプロトコルとaduinoデータインタラクションを使用
概要
Modbusはシリアル通信プロトコルで、Modicon社(現在のシュナイダー電気Schneider Electric)が1979年にプログラマブルロジックコントローラ(PLC)通信を使用するために発表した.Modbusはすでに工業分野の通信プロトコルの業界標準(De facto)となり、現在は工業電子機器間でよく使われる接続方式である.
Modbusプロトコルはシリアルポート、イーサネットを経由することができ、ほとんどのModbusデバイス通信はシリアルポートEIA-485を通じて2種類のModbus RTU(バイナリデータ)、Modbus ASCII(文字列)に分けられる.
Modbusプロトコルはmaster/slaveアーキテクチャ、半二重、バスメカニズムであり、485の2本の差分信号線を考えると、そうするしかない.
ModBusRTU通信規約対応:初期構造=≧4バイトのタイムアドレスコード=1バイト機能コード=1バイトデータ領域=Nバイトエラーチェック=16ビットCRCコード終了構造=≧4バイトの時間
アドレスコードは多く解釈する必要はありません.
機能コードの定義
Modbusは古くから電気の機構をカスタマイズしているので、どのコイルのデータ名についても自分で転義する必要があります.
きのうコード
名前
さぎょう
1
リードコイル状態
一組の論理コイルの現在の状態を取得する(ON/OFF)
2
読み込み入力状態
一組のスイッチ入力の現在状態を取得する(ON/OFF)
3
リードホールドレジスタ
1つ以上の保持レジスタで現在のバイナリ値を取得する
4
リード入力レジスタ
1つ以上の入力レジスタで現在のバイナリ値を取得する
5
きょうせいたんコイル
論理コイルを1つ強設したオンオフ状態
6
プリセットシングルレジスタ
具体的なバイナリ値を保持レジスタに入れる
7
読み出し異常状態
8個の内部コイルのオンオフ状態を取得し、この8個のコイルのアドレスはコントローラで決定する
8
エコー診断チェック
診断検証メッセージをスレーブに送り,通信処理を評価する
9
プログラミング(484のみ)
ホストシミュレータを使用して、PCスレーブロジックを修正
10
問い合わせ制御(484のみ)
ホストは、長いプログラムタスクを実行しているスレーブと通信し、そのスレーブがその操作タスクを完了したかどうかを尋ねることができ、機能コード9を含むメッセージが送信された後にのみ、本機能コードが送信される
11
読み取りイベント数
ホストに単一の問い合わせを発行させ、操作が成功したかどうかを判定することができ、特にそのコマンドまたは他の応答が通信エラーを発生した場合
12
通信イベントレコードの読み込み
ただし、ホストは、スレーブのModBusトランザクションごとに通信イベントレコードを取得します.トランザクションが完了すると、レコードにエラーが発生します.
13
プログラミング(184/3884484 584)
ホストシミュレータ機能でPCスレーブロジックを修正できる
14
ポーリング(184/3884484 584)
本機能コードは、ホストがタスクを実行しているスレーブと通信し、そのスレーブがプログラム操作を完了したか否かを定期的に問い合わせることができ、機能13を含むメッセージが送信された後にのみ送信される
15
きょうせいマルチコイル
一連の連続論理コイルのオンオフを強制する
16
プリセットマルチレジスタ
具体的なバイナリ値を一連の連続した保持レジスタに入れる
17
スレーブIDのレポート
ホストにアドレッシングスレーブのタイプとそのスレーブ運転LEDの状態を判断させることができる
18
(884とMICRO 84)
ホストにプログラミング機能を模擬させ、PC状態ロジックを修正させることができる.
19
通信リンクのリセット
非修正エラーが発生した場合は、スレーブが既知の状態にあり、順序バイトをリセットできます.
20
汎用パラメータの読み込み(584 L)
拡張メモリファイルのデータ情報の表示
21
書き込み共通パラメータ(584 L)
汎用パラメータを拡張ストレージファイルに書き込むか、変更する
22~64
拡張機能の代替として保持
65~72
ユーザー機能用に予約
ユーザ機能として残る拡張符号化
73~119
不正な機能
120~127
保留
内部作用として残す
128~255
巨人の肩に立ってプログラミングして腰が痛くない.
PCホストとaduinoスレーブを書きます.
アップソースコード
PC側は偉大なpythonを使っています
aduino
Modbusはシリアル通信プロトコルで、Modicon社(現在のシュナイダー電気Schneider Electric)が1979年にプログラマブルロジックコントローラ(PLC)通信を使用するために発表した.Modbusはすでに工業分野の通信プロトコルの業界標準(De facto)となり、現在は工業電子機器間でよく使われる接続方式である.
Modbusプロトコルはシリアルポート、イーサネットを経由することができ、ほとんどのModbusデバイス通信はシリアルポートEIA-485を通じて2種類のModbus RTU(バイナリデータ)、Modbus ASCII(文字列)に分けられる.
Modbusプロトコルはmaster/slaveアーキテクチャ、半二重、バスメカニズムであり、485の2本の差分信号線を考えると、そうするしかない.
ModBusRTU通信規約対応:初期構造=≧4バイトのタイムアドレスコード=1バイト機能コード=1バイトデータ領域=Nバイトエラーチェック=16ビットCRCコード終了構造=≧4バイトの時間
アドレスコードは多く解釈する必要はありません.
機能コードの定義
Modbusは古くから電気の機構をカスタマイズしているので、どのコイルのデータ名についても自分で転義する必要があります.
きのうコード
名前
さぎょう
1
リードコイル状態
一組の論理コイルの現在の状態を取得する(ON/OFF)
2
読み込み入力状態
一組のスイッチ入力の現在状態を取得する(ON/OFF)
3
リードホールドレジスタ
1つ以上の保持レジスタで現在のバイナリ値を取得する
4
リード入力レジスタ
1つ以上の入力レジスタで現在のバイナリ値を取得する
5
きょうせいたんコイル
論理コイルを1つ強設したオンオフ状態
6
プリセットシングルレジスタ
具体的なバイナリ値を保持レジスタに入れる
7
読み出し異常状態
8個の内部コイルのオンオフ状態を取得し、この8個のコイルのアドレスはコントローラで決定する
8
エコー診断チェック
診断検証メッセージをスレーブに送り,通信処理を評価する
9
プログラミング(484のみ)
ホストシミュレータを使用して、PCスレーブロジックを修正
10
問い合わせ制御(484のみ)
ホストは、長いプログラムタスクを実行しているスレーブと通信し、そのスレーブがその操作タスクを完了したかどうかを尋ねることができ、機能コード9を含むメッセージが送信された後にのみ、本機能コードが送信される
11
読み取りイベント数
ホストに単一の問い合わせを発行させ、操作が成功したかどうかを判定することができ、特にそのコマンドまたは他の応答が通信エラーを発生した場合
12
通信イベントレコードの読み込み
ただし、ホストは、スレーブのModBusトランザクションごとに通信イベントレコードを取得します.トランザクションが完了すると、レコードにエラーが発生します.
13
プログラミング(184/3884484 584)
ホストシミュレータ機能でPCスレーブロジックを修正できる
14
ポーリング(184/3884484 584)
本機能コードは、ホストがタスクを実行しているスレーブと通信し、そのスレーブがプログラム操作を完了したか否かを定期的に問い合わせることができ、機能13を含むメッセージが送信された後にのみ送信される
15
きょうせいマルチコイル
一連の連続論理コイルのオンオフを強制する
16
プリセットマルチレジスタ
具体的なバイナリ値を一連の連続した保持レジスタに入れる
17
スレーブIDのレポート
ホストにアドレッシングスレーブのタイプとそのスレーブ運転LEDの状態を判断させることができる
18
(884とMICRO 84)
ホストにプログラミング機能を模擬させ、PC状態ロジックを修正させることができる.
19
通信リンクのリセット
非修正エラーが発生した場合は、スレーブが既知の状態にあり、順序バイトをリセットできます.
20
汎用パラメータの読み込み(584 L)
拡張メモリファイルのデータ情報の表示
21
書き込み共通パラメータ(584 L)
汎用パラメータを拡張ストレージファイルに書き込むか、変更する
22~64
拡張機能の代替として保持
65~72
ユーザー機能用に予約
ユーザ機能として残る拡張符号化
73~119
不正な機能
120~127
保留
内部作用として残す
128~255
巨人の肩に立ってプログラミングして腰が痛くない.
PCホストとaduinoスレーブを書きます.
アップソースコード
PC側は偉大なpythonを使っています
#!/usr/bin/env python
# -*- coding: utf_8 -*-
"""
Modbus TestKit: Implementation of Modbus protocol in python
(C)2009 - Luc Jean - [email protected]
(C)2009 - Apidev - http://www.apidev.fr
This is distributed under GNU LGPL license, see license.txt
"""
import serial
import modbus_tk
import modbus_tk.defines as cst
from modbus_tk import modbus_rtu
import struct
import time
#PORT = 1
PORT ='COM3' #"/dev/ttyUSB0"
#ser =serial.Serial(port=PORT, baudrate=9600, bytesize=8, parity='N', stopbits=1, xonxoff=0,timeout=0)
#'''
ser=serial.Serial()
ser.port = PORT
ser.baudrate = 9600
# ,
ser.timeout = 2
ser.open()
#'''
time.sleep(2)
def sendtest():
dat = [101, 3, 0, 0, 0, 1, 140, 46]
datlen = len(dat)
packstyle = str(datlen) + 'B' # B 0-255
req = struct.pack(packstyle, *dat)
ser.write(req)
print("send")
def main():
"""main"""
logger = modbus_tk.utils.create_logger("console")
try:
#Connect to the slave
master = modbus_rtu.RtuMaster(
ser
)
print(master._serial.is_open)
master.set_timeout(5)
master.set_verbose(True)
logger.info("connected")
print("connected")
try:
logger.info(master.execute(101, cst.READ_HOLDING_REGISTERS, 0, 10))
except:
pass
logger.info("111")
'''
2019-02-28 06:36:23,847 INFO modbus_rtu.__init__ MainThread RtuMaster COM3 is opened
2019-02-28 06:36:23,848 INFO modbus.main MainThread connected
connected
2019-02-28 06:36:23,848 DEBUG modbus.execute MainThread -> 101-3-0-1-0-1-221-238
XMT: [101][003][000][000][000][001][012][046]
RCV: [101][003][002][000][032][073][116]
READ_COILS = 1
READ_DISCRETE_INPUTS = 2
READ_HOLDING_REGISTERS = 3 【 】
READ_INPUT_REGISTERS = 4
WRITE_SINGLE_COIL = 5
WRITE_SINGLE_REGISTER = 6
WRITE_MULTIPLE_COILS = 15 【 】
WRITE_MULTIPLE_REGISTERS = 16 【 】
#
1,2,3,4,5,6,15,16
2,4,5,6,15,16
#modbus-tk
READ_COILS = 1
READ_DISCRETE_INPUTS = 2
READ_HOLDING_REGISTERS = 3
READ_INPUT_REGISTERS = 4
WRITE_SINGLE_COIL = 5
WRITE_SINGLE_REGISTER = 6
READ_EXCEPTION_STATUS = 7
DIAGNOSTIC = 8
REPORT_SLAVE_ID = 17
WRITE_MULTIPLE_COILS = 15
WRITE_MULTIPLE_REGISTERS = 16
READ_WRITE_MULTIPLE_REGISTERS = 23
DEVICE_INFO = 43
'''
print(cst.WRITE_SINGLE_REGISTER)
#send some queries
#logger.info(master.execute(101, cst.READ_COILS, 0, 10))#101-1-0-0-0-10-180-41
#logger.info(master.execute(101, cst.READ_DISCRETE_INPUTS, 0, 8))#101-2-0-0-0-8-113-232
#logger.info(master.execute(101, cst.READ_INPUT_REGISTERS, 100, 3))#101-4-0-100-0-3-249-240
logger.info(master.execute(101, cst.READ_HOLDING_REGISTERS, 0, 1))
#deviceid 101 03 HOLDING_REGISTER address0001 length1
#logger.info(master.execute(101, cst.WRITE_SINGLE_COIL, 7, output_value=1))#101-5-0-7-255-0-53-223
#logger.info(master.execute(101, cst.WRITE_SINGLE_REGISTER, 100, output_value=54))#101-6-0-100-0-54-64-39
#101 - 6 - 0 - 100 - 0 - 54 - 64 - 39
#logger.info(master.execute(101, cst.WRITE_MULTIPLE_COILS, 0, output_value=[1, 1, 0, 1, 1, 0, 1, 1]))#101-15-0-0-0-8-1-219-185-21
logger.info(master.execute(101, cst.WRITE_MULTIPLE_REGISTERS, 0, output_value=range(12)))
logger.info(master.execute(101, cst.READ_HOLDING_REGISTERS, 0, 12))
except modbus_tk.modbus.ModbusError as exc:
print(123)
print("%s- Code=%d", exc, exc.get_exception_code())
#logger.error("%s- Code=%d", exc, exc.get_exception_code())
if __name__ == "__main__":
import time
#
'''sendtest()
time.sleep(1.0)
sendtest()
time.sleep(1.0)
sendtest()
time.sleep(1.0)'''
main()
while(1):
#sendtest()
time.sleep(1.0)
print(1)
aduino
#include
// size of data which will be read and written
#define DATA_SIZE 100
// data array which will be read and written
u16 _D[DATA_SIZE];
// address (kind of name) of above data, may be anything
#define VIRTUAL_ADDRESS 0x0000
#define OUR_ID_AS_A_SLAVE 101
#define PIN_CONNECTED_TO_BOTH_DE_AND_RE 3
ModbusRTUSlave rtu(OUR_ID_AS_A_SLAVE, &Serial, PIN_CONNECTED_TO_BOTH_DE_AND_RE);
void setup()
{
rtu.addWordArea(VIRTUAL_ADDRESS, _D, DATA_SIZE);
rtu.begin(9600);
//Serial.begin(9600); // not needed, for logging purpose only
// set some value in data array to test if master can read and modify it
_D[0] = 160;
}
void loop()
{
// waiting for requests from master
// reading and writing _D according to requests from master happens here
rtu.process();
}