Raspberry Pi Pico Wを試してみました【Arduino使用】

Raspberry Pi/電子工作
スポンサーリンク

こんにちは、あろっちです。

Raspberry Pi Pico Wを入手したのでArduinoで試してみたいと思います。

参考URL:

Just a moment...

デバッガー使用方法は次の記事を参考にしてください。

Arduino IDE以外の開発環境についての記事はこちら

特徴

無線通信モジュールを搭載したRaspberry Pi Picoです。

  • Raspberry Pi Pico互換ボード
  • 無線通信モジュール Infineon CYW43439搭載
  • Wi-Fi
    IEEE802.11n (Wi-Fi 4、2.4GHz)
    WPA3 (※1)
    SoftAP(最大4クライアント接続可)、Station、SoftAP+Stationモード(※2)をサポート
  • 工事設計認証番号: 008-220422

※1 WPA3は通信を暗号化するためのセキュリティプロトコルです。

※2 SoftAP、Stationモードについて

SoftAP(ソフトウェアアクセスポイント)
→サーバー(ルーター)として振る舞うモードです。
平たく言うと単独でWi-Fiを動作させることができるモードです。
最大4台までクライアントを接続できます。

Station
→クライアントとして動作するモードです。
平たく言うと、他のWi-Fi(自宅のルーターなど)に接続して動作するモードです。

MCURP2040 デュアルコア ARM Cortex M0+プロセッサ、最大動作周波数 133 MHz
フラッシュ
メモリ
2MB
GPIO26(ピン配列はRaspberry Pi Pico互換)

RP2040搭載ボードまとめ記事(参考サイト)

ピン配列

ギャラリー

技適マークは梱包材に貼られています。そのため保管しておく必要があります。

ピンのシルク印字が確認できます

ピンヘッダー実装後

USBマスストレージモード

以下の記事を参考にしてください。

Arduino IDEの設定

  • Arduino IDEにボードを追加
    ※実施済みの場合、この手順は不要です。

事前にRaspberry Pi Pico/RP2040ボード(Arduino-Pico)を追加します。
追加方法は、以下の記事をご覧ください。

  • Raspberry Pi Pico/RP2040ボード(Arduino-Pico)のインストール

[ツール] > [ボード] > [ボードマネージャ]をクリックし、検索ボックスに「rp2040」と入力し、[Raspberry Pi Pico/RP2040]ボードをインストールします。

  • ボードの選択

[ツール] > [ボード] > [Raspberry Pi RP2040 Boards(Ver)※] > [Raspberry Pi Pico W]を選択します。

※Boards(Ver)の表示はArduino IDE 1系のみ

  • シリアルポートの選択

[ツール] > [シリアルポート]からRaspberry Pi Pico Wが接続されているシリアルポートを選択します。

Chromebookなどシリアルポートから書き込みできない環境の場合、手動でスケッチを書き込みできます。

サンプルプログラム(Arduinoスケッチ)

スケッチ例

Arduino IDEのスケッチ例をいくつか試してみます。

SPI接続のLCDに関しましてLovyanGFX定義例の記事を書きました。

Blink

ファイル > スケッチ例 > 01.Basics > Blinkを開きRaspberry Pi Pico Wに書き込みます。

1秒周期でLEDが点滅します

HelloServer

ファイル > スケッチ例 > WebServer > HelloServer

以下の箇所(your-ssid、your-password)を接続先Wi-FiのSSIDとパスワードに書き換えてスケッチを書き込みます。

#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK "your-password"
#endif

シリアルモニターを開くとHelloServerのIPアドレスが確認できます。
※確認できない場合はRaspberry Pi Pico Wを再起動してください。

接続してみる

ブラウザからIPアドレスを入力します。

http://IPアドレス

http://IPアドレス/inline

http://IPアドレス/適当な文字列

以下は文字列の指定例: http://IPアドレス/test?p=aloseed

HelloServer AP(アクセスポイント)版

AP(アクセスポイント)の例としてスケッチ例のHelloServerを改修してアクセスポイント版を作成しました。

接続先Wi-Fi不要で単独で動きます。

以下のWi-Fi(SSID)にスマホなどから接続してください。

ネットワーク名 (SSID)PicoW
パスワード0123456789
IPアドレスおよびデフォルトゲートウェイ192.168.40.1
サブネットマスク255.255.255.0

接続後、ブラウザから「http://192.168.40.1/」にアクセスするとHelloServerの画面が表示されます。

こちらのWi-Fiお試し後はWi-Fi切断を必ず実施してください。
自動接続するようになってしまった場合は自動接続設定の解除もしくはWi-Fi情報自体を削除してください。

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

#ifndef STASSID
#define STASSID "PicoW"
#define STAPSK "0123456789"
#endif

