M5Stack用絶縁型RS485ユニット
M5Stack用に接続して機能を追加するユニットは数多く販売されていますが、その中にRS485通信を可能にする、RS485ユニットというものがあります。
RS485での通信は産業用の装置で使われており、ツイストペア1対(+シグナルグラウンド1線)の合計3本で、そこそこ高速な通信ができます。
また、10/100Mbpsイーサーネットが規格上100mまでなのに対し、RS485は最大1200mまで通信可能です。
最近は2線でイーサーネット通信できるSingle Pair Ethernet(SPE)が出てきており、RS485のポジションを変えようとしていますが、まだまだRS485が主流です。
そんなRS485で産業用の装置と接続するのに便利だと思い、RS485ユニットを購入しました。
このユニットを使ってみたので、その導入方法を記したいと思います。
想定する構成
RS485ユニットをM5AtomS3に接続し、UIFlow2で書いたプログラムにより制御します。
RS485ユニットの通信相手は、PCとUSB接続したRS485/USBコンバータを使います。
RS485/USBコンバータは、ドライバーをPCにインストールすることで、TeraTermから使えるようになります。
ブロック図
実装例
注:簡単のため終端抵抗をつけていません。
RS485ユニットの準備
RS485ユニットを買うと、シールが付いてきます。
これは端子台に貼り付けて使いますので、台紙から剥がして貼っておいてください。
シールを貼り付けたコネクタ(赤色矢印の先)をユニット本体に接続した様子。
ユニットのシールに書いてある「GXAB」と、コネクタの「GVAB」の色があっていないのが気になる...
UIFlow2.0の準備
M5BurnerをPCにインストールし、M5AtomS3の最新のファームウェアを書き込みます。
なお、ファームウェア書き込みにはアカウント作成とログインが必要です。
本記事執筆時点では、最新のフォームウェアはv2.1.7でした。
次に、UIFlow2のサイトに行き、プログラムを書きます。
RS485/USBコンバータ、TeraTerm準備
RS485/USBコンバータはいろいろありますが、今回はラインアイのコンバータSI-35USB-2を使いました。
メーカサイトでドライバーが配布されているので、インストールしておきます。
USB接続したデバイスでシリアル通信をするターミナルとして、TeraTermを利用します。
以下のサイトからダウンロードしてインストールしておいてください。
また、今回の接続は2線式のため、ディップスイッチ「SW-B-2」はOFF側にしておきます。
2線式では送信と受信を同じ組線で行うため、送信した内容を受信してしまいます。
これをふせぐため、ディップスイッチ「SW-B-1」はON側にして、エコーを抑制します。
RS485ケーブルの準備
RS485ケーブルとか都合よく持っていないので、LANケーブルを改造して作りました。
LANケーブルはツイストペアケーブル4対の組み合わせです。
そのうちの1対を2線式の通信のために使います。
今回は、橙色と橙白色の組み合わせのツイストペアを通信に使います。
なお、通信に使わない対はまとめてグラウンドに接続し、シグナルグラウンドとします。
4対のうちどの色を通信に使うかは自由なのですが、
だからといってRX側に橙色、TX側に茶色という組み合わせにすると、
工場や制御室の角などの暗い場所での作業の際、見分けがつきにくくなります。
また、色覚多様性への配慮も必要です。
そこで私のおすすめは橙色と青色の組み合わせです。
薄型ではなく太いLANケーブルのほうが、芯線が太く工作しやすいのでおすすめです。
芯線がより線だったため、ハンダで一本にまとめています。
理想的にはケーブルの先端をフェルール端子や丸棒端子などにすれば頑丈になるのですが、
高価な圧着工具を持っていなかったのでできませんでした。
UIFlow2.0でプログラミング
UIFlow2.0では、以下の図のようにブロックを配置するだけで動作を定義できる、ビジュアルプログラミングを利用できます。
プログラムの動作例として、ボタンをクリックすると「Hello」をPC側に送り、逆にPC側からの文字は画面に表示します。
あらかじめ設定画面でRS485ユニットを追加しておいてください。
プログラミングが完了すると、AtomS3を接続し、プログラムを書き込みましょう。
いざ通信
RS485ユニットとUSBコンバータをRS485で接続します。
今回は以下のような配線です。
どのように配線すればいいのかわからず様々な組み合わせを試すことで正しい配線が判明したので、
みなさんも分からなければ色々試したらいいと思います。
あと、今回は手間だったので終端抵抗をつけていません。割愛しています。
ケーブル | RS485ユニット側 | USBコンバータ側 |
---|---|---|
橙色 | A | TR+ |
橙・白 | B | TR- |
それ以外 | G | GND |
TeraTermを起動し、新しい接続の設定画面で、「シリアル」を選び、ポートとしてUSB接続したUSBコンバータを選びます。(私の環境では「COM6」)
COM5やCOM6という文字は、PC環境によって変わります。
次に、シリアル通信の設定をRS485ユニット側と同じにします。
メニューバーの「設定」「シリアルポート」をクリックし、設定画面を表示させます。
設定が同じであることを確認したら、画面を閉じてください。
UIFlow2.0側 | Tera Term側 | 設定値 |
---|---|---|
baudrate | スピード | 9600 |
data bits | データ | 8 |
stop bits | ストップビット | 1 |
parity | パリティ | none |
ctrl pin | フロー制御 | none |
それではまず、RS485ユニット→USBコンバータをテストします。
M5AtomS3の画面がボタンになっているため、画面を押すとクリック音がします。
同時に、TeraTermの画面に「Hello」が表示されます。
次に、USBコンバータ→RS485ユニットをテストします。
TeraTermの画面に文字を入力すると、M5AtomS3に文字が表示されます。
ゆっくり入力すると1文字づつ表示されますが、素早く入力すると複数の文字が表示されます。
※AtomS3のディスプレイが指紋で汚れたので写真は割愛
以上で、RS485ユニット↔️USBコンバータで通信できたことを確認できました。
ユニットで改善してほしい点
コネクタがヨーロピアン端子台でない
日本で使われるPLCではヨーロピアン端子台(ヨーロッパ端子台、緑色のアレ)であることが多いです。
RS485ユニットで使われる「VH-3.96 4P」は珍しいです。
4線式(全二重)に非対応で、2線式(半二重)のみ対応
RS485では、送信と受信を別々のペアケーブルで行う4線式(全二重)と、送信と受信を同じペアケーブルで行う2線式(半二重)があります。
2線式のほうがケーブルの本数が少なくてすみ、コストとスペースを節約できるため、多く使われています。
しかし、もしかしたら4線式で接続しなければならないケースもあるので、4線式にも対応しているとよいと思いました。
抵抗が外付け
RS485では信号が反射しないよう、両端には120オーム程度の終端抵抗をつけます。
この製品では電子部品の抵抗がそのままパッケージに付属そており、必要な場合は抵抗を自分で端子台の間につける仕様です。
このような場合、使わないときは抵抗を外して保管しなければならず、いざ使おうとしたときに見つからず困ることが多いです。
通信ユニットの中には、ディップスイッチで終端抵抗の切り替えが可能なものもあり、
そのような製品だと抵抗をなくす心配がなくなり、安心できます。
...実は私はすでに抵抗をなくしてしまいました。
UIFlow2 MicroPython例
ビジュアルプログラミングで自動生成されたソースコードを以下に載せます。
マウスでポチポチ操作するビジュアルプログラミングが面倒な場合、このプログラムをUIFlow2の画面にコピーすれば同じように動きます。
import os, sys, io
import M5
from M5 import *
from hardware import *
from unit import ISO485Unit
label0 = None
iso485_0 = None
text = None
def btnA_wasClicked_event(state):
global label0, iso485_0, text
iso485_0.write('Hello'+'\r\n')
label0.setText(str('a'))
def setup():
global label0, iso485_0, text
M5.begin()
label0 = Widgets.Label("label0", 27, 20, 1.0, 0xffffff, 0x222222, Widgets.FONTS.DejaVu18)
BtnA.setCallback(type=BtnA.CB_TYPE.WAS_CLICKED, cb=btnA_wasClicked_event)
iso485_0 = ISO485Unit(2, port=(1, 2))
iso485_0.init(tx_pin=2, rx_pin=1, baudrate=9600, data_bits=8, stop_bits=1, parity=None, ctrl_pin=None)
text = 'a'
def loop():
global label0, iso485_0, text
M5.update()
text = iso485_0.readline()
if text:
label0.setText(str(text.decode()))
if __name__ == '__main__':
try:
setup()
while True:
loop()
except (Exception, KeyboardInterrupt) as e:
try:
from utility import print_error_msg
print_error_msg(e)
except ImportError:
print("please update to latest firmware")