RP2040-GEEK ラズパイPicoでSDカードと液晶使うならこれ1台でOK!

RP2040-GEEK アイキャッチ

「Raspberry Pi Pico」に「microSD(TF)カードリーダー」と「TFT液晶ディスプレイ」を搭載した「RP2040-GEEK」の使い方を詳しく紹介します。

SDカードに保存した画像データを利用するプログラムや、アナログ入力やシリアル通信で取得したデータの表示、microSDカードにデータを記録するデータロガーの作成等、SDカードと液晶表示を組み合わせたデバイスの開発はこれ1台で完結できます。
開発環境には「ArduinoIDE」を使用します。
「Raspberry Pi Pico」と基本的な使用方法は同じです。

「Pico」の基本的な使用方法や「ArduinoIDE」を使用した開発環境の準備等は以下のリンクで詳しく紹介しています。

ラズパイPico/Pico2/PicoWのArduinoIDE2のインストール方法や使い方紹介
Raspberry Pi Pico/Pico2/PicoWのC言語での開発環境 ArduinoIDE2のインストールから初期設定、使い方、Lチカで動作確認まで詳しく紹介
スポンサーリンク

1.RP2040-GEEKとは

「RP2040-GEEK」とは、中国の電子部品メーカーで「Raspberry Pi」や「Arduino」に関連した製品を多数展開している「WAVESHARE」製のシングルボードコンピューターです。

コントローラーには「Raspberry Pi Pico」と同じ「RP2040」が使用されており、使用方法も「Pico」と同じように使用することができます。

RP2040-GEEK 外観
RP2040-GEEK 外観
最大の特徴は「1.14 インチ(240×135)のカラー液晶画面」と、「microSD(TF)カードリーダー」が搭載されていることです。
個別に各部品を揃えて配線するよりもコンパクトで安価に実現することができます。

使用できる端子は「Pico」と比べると少ない(計6点)ですが、3つのコネクタが搭載されており、全て入出力端子として使用でき、各種通信(UART、I2C)、アナログ入力にも割り付けて使用できます。

その他、USB(Type-A)搭載で直接パソコンに接続して開発が可能です。
専用のファームウェアを書き込めば「デバッグプローブ」としても使用可能で、コネクタ付配線も付属しています。

USBメモリーのような見た目をしていますが、USBストレージデバイスとしてパソコンに認識させて使用するのは難しいと思います。
(パソコンとはシリアル通信でデータをやり取りします。)

「Paspberry Pi Pico」の使い方や「Pico」をデバッグプローブとして使用する方法は以下のリンクで詳しく紹介しています。

ラズパイPico/PicoWの使い方を3つの開発環境Python、ArduinoIDE、PlatformIOで紹介
Raspberry Pi Pico/Pico Wの使い方を端子配列からPython(MicroPython)とC言語の開発環境、Lチカ方法まで紹介。PythonはTonny、C言語はArduinoIDEとPlatformIOの3種類で詳しく紹介します。
ラズパイPicoでPicoをデバッグ!Picoprobeの製作と使い方
Raspberry Pi PicoをデバッグプローブにしてPicoをデバッグ。Picoprobeの製作方法からArduinoIDEでのデバッグ方法まで詳しく紹介

処理速度が速くなりメモリは倍増した「Pico2」と同じ「RP2350」を搭載した「RP2350-GEEK」も発売されているので用途に応じて選定しましょう。

スポンサーリンク

2.外観、デモ画面

外観や工場出荷時のデモ画面については以下のようになります。

・外観

RP2040-GEEK 外観

梱包状態は上画像のように届きました。
箱は少し潰れて届きましたがいつものことです^^

RP2040-GEEK 外観

中身は上画像のように本体と付属のコネクタ付き配線が入っています。

RP2040-GEEK 外観

各コネクタ付配線は上画像のように接続して使用できます。

RP2040-GEEK 外観

USB Type-Aが搭載されて、直接パソコンに接続して使用できますが、USBメモリーのように直接データを保存するのは難しいと思います。

RP2040-GEEK 外観

側面にはJST製のSHコネクタが3箇所搭載されています。「Raspberry Pi Pico」と同じ機能の「BOOT」ボタンも側面にあります。

RP2040-GEEK 外観

microSD(TF)カードのスロットも搭載されており、microSDカードを使用したプログラムの開発をすぐに行うことができます。

・デモ画面

工場出荷時のデモ画面は以下のような6つの画面が順番に繰り返し表示されます。

RP2040-GEEKデモ画面
RP2040-GEEKデモ画面
RP2040-GEEKデモ画面
RP2040-GEEKデモ画面
RP2040-GEEKデモ画面
RP2040-GEEKデモ画面
デモ画面はシンプルなので、下の方で紹介する「サンプルプログラム」を書き込んで、各機能の動作確認をしてみましょう。
スポンサーリンク

3.基本仕様

「RP2040-GEEK」の基本仕様は「Raspberry Pi Pico」と同じで、以下表のようになります。
使用できる端子は「Pico」より少なく合計6点となります。

項目詳細
コントローラRP2040
クロック最大133MHz
(デュアルコア Arm Contrex M0+プロセッサ)
Flash / SRAM2MB / 264kB
電源電圧(USB)DC5V±10%
USBUSB Type-A
入出力多機能GPIO x 6
通信機能UART x 2 / I2C x 2
SPI x 2(液晶表示器とSDカードリーダーで使用)
アナログ入力ADC(12bitアナログコンバータ) x 2
液晶表示器SPI1
1.14-inch 240×135(ST7789VW)
Pixel 65K color IPS LCD display
TF(microSD)
カードリーダー
SPI0
SDIO interface
寸法W61 x H25 x D9 (mm)

