フォト
2017年8月
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31    
無料ブログはココログ

« Arduinoで16x16 LEDドットマトリックスを利用する(8) | トップページ | 野良猫物語(1) »

2015年1月31日 (土)

Linuxで直接シリアルデバイスを利用する際の注意点等

Linuxにて、直接 /dev/ttyUSB0、/dev/ttyACM0 なんかのデバイスを使って
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まわりの利用権限
 

« Arduinoで16x16 LEDドットマトリックスを利用する(8) | トップページ | 野良猫物語(1) »

arduino」カテゴリの記事

AVR」カテゴリの記事

コメント

コメントを書く

(ウェブ上には掲載しません)

トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/571408/61063579

この記事へのトラックバック一覧です: Linuxで直接シリアルデバイスを利用する際の注意点等:

« Arduinoで16x16 LEDドットマトリックスを利用する(8) | トップページ | 野良猫物語(1) »