7839

雑草魂エンジニアブログ

【ラズパイ】pySerial を用いたシリアル通信(GPIO編)

前回のシリアル通信 は、USBポートを使用していたが、今回はRaspberry Piの GPIO を用いてシリアル通信を行ったので、備忘録として残しておく。

pySerialで接続可能なポートの確認

まずは、GPIOの信号をどこのポートに送ればいいか調べるために、ポートの確認を行った。 pySerialに含まれるモジュール serial.tools.list_ports を使うことで、接続可能なポートを取得することができる。

import serial.tools.list_ports

def search_com_port():
    coms = serial.tools.list_ports.comports() # ポートデータ取得
    comlist = []
    for com in coms:
        comlist.append(com.device)

    print('Connected COM ports: ' + str(comlist))
    return comlist

Tools — pySerial 3.0 documentation

ここで取得できるポートは以下の通りであった。

  • /dev/ttyAMA0
  • /dev/ttyUSB0

/dev/ttyAMA0 はUSBを接続していないときでも必ず検出されるので、こちらが GPIO のポートであると勝手に思っていたが、これが間違いであった。

Raspberry Pi 3 のシリアル通信に関して

Raspberry Pi 3 は、以下のような設定になっていることがわかった。

  1. Bluetooth機能が追加され、その通信に従来のシリーズで利用していたURAT0(ttyAMA0)が割り当てられた。
  2. [1]により、GPIOのシリアル通信がデフォルトで利用できなくなった。
  3. [1]により、UART1(ttyS0)が追加された。UART1はソフトウェア制御のため、CPUのコアクロックに依存してしまう問題点あり。
  4. コアクロックはデフォルト設定では可変のため、CPUの負荷等で変化する。それに依存しているUART1のボーレートも同様に変化してしまうため、通信が失敗する可能性がある。

そのため、以下の設定が必要であった。

  1. GPIOのシリアル通信を有効化する
  2. Linuxのシリアルコンソールを無効化する

GPIOのシリアル通信を有効化する

raspi-configでシリアル通信を有効化する。

$ sudo raspi-config
  1. 「5 Interfacing Options」を選択
  2. 「P6 Serial」を選択
  3. 「Would you like a login shell to be accessible over serial?」に対してYesを選択する
  4. 「Finish」を選択

再起動することで、設定が適応される。

Linuxのシリアルコンソールを無効化する

プライマリUART(/dev/serial0)がLinuxのシリアルコンソールとして使用されている。シリアル通信で使用するため、Linuxのシリアルコンソールとして使用されないように変更する必要がある。もし無効化しない場合、シリアルポートにLinuxのシリアルコンソールのデータ(ログイン・シェル等のやり取りのための文字データ)が流れてしまうので、誤作動の原因になるので注意が必要である。

/boot/cmdline.txtを修正し、serial0をコンソールとして使わないように設定する。

$ cat /boot/cmdline.txt 
$ dwc_otg.lpm_enable=0 console=tty1 console=serial0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet splash plymouth.ignore-serial-consoles

エディターで「console=serial0,115200」を削除し、再起動する。

シリアル通信試験

今回は、Windows PCとRaspberry Piを接続して、実際にシリアル通信ができているか確認を行った。

準備物

Raspberry PiのGPIOのPIN配置は以下の通りである。

f:id:serip39:20200703191035p:plain

今回は、GND(6)・Tx(8)・Rx(10) を使い、USBドングルと接続する。 シリアル通信の時に、よく間違いがちであるが、配線はテレコに接続する必要がある。

f:id:serip39:20200703192615p:plain

Linuxコンソールからシリアル通信

まずは、Pythonではなく、直接コンソールからシリアル通信を行った。

# 通信速度設定
$ stty -F /dev/serial0 9600

# HelloWorld送信
$ echo "Hello World" >> /dev/serial0

Windows PCでTeraTermを起動して「Hello World」と表示されて、無事に確認することができた。

pySerialでシリアル通信

次に、PythonのpySerialを使って、シリアル通信を行った。 前回のプログラムから、ポートの設定のみを変更した。

import serial
import struct

use_port = '/dev/serial0'

_serial = serial.Serial(use_port)
_serial.baudrate = 9600
_serial.parity = serial.PARITY_NONE
_serial.bytesize = serial.EIGHTBITS
_serial.stopbits = serial.STOPBITS_ONE
_serial.timeout = 5 #sec

commands = [ 0xB6, 0x01, 0x02, 0x00 ]

for cmd in commands:
    data = struct.pack("B", cmd)
    _serial.write(data)

_serial.flush()

_serial.close()

TeraTermで16進数が表示されれば、通信完了であるが、おそらく通常の設定の場合は文字化けしてしまう。

TeraTermで16進数を表示する方法

TeraTermで16進数を表示する方法

設定ファイルを変更して、「16進デバッグモード」を起動する必要がある。

  1. 設定ファイル「TERATERM.INI」を読み出す。デフォルトでは、program files > Tera Termフォルダの中にある。
  2. 以下の部分(384行目あたり)を修正して、Debug=onにする。

    ; Display all characters (debug mode)
      Debug=on
    
  3. TeraTermを再起動する

  4. 画面上で「Shift+Esc」を押すことで、モードが以下のように切り替わる。
    通常表示 → デバッグモード → 16進デバッグモード → 非表示(→通常に戻る)

16進デバッグモードにして、再度シリアル信号を送信することで、きちんと表示され、無事に確認することができた。

まとめ

今回は、前回に引き続き、シリアル通信を行った。Raspberry Pi のGPIOを用いて通信ができたので、他のモジュールとの組み合わせが可能となった。デバイスであるRaspberry Piの特性で最初戸惑ってしまったが、きちんと設定することで動作させることができた。デバイス側の特性もきちんと確認する必要があると再認識することができた。また、Linuxの基本的なコマンドもしっかりと覚えて、使いこなせるようになりたいと思えた。

それでは、ステキな開発ライフを。