Raspberry Pi PicoでSDカードを使う方法!CSV保存も【初心者OK!】

  • URLをコピーしました!

皆さんこんにちは。yossyです。

ラズピコを使った工作をしていると、「ファイルにセンサーのデータを保存したい!」「外部のファイルをラズピコで読み込みたい!」のように思うことがありますよね。データの保存や読み込みができれば、保存したデータを分析したり、読み込んだデータからラズピコの動作を制御したりできます。

そこで、この記事では

  • SDカードを使うための準備
  • MicroPythonを使ったファイルの読み書き
  • CSVファイルを使う方法

を解説します。

この記事を読めば、Raspberry Pi PicoでSDカードを使って、便利にファイルを扱えるようになります!

目次

SDカードをRaspberry Pi Picoで使う方法:基本編

それでは早速、Raspberry Pi PicoでSDカードを使う方法を解説します。

必要なもの

Raspberry Pi PicoでSDカードを使うためには、SDカードモジュールを使います。

SDカードモジュールはSPIという通信方式でラズピコと通信します。SPIは4本の通信線を使います。

SDカード本体についてですが、Raspberry Pi Picoで使うSDカードは32GBまでしか対応していません。これはSDカードのフォーマットに関係していて、SDカードをFAT32でフォーマットする必要があるためです。

・SDカードモジュール

・MicroSDカードモジュール

・MicroSDカード(32GB・アダプター付き)

配線

SDカードモジュールとRaspberry Pi Picoを配線します。

SDカードモジュールによって一部の表記が異なるので、いくつかの形式を表にしています。
詳しくは各モジュールの説明書やデータシートを確認してください。(これだけ書いても他の表記があるかもしれないです。)

SPI表記(別名含む)SDカード表記Raspberry Pi Picoのピン説明
MOSI / DI / SDI / CMD / DATA-INCMDGPIO3Pico → SDカードへのデータ出力
MISO / DO / / SDO / DAT0 / DATA-OUTDAT0GPIO4SDカード → Picoへのデータ入力
SCK / SCLK / CLK / CLOCKCLKGPIO2クロック信号
CS / SS / SDCS / Chip SelectCD*/DAT3GPIO5チップセレクト
VCC / 3.3V / 5VVDD3.3Vまたは 5V(VBUS)電源プラス
GNDVSSGND電源マイナス

*CDが単体で出てきている場合は、SDカードの挿入検知ピンになります。

yossy

SPIの表記は複雑です。しっかり確認して作業しましょう!

ライブラリ(sdcard.py)のインストール

Raspberry Pi PicoでSDカードを使うためのライブラリをインストールします。