4.端子配列、端子機能

端子配列について、出力端子は全てコネクタになっていて使用できるのは「6ピン」分だけです。
コネクタは3箇所あり「Raspberry Pi Pico」の「BOOTSEL」ボタンと同じ機能の「BOOT」ボタンも側面にあります。

RP2040-GEEK基本仕様、機能

端子機能の詳細は以下表のようになります。

RP2040-GEEK端子機能一覧表

コネクタ経由で使用できる端子「GP2〜5,28,29」は全て「入出力端子」として割り付けて使用することができます。

アナログ入力は「ADC2/3」の2点だけ使用可能で「Raspberry Pi Pico」で自由に使用できなかった「ADC3(GP29)」が自由に使用できます。

各種通信機能も割り付けて使用できますが「UART、I2C」ともに2系統ある通信の使用できるコネクタが決まっているため、上表で番号を確認して割り付けて使用してください。

出力電源については「3.3V」しか出力されていないため、通信で使用するデバイスが「5V」だけでなく「3.3V」でも動作可能なものか確認しておく必要があるため注意しましょう。

5.動作確認に使用した配線図

今回の動作確認に使用した配線図は以下のようになります。
microSDカードの動作確認には別途microSDカードが必要です。(16GBで動作確認済)

RP2040-GEEK動作確認用配線図
サンプルプログラムを使用した動作確認では、何も接続しなくても液晶表示の確認はできます。
「スイッチ」と「LED」「ボリューム」は入出力とアナログ入力の確認に必要です。
microSD(TF)カードの動作確認には「スイッチ」のみ使用します。
LEDは抵抗内蔵のものを使用しています。
抵抗内蔵でないものはLEDに合わせて抵抗を接続してご使用ください。

LEDやボリュームの使い方は以下のリンクで詳しく紹介しています。

ボリューム(可変抵抗器)の使い方、つなぎ方、抵抗値計算等を回路図も使って詳しく解説
ボリュームというと音量調節のイメージですが、明るさや回転数等を調整するのにも使用されます。「抵抗(固定抵抗器)」が固定の抵抗値を持つのに対して「可変抵抗器」は抵抗値を調整することができます。このボリューム(可変抵抗器)について紹介します。
LED(発光ダイオード)の使い方。Lチカでの動作確認方法
LEDが登場するまで光源としては白熱電球が主流でした。白熱電球は電気を熱に変えて光りますがLEDは+と-の電気が結合する時のエネルギーで光り、電気を直接光に変換するため発光効率が非常に良いです。

6.ArduinIDEの初期設定

・インストール、初期設定

開発環境に使用する「ArduinoIDE」のインストール方法は以下のリンク先で詳しく紹介しています。

Arduino IDE 2のインストール方法、初期設定、使い方
バージョンアップして使いやすくなったArduino IDE 2のインストールから使い方まで詳しく紹介、便利な機能やM5Stack、ラズパイPicoでの使用方法も紹介します。

「AruduinoIDE」の使用方法、プログラムの書き込み方法は「Raspberry Pi Pico」と同じで以下のリンク先で詳しく紹介しています。

ラズパイPico/Pico2/PicoWのArduinoIDE2のインストール方法や使い方紹介
Raspberry Pi Pico/Pico2/PicoWのC言語での開発環境 ArduinoIDE2のインストールから初期設定、使い方、Lチカで動作確認まで詳しく紹介

・ボード選択、シリアルポートの選択

「RP2040-GEEK」は「Raspberry Pi Pico」と同じように使用できるため「ボード」の選択は下画像のように「Raspberry Pi Pico」を選択してください。

RP2040-GEEK AruduinoIDEボード設定

シリアルポートの選択は、下画像のようにRP2040の互換ボードとして認識されるようなので、以下のように認識されているポートを選択してください。

RP2040-GEEK AruduinoIDEポート設定
うまく認識されない場合は本体側面の「BOOTボタン」を押しながらパソコンと接続して、認識された[UF2 Board]を選択して書き込んでください。
その後[COM番号]が表示されるため、以降の書き込みはこの[COM番号]を選択してください。

・ライブラリの準備

「RP2040-GEEK」を使用するために最低限必要なライブラリは以下になります。

・Adafruit GFX Library:Adafruitのグラフィックスライブラリ
・Adafruit ST7735 and ST7789 Library:ST7789液晶ディスプレイ制御用
・SD:SDカード操作用
・JPEGDecoder:JPEG画像デコード用(JPEG画像を表示しないなら不要)

「ArduinoIDE」でライブラリをインストールする方法は以下のリンク先で詳しく紹介しています。

Arduino IDE 2のインストール方法、初期設定、使い方
バージョンアップして使いやすくなったArduino IDE 2のインストールから使い方まで詳しく紹介、便利な機能やM5Stack、ラズパイPicoでの使用方法も紹介します。

7.サンプルプログラムで動作確認

動作確認用のサンプルプログラムとして以下の4種類を準備しました。

基本的な使い方の確認用として、できるだけシンプルに作成しています。
ご使用の目的に合わせてアレンジしてご使用ください。

・液晶表示の使い方

サンプルプログラムを実行すると、フォントを指定した文字表示や、座標、色の指定方法、線や図形の表示等、基本的な液晶表示の使い方が確認できます。

