Putar musik .wav dari kartu memori SDCard dengan arduino

jenis file suara menurut sistem kompres data-nya terdiri atas file suara terkompresi dan file suara tidak dikompresi (compressed/uncompresses), yaitu metode penyimpanan data suara digital yang bertujuan memperkecil ukuran file suara dan dengan penurunan kualitas suara sekecil-kecilnya.

File suara tidak dikompres memiliki keunggulan kualitas yang asli selain itu tidak memerlukan proses dekompresi yang rumit untuk mengambil/memutar-nya menjadi suara.

WAV (waveform audio file format) adalah contoh file suara yang tidak dikompres. karena masih menyimpan data aslinya jenis file ini memiliki ukuran yang besar. tidak seperti file suara terkompresi seperti .mp3, .aac, .ogg, .wma yang mmembutuhkan algoritma/codec untuk membuka datanya, .wav bisa langsung digunakan. sehingga .wav sangat cocok untuk perangkat mikrokontroller seperti arduino yang memiliki kecepatan dan memory yang kecil.

play .wav dengan arduino

file wav disimpan dan di ambil data-nya dengan metode PCM (pulse code modulation). file wav memiliki struktur header 44 byte yang berisi informasi jum;ah channel (mono/stereo), sample rate, bit per sampel dan informasi lainnya.

Khusus penggunaan arduino untuk memutar  file .wav dengan kecepatan 16MHz hanya efektif di sample rate 32.000, 16.000, 8.000 dengan kanal mono dan 8 bit per sampel.

Skema memutar file suara .wav menggunakan arduino dari microSD

Rangkaian speaker bukan stereo (tapi unbalanced audio connection)

(seandainya menggunakan ampli) jangan hubungkan ground arduino dan ground ampli jika keluaran suara ke speaker menggunakan 2 kabel pin 9 dan 10 (gunakan salah satu saja jika ground terhubung)

koding memainkan suara dari kartu memori berbasis arduino:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
#define pinSpeakerA     9
#define pinSpeakerB     10
 
#define pinCS           8
#define faktorKali      2
 
#include <SD.h>
#include <SPI.h>
 
 
bool suaraDimainkan;
uint32_t sampleCounter;
byte ulangPerSampel;
byte ulang;
 
struct  HeaderWAV
{
  char                RIFF[4];
  unsigned long       ChunkSize;
  char                WAVE[4];
  char                fmt[4];
  unsigned long       Subchunk1Size;
  unsigned short      AudioFormat;
  unsigned short      NumOfChan;
  unsigned long       SamplesPerSec;
  unsigned long       bytesPerSec;
  unsigned short      blockAlign;
  unsigned short      bitsPerSample;
  char                Subchunk2ID[4];
  unsigned long       Subchunk2Size;
 
};
 
HeaderWAV headerWAV;
File fileSuara;
 
 
void setup(void)
{
  pinMode(pinSpeakerA, OUTPUT);
  pinMode(pinSpeakerB, OUTPUT);
 
  Serial.begin(9600);
  Serial.println("Memutar file suara .wav pada kartu memory SDCard dengan arduino");
  Serial.println("https://www.project.semesin.com/");
 
  if (!SD.begin(pinCS))
  {
    Serial.println("SD fail");
    return;
  }
}
 
void loop(void)
{
  if (!suaraDimainkan)
  {
    mainkanSuara("pulang.wav");
  }
  else
  {
    lanjutkanSuara();
  }
}
 
void mainkanSuara(char *namaFile)
{
  fileSuara = SD.open(namaFile);
  if ( !fileSuara )
  {
    Serial.println("File suara tidak ditemukan");
    return 0;
  }
 
  byte *alamat = (byte*)&headerWAV;
  for (byte i = 0; i < sizeof(headerWAV); i++)
  {
    byte data = fileSuara.read();
    *alamat++ = data;
  }
  Serial.print("namaFile=");
  Serial.println(namaFile);
  Serial.print("headerWAV.SamplesPerSec=");
  Serial.println(headerWAV.SamplesPerSec);
  Serial.print("headerWAV.NumOfChan=");
  Serial.println(headerWAV.NumOfChan);
  Serial.print("headerWAV.bitsPerSample=");
  Serial.println(headerWAV.bitsPerSample);
  Serial.print("headerWAV.Subchunk2Size=");
  Serial.println(headerWAV.Subchunk2Size);
 
  ulangPerSampel = 32000L / headerWAV.SamplesPerSec;
  ICR1 = 256;
  TCCR1A = _BV(COM1A1) | _BV(COM1B1) | _BV(WGM11);
  TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10);
 
  sampleCounter = 0;
  ulang = 0;
  suaraDimainkan = true;
}
 
