15
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

CRC-16/Modbus計算の実装

Last updated at Posted at 2018-11-12

はじめに

ステッピングモーターをリモートで動作させる際のマスタ側のクエリのメッセージ構成が、

  • スレーブアドレス(8ビット)
  • ファンクションコード(8ビット)
  • データ(N * 8ビット)
  • エラーチェック(16ビット)

となっていた。
このエラーチェックにCRC-16方式が採用されていたため、その実装を行なった。

詳細

実際に使用したものは、オリエンタルモーターのAZD-KDドライバ。
モーター構成:オリエンタルモーター

これをリモートでコントロールするために、RS-485通信によるModbus RTU制御を行なった。
このときのクエリのメッセージを作成する際に、エラーチェックのメッセージを作成する必要があった。

環境

Python 3.7.1

アルゴリズム

CRC-16の計算方法を以下に示す。

  1. 初期値をFFFFhとし、FFFFhと最初のアドレス(8ビット)の排他的論理和(XOR)を計算
  2. 1.の結果を1bit右シフト。これを桁あふれが1になるまで繰り返す
  3. 2.の結果とA001hのXORを計算
  4. シフトが8回になるまで2.と3.を繰り返す
  5. 4.の結果と次のアドレス(8ビット)のXORを計算。すべてのバイトに対して2.から4.を繰り返す。最後の計算結果がCRC-16の計算結果となる。

排他的論理和(XOR)

入力A 入力B 出力
異なる入力だと真、同じ入力なら偽。

複数桁は桁ごとに各々で計算する。

   0101 0101 0101
^) 0010 0101 1010
------------------
   0111 0000 1111

実装

Pythonで実装。CRC-16の計算のみ示す。

フローチャート

data_byteを更新に対してYES/NOなのは目をつむってください(更新できる→YES、更新できない→NO)。

クエリ

メッセージは、リモートI/Oへのアクセスのため以下のようになった。

構成 内容
スレーブアドレス 01h スレーブアドレス1(設定)
ファンクションコード 03h 保持レジスタからの読み出し
データ(レジスタアドレス(上位)) 00h 読み出す起点となるレジスタアドレス(上位)
データ(レジスタアドレス(下位)) 7Fh 読み出す起点となるレジスタアドレス(下位)
データ(レジスタ数(上位) ) 00h 起点のレジスタアドレスから読み出すレジスタの数(上位)
データ(レジスタ数(下位) ) 01h 起点のレジスタアドレスから読み出すレジスタの数(下位)
エラーチェック(下位) - ここを求める。
エラーチェック(上位) - ここを求める。

コード

crc16.py
# -*- coding: utf-8 -*-

# エラーチェック以外のクエリ
command = b"\x01\x03\x00\x7f\x00\x01"

# 最初のCRCレジスタ値をFFFFhに設定
crc_register = 0xFFFF
for data_byte in command:
    # CRCレジスタとデータバイトのXOR
    tmp = crc_register ^ data_byte
    # シフト回数を記憶
    shift_num = 0
    # シフトが 8回になるまで繰り返す
    while(shift_num < 8):
        if(tmp&1 == 1): # 桁あふれが1なら
            tmp = tmp >> 1
            shift_num += 1
            tmp = 0xA001 ^ tmp
        else:
            tmp = tmp >> 1
            shift_num += 1
    # 計算結果をcrc_registerにセット
    crc_register = tmp
# 計算結果をbytes型へ変換
crc = crc_register.to_bytes(2, 'big')

# 結果を表示
print(crc)

実際は、右シフトする前にtmpの1桁めの値を確認するために、tmp%2 tmp&1で0か1かを確認した後に右シフト処理を行なっています。
もっと良いやり方があればご教授願います。

結果

実行

$ python crc16.py

結果

$ b'\xd2\xb5'

これから、以下のような結果を得ることができました(順番に注意:下位→上位の順)。

構成 内容
エラーチェック(下位) B5h CRC-16の計算結果(下位)
エラーチェック(上位) D2h CRC-16の計算結果(上位)

よってb'\x01\x03\x00\x7f\x00\x01\xb5\xd2'というクエリを送信し、スレーブからのレスポンスを読むことでステッピングモーターのリモートI/Oを読むことができました。

15
16
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?