以下がサンプルプログラムを実行した画面になります。

RP2040-GEEK液晶画面フォント、図形の表示

色の指定は以下の「Adafruit_ST7789ライブラリ」に登録されている色か、16ビット(565)カラーで指定できます。

// 登録色一覧(16bit指定値)
ST77XX_BLACK    // 黒(0x0000)
ST77XX_WHITE    // 白(0xFFFF)
ST77XX_RED      // 赤(0xF800)
ST77XX_GREEN    // 緑(0x07E0)
ST77XX_BLUE     // 青(0x001F)
ST77XX_CYAN     // 水色(0x07FF)
ST77XX_MAGENTA  // 紫(0xF81F)
ST77XX_YELLOW   // 黄(0xFFE0)
ST77XX_ORANGE   // 橙(0xFC00)
文字はフォント無しでも表示できますが、ドット文字のようになるのでフォントの指定がおすすめです。

フォントは下画像のように「Adafruit_GFX_Library」内の「Fonts」フォルダ内にたくさんあります。
ファイル名がフォント名になるので、いろいろ読み込んで試してみてください。

Adafruit GFX フォント一覧
Windowsの場合は以下の場所にフォントファイルがあります。
[Documents] → [Arduino ]→ [libraries] → [Adafruit_GFX_Library] → [Fonts]

液晶表示のサンプルプログラムは以下になります。
コピペで貼り付けて書き込んでください。コピーは下の黒塗り部右上のアイコンクリックでもできます。

#include <Adafruit_GFX.h>    // Adafruitのグラフィックスライブラリ
#include <Adafruit_ST7789.h> // ST7789液晶ディスプレイ用のライブラリ
#include <SPI.h>             // SPI通信を行うためのライブラリ

#define TFT_CS   9  // TFT液晶のCSピン
#define TFT_DC   8  // TFT液晶のDCピン 
#define TFT_MOSI 11 // TFT液晶のMOSIピン
#define TFT_SCK  10 // TFT液晶のSCKピン
#define TFT_RST  12 // TFT液晶のRSTピン

// Adafruit_GFXのフォント読み込み(必要なものだけ有効にする。他にもたくさんあります)
// #include <Fonts/FreeMono12pt7b.h>
#include <Fonts/FreeSans12pt7b.h>
// #include <Fonts/FreeSerif12pt7b.h>
// #include <Fonts/FreeMonoBold12pt7b.h>
// #include <Fonts/FreeSansBold12pt7b.h>
// #include <Fonts/FreeSerifBold12pt7b.h>
#include <Fonts/FreeSansBold18pt7b.h>

Adafruit_ST7789 tft = Adafruit_ST7789(&SPI1, TFT_CS, TFT_DC, TFT_RST);  // TFT液晶のインスタンス設定

// 初期設定 -----------------------------------------
void setup(void) {
  Serial.begin(9600); // シリアル通信初期化

  // SPI1初期設定(TFT液晶用)
  SPI1.setSCK(TFT_SCK); // TFTのSCK (GP10)
  SPI1.setTX(TFT_MOSI); // TFTのMOSI (GP11)

  // 出力端子初期設定
  pinMode(25, OUTPUT);    // TFTバックライト用端子
  digitalWrite(25, HIGH); // TFTバックライト点灯

  // TFT液晶の初期設定
  tft.init(135, 240);     // TFT初期化(画面サイズ指定)
  tft.fillScreen(0x2102); // 背景の塗りつぶし(16bitカラーで指定)
  tft.setRotation(3);     // 画面回転(0-3)
}

// メイン -----------------------------------------
void loop() {

  // タイトル表示
  tft.setTextSize(1);     // 文字サイズ(1)
  tft.setFont(&FreeSans12pt7b);   // フォント
  tft.setTextColor(ST77XX_GREEN); // 文字色(登録色で指定)

  tft.setCursor(6, 20);   // 表示開始位置左上角(X,Y)
  tft.println("LCD");     // 表示内容
  tft.setCursor(0, 45);   // 表示開始位置左上角(X,Y)
  tft.println("TEST");    // 表示内容

  tft.setTextSize(2);     // 文字サイズ(2)
  tft.setTextColor(ST77XX_ORANGE);  // 文字色
  tft.setCursor(75, 40);  // 表示開始位置左上角(X,Y)
  tft.println("ST7789");  // 表示内容
  
  tft.setTextSize(1);               // 文字サイズ(1)
  tft.setFont(&FreeSansBold18pt7b); // フォント
  tft.setTextColor(0x02DF);         // 文字色(16bitカラーで指定)
  tft.setCursor(5, 83);             // 表示開始位置左上角(X,Y)
  tft.println("RP2040-GEEK");       // 表示内容

  // 図形表示
  tft.drawLine(0, 50, 240, 50, ST77XX_WHITE);  // 線(始点終点指定)
  tft.drawFastVLine(68, 0, 45, ST77XX_CYAN);   // 線(指定座標から垂線)
  tft.drawFastHLine(0, 90, 240, ST77XX_WHITE); // 線(指定座標から平行線)

  tft.drawCircle(16, 113, 16, ST77XX_YELLOW);  // 円
  tft.fillCircle(52, 113, 16, ST77XX_RED);     // 円(塗り潰し)

  tft.drawTriangle(69, 130, 89, 95, 109, 130, ST77XX_BLUE);    // 三角
  tft.fillTriangle(114, 130, 134, 95, 154, 130, ST77XX_CYAN);  // 三角(塗り潰し)

  tft.drawRect(159, 95, 36, 36, ST77XX_GREEN);    // 四角
  tft.fillRect(200, 95, 36, 36, ST77XX_MAGENTA);  // 四角(塗り潰し)

  delay(500); // 遅延時間
}