const char* ssid = STASSID;
const char* password = STAPSK;

const IPAddress ip(192, 168, 40, 1);
const IPAddress subnet(255, 255, 255, 0);

WebServer server(80);

const int led = LED_BUILTIN;

void handleRoot() {
  digitalWrite(led, 1);
  server.send(200, "text/plain", "hello from pico w!\r\n");
  digitalWrite(led, 0);
}

void handleNotFound() {
  digitalWrite(led, 1);
  String message = "File Not Found\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i = 0; i < server.args(); i++) {
    message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
  digitalWrite(led, 0);
}

void setup(void) {
  pinMode(led, OUTPUT);
  digitalWrite(led, 0);
  Serial.begin(115200);

  WiFi.mode(WIFI_AP);
  WiFi.softAPConfig(ip, ip, subnet);
  WiFi.begin(ssid, password);

  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  if (MDNS.begin("picow")) {
    Serial.println("MDNS responder started");
  }

  server.on("/", handleRoot);

  server.on("/inline", []() {
    server.send(200, "text/plain", "this works as well");
  });

  server.on("/gif", []() {
    static const uint8_t gif[] = {
      0x47, 0x49, 0x46, 0x38, 0x37, 0x61, 0x10, 0x00, 0x10, 0x00, 0x80, 0x01,
      0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x2c, 0x00, 0x00, 0x00, 0x00,
      0x10, 0x00, 0x10, 0x00, 0x00, 0x02, 0x19, 0x8c, 0x8f, 0xa9, 0xcb, 0x9d,
      0x00, 0x5f, 0x74, 0xb4, 0x56, 0xb0, 0xb0, 0xd2, 0xf2, 0x35, 0x1e, 0x4c,
      0x0c, 0x24, 0x5a, 0xe6, 0x89, 0xa6, 0x4d, 0x01, 0x00, 0x3b
    };
    char gif_colored[sizeof(gif)];
    memcpy_P(gif_colored, gif, sizeof(gif));
    // Set the background to a random set of colors
    gif_colored[16] = millis() % 256;
    gif_colored[17] = millis() % 256;
    gif_colored[18] = millis() % 256;
    server.send(200, "image/gif", gif_colored, sizeof(gif_colored));
  });

  server.onNotFound(handleNotFound);

  /////////////////////////////////////////////////////////
  // Hook examples

  server.addHook([](const String & method, const String & url, WiFiClient * client, WebServer::ContentTypeFunction contentType) {
    (void)method;       // GET, PUT, ...
    (void)url;          // example: /root/myfile.html
    (void)client;       // the webserver tcp client connection
    (void)contentType;  // contentType(".html") => "text/html"
    Serial.printf("A useless web hook has passed\n");
    return WebServer::CLIENT_REQUEST_CAN_CONTINUE;
  });

  server.addHook([](const String&, const String & url, WiFiClient*, WebServer::ContentTypeFunction) {
    if (url.startsWith("/fail")) {
      Serial.printf("An always failing web hook has been triggered\n");
      return WebServer::CLIENT_MUST_STOP;
    }
    return WebServer::CLIENT_REQUEST_CAN_CONTINUE;
  });

  server.addHook([](const String&, const String & url, WiFiClient * client, WebServer::ContentTypeFunction) {
    if (url.startsWith("/dump")) {
      Serial.printf("The dumper web hook is on the run\n");

      // Here the request is not interpreted, so we cannot for sure
      // swallow the exact amount matching the full request+content,
      // hence the tcp connection cannot be handled anymore by the
      auto last = millis();
      while ((millis() - last) < 500) {
        char buf[32];
        size_t len = client->read((uint8_t*)buf, sizeof(buf));
        if (len > 0) {
          Serial.printf("(<%d> chars)", (int)len);
          Serial.write(buf, len);
          last = millis();
        }
      }
      // Two choices: return MUST STOP and webserver will close it
      //                       (we already have the example with '/fail' hook)
      // or                  IS GIVEN and webserver will forget it
      // trying with IS GIVEN and storing it on a dumb WiFiClient.
      // check the client connection: it should not immediately be closed
      // (make another '/dump' one to close the first)
      Serial.printf("\nTelling server to forget this connection\n");
      static WiFiClient forgetme = *client;  // stop previous one if present and transfer client refcounter
      return WebServer::CLIENT_IS_GIVEN;
    }
    return WebServer::CLIENT_REQUEST_CAN_CONTINUE;
  });

  // Hook examples
  /////////////////////////////////////////////////////////

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

void loop(void) {
  server.handleClient();
  MDNS.update();
}

OLEDクロック

OLED(I2C)を使った時計です。
Raspberry Pi Pico Wということで、Wi-Fiを通してNTPで時刻合わせを行うように実装してみました。

こちらの動画では自作のボードを使っていますが、以下の動画のようにブレッドボードで製作できます。

透過OLEDも使えました。

このOLED割とくっきり映るので見栄えがよい気がします

スケッチ

使用しているライブラリについて
  • U8g2

Arduino IDEのライブラリマネージャーから検索してインストールできます。

Arduino IDE 2.0.4のライブラリマネージャー画面
#include <WiFi.h>
#include <Wire.h>
#include <U8g2lib.h>

// WiFi接続情報
const char *ssid = "your-ssid";
const char *password = "your-password";

// 曜日表示文字
const char *weekChar[7] = { "日", "月", "火", "水", "木", "金", "土" };

// U8g2コンストラクタ
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/U8X8_PIN_NONE);

