UARTを利用してESP32とシリアル通信する

# Goal
- UART通信を利用してESP32とWindows間で通信してみる
- USB to TTL変換ケーブルを使ってみる

# 利用した開発ボード
ＥＳＰ３２－ＤｅｖＫｉｔＣ　ＥＳＰ－ＷＲＯＯＭ－３２開発ボード
http://akizukidenshi.com/catalog/g/gM-11819/

# UART通信って？

ちょっと調べたら以下のような感じらしい。

- 1対1の接続
- 基本は信号線が2本
    - TX(TXD):送信
    - RX(RXD):受信
- 接続機器同士はクロスで接続する
    - TX -> RX
    - RX <- TX
- 信号線の電圧には5vと3.3Vの2種類ある。通信機器同士は同じ電圧で利用しないと最悪壊れる
- 信頼性を高めるためフロー制御が必要な場合は以下の信号線も利用する
    - RTS(Request to Send)
    - CTS(Clear to Send)
- 通信速度（ボーレート）を接続機器間で合わせる必要がある

# パソコン側の準備

今回はこちらを購入してみました。USBで仮想COMポートを作成してUART通信できるようになります。

DSD TECH SH-U09C USB - TTLシリアルアダプター + FTDI FT232RLチップ Windows 10 8 7 Mac OS X対応
https://www.amazon.co.jp/gp/product/B07BBPX8B8/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8&psc=1

## シリアルアダプターの準備設定

USBなのでとりあえずUSBポートに刺してみました。おお、自動でドライバ入れてくれました！この辺りはさすがwindowsですね！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144344/f9e059d8-0dcb-f1cb-d9b7-6f6fd4679c47.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144344/549f5883-8d33-bff2-32aa-d841fad54ecc.png)

プロバイダーがFTDI(シリアル変換チップのメーカー）となっているので問題なさそうな予感です！このまま行こう:relaxed:

## シリアル通信のターミナルソフト

[Teraterm](https://forest.watch.impress.co.jp/library/software/utf8teraterm/)を使います。SSH接続以外で使うのは初めてですね:v:

# ESP32側の準備

## Arduino UNOでのシリアル通信用の接続方法を調べる

まずは情報の多いArduinoについて調べました。するとArdunoではUARTで利用できるピンがデフォルトでは決まっているようです。例えばArduino UNOであれば下記のとおり `0` と`1` となります。これはUNOの基盤にも `TX -> 1`  `RX <- 0` とわかりやすく書いてありますね。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144344/a45a9f8f-3823-de86-0191-655dccf1c216.png)

https://www.arduino.cc/reference/en/language/functions/communication/serial/

なお :point_up: ページには大切なことが書かれていましたが横道にそれますので引用欄にて[^important]

[^important]: Arduino(やESP32)へのプログラムの転送時に、RX/TXピンに何らかの線が接続されているとアップロードに失敗する原因となると記載あるので、アップロード時にはピンを外すことを忘れないようにしましょう。

また、上記サイトには書かれていませんが、通常のGPIOピンをUART通信に利用できるソフトウェアシリアルも利用可能なようです。このあたりは下記のサイトが非常に参考になりました。

https://asukiaaa.blogspot.com/2019/03/arduino.html
https://shizenkarasuzon.hatenablog.com/entry/2018/09/10/093648

### 用語をいったんまとめる

- ハードウェアシリアル
    - ハードウェアで持つ機能を用いてシリアル通信する。これらで利用するピンが「デフォルトで決まっているピン
- ソフトウェアシリアル
    - ソフトウェア上でシリアル通信する。基本的にどのピンでも割り当てることが可能

## ESP32への接続について

ESP32用のライブラリを直接見てみると下記のとおり3系統使えることがわかります。これらはハードウェアシリアルとのこと[^esp32-hardware-serial]です。

| 変数名    | RXピン(default) | TXピン(default)   |
|:---------:|:--------------:|:-----------------:|
| Serial    |               3|                  1|
| Serial1   |               9|                 10|
| Serial2   |              16|                 17|

https://github.com/espressif/arduino-esp32/blob/0607d36734d52d67be1b88764bf446fac7eb62f3/cores/esp32/HardwareSerial.cpp#L35-L53

なおGPIOのマッピングは下記のとおりですので、この通り繋いでみます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144344/b6bfe892-b036-f5f7-3134-57fb2108dd7e.png)

https://github.com/espressif/arduino-esp32

[^esp32-hardware-serial]: "The ESP32 chip has three UART controllers (UART0, UART1, and UART2) that feature an identical set of registers for ease of programming and flexibility." https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/uart.html

# ハードウェアシリアルを試す

## `UART0` で接続

動作確認用にLEDを入れているので下記のような感じになりました。

![185DF9DF-2E20-46C8-9EDB-CB5BB4D2EA91.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144344/a8f206ea-8837-b421-61a3-b7b9cf54af1b.jpeg)