・入出力端子、アナログ入力の使い方

サンプルプログラムを実行すると、基本的な入出力端子の動作確認とアナログ入力の使用方法を確認できます。入出力端子は全ての端子(GP〜)に割り付けて使用できます。

動作確認用の配線図は下画像のようになります。

RP2040-GEEK動作確認用配線図

以下が実際に動作確認している画像になります。

RP2040-GEEK入出力、ADC動作確認

プログラムを実行すると液晶画面に2つのアナログ入力値と電圧換算値が表示されます。

RP2040-GEEK入出力、ADC動作確認

ボリュームを操作すると各数値が変化するのが確認できます。

RP2040-GEEK入出力、ADC動作確認

スイッチ1(赤)を押すとLED1(赤)が点灯して画面背景色が赤色になります。

RP2040-GEEK入出力、ADC動作確認

スイッチ2(黄)を押すとLED2(黄)が点灯して画面背景色が黄色になります。


入出力、アナログ入力の動作確認をするサンプルプログラムは以下になります。
コピペで貼り付けて書き込んでください。コピーは下の黒塗り部右上のアイコンクリックでもできます。

#include <Adafruit_GFX.h>    // Adafruitのグラフィックスライブラリ
#include <Adafruit_ST7789.h> // ST7789液晶ディスプレイ用のライブラリ
#include <SPI.h>             // SPI通信を行うためのライブラリ

#define TFT_CS   9  // TFT液晶のCSピン
#define TFT_DC   8  // TFT液晶のDCピン 
#define TFT_MOSI 11 // TFT液晶のMOSIピン
#define TFT_SCK  10 // TFT液晶のSCKピン
#define TFT_RST  12 // TFT液晶のRSTピン

// Adafruit_GFXのフォント読み込み
#include <Fonts/FreeSans12pt7b.h>

Adafruit_ST7789 tft = Adafruit_ST7789(&SPI1, TFT_CS, TFT_DC, TFT_RST);  // TFT液晶表示用のインスタンス設定

// 初期設定 -----------------------------------------
void setup(void) {
  Serial.begin(9600); // シリアル通信初期化

  // SPI1初期設定(TFT液晶用)
  SPI1.setSCK(TFT_SCK);   // TFTのSCK (GP10)
  SPI1.setTX(TFT_MOSI);   // TFTのMOSI (GP11)

  // 出力端子初期設定
  pinMode(25, OUTPUT);    // TFTバックライト用端子
  digitalWrite(25, HIGH); // TFTバックライト点灯

  pinMode(2, OUTPUT);   // LED1用端子
  pinMode(3, OUTPUT);   // LED2用端子
  digitalWrite(2, LOW); // LED1消灯
  digitalWrite(3, LOW); // LED2消灯

  // 入力端子初期設定
  pinMode(4, INPUT_PULLUP); // スイッチ1用端子
  pinMode(5, INPUT_PULLUP); // スイッチ2用端子

  // アナログ入力初期設定
  analogReadResolution(12); // 分解能12bit(0〜4095)

  // TFT液晶の初期設定
  tft.init(135, 240);           // TFT初期化(画面サイズ指定)
  tft.fillScreen(ST77XX_BLACK); // 背景の塗りつぶし
  tft.setRotation(3);           // 画面回転
  tft.setFont(&FreeSans12pt7b); // フォント
}

// メイン -----------------------------------------
void loop() {
  // スイッチ状態確認、LED点灯/消灯、画面色変更
  if (digitalRead(4) == false) {  // スイッチ1がONなら
    tft.fillScreen(ST77XX_RED);   // 背景の塗りつぶし
    digitalWrite(2, HIGH);        // LED1点灯
  } else if (digitalRead(5) == false) { // スイッチ2がONなら
    tft.fillScreen(ST77XX_YELLOW);// 背景の塗りつぶし
    digitalWrite(3, HIGH);        // LED2点灯
  } else {  // スイッチが押されてなければ
    tft.fillScreen(ST77XX_BLACK); // 背景の塗りつぶし
    digitalWrite(2, LOW);         // LED1消灯
    digitalWrite(3, LOW);         // LED2消灯
  }
  // アナログ入力処理
  float ad_val1;       //アナログ入力2変換値(0~4095)格納用
  float ad_volt1;      //アナログ入力2電圧(0~3.3V)格納用
  float ad_val2;       //アナログ入力3変換値(0~4095)格納用
  float ad_volt2;      //アナログ入力3電圧(0~3.3V)格納用
  ad_val1 = analogRead(28);           //アナログ入力2変換値(0~4095)取得
  ad_volt1 = (3.3 / 4096) * ad_val1;  //アナログ入力2電圧(0~3.3V)換算
  ad_val2 = analogRead(29);           //アナログ入力3変換値(0~4095)取得
  ad_volt2 = (3.3 / 4096) * ad_val2;  //アナログ入力3電圧(0~3.3V)換算

  // 液晶画面表示
  tft.setCursor(0, 17);             // カーソル位置
  tft.setTextColor(ST77XX_WHITE);   // 文字色
  tft.println("I/O, ANALOG TEST");  // 文字表示
  tft.setTextColor(ST77XX_GREEN);   // 文字色
  tft.printf("Value1 : %.0f\n",ad_val1);      // 文字表示
  tft.printf("Volt1    : %3.2fV\n",ad_volt1);
  tft.setTextColor(ST77XX_ORANGE);            // 文字色
  tft.printf("Value2 : %.0f\n",ad_val2);      // 文字表示
  tft.printf("Volt2    : %3.2fV",ad_volt2);

  delay(300);
}