void lanjutkanSuara()
{
  if (TIFR1 & _BV(TOV1))
  {
    TIFR1 |= _BV(TOV1);
    if (!(ulang++ % ulangPerSampel))
    {
      if (sampleCounter++ >= headerWAV.Subchunk2Size)
      {
        Serial.println("Selesai");
        stopPlayback();
      }
      else
      {
        byte data = fileSuara.read();
 
        uint16_t sample = data;
        OCR1B = 256 - sample;
        OCR1A = sample;
      }
    }
  }
}
 
 
void stopPlayback()
{
  TIMSK1 &= ~_BV(OCIE1A);
  TCCR1B &= ~_BV(CS10);
  OCR1A = 128;
  OCR1B = 128;
 
  fileSuara.close();
  digitalWrite(pinSpeakerA, LOW);
  digitalWrite(pinSpeakerB, LOW);
 
  suaraDimainkan = false;
}

contoh file .wav mono 16kHz 8 bit:
pulang.wav

Audio Player

Mengirim file di SDCard ke PC melalui ESP8266 dengan Arduino

Mengunduh file (download) dari web server melaui web browser biasa kita lakukan. protokol yang umum digunakan adalah FTP atau HTTP. Perancangan kali ini menggunakan Arduino sebagai file server. File-filenya disimpan dalam SDCard, dan untuk berkomunikasi dengan jaringan menggunakan modul wifi ESP8266.

Perancangan sistem file server arduino ini mampu menampilkan File SDCard ke web browser, daftar file file ini merupakan isi dari root direktori kartu memori.

Untuk mendownload file dari arduino, buka browser di halaman sesuai alamat IP Wifi ESP8266 kemudian klik file yang akan didownload, atau jika ingin mendownload secara langsung bisa melalui link http://(alamat ip ESP8266)/namafile.ext.

Komponen yang digunakan :

  1. Arduino Mega
  2. Modul MicroSD
  3. Modul ESP8266 ESP12E

skema download file dari kartu memori melalui ESP8266 :

Sebelum digunakan edit dulu bagian ini :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include <SPI.h>
#include <SD.h>
#include "WiFiEsp.h"
 
char ssid[] = "Twim";
char pass[] = "12345678";
int status = WL_IDLE_STATUS;
 
WiFiEspServer server(80);
File FileSDCard;
 
void setup() {
  Serial.begin(115200);
  Serial.println("Mengirim file di SDCard ke PC melalui ESP8266 dengan Arduino");
  Serial.println("https://www.project.semesin.com");
 
  Serial1.begin(115200);
  WiFi.init(&Serial1);
 
  if (!SD.begin(53))
  {
    Serial.println("Gagal memulai kartu memori!");
    while (true);
  }
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("Modul ESP8266 tidak ditemukan");
    while (true);
  }
 
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to WPA SSID: ");
    Serial.println(ssid);
    status = WiFi.begin(ssid, pass);
  }
 
  Serial.println("You're connected to the network");
  printWifiStatus();
  server.begin();
}
 
