Arduino UNO R4 WiFiによる双方向通信(その1)

Arduino

はじめに

ここでは、Arduino UNO R4 WiFiとPCを無線で接続し、PCからの指令によりUNOが動作し、UNOに接続されているセンサーの情報をPCで取得できるようにする。

マトリクスLEDに文字を表示する

UNOとPCの連携ができることを示す例として、PCのほうから’1’を入力するとUNO上のマトリクスLEDに’A’という文字が表示され、’0’を入力すると表示が消えるようにした。UNO側のプログラムは以下のようになる。

#include <WiFiS3.h>              // UNO R4 WiFi 用
#include "Arduino_LED_Matrix.h"  // 基板上 8x12 LED マトリクス

// ====== AP(アクセスポイント)設定 ======
const char* ssid = "UNO_R4_AP";
const char* pass = "12345678";   // 8文字以上

WiFiServer server(5000);         // PCはポート5000にTCP接続

ArduinoLEDMatrix matrix;

// 'A' の 8x12 ビットマップ(行=8, 列=12)
uint8_t A_bitmap[8][12] = {
  {0,0,0,1,1,1,1,0,0,0,0,0},
  {0,0,1,1,0,0,0,1,1,0,0,0},
  {0,1,1,0,0,0,0,0,1,1,0,0},
  {0,1,1,0,0,0,0,0,1,1,0,0},
  {0,1,1,1,1,1,1,1,1,1,0,0},
  {0,1,1,0,0,0,0,0,1,1,0,0},
  {0,1,1,0,0,0,0,0,1,1,0,0},
  {0,1,1,0,0,0,0,0,1,1,0,0}
};

void setup() {
  Serial.begin(9600);          // (任意)デバッグ用
  matrix.begin();
  matrix.clear();

  // AP起動(PCと直結)
  while (WiFi.beginAP(ssid, pass) != WL_AP_LISTENING) {
    delay(500);
  }
  server.begin();

  // (任意)APのIP は通常 192.168.4.1
  IPAddress ip = WiFi.localIP();
  Serial.print("AP IP: "); Serial.println(ip);
  Serial.println("Ready: connect PC to Wi-Fi \"UNO_R4_AP\" then TCP 192.168.4.1:5000");
}

void loop() {
  WiFiClient client = server.available();
  if (!client) return;

  // クライアント接続を維持して読み取る
  while (client.connected()) {
    while (client.available()) {
      char c = client.read();

      if (c == '1') {
        matrix.renderBitmap(A_bitmap, 8, 12);  // 'A' 表示
        client.println("OK: A shown");
      } else if (c == '0') {
        matrix.clear();                        // 消灯
        client.println("OK: cleared");
      } else {
        // 改行類は無視(WindowsのCR/LF対策)
        if (c != '\r' && c != '\n') {
          client.println("Send '1' to show A, '0' to clear");
        }
      }
    }
    // 小休止
    delay(1);
  }
  client.stop();
}

プログラムが書けたら、UNOに転送する。

WiFiで「UNO_R4_AP」に接続する。パスワードは「12345678」である。

次に、TeraTermなどの通信ターミナルを起動する。IPアドレスは「192.168.4.1」、サービスは「Telnet」、TCPポート#は「5000」にする。

「OK」を入力すると、黒一色の画面が現れる。この画面で「1」を入力すると、画面は以下のようになり、LEDに「A」の文字が表示される。

次に「0」を入力すると、画面は以下のようになり、LEDの表示は消える。

ここまでのまとめ

telnet接続で、PCからの情報をUNOが受け取り、動作を変えることができた。次は、UNOにセンサーを接続し、その情報を受け取り、PCに表示することを考えたい。

明るさを検知する(有線)

センサーとしてCdSセルを用います。センサーには周囲の状況に応じて抵抗値が変化するものがあります。CdSセルは明るさにより抵抗値が変化します。CdSセルは光が当たると内部の抵抗値が小さくなります。

Arduinoでは、センサーの状況を電圧で取り扱います。そのため、以下のような回路を組んで、CdSセルの内部抵抗の変化を電圧値として取り出します。

では、Arduinoを使って電子回路を作成します。回路図は以下のようになります。

実体配線図も示します。

以下のプログラムは、抵抗の両端の電圧をArduinoIDEのシリアルモニタに表示するプログラムです。

int CDS = 0; //抵抗Rの両端の電圧をA0に接続

void setup() {
  Serial.begin(9600); //シリアル接続の初期設定 
}

void loop() {
  int analog_val; //アナログ入力の値(0-1023)
  float input_vol; //アナログ入力の値を電圧に変換した値
  String message = ""; //シリアルモニタに表示する文字列

  analog_val = analogRead(CDS); //アナログ入力の値をanalog_valに代入
  input_vol = float(analog_val) * (5.0 / 1023.0); //analog_valの値を電圧に変換

  if (input_vol > 1.0) {
    message = "Lighted : "; //明るいとき 
  }
  else {
    message = "Dark : "; //暗いとき
  }
  Serial.print(message); //LightedかDark
  Serial.print(input_vol); //電圧値を出力
  Serial.println("V"); //電圧の単位はV

  delay(500); //0.5sec待機
}