・microSD(TF)カードの使い方

サンプルプログラムを実行すると、microSD(TF)カードにデータを保存したり、データを読み出して画面に表示させたり、保存したファイルを削除する動作が確認できます。

サンプルプログラムでは、電源ONからの経過時間をボタンを押すごとにmicroSDカードに保存します。保存したデータは読み出しボタンを押すことで読み出して画面に表示できます。
読み出しボタン長押しでデータを保存したファイルを削除できます。

以下が実際に動作確認している画像になります。

RP2040-GEEK SDカードの読み書き動作確認

プログラムを実行すると上画像のような画面が表示されます。

RP2040-GEEK SDカードの読み書き動作確認

スイッチ1を押すごとに上画像のように電源ONしてからの経過時間が表示され、microSDカードにプログラムで指定したファイル名(test.txt)で保存されます。

RP2040-GEEK SDカードの読み書き動作確認

スイッチ2を押すと上画像のように保存されたデータを読み出して液晶画面に表示します。

RP2040-GEEK SDカードの読み書き動作確認

スイッチ2を長押し(2秒以上)するとデータが保存されているファイルが削除されます。

最低限のエラーも下画像のように表示されます。

RP2040-GEEK SDカードの読み書きエラー表示

microSDカードが入っていない時のエラー

RP2040-GEEK SDカードの読み書きエラー表示

ファイルを削除しようとした時にファイルが見つからなかった時のエラー


microSD(TF)カードの読み書きを行うサンプルプログラムは以下になります。
コピペで貼り付けて書き込んでください。コピーは下の黒塗り部右上のアイコンクリックでもできます。

#include <Adafruit_GFX.h>    // Adafruitのグラフィックスライブラリ
#include <Adafruit_ST7789.h> // ST7789液晶ディスプレイ用のライブラリ
#include <SPI.h>             // SPI通信を行うためのライブラリ
#include <SD.h>              // SDカード操作用のライブラリ

#define TFT_CS   9  // TFT液晶のCSピン
#define TFT_DC   8  // TFT液晶のDCピン 
#define TFT_MOSI 11 // TFT液晶のMOSIピン
#define TFT_SCK  10 // TFT液晶のSCKピン
#define TFT_RST  12 // TFT液晶のRSTピン

#define SD_CS   23  // SD(TF)カードリーダのCSピン
#define SD_MISO 20  // SD(TF)カードリーダのMISOピン
#define SD_MOSI 19  // SD(TF)カードリーダのMOSIピン
#define SD_SCK  18  // SD(TF)カードリーダのSCKピン

#include <Fonts/FreeSans12pt7b.h> // Adafruit_GFXのフォント読み込み
#define SWITCH_PRESS_TIME 2000 // スイッチ2長押し時間(ms)
#define SD_FILENAME "/test.txt" // SD(TF)カードに保存するファイル名

Adafruit_ST7789 tft = Adafruit_ST7789(&SPI1, TFT_CS, TFT_DC, TFT_RST);  // TFT液晶表示用のインスタンス設定

// 変数宣言
unsigned long lastPressedTime = 0; // スイッチ2の最後に押された時間保持用
bool swState1 = false; // スイッチ1状態保持用
bool swState2 = false; // スイッチ2状態保持用

// 初期設定 -----------------------------------------
void setup(void) {
  Serial.begin(9600); // シリアル通信初期化

  // SPI0初期設定(SDカード用)
  SPI.setTX(SD_MOSI); // SD(TF)カードリーダのMOSI(GP19)
  SPI.setRX(SD_MISO); // SD(TF)カードリーダのMISO(GP20)
  SPI.setSCK(SD_SCK); // SD(TF)カードリーダのSCK(GP18)

  // SPI1初期設定(TFT液晶用)
  SPI1.setSCK(TFT_SCK);   // TFTのSCK (GP10)
  SPI1.setTX(TFT_MOSI);   // TFTのMOSI (GP11)

  // 出力端子初期設定
  pinMode(25, OUTPUT);    // TFTバックライト用端子
  digitalWrite(25, HIGH); // TFTバックライト点灯
  pinMode(2, OUTPUT);     // LED1用端子
  digitalWrite(2, LOW);   // LED1消灯
  pinMode(3, OUTPUT);     // LED2用端子
  digitalWrite(3, LOW);   // LED2消灯

  // 入力端子初期設定
  pinMode(4, INPUT_PULLUP); // スイッチ1用端子
  pinMode(5, INPUT_PULLUP); // スイッチ2用端子

  // TFT液晶の初期設定
  tft.init(135, 240);           // TFT初期化(画面サイズ指定)
  tft.fillScreen(ST77XX_BLACK); // 背景の塗りつぶし
  tft.setRotation(3);           // 画面回転
  tft.setFont(&FreeSans12pt7b); // フォント
  tft.setCursor(0, 18);         // カーソル位置
  // 初期表示画面
  tft.println("- SD STRAGE TEST -");  // メッセージ表示
  tft.drawFastHLine(0, 22, 240, ST77XX_WHITE); // 線(指定座標から平行線)
  tft.println("SW1(GP4) : SAVE");     // スイッチ1をONでデータ保存
  tft.println("SW2(GP5) : READ");     // スイッチ2をONでデータ読み出し
  tft.println("SW2 Longpress");       // スイッチ2長押しでデータ(ファイル)削除
  tft.println("                    : DELETE");

  // SDカードの初期化
  if (!SD.begin(SD_CS)) {
    Serial.println("SDカードの初期化に失敗しました");
    dispMessage("SD card not found!", ST77XX_RED);  // 液晶画面メッセージ表示関数呼び出し
    return;
  } else {
    Serial.println("SDカードが初期化されました");
  }
}