void loop() {
  WiFiEspClient client = server.available();
  if (client) {
    boolean currentLineIsBlank = true;
    String request = "";
 
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        request += c;
        if (c == '\n' && currentLineIsBlank) {
          break;
        }
        if (c == '\n') {
          currentLineIsBlank = true;
        }
        else if (c != '\r') {
          currentLineIsBlank = false;
        }
      }
    }
    client.println("HTTP/1.1 200 OK");
    client.println("Connection: close");
 
    Serial.println(request);
    Serial.println();
    Serial.println("Mengirim respon");
 
    int startFilename = request.indexOf('/') + 1;
    int endFilename = request.indexOf("HTTP/1.1") - 1;
 
    String fileRquest = request.substring(startFilename, endFilename);
    Serial.print("Permintaan file : ");
    Serial.println(fileRquest);
 
    if(fileRquest == "")
    {
      File root = SD.open("/");
      client.println("Content-Type: text/html");
      client.println();
      client.print("<!DOCTYPE HTML>");
      client.print("<html>");
      client.print("Daftar file:<br>");
 
      while (true)
      {
        File entry =  root.openNextFile();
        if (! entry) {
          break;
        }
        client.print("<a href=\"");
        client.print(entry.name());
        client.print("\">");
        client.print(entry.name());
        client.print("</a><br>");
        entry.close();
      }
      client.print("</html>\r\n");
    }
    else if (!SD.exists(fileRquest))
    {
      client.println("Content-Type: text/html");
      client.println();
      client.print("<!DOCTYPE HTML>");
      client.print("<html>");
      client.print("Maaf file tidak ditemukan");
      client.print("</html>");
    }
    else
    {
      Serial.print("Mengirim file : ");
      Serial.println(fileRquest);
      FileSDCard = SD.open(fileRquest, FILE_READ);
 
      client.print("Content-Length:");
      client.println((String)FileSDCard.size());
      client.println("Content-Type: text/plain");
      client.print("Content-Disposition: attachment; filename=\"");
      client.print(fileRquest);
      client.println("\"");
      client.println("Content-Transfer-Encoding: binary");
      client.println();
 
      for(uint16_t i=0;i<FileSDCard.size();i++)
      {
        client.write(FileSDCard.read());
      }
      FileSDCard.close();
    }
    delay(10);
    client.stop();
    Serial.println("Client disconnected");
  }
}
void printWifiStatus()
{
  IPAddress ip = WiFi.localIP();
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());
  Serial.print("IP Address: ");
  Serial.println(ip);
  Serial.println();
  Serial.print("To see this page in action, open a browser to http://");
  Serial.println(ip);
  Serial.println();
}

keluaran serial monitor:

library yang digunakan :
WifiEsp.zip

Membaca file txt dari SDCard/kartu memori kedalam struct menggunakan Arduino (Aplikasi Bel Sekolah)

SDCard/microSD/kartu memori merupakan media penyimpanan yang banyak digunakan pada perangkat-perangkat elektronik untuk menyimpan foto, video, data dll. Dalam aplikasi arduino SDCard bisa dibaca/ditulis dalam protokol SPI, format yang didukung adalah FAT.

Dalam perancangan ini saya menggunakan file .txt yang tersusun sebagai database (contoh database jadwal bel sekolah), dan dibaca dengan arduino untuk kemudian dimasukkan kedalam tabel “jadwalBelajar”.

format yang digunakan adalah

Aktif | Waktu | Hari aktif | Minggu aktif | Kegiatan

Aktif
Sebagai status item/baris jadwal diaktifkan atau tidak(diabaikan)
isiannya Aktif, Tidak Aktif

Waktu
Format waktu jam:menit

Hari aktif
hari dimana item jadwal diaktifkan
isiannya: Senin, Selasa, Rabu, Kamis, Jum’at, Sabtu, Minggu atau kombinasinya dalam bentuk array didalam tanda ‘{‘ dan ‘}’

minggu aktif
isiannya kombinasi minggu bentuk array didalam tanda ‘{‘ dan ‘}’

Kegiatan
text Kegiatan

Skema:

sketch/program:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
#include <avr/pgmspace.h>
#include <SPI.h>
#include <SD.h>
 
struct Waktu
{
  byte jam;
  byte menit;
};
 
struct TabelMataPelajaran
{
  byte aktif;
  Waktu waktu;
  byte hariAktif;
  byte mingguAktif;
  byte kegiatan;
};
 
