ESP32 UART コールバックで受信する(Arduino)

ESP32 UART コールバックで受信する(Arduino)

今回はArduinoでUARTの受信割り込みを使ってみます。

この記事は JTAG でデバッグすることを前提にして書いています。
環境構築については こちら をご覧になってください。

投稿時の開発環境を記しておきます。

PC:
Windows10 OS

開発ボード :
ESP32-DevKitCーVE
(Soc : ESP32-D0WD-V3)

デバッガー(H/W):
FT2232D

デバッガー (S/W) :
Visual Studio Code + PlatformIO + Arduino Framework

概要

ブロック図を載せておきます。

デバッガー FT2232D は USBシリアルポートを2つ持っていて、JTAGデバッッグの他にシリアル通信を行うことができます。

これによりMonitorとは別に、PCとESP32間でUARTの通信を行うことができます。

今回は Tera Term で USBシリアルのCOMポートを使って ESP32 と通信してみます。

PCから送信したものを ESP32で受け取って、それをそのまま返信するという簡単なものです。

プロジェクトをつくる

VSCodeで、もし使っていたプロジェクトを開いていたら、File – Close Folder して閉じておきます。

その後にVSCodeからPlatformIOをOpenします。

以下の内容でプロジェクトを新規に作成します。

Name : ESP32A-uartReceiver
Board : Espressif ESP32 Dev Module
Framework : Arduino Framework

Name : ESP32A の “A” は Framework (Arduino Framework)の頭文字を示しています。

(後から見てわかるように、Arduinoを使うことを明示しています)

platformio.ini に以下の4行を追加して、 Ctrl + s で保存しておきます。

COM[8]の8の部分はデバイスマネージャーのポート(COMとLPT)で Silicon Labs CP210x から始まるCOMの番号を記述します。

upload_port はプログラムをアップロードする時に使うCOMポートを指定します。
monitor_port は printf()出力をモニターするCOMポートを指定します。

debug_tool = minimodule
upload_port = COM[8]
monitor_port = COM[8]
monitor_speed = 115200

UARTのクラス

ArduinoではC++のクラスが使われています。
UARTは HartwareSerialというクラスを使うことで比較的容易にコーディングができるようになっています。
C言語で書かれたESP-IDFの細かい処理をC++のクラスでラップしているイメージです。

platformIOで一度Arduinoフレームワークのプロジェクトを作成すると、以下のフォルダがつくられます。

C:\Users\xxxxx\.platformio\packages\framework-arduinoespressif32\

xxxxx は皆さまのユーザー名です。

更に以下のフォルダに HardwareSerial.cpp , HardwareSerial.h のファイルがあるので中を見ておくと良いでしょう。

C:\Users\xxxxx\.platformio\packages\framework-arduinoespressif32\cores\esp32

良くお目にかかる、begin() や available() などの関数はこちらで定義されていることがわかります。

良く見るコード

このループに処理が来ればバッファにあるだけのデータを読み出すことができますが、他が忙しくてここのループにたどり着けない場合には受信データを取りこぼしてしまう可能性があります。

while (Serial.available()) {
  int c = Serial.read();
// 以降 省略
}

受信バッファのサイズを増やす

バッファはリングになっています。
ガンガン受信して読み出す前に一周してしまうと上書きされますから、サイズを増やすのもひとつの手段です。
HardwareSerialクラスでは初期値が 256 のようです。(クラスのコンストラクタをご確認ください)

例えば以下の例ではバッファのサイズを 2048 に設定します。
ここに指定するサイズは 128 以上にする必要があります。
それから begin() する前に設定する必要があります。

void setup() {
  Serial1.setRxBufferSize(2048);  // begin()より前
  Serial1.begin(19200, SERIAL_7E1, 22, 23);
}

仕様によってはバッファサイズを増やすことも検討してみてください。

コールバック関数を使う

とりこぼしを起きにくくするにはコールバックを使うのがお薦めです。
HardwareSerialクラスのソースを覗いてみたところ、コールバックを使う方法が見つかりました。
HardwareSerial::onReceive()を使ってコールバック関数を登録します。

onReceive()で受信処理用コールバック関数を登録すると、データを正常に受信した時に優先度の高いタスクからコールバック関数が呼ばれるしくみになっています。

コーディングする

main.cppを以下のようにコーディングします。

#include <Arduino.h>

void onReceiveData() {
  while (Serial1.available()) {
    Serial1.write(Serial1.read());
  }
}

void setup() {
  Serial1.onReceive(&onReceiveData);  // begin()より前
  // begin(bps, config, rx_pin, tx_pin, ...)
  Serial1.begin(19200, SERIAL_7E1, 22, 23);
}

void loop() {}

ビルドして実行する

まず通信相手のパソコン側の設定を行います。

Tera Term を起動して USBシリアルのCOMポートを選択し、設定 – シリアルポートで以下の通信パラメーターを設定します。

それから設定 – 端末でローカルエコーのチェックを入れておきます。

ビルドしてエラーがないことを確認して、メニューから Run – Start Debugging (またはF5キー)すると少ししてから

loopTaskWDTEnabled = false; の行で停止します。

もう一度 F5キーを押すとプログラムを実行します。

Tera Term からキーを入力してエコーバックしてくれば成功です。
(押したキーが2文字ずつ表示されます)

いかがでしたか?
UARTの受信にはぜひコールバックをお試しください。

UARTカテゴリの最新記事