Raspberry Pi Pico筆記(14):外接 SD Card 資料寫入與讀取

上一篇實作 RFID 感應相關的應用,如果可以將授權的卡片號碼寫在檔案內,卡片感應時比對檔案內的卡號,允許的才給予放行(綠燈),這樣會比較接近實際的應用,本篇先實作瞭解如何將 Pico 開發板上的溫度寫入 SD 卡,瞭解檔案開啟、寫入、讀取及列出檔案等功能。

[材料]

  • Raspberry Pi Pico x1
  • SD Card 模組 x1
  • 麵包板 x1
  • 排線 n 條

[接線圖]

Pi PicoSC Card 模組
Pin 36(3.3V)VCC
Pin 38(GND)GND
Pin 12(GPIO9)CS
Pin 14(GPIO10)SCK
Pin 15(GPIO11)MOSI
Pin 16(GPIO12)MISO


[SDCard函式功能]

.開啟檔案
以 mode 模式開啟路徑下的檔案。
open(filename, mode)
filename 是檔案的路徑及檔案名稱。mode 包含以下各種類型:
  • 「r」: 讀取(Read) - 預設值.開啟檔案提供讀取,當檔案不存在時,會產生錯誤。
  • 「a」: 增加(Append) - 開啟檔案提供資料增加,當檔案不存在時,會建立新檔案。
  • 「w」: 寫入(Write) - 開啟檔案提供資料寫入,當檔案不存在時,會建立新檔案。
  • 「x」: 建立(Create) - 建立指定的檔案,假使檔案存在時,會產生錯誤。

以下為檔案開啟的幾個範例:
#開啟可寫入的檔案,如檔案已存在,會清空內容
file = open("/sd/pico.txt", "w")
file.write("File opened\r\n")

#開啟檔案,增加資料在檔案最後
file = open("/sd/pico.txt", "a")
file.write("Added last line to file\r\n")
 
#開啟檔案為唯讀模式,不能寫入
file = open("/sd/pico.txt", "r")
print("Only Read file")
.讀取檔案內容
讀取全部檔案內容。如刮號內帶有參數(數字) n,表示僅讀取 n 個位元。
read()
read(n)
.讀取檔案內容,一次一列。
讀取檔案內容, 傳回目前指標所指之內容,一次讀取一列。
readline()
.讀取檔案內容存到陣列中,一次一列。
讀取檔案內容, 將內容放在陣列中傳回,一次讀取一列。
readlines()
.將資料寫入檔案
將字串 string 寫入檔案。
write(string)
.關閉檔案
關閉開啟的檔案。
close()
.列出目錄內的檔案
列出指定目錄內的檔案,需要匯入作業系統(OS)模組,執行 OS模組的 listdir()函式來刪除檔案。
import os
os.listdir()
.刪除檔案
要刪除檔案,需要匯入作業系統(OS)模組,執行 OS模組的 remove()函式來刪除檔案。
import os
os.remove("picofile.txt")
這時如果檔案不存在,會出現錯誤,可以改成以下判斷檔案是否存在後,再刪除檔案。
import os
if os.path.exists("picofile.txt"):
  os.remove("picofile.txt")
else:
  print("The file does not exist")
.刪除目錄
要刪除目錄,需要匯入作業系統(OS)模組,執行 OS模組的 rmdir()函式來刪除檔案。
import os
os.rmdir("folder")

[程式一]

程式會用到 sdcard.py 函式庫,可到 這裡 下載。本程式說明檔案寫入的方法,將開發板的溫度,每 5 秒鐘寫入一筆當時的問度到 SD Card 中,寫入 5 筆資料就結束程式。
from machine import Pin, SPI
from machine import ADC

import utime
import sdcard
import os

#建立 SPI連線
sd_spi = SPI(1, sck = Pin(10, Pin.OUT), mosi = Pin(11, Pin.OUT),
            miso = Pin(12, Pin.OUT))

# 建立SDCard物件
sd = sdcard.SDCard(sd_spi, Pin(9, Pin.OUT))

# 掛載 SD card 到 /SD 資料夾
os.mount(sd, '/sd')
print(os.listdir("/sd"))  #列出SD卡的檔案清單
print("Mounted")

file = open("/sd/data.txt", "w")