/*********************** 液晶画面メッセージ表示関数 **********************/
void dispMessage(const char* text, uint16_t collor) {
  tft.fillScreen(collor); // 背景の塗りつぶし
  tft.setCursor(0, 70);   // カーソル位置
  tft.print(text);        // メッセージ表示
}

/************************* CSVデータ書き込み関数 ************************/
void writeSdData(const char* text) {
  // SDカードのファイルを開く
  File myFile = SD.open(SD_FILENAME, FILE_WRITE);
  // データ書き込み
  if (myFile) { // ファイルが開けたら
    myFile.printf("%s : %d\n", text, millis()); // テキストとミリ秒をファイルに書き込み
    myFile.close(); // ファイルを閉じる
  } else { // ファイルが開けなければ
    Serial.println("ファイルを開けませんでした");
    dispMessage("Can't open file!", ST77XX_RED);  // 液晶画面メッセージ表示関数呼び出し
  }
  // 書き込みデータ表示
  tft.fillScreen(ST77XX_BLACK); // 背景の塗りつぶし
  tft.setCursor(0, 70); // カーソル位置
  
  tft.printf("%s : %lums\n", text, millis()); // テキストとミリ秒を画面に表示
  Serial.printf("%s : %lums\n", text, millis());  // シリアル出力
}

/********************* SDカード データ読み込み関数 ********************/
void readSdData(const char* fileName) {
  // SDカードのファイルを開く
  File myFile = SD.open(fileName);

  if (myFile) { // ファイルが開けたら
    tft.fillScreen(ST77XX_BLACK); // 背景の塗りつぶし
    tft.setCursor(0, 18);         // カーソル位置
    // データ読み込み表示
    while (myFile.available()) {  // ファイルにデータがあれば繰り返し
      char data = myFile.read();  // データを1文字づつ読み込む
      tft.print(data);            // TFT出力
      Serial.print(data);         // シリアル出力
    }
    myFile.close(); // ファイルを閉じる
  } else {  // ファイルが開けなければ
    Serial.println("ファイルが読み込めませんでした"); // シリアル出力
    dispMessage("Can't read file!", ST77XX_RED); // 液晶画面メッセージ表示関数呼び出し
  }
}
/********************* SDカード データ削除関数 ********************/
void deleteSdData(const char* fileName) {
  if (SD.exists(fileName)) {  // ファイルが存在すれば
    // ファイルを削除
    if (SD.remove(fileName)) {  // ファイル削除が成功すれば
      Serial.println("ファイルを削除しました");
    } else {  // ファイル削除に失敗したら
      Serial.println("ファイルの削除に失敗しました");
      dispMessage("Delete Failed!", ST77XX_RED);  // 液晶画面メッセージ表示関数呼び出し
    }
  } else {  // ファイルがなければ
    Serial.println("ファイルが見つかりません");
    dispMessage("file not found!", ST77XX_RED);  // 液晶画面メッセージ表示関数呼び出し
  }
}

// メイン -----------------------------------------
void loop() {
  unsigned long nowTime = millis(); // 経過時間を現在時間として取得(ms)
  // SDデータ書き込み処理
  if (digitalRead(4) == false && swState1 == false) {  // スイッチ1がONでスイッチ1状態がfalseなら
    digitalWrite(2, HIGH); // LED1点灯
    writeSdData("Time");   // 文字表示
    swState1 = true;       // スイッチ1状態をtrueへ
  }
  if (digitalRead(4) == true) {  // スイッチ1がOFFなら
    swState1 = false;      // スイッチ1状態をfalseへ
    digitalWrite(2, LOW);  // LED2消灯
    delay(50);             // スイッチOFF待ち(チャタリング防止)
  }
  // SDデータ読み込み処理
  if (digitalRead(5) == false && swState2 == false) {  // スイッチ2がONでスイッチ2状態がfalseなら
    // SDをデータ読み込んで内容を液晶画面に表示
    readSdData(SD_FILENAME);  // ファイル名を指定してSDデータ読み出し関数呼び出し
    digitalWrite(3, HIGH); // LED2点灯
    swState2 = true;       // スイッチ2状態をtrueへ
  }
  // SDデータ削除処理
  if (digitalRead(5) == false) { // スイッチ2がONなら
    if (nowTime - lastPressedTime >= SWITCH_PRESS_TIME) { // スイッチ2が2秒以上長押しなら
      lastPressedTime = nowTime; // 最後に押された時間を更新
      // SDデータ削除
      deleteSdData(SD_FILENAME);    // ファイル名を指定してSDデータ削除関数呼び出し
      dispMessage("Delete file!", ST77XX_BLUE);  // 液晶画面メッセージ表示関数呼び出し
    }
  } else {  // スイッチ2がOFFなら
    swState2 = false;     // スイッチ2状態をfalseへ
    lastPressedTime = nowTime;  // 最後に押された時間を更新
    digitalWrite(3, LOW); // LED2消灯
    delay(50);            // スイッチOFF待ち(チャタリング防止)
  }
}