sdcard.py(https://github.com/micropython/micropython-lib/blob/master/micropython/drivers/storage/sdcard/sdcard.py)にアクセスして、右上のボタンを押して、ライブラリをコピーしましょう。

コピーしたライブラリのコードを、Thonnyで新しいファイルを作成して貼り付け。sdcard.pyという名前でRaspberry Pi Pico本体に保存します。これでライブラリのインストールは完了です。

プログラム(書き込み・読み込み)

ライブラリがインストールできたので、実際にSDカードを使うためのプログラムを書きます。

from machine import Pin, SPI
import sdcard
import os

#SPIの初期化
spi = SPI(0,
          baudrate=1_000_000,
          polarity=0,
          phase=0,
          sck=Pin(2),
          mosi=Pin(3),
          miso=Pin(4))
          
cs = Pin(5, Pin.OUT)

sd = sdcard.SDCard(spi, cs) #SDカードのオブジェクトを作成
os.mount(sd, "/sd") #SDカードをマウント

#SDカードに書き込み
with open("/sd/test.txt", "w") as f:
    f.write("Hello, SDCard!")

#SDカードから読み込み
with open("/sd/test.txt", "r") as f:
    print(f.read())

このプログラムを実行すると、SDカード内にtest.txtが作成されて、シェルに中身が表示されます。PCでSDカードを読み込んでみると、test.txtが作成されているのが確認できます。

プログラムの解説

ここからは、プログラムの解説です。

前半

from machine import Pin, SPI
import sdcard
import os

#SPIの初期化
spi = SPI(0,
          baudrate=1_000_000,
          polarity=0,
          phase=0,
          sck=Pin(2),
          mosi=Pin(3),
          miso=Pin(4))
          
cs = Pin(5, Pin.OUT)

sd = sdcard.SDCard(spi, cs) #SDカードのオブジェクトを作成
os.mount(sd, "/sd") #SDカードをマウント

前半部分を解説します。

まずは、SDカードを使うために必要なモジュール・ライブラリをインポートします。

次に、SPIの初期化を行います。今回はSPI0を使用します。baudrate,polarity,phaseは設定しなくても動作します。デフォルト値が同じ値になっているからですが、書いておくとデバッグするときにわかりやすいかもしれません。csはチップセレクトといい、SPI通信をするために必要なピンの一つです。

sdという名前でSDカードのオブジェクトを作成します。

os.mount(sd, "/sd")は、SDカードを/sdというフォルダにマウント(接続)。これでSDカードを使う準備ができました。

後半

#SDカードに書き込み
with open("/sd/test.txt", "w") as f:
    f.write("Hello, SDCard!")

#SDカードから読み込み
with open("/sd/test.txt", "r") as f:
    print(f.read())

後半の部分を解説します。

まずは書き込み。with open("/sd/test.txt", "w") as f:は、"/sd/test.txt"というファイルをfとして"w"(書き込みモード)で開くという意味です。書き込みモードを指定すると、ファイルが存在しない場合は作成され、存在する場合は上書きされます。

f.write()fに対して書き込みを行います。

読み込みの場合は"r"を指定します。この場合、ファイルが存在すれば開くことができます。ただし、存在しない場合はエラーになるので、try/exceptでエラー処理するか、先にファイルが存在するかを確認してから開くようにしましょう。

読み込みでファイルを開いたら、f.read()とするとファイルの中身を扱うことができます。

withについて

追加で、withについて説明します。

Pythonでのwith open() as f:は、ファイル操作を安全・シンプルに行うための文法です。

基本的な書き方は次の通り。

with open("ファイル名", "モード") as f:
    # ファイルを使った処理
    f.write("こんにちは!")

なぜこれを使うかですが、open()を単体で使うときのコードを見るとわかります。

f = open("test.txt", "w")
f.write("こんにちは")
f.close()  # ← 忘れるとやばい

Pythonではopen()を使ってファイルを開いたあとは、必ずclose()してファイルを閉じる必要があります。もしclose() し忘れると、ファイルが壊れたりするなどのトラブルに繋がります。

ここでwithを使ってファイル操作をすると、内部で

f = open("test.txt", "w")
try:
    # ここに処理を書く
    f.write("こんにちは")
finally:
    f.close()  # ← 失敗してもちゃんと閉じる!

という処理がされ、ファイル操作の成功・失敗に関わらずにclose()してくれるのです。

yossy

とっても便利な文法ですね!

他のファイル・フォルダ操作

その他、よく使われるファイルやフォルダの操作は次の通りです。

操作コマンド例
一覧表示os.listdir("/sd")
ファイル削除os.remove("/sd/abc.txt")
名前変更os.rename("/sd/a.txt", "/sd/b.txt")
フォルダ作成os.mkdir("/sd/folder")
フォルダ削除os.rmdir("/sd/folder")
ファイル追記open(..., "a")

基本的にはPythonの操作と同じですが、一部対応していないものがあるので気をつけましょう。

内部ストレージを使う

SDカードではなく、内部ストレージを使う場合はパスを"/"にします。

SPIの設定やSDカードのライブラリをインストールする必要がないので、シンプルなファイルを扱うときは内部ストレージがおすすめです。ただし、容量が小さいので気をつけましょう。

エラーが出るときは

エラーが出る場合は、以下の点を確認してみてください。

  • SDカードモジュールとラズピコの配線
  • SDカードがFAT32でフォーマットされているか
  • SDカードが壊れていないか
  • ファイルを読み込むときに、ファイルが存在しているか
  • フォルダを消すときに中身が入っていないか
yossy

一部相性問題があるSDカードもあったりします。

応用編:Raspberry Pi PicoでCSVファイルを使う

応用編として、Raspberry Pi PicoでCSVファイルを使う方法を紹介します。CSVファイルを使えばデータの処理がとても行いやすくなります。

CSVファイルとは?

CSVファイルは、カンマで区切られたテキストファイルで、表形式のデータを保存するのに使われます。例えば、次のようなデータがあるとします。

名前,年齢,職業
山田太郎,20,学生
田中花子,25,会社員
佐藤健,30,医師

エクセルやGoogleスプレッドシートなどの表計算ソフトで開くと、写真のように表示することができます。

CSVファイルを使えば、データを使いやすい形式で扱うことができます。

CSVファイルを使うためのプログラム

このプログラムでは、ラズピコのADC4に接続された内蔵温度センサーの値を10回計測し、CSV形式で保存します。

from machine import ADC, Pin, SPI
import sdcard
import os
import time

# SPI & SDカードの初期化
spi = SPI(0,
          baudrate=1_000_000,
          polarity=0,
          phase=0,
          sck=Pin(2),
          mosi=Pin(3),
          miso=Pin(4))
cs = Pin(5, Pin.OUT)
sd = sdcard.SDCard(spi, cs)
os.mount(sd, "/sd")

# ファイルパス
file_path = "/sd/data.csv"

# ヘッダーが無ければ追加
if "data.csv" not in os.listdir("/sd"):
    with open(file_path, "w") as f:
        f.write("count,temperature_C\n")

# 内蔵温度センサー(ADC4)
sensor_temp = ADC(4)

# 計測ループ
for i in range(10):  # 10回測定(必要に応じて変更OK)
    # センサーから値を取得
    reading = sensor_temp.read_u16()
    
    # 温度に変換(公式式)
    voltage = reading * 3.3 / 65535
    temperature = 27 - (voltage - 0.706) / 0.001721
    
    # ファイルに追記
    with open(file_path, "a") as f:
        f.write(f"{i+1},{temperature:.2f}\n")
    
    print(f"{i+1}回目: {temperature:.2f}℃")
    time.sleep(1)  # 1秒ごとに記録

これを実行すると、SDカードにdata.csvが作成されて計測回数と内部温度センサーの値が保存されます。

もしこれをPCで開く際、Excelを使用すると文字化けする場合があるので気をつけてください。治す方法はありますが、Googleスプレッドシートで開くと正しく表示されるのでそちらをおすすめします。

プログラムの解説

前半はほとんど変わらないので説明は省きます。

# ファイルパス
file_path = "/sd/data.csv"

# ヘッダーが無ければ追加
if "data.csv" not in os.listdir("/sd"):
    with open(file_path, "w") as f:
        f.write("count,temperature_C\n")

この部分はdata.csv/sd内になければ、新しくファイルを作成して、ヘッダーを追加します。
if文の条件式にあるinは、リストや文字列の中に要素があるかをチェックします。今回はnot inなので、要素がなければ中の処理が実行されます。


ここからメインのプログラムです。

# 内蔵温度センサー(ADC4)
sensor_temp = ADC(4)

# 計測ループ
for i in range(10):  # 10回測定(必要に応じて変更OK)
    # センサーから値を取得
    reading = sensor_temp.read_u16()
    
    # 温度に変換(公式式)
    voltage = reading * 3.3 / 65535
    temperature = 27 - (voltage - 0.706) / 0.001721
    
    # ファイルに追記
    with open(file_path, "a") as f:
        f.write(f"{i+1},{temperature:.2f}\n")
    
    print(f"{i+1}回目: {temperature:.2f}℃")
    time.sleep(1)  # 1秒ごとに記録

温度センサーのオブジェクトを作成してセンサーから値を読み取り、生の値→電圧→温度と変換します。

計算した温度をファイルに追記します。追記モードでファイルを開くには"a"を指定します。


データを書き込むときに、f.write(f"{i+1},{temperature:.2f}\n")と難しそうな書き方をしていますが、やってることがわかれば簡単です。

まずf"{変数・式}" の部分は、{}の中に書いてある変数や式を文字列に埋め込む事ができます。また、後ろに:.2fとすると、小数第2位までにする事ができます。今回それぞれの{}の中身は、

  • i+1→計測回数
  • temperature:.2f→温度の小数第2位まで

となっています。

次に、\n ですが、これは改行を表します。CSVは行ごとに改行されるので、行の最後に\nを追加しています。

おまけ:CSVをラズピコで読み取る

先ほどのコードで作成したCSVを、1行ずつ読み取るコードです。

file_path = "/sd/data.csv"

with open(file_path, "r") as f:
    # 最初の1行(ヘッダー)を読み飛ばす
    header = f.readline()

    # 残りの行を1つずつ読み込む
    for line in f:
        line = line.strip()  # 改行を取り除く
        values = line.split(",")  # カンマで区切る
        count = int(values[0])  # 回数(int型に変換)
        temp = float(values[1])  # 温度(float型に変換)
        print(f"{count}回目の温度: {temp}℃")

読み込みでファイルを開いた後、f.readline()をして1行目を読み飛ばす処理をします。これはPythonのファイルオブジェクトが読み取り位置を覚えているので、次の処理でデータがある2行目にアクセスできるようにするためです。

そうしたら、for文で2行目から1行ずつ読み込みます。.strip()で改行を取り除き、.split(",")を使ってカンマで区切ります。

yossy

stripとsplit、若干名前がややこしいですね

あとはintやfloatなどに加工して、使うことができます。読み取ったデータを2次元配列にすると便利そうです。

まとめ

今回はRaspberry Pi PicoでSDカードを使う方法を紹介しました。

SPIやファイルの操作など、難しい話が多かったかもしれません。できるだけわかりやすく説明することを心がけました。

SDカードはCSVを使ってログを保存したり、外部のデータを使ったりするのにピッタリなのでぜひ活用したいですね。

この記事が気に入ったら
いいねしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次