# 列出 SD card 容量
print("Size: {} MB".format(sd.sectors/2048))

utime.sleep(2)
to_volts = 3.3 / 65535
temper_sensor = ADC(4)   #從ADC(4)取得溫度感測器的電壓值

count = 0
while count < 5:   #讀取5筆溫度資料
    time = utime.localtime()
    temper_volts = temper_sensor.read_u16() * to_volts  #取得當時溫度的電壓
    celsius_degrees = 27 - (temper_volts - 0.706) / 0.001721    #計算攝氏溫度

    print(celsius_degrees)
    file.write(str(celsius_degrees))  #寫入溫度值
    file.write("\r\n")   #換行
    utime.sleep(5)   #等待 5 秒鐘
    count = count + 1
    
file.close()

[程式二]

本程式將上述寫入 SD Card 的資料,讀取檔案內的溫度值,一次一列,將讀取的值顯示在畫面上。
from machine import Pin, SPI

import utime
import sdcard
import os

#建立 SPI連線
sd_spi = SPI(1, sck = Pin(10, Pin.OUT), mosi = Pin(11, Pin.OUT),
            miso = Pin(12, Pin.OUT))

# 建立SDCard物件
sd = sdcard.SDCard(sd_spi, Pin(9, Pin.OUT))

# 掛載 SD card 到 /SD 資料夾
os.mount(sd, '/sd')
print(os.listdir("/sd"))  #列出SD卡的檔案清單
print("Mounted")

file = open("/sd/data.txt", "r")

# 列出 SD card 容量
print("Size: {} MB".format(sd.sectors/2048))

while True:   #迴圈讀取溫度資料
   line = file.readline()           #讀取一列
   print(line)
   if not line:
       break     #傳回空字串時 (False) 跳出迴圈
 
file.close()

[程式三]

本程式將上述寫入 SD Card 的資料,讀取檔案內的溫度值,一次讀取檔案全部,再將讀取的值顯示在畫面上。
from machine import Pin, SPI

import utime
import sdcard
import os

#建立 SPI連線
sd_spi = SPI(1, sck = Pin(10, Pin.OUT), mosi = Pin(11, Pin.OUT),
            miso = Pin(12, Pin.OUT))

# 建立SDCard物件
sd = sdcard.SDCard(sd_spi, Pin(9, Pin.OUT))

# 掛載 SD card 到 /SD 資料夾
os.mount(sd, '/sd')
print(os.listdir("/sd"))  #列出SD卡的檔案清單
print("Mounted")

# 列出 SD card 容量
print("Size: {} MB".format(sd.sectors/2048))

file = open("/sd/data.txt", "r")
line = file.read()          
print(line)

file.close()

[程式四]

這段程式,列出指定目錄下所有的檔案。
from machine import Pin, SPI
import sdcard
import os

sd_spi = SPI(1, sck = Pin(10, Pin.OUT), mosi = Pin(11, Pin.OUT),
             miso = Pin(12, Pin.OUT))

# 建立SDCard物件
sd = sdcard.SDCard(sd_spi, Pin(9, Pin.OUT))

# 掛載 SD card 到 /SD 資料夾
os.mount(sd, "/SD")
print("Mounted")

# 列出 SD card 容量
print("Size: {} MB".format(sd.sectors/2048))

# 列出 SD card 目錄
print(os.listdir("/SD"))

# 卸載 SD card ("/SD" 目錄就不存在)
os.umount("/SD")

[結果]

程式一在實作的過程中,發生 SD 卡寫入錯誤時,如果將程式中「file = open("/sd/data.txt", "w")」的「/sd/」路徑刪掉,檔案會寫到 Pico 的 2MB 記憶體中,未來的實作中,可多利用版載的記憶體儲存結果加以利用。程式執行結果如下:

在程式執行的過程中,發生 SD 卡讀取的錯誤,檢查程式應該沒有問題,但是還是發生錯誤,最後選了 16MB 的 SD 卡就能正常讀寫。若改用上圖照片中的 8GB SD 卡,出現無法得知 SD 卡版本的問題:
若改用上圖照片中的 256MB SD 卡,出現等待逾時的問題:

程式二的執行結果如下:

程式三的執行結果如下:

程式四的執行結果如下:

[參考資料]

Share on Google Plus

0 Comments:

張貼留言