こんにちは、「メカのりまき」です。
この記事では、PCとArduinoボード間で通信を行う際に利用する「シリアル通信」について説明したいと思います。
まだ、「Arduino IDE」を使用したことがないという方は、前回の記事を先にご覧になることをお勧めします。
本記事で使用するもの
本記事で私が使用した物は以下の通りです。
- 「Arduino IDE2.0.3」をインストールしたPC(Windows11)
- USBケーブル
- Arduino Uno R3(ELEGOO UNO R3でも可)
「Arduino IDEのバージョンやOSの違いによって、画面構成や手順が異なる部分が出てくると思われますので、ご注意ください。
また、「Arduino Uno R3」の互換ボードであれば、「ELEGOO UNO R3」以外のボードでも、本記事と同様な手順で動作可能だと思われますが、動作検証はしていないので、その点はご了承ください。
シリアル通信について
「シリアル通信」とは1つの信号線を使って、データを1ビットずつ順番に送信する通信のことです。
ここで、1ビット(bit)とは、コンピュータが扱う最小単位で、2進数の1桁、つまり0か1を表しています。
シリアル通信のイメージとしては、下に示すアニメーションのような感じです。
「通信開始」ボタンを押すとアニメーションが開始されます。
データが順番に送られていくイメージができたでしょうか。
この送られた0と1の組み合わせから、コンピュータはそれを数字や文字などに変換して、私たちに分かるように表示をしてくれたりします。
ちなみに、シリアル通信のシリアルは英語で「serial」と書き、「連続的な」という意味を持っています。
シリアル食品(穀物食品)を意味する「cereal」とは別物なので注意してください。
シリアル通信を使った通信方法
シリアル通信を使った通信方法にはいくつか種類があり、代表的な例としては「UART通信」、「I2C通信」、「SPI通信」などがあります。
上記の例を全て説明すると記事が長くなってしまうので、本記事では、PCとArduinoボードの通信を行う際に利用する「UART通信」という通信方法について説明したいと思います。
UART(ユーアート)通信について
「UART通信」とは、下図のようにデータ送信用とデータ受信用の2つの信号線でやり取りを行う通信方式です。
ここで、受信側を「RX」、送信側を「TX」と呼びます。
図に「GND(グランド)」と書かれた青い線がありますが、これは、デバイス間で電位の基準(0V)を統一させるための線です。
この線を繋げることにより、デバイス間で安定した通信を行ったり、部品に意図した電流を流したりすることができるようになります。
USBケーブルで繋いだArduinoボードの電源が入るのは、実はこの「GND」線がUSBケーブルの中に有るおかげだったりします。
「GND」については、別の記事で説明いたしますので、今はあまり気にせず、部品間で電気的なやり取りを行うときに必要な線とだけ覚えておいてください。
ArduinoでのUART通信
「Arduino Uno R3」のデジタル入出力ピン0番と1番を見てみると、0番ピンにはRX、1番ピンにはTXと書かれているのが分かります。
これは、0番ピンと1番ピンがデジタル入出力ピンでありながら、UART通信を行うために使われるピンでもあるためです。
また、この二つのピンは「Arduino Uno R3」の内部でUSB-シリアル通信の変換を行う「ATmega16U2チップ」にも繋がっており、それによって、PCと通信ができるようになっています。
デジタル入出力ピン0と1の注意点
ここまで、「シリアル通信」、「UART通信」について、そして、ArduinoボードでUART通信を行うためには0番ピンと1番ピンを利用するということを説明しました。
正直な話、上記で説明したことを理解していなくても、下記で説明するスケッチを書き込めば、PCとArduinoボードで通信を行うことができます。
ただし、0番ピンと1番ピンについて、以下のことは覚えておいたほうが良いです。
スケッチを書き込む際は0番ピンと1番ピンに何も接続しないようにする
上記でUART通信に利用すると説明した0番ピンと1番ピンですが、「Arduino IDE」からArduinoボードにスケッチを書き込む際にも、この2つのピンは利用されます。
そのため、0番ピンと1番ピンに何かを接続した状態で書き込みを行うとエラーが発生することがあります。
よって、書き込みを行う際は、0番ピンと1番ピンに何も接続されていない状態にしたほうが良いです。
PCとシリアル通信を行う際は、0番ピンと1番ピンはデジタル入出力ピンとして利用できない
PCとUSBケーブルを繋いでシリアル通信を行う場合、0番ピンと1番ピンはUART通信の「RX」、「TX」として使用されます。
つまり、シリアル通信を行っている場合、0番ピン、1番ピンは何もしていないように見えても、Arduinoボード内部では、しっかりと仕事をしている状態ということになります。
よって、同時進行で0番ピンと1番ピンをデジタル入出力ピン(接続したデバイスから情報を受け取ったり、接続したデバイスを制御したりするピン)として、利用するといったことはできないので注意してください。
逆に言えばPCと通信を行っていなければ、0番ピンと1番ピンをデジタル入出力ピンとして使用できるということになります。
しかし、書き込みの際は0番ピンと1番ピンに何も接続されていない状態するなどの手間はあるため、理由が無い場合は、0番ピンと1番ピンは空けておくことをお勧めします。
ちなみに、今回の記事では紹介しませんが、PC以外のデバイスとUART通信を行うために、0番ピンと1番ピンを使用するということはあります。
ただし、この場合も書き込みの際は、0番ピンと1番ピンに何も接続されていない状態にするという手間はあるので注意が必要です。
PCと通信するためのスケッチ
今回は「Arduino IDE」の「シリアルモニタ」というものを使って、PCと文字のやり取りを行うスケッチを作成します。
今回行う文字のやり取りのイメージは、以下のような感じです。
新しいスケッチを作成する
「Arduino IDE」を立ち上げると、前回書いたスケッチの画面が表示されます。
そのまま前回書いたスケッチを編集すると、設定によっては上書き保存されてしまうため、以下の操作で新規のファイルを作成します。
「ファイル」タブをクリックした後、「New Sketch」をクリックすると、まっさらな新しいスケッチが表示されます。
スケッチを書き込む
続いて、Arduinoボードを接続し、以下のようなスケッチを書き込んでください。(コピー&ペーストでも可)
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 32 |
/* Arduinoで遊ぼう(4,シリアル通信); 2024/09/10 Serial_test //スケッチの詳細はこちら↓ https://mecha-norimaki.com/arduino_start_04/ 2024/09/10 コメントを追加しました。 2024/09/10 変数の名前を変更しました。 */ //データを格納するための変数を宣言 char inputChar; void setup() { //シリアル通信の初期化 Serial.begin(9600); //Helloという文字列を出力する Serial.println("Hello"); } void loop() { //受信したデータ数を確認して、データがあった場合、受信した文字の出力する if (Serial.available() > 0) { inputChar = Serial.read(); Serial.print(inputChar); } } |
もし、Arduinoボードの接続の仕方やスケッチの書き込み方が分からくなった場合は、前回の記事で説明していますので、やり方を確認してみてください。
シリアルモニタを扱う
今回のスケッチは書き込みを行っただけでは、変化をみることができないため、以下の手順でPCとの通信を確認します。
シリアルモニタを表示させる
まず、「Arduino IDE」の画面右上にある虫眼鏡のアイコンをクリックします。
すると、「シリアルモニタ」が開き、画面の下部分にシリアルモニタが追加されるのが確認できます。
ここで、開いた「シリアルモニタ」を利用すれば、Arduinoボードから送られてくるデータを表示させたり、キーボードで打ち込んだ文字のデータをArduinoボードに送信したりすることができます。
以下では、それらの方法について、説明をしたいと思います。
データの表示を確認する
まずは、Arduinoボードから送られてくるデータの表示を確認します。
シリアルモニタ右側の「~baud」と書かれた部分が「9600baud」になっているかを確認します。
「9600baud」の状態でしばらく待っていると、「Hello」という表示が出てきます。
もし、待っていても全然表示されない場合は、Arduinoボードのリセットボタンを押してみてください。
それでも、出てこない場合は、「void setup()」の中身が間違えていないか確認してみてください。
また、「-1」という数字や良く分からない文字が大量に出てきた場合は、「void loop()」の中身が間違えていないか確認してみてください。
「Hello」と表示されている場合は、Arduinoボードから送られてくるデータの表示は成功です。
データの送信を確認する
次に、キーボードで打ち込んだ文字のデータをArduinoに送信できているかの確認をおこないます。
「~baud」と書かれた枠の左の枠をクリックし「改行なし」を選択した後、さらにその左にあるメッセージと書かれた枠にテキストを打ち「Enter」キーを押します。
(日本語を打ち込むと文字化けするので、アルファベット、数字、記号などを入力)
すると、テキストがArduinoボードに送信され、「Hello」の下に、打ち込んだテキストが表示されます。
下の写真のように続けて、テキストを打ち込むと先ほどの右隣りに表示が追加されていきます。
改行したい場合は、STEP3で「改行なし」とした部分を「LFのみ」や「CRおよびLF」にすると、文字を送信したあと、改行されるようになります。
上記の操作で、打ち込んだテキストが正常に表示されていれば、データの送信は成功です。
スケッチの解説
上記の操作では、Arduinoボードとの通信がしっかり行えているかを、シリアルモニタにより確認しました。
では、今回のような通信を行うために、どのような処理を行っていたか、スケッチを見て順番に説明していきたいと思います。
初期化処理とループ処理
「void setup()」の中には初期化の際に行う処理、「void loop()」の中には繰り返し行いたい処理を記述します。
これは、Arduinoの処理に必須で、スケッチを書くたびに毎回出てくるので、覚えてください。
詳しくは前回の記事で説明しているので、忘れてしまった方は、前回の記事で確認してみてください。
変数宣言
13 14 |
//データを格納するための変数を宣言 char inputChar; |
今回のスケッチでは、一番初めに変数宣言というものを行っています。
この変数宣言というのは、あらかじめデータを格納する場所を決めておいて、後から自由に中身を書き換えたり、読み出したりできるようにしようというものです。
データを格納するための箱を用意するという風にイメージをすると少し分かりやすくなります。
上記の場合、1文字分のデータが入る「char」という種類の箱を用意し、その箱に「inputChar」という名前を付けるということをしています。
こうすることで、後から「inputChar」の中にデータを入れてくれ、「inputChar」の中のデータを取り出してくれといった命令をすることができるようになります。
ここで、箱の種類「char」の部分を「型」、箱の名前「inputChar」の部分を「変数名」と呼びます。
「型」は格納したいデータの種類によって、予め用意されている物の中から選び、「変数名」はアルファベット、数字、アンダーバー( _ )を使って好きな名前を自分で付けます。
シリアル通信の初期化
18 19 |
//シリアル通信の初期化 Serial.begin(9600); |
シリアル通信を行う際の初期処理を行います。
( )の中の数値はデータを送る速度を表していて、通信を行う相手側と合わせる必要があります。
「Arduino IDE」側の通信速度は、下の写真の赤枠部分で変更できます。
この数値を大きくすると、データを送る速さが速くなり、通信の処理も速くなるのですが、数値を大きくしすぎると、データがうまく送信できないことがあるので、うまく使い分ける必要があります。
なお、「Serial.begin()」を行うと、シリアル通信が開始するため、これ以降は、0番ピンと1番ピンでのデジタル入出力は行えなくなります。
一応、「Serial.end()」という文で、シリアル通信を停止させることはできますが、私はあまり使ったことがないです。
文字列の出力
21 22 |
//Helloという文字列を出力する Serial.println("Hello"); |
「Serial.println()」は( )の中身を出力した後、改行を行います。
文字列を出力したい場合は上記のようにダブルクォーテーション( ” )で出力したい文字を囲います。
数値や変数を出力したいときは、ダブルクォーテーションは付けません。
受信したデータ数の確認
1 |
Serial.available() |
シリアルモニタで送信したデータは、ボード内の「シリアルバッファ」という部分に保存されています。
「Serial.available()」はこの「シリアルバッファ」に保存されている文字数を確認します。
条件分岐(if文)
28 29 30 31 32 |
if(Serial.available() > 0){ //処理1; //処理2; //処理3; } |
ifの後の( )内の条件が正しければ、中身の処理が上から順番に実行されます。
上記の場合は、「シリアルバッファ」に保存されている文字数が0よりも多い場合、中身の処理が上から順番に実行されます。
( )内の条件が正しくなければ、中身の処理は行われず、次に進みます。
受信した文字の読み込み
29 |
inputChar = Serial.read(); |
まず、「Serial.read()」はシリアルバッファから先頭の1文字分のデータを読み取って、シリアルバッファからその文字を消します。
そして、先ほど上記で用意した「inputChar」の中身を、「Serial.read()」で読み取った文字に書き換えるということが、上のスケッチでは行われています。
今回は「条件分岐」でシリアルバッファ内に文字があることを確認してから、「Serial.read()」を行うようになっていますが、もし、シリアルバッファが空の状態で、「Serial.read()」を行うと「-1」という数値が返ってきます。
受信した文字の出力
30 |
Serial.println(inputChar); |
「inputChar」の中身を出力しています。
「Serila.println()」では( )内を出力した後に改行を行いましたが、「Serila.print()」の場合は改行を行わないという違いがあります。
(先ほど書いたスケッチの「Serila.print(inputChar)」を「Serila.println(inputChar)」に変更した場合、1文字ごとに改行が行われます。)
まとめ
今回のスケッチを図でまとめると下のようになります。
今回の記事では、覚えることが多く、スケッチも複雑だったので、全部理解するのは、難しかったと思います。
「変数宣言」、「条件分岐」とシリアルモニタへの出力は、今後の記事でもよく出てくると思うので、分からなくなったら、この記事に戻ってきて復習をしてみてください。
次回の記事では、「変数宣言」、「条件分岐」について、もう少し詳しく説明した後、最後にシリアルモニタを利用して、13番ピンのLEDを制御するやり方について説明したいと思います。
本記事はここまでです。ご清覧ありがとうございました。
広告
楽天モーションウィジェットとGoogleアドセンス広告です。
気になる商品がございましたら、チェックをしてみてください。