const PROGMEM char kegiatan[][21] =
{
  "Jam Pelajaran 1\0    ",
  "Jam Pelajaran 2\0    ",
  "Jam Pelajaran 3\0    ",
  "Jam Pelajaran 4\0    ",
  "Jam Pelajaran 5\0    ",
  "Jam Pelajaran 6\0    ",
  "Jam Pelajaran 7\0    ",
  "Jam Pelajaran 8\0    ",
  "Jam Pelajaran 9\0    ",
  "Jam Pelajaran 10\0   ",
  "Jam Pelajaran 11\0   ",
  "Jam Pelajaran 12\0   ",
  "Jam Pelajaran 13\0   ",
  "Jam Pelajaran 14\0   ",
  "Jam Pelajaran 15\0   ",
  "Masuk\0              ",
  "Upacara\0            ",
  "Istirahat\0          ",
  "Selesai Istirahat\0  ",
  "Kepramukaan\0        ",
  "Khusus\0             ",
  "Pulang\0             ",
  "Pulang Jumat\0       ",
  "Pulang Sabtu\0       "
};
 
const char namaHari[][7] PROGMEM =
{
  "Minggu",
  "Senin\0",
  "Selasa",
  "Rabu\0 ",
  "Kamis\0",
  "Jum'at",
  "Sabtu\0"
};
 
const char Aktifasi[][12] PROGMEM =
{
  "Aktif\0     ",
  "Tidak aktif"
};
 
#define hariAktifSenin 1<<6
#define hariAktifSelasa 1<<5
#define hariAktifRabu 1<<4
#define hariAktifKamis 1<<3
#define hariAktifJumat 1<<2
#define hariAktifSabtu 1<<1
#define hariAktifMinggu 1<<7
 
 
#define _hariAktif(Sen,Sel,Rab,Kam,Jum,Sab,Mgu) (Mgu<<7)|(Sen<<6)|(Sel<<5)|(Rab<<4)|(Kam<<3)|(Jum<<2)|(Sab<<1)
#define _mingguAktif(Mgu1,Mgu2,Mgu3,Mgu4,Mgu5) (Mgu1<<7)|(Mgu2<<6)|(Mgu3<<5)|(Mgu4<<4)|(Mgu5<<3)
#define _waktu(Jam, Menit) {Jam, Menit}
#define Aktif 1
#define TidakAktif 0
 
TabelMataPelajaran jadwalBelajar[150];
Waktu waktu;
File fileJadwal;
char buffer[21];
 
void setup() {
  Serial.begin(9600);
  Serial.println("Membaca file txt dari SDCard/kartu memori kedalam struct menggunakan Arduino");
  Serial.println("(Aplikasi Bel Sekolah)");
  Serial.println("https://www.project.semesin.com");
}
 
