ESP32 UARTでselectする

ESP32 UARTでselectする

今回はUARTのサンプル select を動かしてみます。

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

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

PC:
Windows10 OS

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

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

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

概要

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

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

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

今回は Tera Term で COM n2 の通信ポートを使って ESP32 とつないで select プログラムを動かしてみます。

PCから送信したものを ESP32で受け取るという簡単なものです。

selectはsocket通信で使われている手段のようですが、UART通信でも扱うことができます。

socketとUARTを併用して扱うことができるようなので、複数の受信を待つ場合に効果を発揮することができます。

お勉強がてら、ここではUARTひとつのselectサンプルを動かしてみます。

プロジェクトをつくる

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

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

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

Name : ESP32E-UART-select
Board : Espressif ESP32 Dev Module
Framework : Espressif IoT Development Framework

Name : ESP32E の “E” は Framework (Espressif IoT Development Framework)の頭文字を示しています。

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

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

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

debug_tool = minimodule
upload_port = COM[4]
monitor_speed = 115200

UARTのAPIリファレンスとサンプル

UARTのAPIは こちら を参照してください。

サンプルプログラムは こちら を参考にしました。

PlatformIOで Eresspsif IoT Development Framework を選択したことにより、以下のローカルフォルダからも参照可能なはずです。

C:\Users\xxxxx\.platformio\packages\framework-espidf\examples\peripherals\uart\uart_select

以下にselectで複数の受信を待つサンプルがありますので、こちらもぜひ試してみてください。
UARTとsocketで複数を受信するサンプルです。

C:\Users\xxxxx\.platformio\packages\framework-espidf\examples\system\select

(xxxxxは皆さまのユーザー名)

コーディングする

main.c を以下のようにコーディングしてビルドしておきます。
//以降にコメント文をつけてみました。

UARTのAPIについては こちら をご覧ください。

#include <stdio.h>
#include <sys/fcntl.h>
#include <sys/errno.h>
#include <sys/unistd.h>
#include <sys/select.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_vfs.h"
#include "esp_vfs_dev.h"
#include "driver/uart.h"

#include "soc\uart_reg.h"

static const char* TAG = "uart_select_example";

// (1)select()を使うスレッド
static void uart_select_task(void *arg)
{
    // (2)UART設定用の構造体
    uart_config_t uart_config = {
        .baud_rate = 115200,
        .data_bits = UART_DATA_8_BITS,
        .parity    = UART_PARITY_EVEN,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
        .source_clk = UART_SCLK_APB,
    };
    // (3)ドライバーのインストール
    uart_driver_install(UART_NUM_1, 2*1024, 0, 0, NULL, 0); // NUM_1 でテストする

    // (4)パラメーターの設定
    uart_param_config(UART_NUM_1, &uart_config);

    // (5)UART1として使うピンの指定
    uart_set_pin(UART_NUM_1, 23, 22, -1, -1);   // NUM_1 を FT2232DのUSB-シリアルで使う

    while (true) {

        // (6)ファイルディスクプリタの宣言
        int fd;

        // (7)ファイルディスクプリタのオープン
        if ((fd = open("/dev/uart/1", O_RDWR)) == -1) { // 今回のテスト用: uart/0 -> uart/1 に変更
            ESP_LOGE(TAG, "Cannot open UART");
            vTaskDelay(5000 / portTICK_PERIOD_MS);
            continue;
        }

        // (8)UART1を指定してVFSをセットする
        esp_vfs_dev_uart_use_driver(1); // UART1を使うので 0->1に変更

        while (true) {

            // (9)select()の戻り値
            int s;
            // (10)select()を使うためのFD構造体
            fd_set rfds;

            // (11)select()に指定するタイムアウト値 (5秒)
            struct timeval tv = {
                .tv_sec = 10,
                .tv_usec = 0,
            };

            // (12)構造体の初期化
            FD_ZERO(&rfds);

            // (13)FDの集合に追加
            FD_SET(fd, &rfds);

            // (14)select()で待機する
            s = select(fd + 1, &rfds, NULL, NULL, &tv);

            // s < 0  : 異常
            // s == 0 : タイムアウト
            // else   : 受信した場合 等 
            if (s < 0) {
                ESP_LOGE(TAG, "Select failed: errno %d", errno);
                break;
            } else if (s == 0) {
                ESP_LOGI(TAG, "Timeout has been reached and nothing has been received 1");
            } else {

                // (15)FDの集合に fd が存在するかチェックする
                if (FD_ISSET(fd, &rfds)) {
                    char buf;
                    if (read(fd, &buf, 1) > 0) {
                        ESP_LOGI(TAG, "Received: %c", buf); // (16)受信データあり
                    } else {
                        ESP_LOGE(TAG, "UART read error");
                        break;
                    }
                } else {
                    ESP_LOGE(TAG, "No FD has been set in select()");
                    break;
                }
            }
        }

        // (17)FDを閉じる
        close(fd);
    }

    // (18)タスクを削除(実際には、ここには来ない)
    vTaskDelete(NULL);
}

void app_main(void)
{
    // (19)スレッドの生成
    xTaskCreate(uart_select_task, "uart_select_task", 4*1024, NULL, 5, NULL);
}

ビルドして実行してみる

ビルドエラーがないことを確認したら F5キーを押してデバッグモードに入ります。

タスクバーが青からオレンジ色にかわったら、もう一度F5キーを押してプログラムを動作させます。

Tera Term を起動して(2)に合わせて通信パラメーターを設定します。

Tera Term から文字を送り、(16)のところに来れば成功です。

UARTカテゴリの最新記事