Linuxで直接シリアルデバイスを利用する際の注意点等
arduinoやichigoJamなんかとちょっとした通信を行う場合のメモです。
まあ、自分がハマって苦労した点です。
具体的には、
# cat /dev/ttyUSB0
# echo "ABCDE" > /dev/ttyUSB0
とかやって、データをやり取りする場合に発生する問題点に対応する方法のメモです。
現在の通信速度や通信条件の確認
# stty -a < /dev/ttyUSB0 speed 115200 baud; rows 0; columns 0; line = 0; intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0; -parenb -parodd cs8 -hupcl -cstopb cread clocal -crtscts -cdtrdsr -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc -ixany -imaxbel -iutf8 -opost -olcuc -ocrnl -onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 -isig -icanon -iexten -echo -echoe -echok -echonl -noflsh -xcase -tostop -echoprt -echoctl -echoke
または、
# stty -g < /dev/ttyUSB0 500:0:18b2:0:3:1c:7f:15:4:0:1:0:11:13:1a:0:12:f:17:16:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:0
通信条件の設定
arduinoやichigoJamなんかと、通信したい場合の設定
#stty -F /dev/ttyUSB0 115200 \ -iuclc -ixany -imaxbel -iutf8 -opost -olcuc -ocrnl -onlcr \ -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 -isig \ -icanon -iexten -echo -echoe -echok -echonl -noflsh -xcase \ -tostop -echoprt -echoctl -echoke
空白文字(スペース)を使う場合の注意事項
コマンドライン、シェルプログラムでは空白文字(スペース)は区切り文字
として機能します。
#!/bin/bash line=" AAA BBB CCC DDD" echo ${line} echo -n "[" echo " 123 4 5" | while read -rN 1 c do echo -n "$c" done echo "]"
この実行結果は、
AAA BBB CCC DDD [12345]
となります。
空白文字(スペース)は1文字にまとめられたり、削除されてりしています。
(逆に単語(ワード)部分の取り出しは楽になります)
コマンドラインでの利用では問題ないのですが、
echo ${line} > /dev/ttyUSB0
echo -n "$c" > /dev/ttyUSB0
とかやって、通信データとし空白文字(スペース)もちゃんと送信したい場合は
当然問題となります。
この勝手に空白文字(スペース)をいじられないよにするには、
環境変数IFS(フィールドセパレータ)に空白文字(スペース)を入れないようにします。
デフォルトの設定の確認
# set | grep IFS
IFS=$' \t\n'
これを、シェルプログラム内でのみ、IFS=$'\n' として、セパレータは改行文字のみにします。
#!/bin/bash PRE_IFS=$IFS IFS=$'\n' line=" AAA BBB CCC DDD" echo ${line} echo -n "[" echo " 123 4 5" | while read -rN 1 c do echo -n "$c" done echo "]" IFS=$PRE_IFS
この実行結果は、
AAA BBB CCC DDD [ 123 4 5]
無加工の出力となります。
デバイスがブロックされる場合の対応
通信条件を設定した後、
# cat /dev/ttyUSB01
とすると、シリアル通信データを簡単に表示出来ます。
ただし、受信待ちとなって終了しない場合があります。
調べたのですが、シェルプログラムでのタイムアウトの設定が分かりませんでした。
stty当たりの設定で何とかならないか調べたのですが分かりませんでした。
そこでtimeoutコマンドを使って、タイムアウトを実現しました。
私の使っているCentOSでは標準で用意されているコマンドのようです。
# timeout 2 cat /dev/ttyUSB0
とすると、2秒待ちのタイムアウトとなります。
特定のコマンドをarduinoに送って、その結果を幾つか受信するような場合は、
#!/bin/bash PRE_IFS=$IFS IFS=$'\n' tty="/dev/ttyUSB0" stty -F ${tty} 115200 \ -parenb -parodd cs8 -hupcl -cstopb cread clocal -crtscts \ -iuclc -ixany -imaxbel -iutf8 -opost -olcuc -ocrnl -onlcr \ -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 -isig \ -icanon -iexten -echo -echoe -echok -echonl -noflsh -xcase \ -tostop -echoprt -echoctl -echoke echo -n "$1" > ${tty} echo -e "\n" > ${tty} timeout 2 cat ${tty} | while read line do echo "${line}" usleep 1000 done echo "" > ${tty} IFS=$PRE_IFS
こんな感じで、対応しています。
例では、コマンドラインの文字列を送信して、その結果として
複数のデータを表示するとうものです。
シリアル通信デバイスの利用権限 (2016/01/19 追記)
USB-UARTモジュールをLinuxマシンに挿入して利用権限を調べると次のように
なっています(CentOS 6.4 、Raspbian Jessieで確認)
$ ls -l /dev/ttyU*
crw-rw---- 1 root dialout 188, 0 1月 19 00:11 /dev/ttyUSB0
グループ dialoutに利用権限があります。
そこで一般ユーザがシリアル通信デバイスを気楽に利用できるようにするには
グループ dialoutに登録すればよいです。
#sudo gpasswd -a USER dialout
または(ubuntu、Raspbian Jessieの場合)
#sudo adduser USER dialout
これでUSERがdialoutの一員になり以降、/dev/ttyUSBxxxや/dev/ttyACMxxが
使えると思います。
関連記事
・IchigoJam用の支援ツールLinux版を作成しました ・・・ シェルプログラムでシリアル通信
・Raspberry Pi 2(Raspbian Jessie) のGPIOのシリアルポートを使う
・Raspbian Jessie のGPIOまわりの利用権限
最近のコメント