void loop() {
  if (!SD.begin(53))
  {
    Serial.println("Gagal memulai kartu memori!");
  }
  else
  
    if (!SD.exists("Jadwal.txt"))
    {
      Serial.println("file Jadwal.txt tidak ditemukan");
    }
    else
    {
      char c;
      byte index;
      String str;
      fileJadwal = SD.open("Jadwal.txt", FILE_READ);
      while(1)
      {
        c = fileJadwal.peek();
        if(c == -1)
        {
          break;
        }
        else if(c == '/')
        {
          while(fileJadwal.read() != '\n');
          continue;
        }
        else if((c == '\r') || (c == '\n') || (c == '\t') || (c == ' '))
        {
          fileJadwal.read();
          continue;
        }
        jadwalBelajar[index].aktif = ambilCSVAktif(fileJadwal);
        ambilCSVWaktu(&jadwalBelajar[index].waktu.jam,&jadwalBelajar[index].waktu.menit, fileJadwal);
        jadwalBelajar[index].hariAktif = ambilCSVHari(fileJadwal);
        jadwalBelajar[index].mingguAktif = ambilCSVMinggu(fileJadwal);
        jadwalBelajar[index].kegiatan = ambilCSVKegiatan(fileJadwal);
 
        copyFlashString(buffer, &Aktifasi[jadwalBelajar[index].aktif][0]);
        Serial.print(buffer);
        Serial.print('\t');
        if(jadwalBelajar[index].waktu.jam < 10) Serial.print('0');
        Serial.print(jadwalBelajar[index].waktu.jam);
        Serial.print(':');
        if(jadwalBelajar[index].waktu.menit < 10) Serial.print('0');
        Serial.print(jadwalBelajar[index].waktu.menit);
        Serial.print('\t');
        Serial.print(jadwalBelajar[index].hariAktif,HEX);
        Serial.print('\t');
        Serial.print(jadwalBelajar[index].mingguAktif,HEX);
        Serial.print('\t');
        copyFlashString(buffer, &kegiatan[jadwalBelajar[index].kegiatan][0]);
        Serial.println(buffer);
      }
      fileJadwal.close();
    }
  }
 
  while(1);//***
}
byte ambilCSVAktif(File file)
{
  String str = ambilCSVDariFile(file);
 
  for(byte i=0;i<sizeof(Aktifasi)/sizeof(Aktifasi[0]);i++)
  {
    copyFlashString(buffer, &Aktifasi[i][0]);
    if(str.equalsIgnoreCase((String)buffer))
    {
      return i;
    }
  }
}
void ambilCSVWaktu(byte* jam, byte* menit, File file)
{
  String str = ambilCSVDariFile(file);
  byte pos1 = str.indexOf(':');
  *jam = str.substring(0,pos1).toInt();
  *menit = str.substring(pos1+1).toInt();
}
byte ambilCSVHari(File file)
{
  String str = ambilCSVDariFile(file);
  for(byte i=0;i<sizeof(namaHari)/sizeof(namaHari[0]);i++)
  {
    copyFlashString(buffer, &namaHari[i][0]);
    if(str.equalsIgnoreCase((String)buffer))
    {
      return 1<<(7-i);
    }
  }
  byte dataHari = 0;
  byte shift = 0x80;
  byte hari[7];
 
  ambilCSVDariString(hari, str);
  for(byte i=0;i<sizeof(hari);i++)
  {
    if(hari[i])
    {
      dataHari += shift;
    }
    shift >>= 1;
     
  }
  return dataHari;
}
 
byte ambilCSVMinggu(File file)
{
  byte dataMinggu = 0;
  byte shift = 0x80;
  byte minggu[5];
  String str = ambilCSVDariFile(file);
 
  ambilCSVDariString(minggu, str);
  for(byte i=0;i<sizeof(minggu);i++)
  {
    if(minggu[i])
    {
      dataMinggu += shift;
    }
    shift >>= 1;
  }
  return dataMinggu;
}
 
byte ambilCSVKegiatan(File file)
{
  String str = ambilCSVDariFile(file);
  for(byte i=0;i<sizeof(kegiatan)/sizeof(kegiatan[0]);i++)
  {
    copyFlashString(buffer, &kegiatan[i][0]);
    if(str.equalsIgnoreCase((String)buffer))
    {
      return i;
    }
  }
}
String ambilCSVDariFile(File file)
{
  String str = "";
  char terminator = ',';
 
  while(1)
  {
    char c = file.peek();
    if(c == '{')
    {
      terminator = '}';
      file.read();
    }
    else if(((c != terminator) && (c != '\r')))
    {
      str += (char)file.read();
    }
    else
    {
      file.read();
      if(terminator == '}')
      {
        terminator = ',';
      }
      else if((terminator == ',') || (c == '\r'))
      {
        break;
      }
    }
  }
  str.trim();
  return str;
}
void copyFlashString(char* buf, const char* alamat)
{
  char c;
  while(c = pgm_read_byte(alamat++))
  {
    *buf++ = c;
  }
  *buf = 0;
}
void ambilCSVDariString(byte *minggu, String str)
{
  while(1)
  {
    int pos = str.indexOf(',');
    *minggu++ = str.substring(0,pos).toInt();
    if(pos == -1)
    {
      break;
    }
    str = str.substring(pos+1);
  }
}

contok keluaran serial monitor:

Contoh file jadwal.txt:
Jadwal.txt

Bel sekolah bluetooth dengan kontrol android : disini