実行結果を右に示します。

Arduinoに入力される電圧は、明るいとき約4.3V、暗いとき約0.9Vであることがわかります。

ここまでのまとめ

センサーの値をUSBケーブルを用いてArduinoに転送し、その値をシリアルモニタに表示することができた。次は、これを無線で行えるようにしたい。

Unoにつないだセンサーの値をPCのブラウザ上に表示する

プログラムを以下に示します(ChatGPT5を使用)。

// ==== Uno R4 WiFi: CdSの電圧をWi-Fi直結でPCに送る(HTTP) ====
// 使うライブラリ: WiFiS3(Uno R4 WiFi 標準)

#include <WiFiS3.h>

const char* AP_SSID = "CdS-AP";
const char* AP_PASS = "12345678";  // 8文字以上
WiFiServer server(80);

const int PIN_CDS = A0;
const float VREF = 5.0f; // 5V基準(USB給電時はおおむね5V)

void sendIndexHtml(WiFiClient& client) {
  client.println("HTTP/1.1 200 OK");
  client.println("Content-Type: text/html; charset=UTF-8");
  client.println("Connection: close");
  client.println();
  client.println(R"HTML(
<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>CdS Live Voltage</title>
<style>
  body{font-family:system-ui, sans-serif;margin:20px;}
  h1{font-size:1.2rem;margin:0 0 8px;}
  .val{font-size:2.4rem;font-weight:700;}
  .sub{color:#666}
</style>
</head>
<body>
  <h1>CdS 電圧 (Uno R4 WiFi)</h1>
  <div class="val" id="v">--.- V</div>
  <div class="sub" id="raw">raw: -</div>
  <div class="sub">更新間隔: 0.5s / エンドポイント: <code>/data</code></div>
<script>
async function tick(){
  try{
    const r = await fetch('/data', {cache:'no-store'});
    const j = await r.json();
    document.getElementById('v').textContent = j.voltage.toFixed(3) + ' V';
    document.getElementById('raw').textContent = 'raw: ' + j.raw + ' / 4095';
  }catch(e){
    console.log(e);
  }finally{
    setTimeout(tick, 500);
  }
}
tick();
</script>
</body>
</html>
)HTML");
}

void sendJson(WiFiClient& client, int raw, float voltage) {
  client.println("HTTP/1.1 200 OK");
  client.println("Content-Type: application/json; charset=UTF-8");
  client.println("Cache-Control: no-store");
  client.println("Connection: close");
  client.println();
  client.print("{\"raw\":");
  client.print(raw);
  client.print(",\"voltage\":");
  client.print(voltage, 5);
  client.print(",\"millis\":");
  client.print(millis());
  client.println("}");
}

void notFound(WiFiClient& client){
  client.println("HTTP/1.1 404 Not Found");
  client.println("Content-Type: text/plain; charset=UTF-8");
  client.println("Connection: close");
  client.println();
  client.println("404 Not Found");
}

void setup() {
  Serial.begin(115200);
  while (!Serial) {}

  // ADCを12bit化(0-4095)
  analogReadResolution(12);

  pinMode(PIN_CDS, INPUT);

  // AP起動
  if (WiFi.beginAP(AP_SSID, AP_PASS) != WL_AP_LISTENING) {
    Serial.println("AP起動に失敗。リセットしてください。");
    while (true) delay(1000);
  }
  delay(1000); // 安定待ち
  IPAddress ip = WiFi.localIP(); // 通常 192.168.4.1
  Serial.print("AP SSID: "); Serial.println(AP_SSID);
  Serial.print("PASS   : "); Serial.println(AP_PASS);
  Serial.print("AP IP  : "); Serial.println(ip);

  server.begin();
  Serial.println("HTTP server started.");
}

void loop() {
  WiFiClient client = server.available();
  if (!client) return;

  // 簡易HTTPパーサ(1行だけ見てルーティング)
  String reqLine = client.readStringUntil('\n'); // 例: "GET /data HTTP/1.1"
  // ヘッダ読み捨て
  while (client.connected()) {
    String line = client.readStringUntil('\n');
    if (line == "\r" || line.length() == 0) break;
  }

  // センサ読む
  int raw = analogRead(PIN_CDS);              // 0..4095(12bit)
  float voltage = (raw / 4095.0f) * VREF;     // V

  if (reqLine.startsWith("GET / ") || reqLine.startsWith("GET /HTTP")) {
    sendIndexHtml(client);
  } else if (reqLine.startsWith("GET /data")) {
    sendJson(client, raw, voltage);
  } else {
    notFound(client);
  }

  delay(1);
  client.stop();
}

プログラムが入力出来たら、Unoにダウンロードします。その後、PCでWiFiにつなぎます。SSID「CdS-AP」、PASS「12345678」です。次に、PCのブラウザで「http://192.168.4.1:80」にアクセスすると、以下のような画面が現れます。

ここまでのまとめ

Unoに接続したセンサーの情報をWiFiでPCに送ることができた。次は、PCとUnoの間の双方向通信を行いたい。

コメント

タイトルとURLをコピーしました