・JPEG画像データの表示

サンプルプログラムを実行すると、microSD(TF)カードに保存されたJPEG画像を読み込んで、液晶画面に表示します。

microSDカードのJPEG画像データを、ファイル名を指定して読み出し「JPEGDecoder」ライブラリでデコードして、座標と色データとして取得します。
  
「JPEGDecoder」ライブラリでは「16×16ピクセル」ごとに処理されるため、直接描画すると「16×16ピクセル」単位で描画されていきます。
サンプルプログラムでは「bitmap」配列に各データを取得してから、ビットマップ画像として一括表示させています。

以下が実際に動作確認している画像になります。

RP2040-GEEK JPEG画像のデコード表示

プログラムを実行すると、プログラムで指定したファイル名のJPEG画像データの情報が上画像のように表示されます。
※MCUはデコードの処理単位です。

RP2040-GEEK JPEG画像の読み込み表示

しばらくすると、JPEG画像がデコード処理されて、上画像のようにビットマップ画像として一括表示されます。

画像サイズは画面サイズに合わせて240×135に加工しておくと、画面いっぱいに表示されます。

ここで使用するJPEG画像サンプルは以下からダウンロードできます。

ダウンロードした画像はパソコンを使用してmicroSDカードに保存しておきましょう。
※クリックしても画像が保存されない場合は「右クリック」から「名前を付けて画像を保存」を選択して保存してください。
サンプル画像以外の画像データを読み込む場合は、以下のサンプルプログラム「18行目」のファイル名「/GEEK.jpg」を、読み込みたい画像のファイル名に変更してください。

JPEG画像を表示するサンプルプログラムは以下になります。
コピペで貼り付けて書き込んでください。コピーは下の黒塗り部右上のアイコンクリックでもできます。

#include <Adafruit_GFX.h>    // Adafruitのグラフィックスライブラリ
#include <Adafruit_ST7789.h> // ST7789液晶ディスプレイ用のライブラリ
#include <JPEGDecoder.h>     // JPEG画像デコーダー用のライブラリ
#include <SPI.h>             // SPI通信を行うためのライブラリ
#include <SD.h>              // SDカード操作用のライブラリ

#define TFT_CS   9  // TFT液晶のCSピン
#define TFT_DC   8  // TFT液晶のDCピン 
#define TFT_MOSI 11 // TFT液晶のMOSIピン
#define TFT_SCK  10 // TFT液晶のSCKピン
#define TFT_RST  12 // TFT液晶のRSTピン

#define SD_CS   23  // SD(TF)カードリーダのCSピン
#define SD_MISO 20  // SD(TF)カードリーダのMISOピン
#define SD_MOSI 19  // SD(TF)カードリーダのMOSIピン
#define SD_SCK  18  // SD(TF)カードリーダのSCKピン

#define FILENAME "/GEEK.jpg"      // JPEG画像ファイル名
#include <Fonts/FreeSans12pt7b.h> // Adafruit_GFXのフォント読み込み

Adafruit_ST7789 tft = Adafruit_ST7789(&SPI1, TFT_CS, TFT_DC, TFT_RST); // 液晶表示処理のインスタンス初期化
JPEGDecoder jpegDec;  // JPEGデコーダのインスタンス

//********************* JPEGデコード画面表示処理関数 *********************//
void jpegDraw(char* filename) {
  uint16_t *pImg;   // ピクセルデータ用のポインタ
  int x, y, bx, by; // 位置座標格納用

  // JPEGファイルをSDカードからデコード実行
  JpegDec.decodeSdFile(filename);
  uint16_t bitmap[JpegDec.width * JpegDec.height];  // デコード画像サイズを取得してビットマップデータ格納用バッファを準備

  // 液晶表示、デコード画像情報(MCU [Minimum Coded Unit]:JPEG画像データの最小処理単位、ここでは16x16ピクセル)
  tft.printf("Size : %d x %d\nMCU : %d x %d\n", JpegDec.width, JpegDec.height, JpegDec.MCUWidth, JpegDec.MCUHeight);
  delay(3000);  // 液晶画面への画像情報表示時間

  // シリアル出力、その他のデコード画像情報
  Serial.printf("Components: %d\nMCU / row: %d\nMCU / col: %d\nScan type: %d\n\n",
                JpegDec.comps,      // コンポーネント数、16ビットカラーRGB565のため1(24ビットカラーなら3)
                JpegDec.MCUSPerRow, // x方向のMCU数(240 / 16 = 15)
                JpegDec.MCUSPerCol, // y方向のMCUの数(135 / 16 = 8.4375 → 9)
                JpegDec.scanType);  // サンプリングやエンコーディング方式

  // 画像データをピクセル単位で描画
  while (JpegDec.read()) { // JPEGデータを読み込む
    pImg = JpegDec.pImage; // 現在のピクセルデータのポインタを取得

    // MCU高さ分ループ
    for (by = 0; by < JpegDec.MCUHeight; by++) {
      // MCU幅分ループ
      for (bx = 0; bx < JpegDec.MCUWidth; bx++) {

        // 現在のピクセルのx, y座標を計算
        x = JpegDec.MCUx * JpegDec.MCUWidth + bx; // x座標
        y = JpegDec.MCUy * JpegDec.MCUHeight + by; // y座標

        // ピクセルが画像範囲内にあるかチェック
        if (x < JpegDec.width && y < JpegDec.height) {
          // tft.drawPixel(x, y, pImg[0]); // 有効にすると、MCU単位で液晶画面に描画されていく
          bitmap[y * JpegDec.width + x] = pImg[0];  // 座標ごとにピクセルカラーを取得してビットマップ画像生成
        }
        // ポインタを次のピクセルデータへ進める
        pImg += JpegDec.comps; 
      }
    }
  }
  // 描画位置を指定してビットマップを描画
  tft.drawRGBBitmap(0, 0, bitmap, JpegDec.width, JpegDec.height);
}

