LoginSignup
4
3

More than 1 year has passed since last update.

Raspberry PiとArduino Unoをシリアルポート(UART)で接続してエコーバックするテストプログラム

Last updated at Posted at 2020-05-12

##はじめに
 Raspberry Pi(以下、ラズパイ)とArduino Unoをシリアルポート(UART)を利用してエコーバックさせるための配線図とテストプログラムを紹介します。これから似たような試作を検討している方やトラブルに悩んでいる方の参考になれば幸いです。
 テストプログラムは、ラズパイ側からASCIIコードを送信して、Arduino Unoでエコーバックします。ラズパイで受信したASCIIコードが送信したコードと一致したときターミナルに表示します。一致しないときは送信したコードと受信したコードを表示してテストプログラムは停止します。なお、配線図は「Fritzing」を使って描いたものを使用しています。
##準備するもの
・ Raspberry Pi 3B+または 4B
・ Raspbian (コードネーム:Buster、Linuxカーネル:4.19.75で確認)
・ wiringPi Ver.2.52 ※Pi 4Bの場合はVer.2.52にアップデートしないと動作しません。アップデートの方法はこちらの記事をご参照ください。
・ ラズパイ用周辺機器一式
・ Arduino Uno Rev3
・ Arduino IDE 1.8.12  ラズパイにインストールする場合はこちらの記事をご参照ください。
・ USBケーブル(Type-Aオス、Type-Bオス)
・ 双方向ロジックレベル変換モジュール AE-LCNV4-MOSFET(秋月電子通商:K-13837)
・ ブレッドボード
・ ジャンパーワイヤ(オス-メス、オス-オス)

##配線図
 ラズパイのGPIOは3.3V系で、Arduino Unoは5V系です。両者の信号線を接続した場合、Arduino Unoの5V系の高い電圧がラズパイのGPIOの内部回路や本体を壊す危険性があります。また、LレベルとHレベルの判定の基準が異なります。そこで、3.3V系と5V系の論理レベルを変換する回路や専用のデバイスが使用されます。本実験では、秋月電子通商が販売している4ビット双方向ロジックレベル変換モジュール「AE-LCNV4-MOSFET」を使用します。本モジュールには双方向の信号線が4回路あります。1回路を示しますが、Nチャンネルエンハンスメント形MOSFETで、3.3Vとと5V系のロジックレベルを変換しています。バイポーラトランジスタではコレクタ-エミッタ間で電流が流れる方向が決まっていますが、MOSFETではソースを基準にゲートに正バイアスを加えれば、ドレインが正であっても負でもあってもチャネルが開かれるため、双方向とも等しいドレイン-ソース抵抗が得られます。そのため、電流はソース-ドレイン間のどちらの方向にでも流すことができるため、双方向の信号になります。
Chap1 MOSFET.png
 本モジュールの電圧が低いLV側にラズパイを、電圧が高いHV側にArduino Unoを接続します。なお、本モジュールでは、ピンヘッダのはんだ付け作業が必要となります。全体の回路図は割愛しますが、ラズパイとArduino Unoの送信(Txd)と受信(Rxd)はクロス配線になります。本実験の通信距離は約20cmです。
Pi Arduino_ブレッドボード.png
##ソースコード
ラズパイとArduino Unoのテストプログラムのソースコードを示します。Arduino Unoのシリアルポートの通信速度は9600bpsで使用される事例が多いのですが、今回より高速な115200bpsに設定しました。なお、Arduino IDEはRaspbainにインストールすることができます。こちらの記事「Arduino IDEをRaspberry Pi 3B+, 4Bにインストールする方法」に、IDEのインストールの方法とサンプルスケッチ(Lチカ)の実行手順の解説がありますのでご参照ください。

Raspberry Pi

 ASCIIコードの0からzまで順番に1文字毎に送信して、Arduino Unoでエコーバックされたデータを受信して、比較しています。データが一致しない場合はエラーを表示して送信をストップします。

EchoBack.c
// gcc -Wall -o EchoBack EchoBack.c -lwiringPi -lpthread -g -O0
#include <stdio.h>			//入出力
#include <stdlib.h>			//一般ユーティリティ
#include <wiringPi.h>		//wiringPi
#include <wiringSerial.h>	//シリアル通信用wiringPi
#include <termios.h>		//ttyパラメータの構造体
#define BPS 115200			//通信速度

int main (void){
	unsigned char txdData;
	int rxdData,error=0;
	int fd;
	struct termios options;		// 通信オプションの構造体の定義
	
	fd = serialOpen( "/dev/ttyS0", BPS);	//シリアルポートのオープン
	tcgetattr(fd, &options);		//通信オプションの取得
	options.c_cflag |= CS8;			//データ 8bit
	options.c_cflag &= ~PARENB;		//パリティなし
	options.c_cflag |= CSTOPB;		//ストップビット 2bit
	options.c_iflag &= ~IXON; 		//出力のXON/XOFFフロー制御なし
	options.c_iflag &= ~IXOFF;		//入力のXON/XOFFフロー制御なし
	tcsetattr(fd,TCSANOW,&options);	// 通信オプションの変更
	
	serialFlush(fd);				//受信バッファのクリア
	
	do{
		for(txdData='0';txdData<='z';txdData++){ 	//0からzまでのASCIIコードを送信する。
			serialPutchar (fd, txdData);			//1文字の送信
			rxdData = serialGetchar(fd);			//1文字の受信
			if(rxdData == txdData){
				printf("%c",rxdData); fflush(stdout);	// 文字の表示		
			}else{
				printf("\n expected %c:%d, received %c:%d \n",txdData,txdData,rxdData,rxdData);
				error++;
				break;
			}
		}
	}while(error == 0);
	serialClose(fd);
	return EXIT_SUCCESS;
}

Arduino Uno

 「受信と送信」の永久ループです。

EchoBack.ino
void setup() {
  Serial.begin(115200,SERIAL_8N2);
}

void loop() {
  if (Serial.available()) {   //受信のチェック
    char  c = Serial.read();
    Serial.write(c);   //エコーバック
  }
}

Arduino Unoの書き込み時の注意点

 Arduino Unoにスケッチを書き込む前に、Arduino Unoの受信信号線(RX)を一旦外してください。RXを接続した状態で書き込んだ場合、IDEのテキストコンソールに「マイコンボードに書き込もうとしましたが、エラーが発生しました」と表示されます。実はArduino Unoには2つのマイコンチップがあります。一つはユーザーがメインに使用するATMEGA328です。ユーザーはUSBケーブルを利用してArduino Unoにスケッチを書き込みますが、ATMEGA328にはUSBのインタフェース回路がありません。そこで、USBインタフェース回路を備えた2つ目のマイコンチップATMEGA16U2がユーザーのPCとATMEGA328の橋渡しをします。ATMEGA16U2はシリアルポートを介してATMEGA328にスケッチを書き込みます。ATMEGA328はRX信号線で受信するのですが、今回のように外部の信号線が接続されていると正しい送信と受信できないため通信エラーになります。
 書き込みが正常に終了しましたら、RX信号線の配線を戻します。なお、書き込む前に、Arduino Unoのリセットボタンを押してください。
##動作確認
 Raspberry PiのEchoBackのプログラムを実行すると、下図のようにターミナルに0からzまでの文字が繰り返し表示されます。
Pi2Uno.jpg
 なお、次に示すArduino Unoのスケッチ(EchoBack2.ino)では、受信した「z」を故意に大文字の「Z」で返信します。ラズパイのターミナルでは送信と受信のデータを文字と10進数で表示して、テストプログラムは停止します。
NG.png

EchoBack2.ino
void setup() {
  Serial.begin(115200,SERIAL_8N2);
}

void loop() {
  if (Serial.available()) {   //受信のチェック
    char  c = Serial.read();
    if (c == 'z'){            //zを受信したとき大文字のZを返します。
      Serial.write('Z');
    }else{
      Serial.write(c);   //エコーバック
    }
  }
}

##補足
 Raspberry PiとArduino Unoとの通信距離を長くしたい場合やノイズの影響を受ける環境下では、RS-232インタフェース回路等で補強します。
##Reference

4
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3