前幾天,需要使用到激光傳感器,需要PLC來控制。就學習了一下PC與PLC通訊。
學的不深,可能有很多問題,歡迎指正。
PLC那一端是電氣的同事幫忙弄的,使用的是MC協議。
一開始,我是用的是二進制方式(這個方式我用不了,應該是PLC那一端設置了ASCII方式吧...不太清楚):
import socket
import re
PORT = 7001
def read_register(host, start_digit, digit_num=1, port=PORT, dic=True):
'''
Example:
read D400 single word: read_register('192.168.100.2', 400)
'''
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((host, port))
str1= '500000ffff03000c00100001040000'\
+ reverse_per_two_char('{:0=6x}'.format(start_digit))\
+ 'a8' + reverse_per_two_char('{:0=6x}'.format(digit_num))
msg = bytes.fromhex(str1) # 轉成字節
client.send(msg)
res = client.recv(1024).hex()
if dic:
# 十六進制轉十進制
return {start_digit: int(reverse_per_two_char(res[-4*digit_num:]), 16)}
else:
return int(reverse_per_two_char(res[-4*digit_num:]), 16)
def reverse_per_two_char(chars):
'''
reverse '010203' to '030201'
'''
return ''.join(reversed(re.findall('..?', chars)))
if __name__ == "__main__":
host = '192.168.100.2'
start_digit = 400
# a = is_open(host)
a = read_register(host, start_digit) # 讀某個寄存器中的內容
b = int(a, 16) # 得到的真實數據
max_distance = 2000 # 傳感器的最大最小測量距離
min_distance = 100
A = max_distance-(27648-b)*(max_distance-min_distance)/(27648 - 0) #三菱PLC協議的轉換公式,轉換成真實距離
print("真實距離:",A)
和PLC能連上,但是讀不了數據,就用了ASCii方式:
import socket
import re
import numpy as np
PORT = 7001
def read_register(host, start_digit, digit_num=1, port=PORT, dic=True):
'''
最終用了ASCII碼的方式
'''
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((host, port))
str1= "500000FF03FF000018000004010000D*"+'{:0=6d}'.format(start_digit)+"0001"
msg = np.fromstring(str1, dtype=np.uint8)
client.send(msg)
res = client.recv(1024)
if dic:
return int(res[22:26],16) # 這幾位是結果
else:
return int(reverse_per_two_char(res[-4*digit_num:]), 16)
if __name__ == "__main__":
host = '192.168.100.2'
start_digit = 400
# a = is_open(host)
a = read_register(host, start_digit) # 讀某個寄存器中的內容
print(a)
二進制:
頭(這裏都是固定的)
#str1 ='5000' '00FF' "FF0300""0C00" "1000"
# |header|Network|Module|Length|Time|
具體的操作,這裏只介紹讀 D400,寫也是類似的
# '0104' '0000' 'a8' '900100' '0100'
# |read command|sub comand|D register|strat digit| digit number
strat digit就是要讀的那個寄存器 400在十六進制裏是190,補齊6位就是000190,前後轉換就是900100
digit number,是要讀的個數,這裏是1 ,0001=>0100
ASCII碼:
#str1 ='5000' '00FF' "03FF00""0018" "0000"
# |header|Network|Module|Length|Time|
# '0104' '0000' 'D*' '000400' '0001'
# |read command|sub comand|D register|strat digit| digit number
這個相比來說更簡單。