// NTPによる時刻同期関数
bool setClock() {
  NTP.begin("ntp.nict.jp", "time.google.com");
  return NTP.waitSet();
}

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

  Wire.begin();
  Wire.setClock(400000);

  u8g2.begin();  // OLED初期化
  u8g2.setContrast(1);

  u8g2.clearBuffer();
  u8g2.setFont(u8g2_font_crox1hb_tf);
  u8g2.drawStr(0, 17, "WiFi connecting...");
  u8g2.sendBuffer();

  // WiFi接続
  WiFi.begin(ssid, password);
  if (WiFi.status() != WL_CONNECTED) {
    u8g2.clearBuffer();
    u8g2.drawStr(0, 17, "WiFi Connection failed");
    u8g2.sendBuffer();

    // Serial.println("WiFi Connection failed");

    for (;;)
      yield();
  }

  // NTP時刻同期
  if (setClock()) {
    // 時刻取得失敗時は停止
    u8g2.clearBuffer();
    u8g2.drawStr(0, 17, "Failed to obtain time");
    u8g2.sendBuffer();

    // Serial.println("Failed to obtain time");
    for (;;)
      yield();
  }

  // WiFi切断
  WiFi.disconnect(true);

  // 日本標準時をセット
  setenv("TZ", "JST-9", 1);
  tzset();
}

void loop() {
  static time_t now;
  static struct tm *timeinfo;
  static int lastSec = -1;
  static char buf[20];

  // 現在時を取得
  time(&now);
  timeinfo = localtime(&now);
  
  // 時刻が変わっているか判定
  if (lastSec != timeinfo->tm_sec) {
    lastSec = timeinfo->tm_sec;
    // Serial.print(asctime(timeinfo));

    // 時刻が変わった時に描画する
    u8g2.clearBuffer();
    // 時計用フォントをセット
    u8g2.setFont(u8g2_font_crox5h_tn);
    // 時分秒の描画
    sprintf(buf, "%2d", timeinfo->tm_hour);
    u8g2.drawStr(0, 17, buf);
    sprintf(buf, "%02d", timeinfo->tm_min);
    u8g2.drawStr(45, 17, buf);
    sprintf(buf, "%02d", timeinfo->tm_sec);
    u8g2.drawStr(87, 17, buf);

    // 年月日の描画
    sprintf(buf, "%4d", timeinfo->tm_year + 1900);
    u8g2.drawStr(0, 40, buf);
    sprintf(buf, "%2d", timeinfo->tm_mon + 1);
    u8g2.drawStr(0, 64, buf);
    sprintf(buf, "%2d", timeinfo->tm_mday);
    u8g2.drawStr(48, 64, buf);

    // 曜日()の描画
    u8g2.setFont(u8g2_font_crox4h_tf);
    u8g2.drawStr(96, 60, "(");
    u8g2.drawStr(122, 60, ")");

    // 年月日時分秒の描画
    // 日本語フォントをセット
    u8g2.setFont(u8g2_font_b16_b_t_japanese1);
    u8g2.drawUTF8(28, 15, "時");
    u8g2.drawUTF8(71, 15, "分");
    u8g2.drawUTF8(113, 15, "秒");
    u8g2.drawUTF8(54, 38, "年");
    u8g2.drawUTF8(28, 62, "月");
    u8g2.drawUTF8(76, 62, "日");
    u8g2.drawUTF8(104, 62, weekChar[timeinfo->tm_wday]);

    u8g2.sendBuffer();
  }

  yield();
}

your-ssid、your-passwordを接続先Wi-FiのSSIDとパスワードに書き換えてスケッチを書き込んでください。

OLEDの配線について

OLED(I2C)ピン/GPIO備考
GNDGND
VCC3.3V
SCL5I2C SCL デフォルト
SDA4I2C SDA デフォルト

関連記事

当ブログのマイコン記事です。ぜひご覧ください。

コメント

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