// 初期設定 -----------------------------------------
void setup(void) {
  Serial.begin(9600); // シリアル通信初期化

  // SPI0初期設定(SDカード用)
  SPI.setTX(SD_MOSI); // SDカードリーダーのMOSI
  SPI.setRX(SD_MISO); // SDカードリーダーのMISO
  SPI.setSCK(SD_SCK); // SDカードリーダーのSCK

  // SPI1初期設定(TFT液晶用)
  SPI1.setSCK(TFT_SCK); // TFTのSCK (GP10)
  SPI1.setTX(TFT_MOSI); // TFTのMOSI (GP11)

  // 出力端子初期設定
  pinMode(25, OUTPUT);    // TFTバックライト用端子
  digitalWrite(25, HIGH); // TFTバックライト点灯

  // TFT液晶の初期設定
  tft.init(135, 240);           // TFT初期化(画面サイズ指定)
  tft.fillScreen(ST77XX_BLACK); // 背景の塗りつぶし
  tft.setRotation(3);           // 画面回転(0-3)
  tft.setTextSize(1);           // 文字サイズ
  tft.setFont(&FreeSans12pt7b); // フォント

  // SDカードの初期化
  if (!SD.begin(SD_CS)) {
    Serial.println("SDカードの初期化に失敗しました");
    return;
  } else {
    Serial.println("SDカードが初期化されました");
  }
  // SDカードからJPEG画像を開く
  File jpegFile = SD.open(FILENAME); // ファイル名を指定して開く

  // ファイルが開けたか確認
  if (!jpegFile) {  // ファイルが開けなければエラー処理
    Serial.println("JPEGファイルを開けませんでした");
    tft.fillScreen(ST77XX_RED); // 背景の塗りつぶし(赤)
    tft.setCursor(40, 70);      // カーソル位置
    tft.print("Can't open file!");      // エラー表示
    return;
  }
  // 開いたJPEG画像のデータ容量を取得
  unsigned long fileSize = jpegFile.size();

  // 処理前のJPEG画像情報表示
  tft.setCursor(0, 30); // カーソル位置
  tft.printf("%s\n%lu bytes\n", FILENAME, fileSize);  // JPEG画像ファイル名とデータ容量表示

  // JPEG画像デコード実行
  jpegDraw(FILENAME); // JPEGデコード画面表示処理関数呼び出し
  jpegFile.close();   // JPEGファイルを閉じる
}

// メイン ---------------------------------------------
void loop() {
    // メインループでは何もしない
}

8.本体の初期化方法

「RP2040-GEEK」の動作がおかしくなったり、手順を最初からやり直したい等で初期状態に戻したい場合もあると思います。

そんな時のために「RP2040-GEEK」本体を初期化する方法も紹介します。
以下のサイトにアクセスして、本体初期化用のファイルをダウンロードします。

表示されたページのに、下画像矢印部のようなリンクがあるので「UF2 file」をクリックします。

ラズパイPicoの初期化方法

クリックすると「flash_nuke.uf2」というファイルがダウンロードされます。

「RP2040-GEEK」本体の「BOOT」ボタンを押しながらパソコンと接続して認識されたフォルダに、このファイルをドラッグ&ドロップするだけで初期化は完了します。

9.まとめ

「RP2040-GEEK」の使い方を詳しく紹介しました。
「RP2040-GEEK」は「Raspberry Pi Pico」と同じコントローラ「RP2040」を搭載しており、「Pico」と同じように使用できます。

「microSD(TF)カードリーダー」と「TFT液晶ディスプレイ」を搭載しているため、これら利用したプログラムなら、個別に用意して配線する必要がなく、安価でコンパクトに実現できます。

使用できる端子は合計6点と限られますが、全て入出力端子として使用でき、アナログ入力やシリアル通信(UART、I2C)も充実しているため、通信で取得したデータを表示して記録するデータロガーに最適なデバイスと思いました。

今回は長くなったのでシリアル通信については触れていませんが、次回はシリアル通信でいろいろなデータを取得して記録するデータロガーの作り方を詳しく紹介したいと思います。

ラズパイPico/PicoWの使い方を3つの開発環境Python、ArduinoIDE、PlatformIOで紹介
Raspberry Pi Pico/Pico Wの使い方を端子配列からPython(MicroPython)とC言語の開発環境、Lチカ方法まで紹介。PythonはTonny、C言語はArduinoIDEとPlatformIOの3種類で詳しく紹介します。
ラズパイPicoでPicoをデバッグ!Picoprobeの製作と使い方
Raspberry Pi PicoをデバッグプローブにしてPicoをデバッグ。Picoprobeの製作方法からArduinoIDEでのデバッグ方法まで詳しく紹介

コメント

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