17. Pembelajaran tentang SD card di Arduino
Materi:
Bab ini menjelaskan penggunaan SD card dari hal yang mendasar, seperti cara menghubungkan modul SD card ke Arduino, cara membaca dan menulis data dari atau ke SD card hingga ke aplikasi untuk menyimpan data suhu di SD card.
17.1 Penyiapan SD Card
Gambar 17.1 Contoh SD card
Kapasitas SD card beraneka ukuran dan umumnya sudah dalam keadaan terformat ketika dibeli. Contoh ditunjukkan di Gambar 17.1. Jika belum diformat, pemformatan dapat dilakukan dengan mudah karena sistem operasi seperti Wind0ws dilengkapi dengan software untuk memformatnya (Gambar 17.2). Format yang digunakan dapat berupa FAT (FAT16) atau FAT32. Format FAT digunakan untuk yang berukuran 26B, sedangkan FAT32 untuk ukuran yang lebih besar.
Gambar 17.2 Pemformatan SD card di Wind0ws
17.2 Modul SD Card
Supaya Arduino dapat membaca SD card, modul SD card (SD card shield) perlu disiapkan. Contoh modul SD card diperlihatkan di Gambar 17.3. Modul ini menggunakan Serial Peripheral Interface (SPI) untuk berkomunikasi dengan Arduino. Oleh karena itu, modul ini mempunyai pin-PIN_berikut:
- MOSI (master output, slave input),
- MISO (master input, slave output),
- SCK (serial clock), dan
- CS (chip select).
Gambar 17.3 Modul SD card
Gambar 17.4 Rangkaian yang menghubungkan Arduino dengan modul SD card
17-3 Pustaka SD
Untuk mengakses SD card, baik untuk kepentingan membaca maupun menulis, pustaka SD dapat dimanfaatkan. Pustaka ini didasarkan pada sdfatlib yang dibuat oleh William Greiman. Nama file yang digunakan menggunakan pola 8.3, dengan nama depan bisa mencapai 8 karakter dan nama ekstensi hingga 3 karakter.
Pustaka SD sudah tersedia di Arduino IDE. Dengan demikian, Anda tidak perlu mengunduh dan menginstalnya.
Untuk kepentingan mengakses file dan direktori di SD card, sejumlah fungsi telah disediakan. Fungsi-fungsi dapat dilihat di Tabel 17.1. Adapun fungsi-fungsi yang berhubungan dengan pengaksesan data akan dibahas secara tersendiri.
Fungsi | Keterangan |
SD.begin()
SD.begin(pin_CS) |
Untuk menginisialisasi pustaka SD dan SD card. Sebuah argumen yang menyatakan PIN_CS boleh disertakan sekiranya PIN_yang digunakan bukanlah PIN_10. Nilai batik berupa true kalau inisialisasi berhasil dilaksanakan atau false untuk keadaan sebaliknya |
SD.exists(nama_file) | Untuk memeriksa keberadaan suatu file. Nilai balik berupa true kalau file atau direktori yang disebutkan di argumen ada atau false kalau tidak ada |
SD.mkdir(nama_file) | Untuk membuat direktori. Nilai balik berupa true kalau direktori yang disebutkan di argumen berhasil diciptakan atau false kalau tidak |
SD.remove(nama_file) | Untuk menghapus file. Nilai balik berupa true kalau file yang disebutkan di argumen berhasil dihapus atau false kalau tidak |
SD.rmdir(nama_file) | Untuk menghapus direktori. Nilai balik berupa true kalau direktori yang disebutkan di argumen berhasil dihapus atau false kalau tidak. Direktori yang akan dihapus harus dalam keadaan kosong |
Setelah Arduino dihubungkan ke modul SD card dan SD card telah dimasukkan ke pembaca kartu, sketch berikut dapat digunakan untuk mengujinya:
// ——————————————–
// Contoh untuk menguji SD card
// ——————————————–
#include <SD.h>
const int PIN_CS=10;
boolean SD ok;
void setup()
{
Serial.begin(9600);
pinMode(PIN_CS, OUTPUT);
SD ok = SD.begin(PIN_CS); if (SD ok)
Serial.println(“SD card OK!”);
else
Serial.println(“Problem di SD card!”);
}
void loop()
{
}
Prinsip kode yang mendasari penyajian isifi/e tes . txt di depan adalah seperti berikut. Pertama-tama, baris
#include<SD.h>
diperlukan untuk menyertakan pustaka SD. Selanjutnya,
pinMode (PIN_CS, OUTPUT) ;
digunakan untuk menentukan PIN_di Arduino yang dihubungkan ke PIN_CS sebagai keluaran.
PengujianSD card ditangani di setup ( ) . Kode yang digunakan:
SD ok SD. begin (PIN_CS) ;
if (SD ok)
Serial.print In (“SD card OK!) ;
else
Serial.print In (“Problem di SD card!);
Tampak bahwa begin ( ) yang dipakai untuk mengetahui SD card bisa diakses atau tidak. Jika begin () memberikan nilai balik berupa true (disimpan di variabel global Sd ok), akan diperoleh hasil seperti berikut:
Jika niiai balik begin ( ) berupa false, nilai balik berupa seperti berikut:
Gambar 17.6 Hasil kalau SD card tidak dikenali
17.4 Penyajian Isi File
Untuk kepentingan latihan ini, sebuah file teks perlu disiapkan. Dengan menggunakan editor teks seperti
Selanjutnya, siapkan rangkaian seperti terlihat di Gambar 17.3. Lalu, sisipkan SD card ke modul SD card dan unggahkan berikut:
// ——————————————–
// Contoh untuk membacaisi file tes.txt
// yang berada dí SD card
// ——————————————–
#include <SD.h>
const int PIN_CS=10;
boolean SD_ok;
void setup()
{
Serial.begin(9600); pinMode (PIN_CS, OUTPUT);
SD_ok = SD.begin(PIN_CS);
if (SD ok)
Serial.print1n(“SD card OK!”);
else
Serial.print1n (“Problem di SD card!”);
}
void loop()
{
if (!SD_ok)
return; // Abaikan perintah-perintah di bawah
// Baca isi file tes.txt
File fileTes = SD.open(“tes.txt”, FILE_READ);
if (fileTes)
{
Serial.print1n(“Pembacaan data di file tes.txt”); while (fileTes.available())
{
char kar= fileTes.read();
Serial.print(kar);
}
Serial.println();
Serial.println();
}
else
{
Serial.println(“File tes.txt tidak dapat dibuka!”);
}
delay(5000); // Tunda untuk pengulangan berikutnya
}
Jika Serial Monitor diaktifkan, akan diperoleh hasil seperti berikut:
Gambar 17.7 Hasil pembacaan file tes.txt
perhatikan bahwa kode di sketch bacasd adalah hasil pengembangan dari sketch tessd. Tambahan yang dilakukan adalah:
- pernyataan berikut digunakan untuk mendeklarasikan objek fileTes yang berkelas File:
File fileTes = SD.open ( “tes . txt” , FILE_READ) ;
Objek fileTes digunakan untuk mengakses file tes.txt yang hanya ditujukan untuk dibaca saja (akses FILE READ). Setelah file dibuka melalui fungsi anggota open ( ) , seluruh operasi pada file tersebut dilaksanakan melalui fileTes.
- Pernyataan
if (fileTes)
{
…
}
akan membuat semua pernyataan yang berada di dalam { } akan dijalankan hanya kalau operasi pembukaan file berhasil dilakukan.
- Pembacaan isi file tes . txt ditangani oleh:
while (fileTes . available ( ) )
{
char kar fileTes . read() ;
Serial . print (kar) ;
}
Penyataan while membuat yang berada di {} akan dijalakan terus-menerus sela masih berada data di file yang belum dibaca.
- Pembacaan sebuah byte di file dilakukan melalui:
char kar = fileTes . read() ;
Dalam hal ini, hasil pembacaan read ( ) diberikan ke kar.
- Pernyataan berikut mengirimkan isi kar ke port serial:
Serial . print (kar) ;
17.5 Penulisan Data ke SD Card
Pada contoh di atas, setiap record mengandung dua field, yang secara berturutan menyatakan nomor pegawai dan nama pegawai.
Sketch berikut memperlihatkan contoh untuk membentuk file bernama list . csv untuk menyimpan data pegawai di depan:
// ——————————————–
// Contoh untuk menyimpan data dalam
// format CSV
// ——————————————–
#include <SD.h>
const int PIN_CS=10;
char NAMAFILE[] = “list.csv”;
void setup()
{
Serial.begin(9600);
pinMode(PIN_CS, OUTPUT);
if (!SD.begin(PIN_CS))
{
Serial.println(“Problem di SD card!”);
return;
}
// Hapus file kalau ada
if (SD.exists(NAMAFILE))
SD.remove(NAMAFILE);
// Simpan ke file list.csv
// 1. Buka file untuk penyimpanan data
File fileCSV = SD.open (NAMAFILE, FILE_WRITE) ;
if (!fileCSV)
{
Serial.println(“Tak dapat membuka file!”);
return; // Akhiri setup()
}
// 2. Tulis data ke SD card
char formatStr[] = “%5d,%-35s\n”;
char data[255];
sprintf(data, formatStr, 32071, “Anna Karenina”); fileCSV.print(data);
sprintf(data, formatStr, 32072, “Saad Abdillah”); fileCSV.print(data);
sprintf(data, formatStr, 32073, “Fahmi Muadz”); fileCSV.print(data);
sprintf(data, formatStr, 32074, “Dani Irianto”); fileCSV.print(data);
// 3. Tutup file supaya data benar-benar disimpan filecsV.close();
Serial.println(“Data sudah disimpan!”);
}
void loop()
{
}
Pada sketch di atas, pernyataan
if (SD.exists (NAMAFILE) )
SD.remove (NAMAFILE) ;
digunakan untuk menghapus file yang namanya sesuai dengan nilai NAMAFILE sekiranya file tersebut sudah ada.
File fileCSV = SD. open (NAMAFILE, FILE WRITE) ;
Argumen FILE WRITE mengisyaratkan bahwa akses pada file berupa penulisan data. Sama seperti pada contoh sebelum ini, FILE fileCSV menyatakan penciptaan objek berkelas File. Dalam hal akses file dilaksanakan dengan menggunakan objek fileCSV.
Pernyataan
char formatStr[] = “%5d,%-35s\n”;
digunakan untuk membentuk string berdasarkan dua data dengan antardata dipisahkan oleh koma. Dalam hal ini, %5d menyatakan tempat berukuran 5 karakter dan dipakai untuk menempatkan bilangan bulat (dinyatakan dengan simbol d). Setelah bilangan bulat diletakkan, tanda koma akan diberikan, dan diikuti dengan penempatan string (dinyatakan simbol %-35s), serta diakhiri dengan karakter newline (pindah baris). Angka 35 menyatakan lebar ruang yang disediakan untuk string. Tanda — menyatakan bahwa string akan
char data [255] ;
dipakai untuk menciptakan string berakhiran NULL dengan panjang karakter maksimal adalah 254 karakter.
Selanjutnya, formatStr dan data digunakan pada pernyataan
sprint f (data, format St r, 32071, “Anna Karenina”) ,
Pernyataan tersebutlah yang merangkaikan data 32071 dan “Anna Karenina” menjadi sebuah string yang mengikuti format di formatStr dan hasilnya diletakkan ke data. Data dalam data inilah yang disimpan ke file melalui:
fileCSV.print (data) ;
Perlu diketahui, tiga data lain disimpan ke file dengan cara serupa di atas.
Hal terpenting yang perlu dilakukan ketika semua data telah dituliskan ke file, file perlu ditutup. Perintah penutupan file di sketch dilakukan melalui:
fileCSV.c10se ;
Dengan melakukan pemanggilan close ( ) , semua data yang telah dikirim ke SD card melalui print akan benar-benar tersimpan setelah close ( ) dieksekusi.
Hasil akhir setelah sketch dipunggahkan ke papan Arduino diperlihatkan di Gambar 17.8.
Gambar 17.8 Informasi penyimpanan file berformat CSV
17.6 Pembacaan File CSV
Di depan telah dijelaskan cara untuk membaca file berformat CSV. File tersebut dapat dibaca melalui sketch. Contohnya dapat dilihat berikut ini,
// ——————————————–
// format CSV Contoh untuk membaca data dalam
// format CSV
// ——————————————–
#include <SD.h>
const int PIN_CS=10;
char NAMAFILE[]= “list.csv”;
void setup()
{
Serial.begin(9600);
pinMode (PIN_CS, OUTPUT);
if (!SD.begin (PIN_CS))
{
Serial.print1n(“Problem di SD card!”);
return;
}
void loop()
{
char buffer[43];
File fileCSV = SD.open (NAMAFILE,FILE_READ); if (!fileCSV)
{
Serial.println(“Tak dapat membuka file!”);
return;
}
while (filecsv.available())
{
int jumByte = filecsv.readBytesUntil(13,buffer,42);
if (jumByte < 42)
break;
buffer[jumByte]=0;// Karakter NULL
// Tampilkan utuh
Serial.print(buffer);
// Pecah menjadi dua data
char nip[6];
char nama[36];
strncpy(nip, buffer, 5);
nip[5]=0; // Karakter NULL
strncpy(nama, buffer + 6, 35);
nama[36]=0; // Karakter NULL
Serial.println(nip);
Serial.println(nama);
}
Serial.println (“——————————–“);
delay(5000);
}
Untuk kepentingan membaca isi file LIST.CSV di SD card, sebuah array bernama buffer disiapkan. Array tersebut dideklarasikan sebagai:
char buffer [43] ;
Array tersebut digunakan untuk menampung data satu baris di file LIST.CSV untuk setiap saat. Jumlah data dalam satu baris adalah 42 karakter. Satu byte tambahan (sehingga totalnya adalah 43 byte) digunakan untuk meletakkan karakter NULL supaya terbentuk suatu string berakhiran karakter NULL.
Pembacaan seluruh baris di file ditangani oleh:
while (fileCSV. available ( ) )\
{
…
}
Pemanggilan fileCSV.avai1able ( ) memberikan nilai balik true sekiranya masih ada data di file yang belum terbaca. Pembacaan satu baris dilaksanakan melalui:
int jumByte fileCSV. readBytesUntiI (13, buffer, 42) ;
Angka 13 menyatakan karakter yang menandai akhir pembacaan data, sedangkan 42 menyatakan jumlah maksimal byte yang dibaca oleh fungsi anggota readBytesUnti1 ( ) milik objek fileCSV. Fungsi ini memberikan nilai balik berupa jumlah byte yang dibaca dan nilai baliknya disimpan di variabel jumByte.
pernyataan
if (jumByte < 42) break;
dimaksudkan untuk mengakhiri while sekiranya jumlah data terbaca kurang dari 42 byte. Adapun pernyataan
buffer [jumByte]=0;
digunakan untuk membuat data di buffer sebagai string, dengan cara memberikan karakter NULL di bagian akhir.
String yang terdapat di buffer dipecah menjadi data NIP dan nama pegawai melalui:
char nip [6] ;
char nama [36] ;
strncpy (nip, buffer, 5) ;
nip [5] O; // Karakter NULL
strncpy (nama, buffer + 6, 35) ;
nama [36] 0; // Karakter NULL
Dalam hal ini, fungsi strncpy() digunakan untuk menyalin n karakter pertama yang ada di buffer.
Sebagai contoh:
strncpy (nip, buffer, 5) ;
akan menyalin 5 karakter pertama di buffer ke nip. Untuk membuat nip berisi string yang berisi 5 karakter, pernyataan berikut perlu diberikan:
nip [5] o;
strncpy (nama, buffer + 6, 35) ;
digunakan untuk menyalin 35 karakter pada buffer dimulai indeks sama dengan 6 (yaitu awal nama pegawai di buffer). Sapa seperti pada nip,
nama [36] o;
dipakai untuk menambahkan pengakhir string (berupa karakter NULL).
Setelah itu, data NIP dan nama pegawai dapat dikirim ke port serial. Perintahnya berupa:
Serial . printin (nip) ;
Serial . printin (nama) ;
Hasil sketch bacalist dapat dilihat di Gambar 17.9.
Gambar 17.9 Isi file LIST.CSV dibaca melalui sketch bacalist
17.7 Penyimpanan Data Suhu
Dasar tentang penyimpanan data ke SD card telah dijelaskan. Oleh karena itu, sekarang saatnya untuk membahas aplikasi yang mengombinasikan SD card dengan peranti lain, yaitu pengukur suhu dan modul Rea/ Time Clock. Dengan begitu, data suhu yang dilengkapi waktu saat suhu terukur dapat disimpan ke SD card. Rangkaian yang diperlukan diperlihatkan di Gambar 17.10. Contoh perwujudan diperlihatkan di Gambar 17.11.
Gambar 17.10 Rangkaian percobaan untuk menyimpan data suhu
Gambar 17.11 Contoh implementasi untuk menyimpan data suhu
Sketch yang diperlukan untuk menguji rangkaian di Gambar 17.10 seperti berikut :
// ——————————————–
// Contoh untuk menyimpan data suhu
// ke SD card
// ——————————————–
#include <SD.h>
#include <Wire.h>
#include <Time.h>
#include <TimeAlarms.h>
#include <DS1307RTC.h>
const int PIN CS=10;
const int PIN_A0=0;
char NAMAFILE[] = “suhu.csv”;
void setup()
{
Serial.begin(9600);
pinMode(PIN CS, OUTPUT) ;
if (!SD.begin(PIN_CS))
{
Serial.println(“Problem di SD card!”);
return;
}
// Set Timer per dua detik
Alarm.timerRepeat(8, simpan_suhu);
Serial.println(“Siap menyimpan data suhu!”);
}
Void loop ()
{
Alarm.delay(1000);
}
void simpan_suhu()
{
// Baca RTC
tmElements_t tm;
// Baca data di RTC
char waktu[20];
if (RTC.read(tm))
{
sprintf(waktu, “%02d/응02d/응04d 응02d: 응02d: 응02d”,
tm.Day, tm.Month, tmYearToCalendar (tm.Year),
tm.Hour, tm.Minute, tm.Second);
Serial.print(waktu);
}
else
return;
// Baca nilai di pin analog 0 int nilaiPin = analogRead(PIN_A0);
// Hitung suhu
float suhu = 0.49 * nilaiPin;
Serial.print(“”);
Serial.println(suhu);
// Simpan ke file
// 1. Buka file untuk penyimpanan data
File fileSuhu = SD.open(NAMAFILE, FILE_WRITE);
if (!fileSuhu)
{
Serial.println(“Tak dapat membuka file!”);
return;
}
// 2. Tulis data ke SD card
fileSuhu.print(waktu);
fileSuhu.print(“,”);
fileSuhu.println(suhu);
// 3. Tutup file supaya data benar-benar disimpan
fileSuhu.close();
}
pada sketch di atas, nama file untuk menyimpan data suhu didefinisikan oleh kode:
char NAMAFILE[ ]=”suhu . csv” ;
SD card diinisialisasi melalui:
if ( ! SD. begin (PIN_CS))
{
Serial . print In (“Problem di SD card! “)
return;
}
penyimpanan data suhu ditangani dengan memanfaatkan pustaka TimeA1arms, yang telah dibahas di Bab 18. Pernyataan yang digunakan untuk kepentingan ini adalah
Alarm. timerRepeat (8, s impan suhu) ;
Pernyataan di atas akan membuat fungsi s impan suhu ( ) dijalankan secara periodis per 8 detik.
Hal pertama yang dilakukan di fungsi s impan suhu ( ) adalah mendeklarasikan variabet tm yang berstruktur tmE1ements. Struktur ini didefinisikan oleh pustaka Time. Variabel tm ini digunakan sebagai argumen saat pemanggilan RTC . read ( ) untuk mendapatkan waktu di modul Real Time Clock. Penyusunan string yang berisi waktu ditangani oleh kode:
{
sprintf(waktu, “%02d/응02d/응04d 응02d: 응02d: 응02d”,
tm.Day, tm.Month, tmYearToCalendar (tm.Year),
tm.Hour, tm.Minute, tm.Second);
Serial.print(waktu);
}
Dalam hal ini, waktu dideklarasikan seperti berikut:
char waktu [20];
Dengan cara seperti itu akan diperoleh string yang berisi data tahun dan jam di waktu.
Pembacaan data suhu dilakukan melalui:
int nilai PinanalogRead (PIN A0) ;
Data suhu dibaca melalui pin PIN A0 (pin analog 0). Selanjutnya, nilai yang diperoleh dikonversi ke suhu dalam satuan Celcius melalui:
float suhu=0.49 * nilai Pin;
Setelah data waktu dan suhu diperoleh, kedua data tersebut disimpan ke SD card melalui:
Pertama-tama,fi/e dibuka melalui:
File fileSuhu= SD.open (NAMAFILE, FILE WRITE) ;
Jika tidak ada masalah, data disimpan dengan melalui:
fileSuhu . print (waktu) ;
fileSuhu . print ( ” ,”);
fileSuhu . println (suhu) ;
Fungsi print ( ) pertama digunakan untuk menyimpan data waktu yang ada di waktu ke SD card. Fungsi print ( ) kedua menambahkan tanda koma dan fungsi print ( ) ketiga merekamkan data suhu yang ada di variabel suhu. Terakhir, file ditutup dengan:
fileSuhu.close ( ) ;