```C:UART0を利用する
int LED = 18;
int count = 0;

void setup() {
  pinMode(LED, OUTPUT);

  Serial.begin(115200);
}

void twinkle(){
  if ((count % 2) == 1) {
    digitalWrite(LED, HIGH);
  } else {
    digitalWrite(LED, LOW);
  }
}

void loop() {
  Serial.print("count = ");
  Serial.println(count);
  twinkle();
  delay(1000);

  count++;
}
```

特に問題なく動きました。ArduinoIDEのシリアルモニタでも見れていますね！（COM3はESP32とUSB接続しているポートです）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144344/e78685c4-20ec-ffc7-d986-3223b6df4314.png)


## `UART1` で接続

ちょっと事前に調べてみると、何やらUART1はそのままでは利用できないような記述がたくさん。下記サイトに解決方法が記載ありました。

https://qiita.com/T-YOSH/items/0ce41136c535c723affb

どうやら、GPIOのうち使えないピンがあるみたいですね。下記に詳細が記載ありました。

https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/gpio.html

参考にした[サイト](https://qiita.com/T-YOSH/items/0ce41136c535c723affb)をもとにちょっと試してみます。

```C:UART1を利用する

int LED = 18;
int count = 0;
int RX_PIN = 22;
int TX_PIN = 23;

void setup() {
  pinMode(LED, OUTPUT);
  Serial1.begin(115200, SERIAL_8N1, RX_PIN, TX_PIN);
}

void twinkle(){
  if ((count % 2) == 1) {
    digitalWrite(LED, HIGH);
  } else {
    digitalWrite(LED, LOW);
  }
}

void loop() {
  Serial1.print("count = ");
  Serial1.println(count);
  twinkle();
  delay(1000);

  count++;
}
```

うまくいきました！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144344/7e2a25c8-ccfb-ad41-8ff5-3d7949be413c.png)

## `UART2` で接続

うまくいくだろうから割愛。
ただ、UART2はUART0, UART1と異なりシステムから予約されていないので、シリアル通信をするならUART2を使ったほうがよさそうです。

## ソフトウェアシリアルで接続

:rotating_light: 結論を先に。結果、利用できませんでした :rotating_light:


ソフトウェアシリアルは利用できないと参考サイトには記載がありましたが、`UART1` の接続で汎用のGPIOを利用できた時点でソフトウェアシリアルなことをやっているような気がしたので同じ戦略でやってみます。

```C:UART3を作ってみた（注：動きません）
int LED = 18;
int count = 0;
int RX_PIN = 22;
int TX_PIN = 23;

HardwareSerial Serial3(3);

void setup() {
  pinMode(LED, OUTPUT);
  Serial3.begin(115200, SERIAL_8N1, RX_PIN, TX_PIN);
}

void twinkle(){
  if ((count % 2) == 1) {
    digitalWrite(LED, HIGH);
  } else {
    digitalWrite(LED, LOW);
  }
}

void loop() {
  Serial3.print("count = ");
  Serial3.println(count);
  twinkle();
  delay(1000);

  count++;
}
```

結果だめでした:sob:。 `UART1` など用意されているものはUARTコントローラときちんと接続されているのでしょうね。ちなみに下記も試しましたが駄目でした。
includeの位置がおかしいのはご愛嬌ということで。

```C:ソフトウェアシリアルを使ってみた（注：動きません）
int LED = 18;
int count = 0;
int RX_PIN = 22;
int TX_PIN = 23;

#include <SoftwareSerial.h>
SoftwareSerial mySerial(RX_PIN, TX_PIN);

void setup() {
  pinMode(LED, OUTPUT);
  mySerial.begin(115200, SERIAL_8N1, RX_PIN, TX_PIN);
}

void twinkle(){
  if ((count % 2) == 1) {
    digitalWrite(LED, HIGH);
  } else {
    digitalWrite(LED, LOW);
  }
}

void loop() {
  mySerial.print("count = ");
  mySerial.println(count);
  twinkle();
  delay(1000);

  count++;
}
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/144344/6ad084e3-feb5-0762-bd47-9da1aed7a183.png)

下記フォルダに `SoftwareSerial.h` もないので別途どなたか作ってらっしゃるライブラリを使うしかなさそうです。
https://github.com/espressif/arduino-esp32/tree/master/cores/esp32

確認していませんが、下記とか使えそうな気がします（無責任）

https://github.com/akshaybaweja/SoftwareSerial

# 今回のはまりどころ

- UART接続時の各端末はクロスで接続すること（当たり前だわな…）
    - USBSBとESP32を接続する場合
        - USBのTXをESP32のRX(に割り当てたピン)へ
        - USBのRXをESP32のTX(に割り当てたピン)へ

- ESP32について
    - Bootボタン長押しでアップロードする（すっかり忘れてた）
    - リセットボタン（EN）を押さないと新しいプログラムが反映されない
        - USB接続後の初回起動時だけはENボタンを押さずに反映されたので気づくのに時間がかかった…

# 感想

- 何も考えずに接続して動かす前にきちんとマニュアルを読もう
- シリアルモニターが使えるようになったのでデバッグが楽になった！
- シリアル通信できることでできることが格段と広がるので次が楽しみ！