[[How2Computing]]


*How to use serial port on Mac OS X [#y0fdbfb6]

//http://gyazo.com/0060e9c32c4f010456ec13e205e77764.png
http://is.ocha.ac.jp/~siio/gyazo/20140726120153.png
http://is.ocha.ac.jp/~siio/gyazo/20140726120104.png
http://is.ocha.ac.jp/~siio/gyazo/20140726115840.png

MacOS Xで、RS232C型シリアルポートを使うためのメモ書きです。
実際には、すでにMacintoshには何年も前からシリアルポートが付いていません。
レガシー(遺産)な技術、すなわち失われた太古の技術と言ってもよいです。
とはいえ、RS232C風のシリアル通信は、簡単で便利なので、世の中ではあちこちで使われています。
それをMacintoshで読む場合には、USBシリアル変換器のようなものを使います。
また、現行のArduinoでは、USBシリアル変換器を内蔵していて、USB経由で、シリアル信号を送ってきます。

USBシリアル変換器やArduinoでは、FTDI社(http://www.ftdichip.com/) の
チップが使われていることが多く、ここのVirtual COM port (VCP)ドライバというのをインストールすると、
/dev以下に旧来のシリアルポートと互換のスペシャルファイルが出来上がります。
また、一部のUSBシリアル変換器 ( http://www.sun-denshi.co.jp/scc/products/mobile/vs60r/vs60r.htm ) や、最新のArduino (Arduino Uno, Arduino MEGA 2560)は、USBの標準のCDCクラス (Communications Device Class) として動作するので、
ドライバーをインストールしなくても、/dev/cu.usbmodemXXXXというようなスペシャルファイルが現れます。


ここでは、このようにUSBを経由して送られてきたシリアル信号を、Mac OS Xで読んでプログラムする方法を紹介します。

まずは、ネットでググった一般的なシリアルポートの情報をメモしておきます。

-http://linuxjf.sourceforge.jp/JFdocs/Serial-HOWTO.html
-http://0n0.fc2web.com/paso/serial/serial01.html



*Arduinoでシリアル通信(送信)するプログラム [#q0344560]

Arduinoで以下のプログラムを作ったとします。

 int outpin=13;
 int inpin=2;
 
 void setup() {                
   // initialize the digital pin as an output.
   // Pin 13 has an LED connected on most Arduino boards:
   pinMode(outpin, OUTPUT);     
   pinMode(inpin, INPUT);
   Serial.begin(9600);
 }
 
 void loop() {
   if ( digitalRead(inpin) == HIGH) {
      digitalWrite(outpin, HIGH);   // set the LED on
      Serial.print("H");
   } else {
      digitalWrite(outpin, LOW);    // set the LED off
      Serial.print("L");
   }
   delay(1000);              // wait for a second
 }

写真のように、2番ピンに押しボタンスイッチを付けると、
これを押すことで13番のLEDが消えます。

http://gyazo.com/63b7dd8b1468470eba4d5b5451114024.png
//http://gyazo.com/25e22833c7482de19c4580f9e0e85a3e.png

また、このプログラムは、9600baudでボタンの状態を知らせます。
ボタンが押されていないと'H'の文字が、押されると'L'の文字がシリアルポートに流れます。


*Arduinoからのシリアル情報をC言語で読み取る [#q062972d]


これをC言語で読むには、以下のようにします。
(逆スラッシュが化けているかもしれないです。コピペするときはお気をつけください)


 // #include <sys/types.h>
 // #include <sys/stat.h>
 #include <unistd.h> //for open() close() read() 
 #include <fcntl.h>
 #include <termios.h>
 #include <stdio.h>
 #include <strings.h>
 #include <signal.h> //to handle ctrl-c
 
 #define BAUDRATE B9600
 #define MODEMDEVICE "/dev/cu.usbmodem621"
 #define _POSIX_SOURCE 1 /* POSIX compliant source */
 #define FALSE 0
 #define TRUE 1
 
 int fd;
 struct termios oldtio, newtio;
 int isrunning = TRUE;
 
 int serialOpen() {
 	fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY ); 
 	if (fd <0) {
 		printf("open error: %s\n",MODEMDEVICE); 
 		return -1; 
 	}
 	tcgetattr(fd,&oldtio); /* save current port settings */	
 	bzero(&newtio,  sizeof(newtio));
 	newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
 	newtio.c_iflag = IGNPAR;
 	newtio.c_oflag = 0;
 	/* set input mode (non-canonical, no echo,...) */
 	newtio.c_lflag = 0;
 	newtio.c_cc[VTIME]    = 0;   /* inter-character timer unused */
 	newtio.c_cc[VMIN]     = 1;   /* blocking read until 1 chars received */
 	tcflush(fd, TCIFLUSH);
 	tcsetattr(fd,TCSANOW,&newtio);
 	return 0;
 }
 
 void serialClose() {
 	tcsetattr(fd,TCSANOW,&oldtio); //restore previous port setting
 	close(fd);
 }
 
 unsigned char serialReadChar() {
 	unsigned char result;
 	int length=0;
 	tcflush(fd, TCIFLUSH); //clear the receiving buffer
 	length = read(fd,&result,1); //blocked until reading 1 byte.
 	return result;
 }
 
 void interrupt(int sig) { isrunning = FALSE; } //ctrl-c handler
 
 int  main() {
 	int c, res;
 	unsigned char result;
 	if(serialOpen() != 0) return -1;
 	signal(SIGINT, interrupt); //set ctrl-c handler
 
 	while (isrunning) {   /*endless loop until ctrl-c is typed */
           printf("value is %c\n", serialReadChar());
 	}
  
	serialClose();
 	return 0;
 }

これを、gcc test.cなどしてコンパイルし、実行すると、
以下のように、読めていることがわかります。
ArduinoのIDEで
/dev/tty.usb..を使っている場合は、上記のように、
/dev/cu.usbl... で動きます.


ちなみに、このプログラムはLinuxなどでも動くと思われます。

http://gyazo.com/fa5ef8361553618306c70d46523ea1a7.png


*Arduinoにシリアル情報をC言語で書き込む(2015.05.29追加) [#q062972d]
上記のプログラムに下記の関数を追加する事でC言語でArduinoへ数字を1文字送信出来るようになります。

 void serialWriteChar(int num){
	unsigned char result;
	int length = 0;
	write(fd,&num,1);
 } 




*Arduinoからのシリアル情報をPythonで読み取る [#e96c175f]

簡単です。

**pyserialをインストールする [#cbdb2cd7]

+pyserialを入手する&br;
--http://pypi.python.org/pypi/pyserial
からpyserialを入手します。
今回は、
pyserial-2.5.tar.gz
を使いました。
+pyserialをインストールする&br;
ダウンロードした圧縮ファイルを開いて、
setup.pyを
 sudo python setup.py install
として動かします。


**シリアルポートからデータを取得する [#u54bbc90]

つぎに、適当にこんなプログラムを書きます。

 import serial
 
 ser=serial.Serial('/dev/cu.usbmodem3a21',9600,timeout=2)
 
 data = ser.read(10)
 
 if len(data) != 0 :
     print data
 
 ser.close()

10個のデータを取得して、約10秒後に表示してくれます(Arduinoから毎秒1個のデータが来るため)。

http://gyazo.com/ca59528f454106a9df41b1cceaf55dbe.png


*Arduinoからのシリアル情報をProcessingで読み取る [#g5db712a]

こちらも簡単です。解説はこちらをみてください。 http://www.processing.org/reference/libraries/serial/

 import processing.serial.*;
 Serial myPort;
 
 void setup(){
     myPort = new Serial(this,"/dev/tty.usbmodem3a11",9600);
 }
 
 void draw(){
   background(0);
   while(myPort.available() > 0 )
     println("value is " + myPort.readChar());
 }

http://is.ocha.ac.jp/~siio/gyazo/20140726121616.png



*Arduinoからのシリアル情報をJavaで読み取る [#t78d8014]

Windowsなどではシリアル通信するクラスが配布されていたと思います。
Macなどには無かったように思います(最近はあるのかもしれない)。
ここでは面倒ですが、
Cでダイナミックライブラリを作って、JNAで読む方法を紹介します。
これができればCで作ったもののすべてがJavaから使えるので嬉しい場面があるかと思います。

ダイナミックライブラリとJNAについては以下をみてください。
-http://is.ocha.ac.jp/~siio/index.php?How2JNA

上記のCプログラムをダイナミックライブラリにします。
このプログラムの名前が、libserread.cだったとしたら、以下のようにコンパイルします。

 cc -dynamiclib -o libserread.dylib libserread.c

このあと、JNAをインストールしたJavaの環境で、以下のプログラムをjavacでコンパイルしてjavaで動かせばokです。(確実にクローズするために60個データを表示してcloseするようにしました。)

 import com.sun.jna.Library;
 import com.sun.jna.Native;
 import com.sun.jna.Platform;
 
 public class TestSerial {
   public interface CLibrary extends Library {
        CLibrary INSTANCE = (CLibrary) Native.loadLibrary("serread", CLibrary.class);
 	int serialOpen();
 	void serialClose();
 	byte serialReadChar();
   }
 
   public static void main(String[] args) {
       CLibrary arduino = CLibrary.INSTANCE;
 
 	arduino.serialOpen();
       for(int i=0;i<60;i++) System.out.println((char)arduino.serialReadChar());
       arduino.serialClose();
   }
 }


*ArduinoとJavaでシリアル通信をやり取りするためのクラス(2015.05.29更新) [#t78d8014]
上記の方法でCのダイナミックライブラリを作り、JavaとArduinoでシリアル通信(読み書き)できるようにするためのクラスです。
これは2014年に研究室有志メンバーで学祭に出店したリジョワーツ魔法魔術学校のアトラクション(薬草学・マンドラゴラ)の制御の為に作ったので、Classの名前がそれ仕様になっています。他で使う際には
クラス名とコンストラクタの部分の「SerialFromMNDR」を任意の名称に変更して使って下さい。
また、Arduinoから情報を読み込むread()はChar型1文字分を読み込みますが、Arduinoへ書き込むwrite()の方は1桁の数字を送るようになっています。それぞれ需要にあわせて、Char型やint型はカスタマイズ氏て下さい。


 import java.io.UnsupportedEncodingException;
 import com.sun.jna.Library;
 import com.sun.jna.Native;
 /*
  * JavaでArduinoとシリアル通信をする 
  */
 public class SerialFromMNDR {	 
	
	  public interface CLibrary extends Library {
	    CLibrary INSTANCE = (CLibrary) Native.loadLibrary("serread", CLibrary.class);
		int serialOpen();
		void serialClose();
		byte serialReadChar();
		void serialWriteChar(int num);
		
	  }
	    
	  CLibrary arduino;
	  
	  public SerialFromMNDR(){
		  arduino = CLibrary.INSTANCE;
	  }
	
	  /* シリアル通信開始 */
	  void open(){
		  arduino.serialOpen();
	  }
	    
	  /* シリアル通信終了 */
	  void close(){
		  arduino.serialClose();
	  }
	
	  /* Arduinoからの信号を読み取る */
	  String read(){
		  byte[] data= new byte[1];
		  data[0] = arduino.serialReadChar();
		  String strAscii = "";
		try {
			strAscii = new String(data, "US-ASCII");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		  return strAscii;
	  }
	  
	  /* Arduinoに一文字送る */
	  void write(int i){
				arduino.serialWriteChar(i);
	  }
	  
 }

このクラスを呼び出して使う際には、まず
 SerialFromMNDR.open();
でシリアル通信を開始します。その後はread()やwrite()で自由にArduinoと通信できるようになります。

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS