レベル変換 (4) UART その4 Arduino UNOが受信-1

 2回目と3回目は、5Vで動作するArduino UNOから送信し、3.3Vで動作するマイコン・ボードが受信するレベル変換の実験をしました。ここでは逆に、「Spresense」もしくは「ラズパイ」からの送信をArduino UNOが受信する場合を実験します。

Spresenseを3.3Vで動作させ送信する

 3.3Vで動作しているSpresenseの送信を11番ピンから行い、抵抗1kΩを通して5Vで動作しているArduino UNOの10番ピンで受信します。

 送信するSpresenseのスケッチです。

#include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 11); // RX, TX

void setup() {
Serial.begin(9600);
Serial.println("Goodnight moon!");
mySerial.begin(9600);
}

void loop() {
mySerial.write("123");
delay(10);
mySerial.write("\n");
}

 受信するArduino UNOのスケッチです。

#include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 11); // RX, TX

void setup() {
Serial.begin(9600);
Serial.println("Goodnight moon!");
mySerial.begin(9600);
}

void loop() {
if (mySerial.available()) {
Serial.write(mySerial.read());
}
delay(1);
}

 

Arduino UNOのシリアルモニタです。

 Analog Discovery2を使って、これらの実験中の波形を示します。画面の上側ブロックがアナログ信号です。オレンジ色がSpresenseからの送信波形で、青色がArduino UNOの10番ピンの受信波形です。
 下側のブロックはUARTのデータをデコードして表示する画面です。オシロスコープのチャネル1(オレンジ色)にDIO2ピンを、オシロスコープのチャネル2(青色)にDIO1ピンをつないでいます。送信している"123"を正しくデコードしています。HIGH/LOWは電源の50%付近を境に判断しているようなので、マイコンが正しくHIGH/LOWを判断できなくとも、デコードできる場合が多いです。

 Arduino UNOの10番ピンは、LOWが0.3V、HIGHが3.5Vで、正常に受信できています。Arduino UNOのマイコンATMega328のI/OピンのHIGHレベルVih電圧は、約2.7V(グラフの読み、スペックでは3.0V)です。したがって、5Vではなく3.5Vでもマージンをもっています。

 この回路は一番単純でうまく働きます。この回路が働く理由は、入力回路に保護用ダイオードが入っていてそこに電流を流して電位差を得るためです。しかし、そのダイオードに流れる電流によっては、十分な放熱が得られないかもしれないなどの理由から長期にわたっての利用を控えるようにという発言もあります。

 外付けにダイオードを入れれば、保護ダイオードに電流を流さずにすみます。けれど、Spresenseの入力は3.3Vへプルアップされています。HIGHの信号がこの端子に出て、Arduino UNOのマーク状態=5Vが電位が高いので、Spresense側へ電流が流れてきますが、内部には電流は流れずに、1kΩへ流れます。

 さらにSpresenseの入力に入っているロジック・レベル・トランスレータLSF0204Rは5Vトレランスですから、電流が流れ込んでも問題は起こりません。そうであれば、1kΩも不要なので直結しました。電圧レベルもほとんど変化なく、通信できています。

 筆者は以上の考察が正しいかどうか検証する力がないので、疑問があれば、次のMOSFETのレベル変換回路を使いましょう。R2 10kΩはもともとSpresenseのI/Oには1kΩのプルアップ抵抗が入っているので不要ですが、入っていても動作に支障はありません。

  Arduino UNOの10番ピンは、LOWが0.2V、HIGHが3.8Vで、正常に受信できています。

 Arduino UNOの受信ピンを10kΩでプルアップします。市販品のレベル変換ボードはこのような回路が多いです。

 Arduino UNOの10番ピンは、LOWが0.5V、HIGHが4.0Vで、正常に受信できています。

 参考のため、プルアップ抵抗なしの実験をします。

 問題なく通信できています。

 第2回の送信の事例でも同じ方向の配線でレベル変換が正常にできていました。つまり、MOSFETを使った回路は、信号方向がどちらでも正しくレベル変換ができる優れものです。

(1) 何も起こっていない状態
 Spresenseの送信端子につながっているゲートとソースが同じく3.3V=HIGHになっていて電位差がありません。つまりMOSFETはOFF状態なので、Arduino UNOの受信端子がつながっているドレインは5Vにプルアップされているので、HIGH=5V状態です。

(2) 3.3V側、ここではSpresenseの送信端子がLOWを出力したとき、ソースは0Vになります。ゲートは3.3Vへ直接つながっているので、MOSFETはONになります。その結果ドレインは0Vになり、Arduino UNOの受信端子もLOWになります。

(3) 逆に5V側、ここではArduino UNO送信端子がLOWを出力したとき、MOSFETにある寄生ダイオードのカソード(=ドレイン)が0Vになり、アノード(=ソース)は3.3Vにプルアップされているので、3.3V側から5V側へ電流が流れます。その結果、ソースが0V付近になりSpresenseの受信端子がLOWになります。

 双方向とはいえ、MOSFETのソースは低い電圧側につながないと正しく動作しません。

 


Raspberry Piが送信

 MOSFETのBSS138を使ったレベル変換回路を通してつなぎます。Arduino UNOからラズパイへ送るときに使った回路をそのまま同じようにつなぎます。この回路は双方向のレベル変換をします。

 ラズパイの送信Txは3.3Vで8番ピン(GPIO14)で、Arduino UNOは5Vで10番ピンで受信します。

ラズパイの送信プログラムです。

import serial
import time

con=serial.Serial('/dev/serial0', 9600, timeout=10)
while 1:
con.write("123")
print ("send\n")
time.sleep(0.1)

 Arduino UNOの受信スケッチです。 

#include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 11); // RX, TX

void setup() {
Serial.begin(9600);
Serial.println("Goodnight moon!");
mySerial.begin(9600);
}

void loop() {
if (mySerial.available()) {
Serial.write(mySerial.read());
}
delay(10);
}

  実行結果です。

 波形です。上の青色がラズパイの送信データ、下のオレンジ色がArduino UNOの受信データです。ラズパイのLOWは0V、HIGHは3.3V、Arduino UNOのLOWは0V、HIGHは3.6Vです。Arduino UNOの入力信号のHIGHレベルVihは2.7V以上なので、対応できています。

 受信側の入力ポートを10kΩで5Vへプルアップします。

 ラズパイの送信データはLOWが0V、HIGHが3.5Vです。受信側のArduino UNOはLOWが0VでHIGHは3.8Vです。Arduino UNO側の5Vへのプルアップがあってもなくても、受信レベルは確保できています。Vihが2.7Vで、3.8Vのほうがノイズマージンは高いので、プルアップ抵抗は入れたほうがよいです。

 簡単な回路を探しました。両方の端子間に4.7kΩを入れただけです。この抵抗は、端子間に流れる電流を制限します。

 ラズパイの送信データ(青色)はLOWが0.1V、HIGHが3.6Vです。受信側のArduino UNO(オレンジ色)はLOWが0.5VでHIGHは3.6Vです。問題なく通信できています。

 4.7kΩを1kΩに変更しました。ラズパイの送信データ(青色)はLOWが0.1V、HIGHが3.6Vです。受信側のArduino UNO(オレンジ色)はLOWが0.1VでHIGHは3.5Vです。問題なく通信できています。

 抵抗1本で接続する方法は、Spresense のところでも考察しましたが、不安があれば、MOSFETの回路を使うほうが安心です。

前へ

レベル変換 (3) UART その3 Arduino UNOから送信-2

次へ

レベル変換 (5) UART その5 Arduino UNOが受信-2