目次

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タイプのフレームを生成できます。


目次

inserted by FC2 system