目次
前
次
LRC計算
シーケンサを中心とする制御で使う計測制御機器で
通信と言えばModbus。
シーケンサは、機器に番号をつけ、スレーブとして
温度、湿度リレーの励磁状態等の物理値を取得する
ために通信回線を利用。そのときに、Modbusを使う
ことが多いです。
RTUと呼ばれるプロトコルでは、マスターはスレーブ
のアドレス、ファンクション番号、パラメータ、CRCを
1バイト単位で送信。
フレームで見れば、以下。
RTUでは、16進数2けたで1バイトを表現するので
一目でわかる類の情報ではありません。
16進数2けたで表現される情報をASCIIにして理解
しやすい様にすれば、各情報は、2バイトになり
ます。
フレームで見れば、以下。
CRC、LRCは、情報を転送したときに、ノイズによる
ビットが反転していないかを受信側でチェックする
ために使います。
LRCの方は、ASCIIで表示されているので、":"の次の
アドレスからデータの終端までを使って算出します。
2バイトで表現されている値を1バイトごとに加算し
合計を2の補数で表現し、1バイトに縮退して表現。
C/C++でLRCを求める関数を作成するために、論理動作が
正しいのかをPythonで確認してみました。
Pythonは、リストを使えるので、RTUの1フレームを
リストに入れて、アドレス、ファンクション番号、
データを抜き出して、LRCを求めて動作確認します。
RTUで、CRCなしで次の情報があるとします。
0x01 0x20 0x11 0x12 0x13 0x14 0x15
Pythonのリストにまとめます。
fx = [0x01,0x20,0x11,0x12,0x13,0x14,0x15]
1バイトをASCIIの2文字にするために、数値を
数字に変換する関数を用意。
def getAsc(x):
mycode = '0123456789ABCDEF'
if x > 15 :
result = '0'
else :
result = mycode[x]
#
return result
def getAscii2(x):
# separate
q = (x >> 4) & 15
r = x & 15
# concatenate
result = []
result.append( getAsc(q) )
result.append( getAsc(r) )
#
return result
RTUの方から、ASCIIの方に変換する関数を
用意しておくのが楽なので、実現関数を
定義。
def makeAsciiFrame(x):
# empty list
result = []
# separate
for e in x :
tmp = getAscii2(e)
result.append( tmp )
#
return result
ここまでの関数を利用して、ModbusASCIIのフレームを
生成する場合は、次のように処理。
fx = [0x01,0x20,0x11,0x12,0x13,0x14,0x15]
fxasc = makeAsciiFrame(fx)
LRCを求めるには、ASCIIになっている数値を
扱うので、数字から数値に変換する関数を
用意。
def getHex(x) :
# default
result = 0
xx = ord(x)
if ord('0') <= xx and xx <= ord('9') :
result = ord(x) - ord('0')
if ord('A') <= xx and xx <= ord('F') :
result = ord(x) - ord('A') + 10
if ord('a') <= xx and xx <= ord('f') :
result = ord(x) - ord('a') + 10
#
return result
2の補数を求めておかないと、LRCにできないので
そのための関数を定義しておきます。
def calc2compliment(x):
# 1's complement
result = x ^ 0xffff
# 2's complement
result += 1
# get 8 bits
result &= 0xff
#
return result
用意した関数を使って、処理してみます。
fx = [0x01,0x20,0x11,0x12,0x13,0x14,0x15]
fxasc = makeAsciiFrame(fx)
sum = 0
for e in fxasc :
# convert
tmp = getHex(e)
# add
sum += tmp
lrc = calc2compliment(sum):
最後に、RTUからASCIIに変換する関数を
定義します。
def genAsciiFrame(x):
# RTU -> ASCII
fasc = makeAsciiFrame(x)
# calculate LRC
sum = 0
for e in fasc :
# convert
tmp = getHex(e)
# add
sum += tmp
lrc = calc2compliment(sum):
# append ':' and LRC
result = []
result.append(':')
for e in fxasc :
xx.append( e )
ee = getAscii2(lrc)
result.append( ee[0] )
result.append( ee[1] )
# add '\r' '\n'
result.append( 0x0d )
result.append( 0x0a )
#
return result
これで、RTUのCRCを除いたフレームから
ASCIIタイプのフレームを生成できます。
目次
前
次