ESP32をSCPI制御で自動計測する その2 Wi-Fi接続

概要

前回はシリアル通信でしたがWi-Fi経由での接続もかんたんに実現可能でしたのでご紹介します。

スケッチ例

#include <WiFi.h>
#include <WiFiClient.h>

#include "Vrekrer_scpi_parser.h"

const uint16_t tcpport = 5025;
WiFiServer server(tcpport);

SCPI_Parser scpi;

void setup() {
  Serial.begin(115200);
  delay(1000);

  WiFi.begin();
  Serial.print("\n================\nWiFi.begin()");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
  Serial.println("WiFi Connected.");
  Serial.printf("IP Address   : %s\n", WiFi.localIP().toString().c_str());
  Serial.printf("Port         : %d\n", tcpport);
  Serial.printf("SCPI Address : TCPIP::%s::%d::SOCKET\n", WiFi.localIP().toString().c_str(), tcpport);
  server.begin();

  // Internationalized Domain Name
  scpi.RegisterCommand("*IDN?",
                       [](SCPI_C commands, SCPI_P parameters, Stream& interface) {
                         interface.println("ESP32,Arduino SCPI,#00,v0.0.0");
                       });

  // Reset
  scpi.RegisterCommand("*RST",
                       [](SCPI_C commands, SCPI_P parameters, Stream& interface) {
                         ESP.restart();
                       });

  // Digital In
  scpi.RegisterCommand("DIn#?",
                       [](SCPI_C commands, SCPI_P parameters, Stream& interface) {
                         int GpioPin = -1;
                         String command = String(commands.Last());
                         command.toUpperCase();
                         sscanf(command.c_str(), "%*[DIN]%u?", &GpioPin);

                         if (digitalRead(GpioPin)) {
                           interface.println("HIGH");
                         } else {
                           interface.println("LOW");
                         }
                       });

  // Analog Set Attenuation
  scpi.RegisterCommand("AAttenuation",
                       [](SCPI_C commands, SCPI_P parameters, Stream& interface) {
                         uint8_t value = String(parameters.First()).toInt();
                         analogSetAttenuation((adc_attenuation_t)value);
                       });

  // Analog In(mV)
  scpi.RegisterCommand("AVIn#?",
                       [](SCPI_C commands, SCPI_P parameters, Stream& interface) {
                         int GpioPin = -1;
                         String command = String(commands.Last());
                         command.toUpperCase();
                         sscanf(command.c_str(), "%*[AVIN]%u?", &GpioPin);
                         interface.println(analogReadMilliVolts(GpioPin));
                       });

  // Analog In(RAW)
  scpi.RegisterCommand("ARIn#?",
                       [](SCPI_C commands, SCPI_P parameters, Stream& interface) {
                         int GpioPin = -1;
                         String command = String(commands.Last());
                         command.toUpperCase();
                         sscanf(command.c_str(), "%*[ARIN]%u?", &GpioPin);
                         interface.println(analogRead(GpioPin));
                       });

  // Digital Out
  scpi.RegisterCommand("DOut#",
                       [](SCPI_C commands, SCPI_P parameters, Stream& interface) {
                         int GpioPin = -1;
                         String command = String(commands.Last());
                         command.toUpperCase();
                         sscanf(command.c_str(), "%*[DOUT]%u", &GpioPin);

                         String value = String(parameters.First());
                         value.toUpperCase();
                         if ((value == "HIGH") || (value == "ON") || (value == "1")) {
                           digitalWrite(GpioPin, HIGH);
                           Serial.printf(">digitalWrite(%d, HIGH)\n", GpioPin);
                         } else if ((value == "LOW") || (value == "OFF") || (value == "0")) {
                           digitalWrite(GpioPin, LOW);
                           Serial.printf(">digitalWrite(%d, LOW)\n", GpioPin);
                         }
                       });
}

void loop() {
  WiFiClient client = server.available();
  if (client) {
    Serial.println("New Client.");
    while (client.connected()) {
      scpi.ProcessInput(client, "\n");
      delay(1);
    }
    client.stop();
    Serial.println("client.stop()");
  }

  scpi.ProcessInput(Serial, "\n");
  delay(1);
}

上記のコードとなります。根本部分は一緒で、Wi-Fi接続が増えているだけになります。

#include <WiFi.h>
#include <WiFiClient.h>

const uint16_t tcpport = 5025;
WiFiServer server(tcpport);

Wi-Fi接続の準備です。SCPIだと5025でTCP/IP待ち受けが多いです。

  WiFi.begin();
  Serial.print("\n================\nWiFi.begin()");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
  Serial.println("WiFi Connected.");
  Serial.printf("IP Address   : %s\n", WiFi.localIP().toString().c_str());
  Serial.printf("Port         : %d\n", tcpport);
  Serial.printf("SCPI Address : TCPIP::%s::%d::SOCKET\n", WiFi.localIP().toString().c_str(), tcpport);
  server.begin();

Wi-Fiに接続します。

上記などを参考にして事前に接続してWiFi.begin()で最後に接続したSSIDに接続するか、WiFiMultiなどで複数のSSIDを設定しておいてください。

  WiFiClient client = server.available();
  if (client) {
    Serial.println("New Client.");
    while (client.connected()) {
      scpi.ProcessInput(client, "\n");
      delay(1);
    }
    client.stop();
    Serial.println("client.stop()");
  }

上記で接続があるかを確認して、接続がある場合には無限ループでTCP/IPを処理します。ProcessInputはStreamクラスを引数として要求するのでシリアルもTCP/IPも同じように処理可能です。

  scpi.ProcessInput(Serial, "\n");
  delay(1);

シリアルの方も同時に処理をしています。基本的にはTCP/IP接続中はシリアルの処理をしないので、同時接続をしない前提のコードとなります。

Python側コード

import time
import pyvisa

rm = pyvisa.ResourceManager("@py")
inst = rm.open_resource(
    "TCPIP::192.168.1.2::5025::SOCKET", read_termination="\n", write_termination="\n"
)

print(inst.query("*IDN?"))

ほぼ変わりません。接続先が”TCPIP::192.168.1.2::5025::SOCKET”の形式になっていますので、IPアドレスをESP32のものに変更すれば接続可能です。SCPIプロトコルを使うと通信の種類を意識しなくて制御が可能になります。

まとめ

非常に便利なTCP/IPですが、Wi-Fi接続をするのでADC2に接続されたアナログ入力が使えなくなります。そしてESP32の場合使いやすいPINはADC2に接続されている場合が多いので注意しましょう。

アナログ入力を使う場合にはちょと注意が必要ですが、I2CやSPI、UARTなどのセンサーなどから情報を収集して、無線系のTCP/IPで制御可能なのは便利だと思います。

コメント