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:


#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.semesin.com/project/");

  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

Menampilkan data audio dari sound card dengan GUI Matlab

Matlab menyedian fasilitas pengambilan data audio langsung dari hardware soundcard (internal/external) menggunakan system audio toolbox atau data acquisition toolbox. Namun toolbox tersebut hanya mendukung beberapa jenis soundcard saja.

Jika hardware tidak didukung dan pengambilan data audio realtime bisa dikesampingkan, maka pengambilan data audio melalui mic/line in masih bisa dilakukan dengan fungsi standar yang disediakan matlab.

Dalam proyek ini digunakan fungsi-fungsi utama berikut:

  1. audiodevinfo, bertugas mengambil informasi perangkat/hardware audio input seperti mic dan line in. Daftar perangkat masukan suara ini ditampilkan dalam pop-up menu sehingga pengguna bisa memilih perangkat yang akan digunakan sebagai masukan audio.
  2. audiorecorder, merupakan fungsi perekam audio standar matlab yang akan mulai merekam saat diberi perintah start() dan akan berhenti saat diberi perintah stop(). Data suara yang terekam bisa diambil dengan perintah getaudiodata();
  3. Timer, berfungsi mengatur jeda pengambilan data suara.

Metode ini akan memiliki jeda tergantung pengaturan waktu di timer, agar terlihat lebih realtime, perioda timer dibuat lebih kecil dan dalam mode tetap/fixedSpacing. Selain itu waktu proses lanjutan seperti analisa ampltudo/phase, FFT, Filter dan lain-lain dibuat seefektif mungkin sehingga jeda (kehilangan data audio) bisa diperkecil.

berikut koding fungsi merekam data suara matlab yang digunakan:

function varargout = audioSoundcard(varargin)
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
    'gui_Singleton',  gui_Singleton, ...
    'gui_OpeningFcn', @audioSoundcard_OpeningFcn, ...
    'gui_OutputFcn',  @audioSoundcard_OutputFcn, ...
    'gui_LayoutFcn',  [] , ...
    'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end

% --- Executes just before audioSoundcard is made visible.
function audioSoundcard_OpeningFcn(hObject, eventdata, handles, varargin)
% Choose default command line output for AudioSpectrumAnalyzer
handles.output = hObject;

% Update handles structure
guidata(hObject, handles);

% uiwait(handles.figure1);
global guiHandle;
global recorder;
global audioData;

global panjangDataRekaman;
global frequencySampling;
global bitsPerSample;
global audioChannel;

panjangDataRekaman = 8191;
frequencySampling = 22050;
bitsPerSample = 16;
audioChannel = 1;

ylim(handles.axes1, [-0.5, 0.5]);
xlim(handles.axes1, [0, panjangDataRekaman]);
title(handles.axes1, 'Real time');
xlabel(handles.axes1, 'sampling (bit)')
ylabel(handles.axes1, 'Amplitude')
hold(handles.axes1,'on');
guiHandle = guidata(hObject);
set(handles.checkboxAktif,'value', 0);

info = audiodevinfo;
nDevices = audiodevinfo(1);
str = {};
set(handles.popupmenuDevice,'string',str);

for i = 1:nDevices
    str = [str, char(info.input(i).Name)];
end
set(handles.popupmenuDevice,'string',str);
set(handles.checkboxAktif,'value',0);

deviceID = get(handles.popupmenuDevice,'value') - 1;
recorder = audiorecorder(frequencySampling, bitsPerSample, audioChannel, deviceID);
audioData = double.empty();

% --- Outputs from this function are returned to the command line.
function varargout = audioSoundcard_OutputFcn(hObject, eventdata, handles)
varargout{1} = handles.output;


% --- Executes on button press in checkboxAktif.
function checkboxAktif_Callback(hObject, eventdata, handles)
global  timerRekam
T = timerfind;
if isempty(T)
    disp('timer empty')
    timerRekam = timerRekaman();
end

if get(handles.checkboxAktif,'value')
    start(timerRekam)
else
    stop(timerRekam)
end

% --- Executes on selection change in popupmenuDevice.
function popupmenuDevice_Callback(hObject, eventdata, handles)
global recorder
global frequencySampling
global bitsPerSample;
global audioChannel;

deviceID = get(handles.popupmenuDevice,'value') - 1;
recorder = audiorecorder(frequencySampling, bitsPerSample, audioChannel, deviceID);


% --- Executes during object creation, after setting all properties.
function popupmenuDevice_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes during object deletion, before destroying properties.
function figure1_DeleteFcn(hObject, eventdata, handles)
T = timerfind;
if ~isempty(T)
    stop(T)
    delete(T)
end

function t = timerRekaman()
t = timer;
t.StartDelay = 0;
t.TimerFcn = @rekamSuara;
t.StopFcn  = @selesaiRekamSuara;
t.Period = 0.5;
t.ExecutionMode = 'fixedSpacing';

function rekamSuara(mTimer,~)
global recorder
global audioData;
global plotData;
global panjangDataRekaman;

if recorder.isrecording
    stop(recorder);
    delete(plotData);
    audioData = [audioData; getaudiodata(recorder)];
    
    if length(audioData) > panjangDataRekaman
        audioData = audioData(length(audioData)-panjangDataRekaman:length(audioData));
    end
    
    tampilGrafik;
end
disp('AmbilSuara...')
recorder.record;

function selesaiRekamSuara(mTimer,~)
disp('Selesai.')

function tampilGrafik()
global guiHandle;
global audioData;
global plotData;
global panjangDataRekaman;

if ~isempty(audioData)
    plotData = plot(audioData, 'b', 'Parent', guiHandle.axes1);
end

Contah capture audio matlab menggunakan fungsi standar pembacaan soundcard:

file pendukung pengambilan data suara dengan matlab:

audioSoundcard.fig

Bel sekolah arduino dengan kontrol android 2 (upgrade lcd)

Bel sekolah adalah pengingat waktu yang digunakan di sekolah sebagai penanda pergantian jadwal.

Bel sekolah digital bisa di aplikasikan dalam bentuk:

    1. Aplikasi komputer
      adalah aplikasi yang ditanam dalam komputer dan bisa dijalankan secara otomatis. sistem ini mudah dalam pengaturan, memiliki data jadwal sangat besar,  peringatan admin, backup, update suara mudah, perekan suara, kunci aplikasi dll. Kelemahannya adalah komputer dan aplifier suara harus tetap hidup dan bergantung kepada adanya daya listrik/ups termasuk biaya listrik, pesan sponsor pada aplikasi gratis,  biaya pengadaan dan perawatan komputer.
    2. Aplikasi android
      Aplikasi / apk android memiliki sama dengan aplikasi komputer dan aplikasi android dapat terhubung dengan  sistem tata suara melalui bluetooth dan kabel audio. kekurangannya adalah device android harus selalu berada dekat dengan sistem (selalu standby)
    3. Aplikasi perangkat mandiri
      Sistem bel sekolah otomatis dapat dibangun dengan perangkat mandiri menggunakan microkontroller dengan biaya murah dan bisa dikembangkan untuk keperluan lainnya seperti :

      • bisa menggunakan baterai sebagai daya cadangannya
      • Pendeteksi gempa dan peringatan
      • Notifikasi sms ke pengajar
      • Mekanuisme kunci pagar
      • Panggilan melalui microphone yang tertuju langsung ke kelas tertentu
      • dan lain-lain sesuai kebutuhan

      Kekurangan sistem ini adalah ruang penyimpanan data jadwal dan suara terbatas, pengaturan jadwal yang sulit melalui tombol/keypad.

Dalam proyek ini menggabungkan perangkat mandiri dengan platform arduino yang dikombinasikan dengan aplikasi/apk android sebagai kontrolnya.

Skema bel sekolah otomatis dengan kontrol android:

komponen bel sekolah arduino control android:

  • Arduino Uno
  • Bluetooth HC-05
  • RTC DS3231
  • LCD 1602 + I2C backpack
  • modul Relay 1 channel
  • DF Player mini mp3
  • Speaker

tampilan Aplikasi bel sekolah android :

sketch/aplikasi bel sekolah bluettoth android :

#define namaSekolah   "Nama Sekolah"

#define SQWPin        A3
#define pinRelay      8
#define relayOn       LOW

#include <avr/sleep.h>
#include <SoftwareSerial.h>
#include <DFPlayer_Mini_Mp3.h>
#include "RTC.h"
#include <EEPROM.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

#define tokenEEPROM 0x83
SoftwareSerial bluetooth(2, 3); // RX, TX
SoftwareSerial mp3Serial(4, 5); // RX, TX
LiquidCrystal_I2C lcd(0x3F, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display

struct Waktu
{
  byte jam;
  byte menit;
};

struct TabelMataPelajaran
{
  byte aktif;
  Waktu waktu;
  byte hariAktif;
  byte mingguAktif;
  byte kegiatan;
};

const char kegiatanText[][17] PROGMEM = {
  "-               ",
  "Jam Pelajaran 1 ",
  "Jam Pelajaran 2 ",
  "Jam Pelajaran 3 ",
  "Jam Pelajaran 4 ",
  "Jam Pelajaran 5 ",
  "Jam Pelajaran 6 ",
  "Jam Pelajaran 7 ",
  "Jam Pelajaran 8 ",
  "Jam Pelajaran 9 ",
  "Jam Pelajaran 10",
  "Jam Pelajaran 11",
  "Jam Pelajaran 12",
  "Jam Pelajaran 13",
  "Jam Pelajaran 14",
  "Jam Pelajaran 15",
  "Masuk           ",
  "Upacara         ",
  "Istirahat       ",
  "Selesai istiraht",
  "Kepramukaan     ",
  "Khusus          ",
  "Pulang          ",
  "Pulang Jum'at   ",
  "Pulang Sabtu    ",
  "Musik 1         ",
  "Musik 2         ",
  "Musik 3         ",
  "Musik 4         ",
  "Musik 5         ",
  "Musik 6         ",
  "Hadits 1        ",
  "Hadits 2        ",
  "Hadits 3        ",
  "Hadits 4        ",
  "Hadits 5        ",
  "Hadits 6        ",
};

enum _kegiatan
{
  TidakAda,
  JamPelajaran1,
  JamPelajaran2,
  JamPelajaran3,
  JamPelajaran4,
  JamPelajaran5,
  JamPelajaran6,
  JamPelajaran7,
  JamPelajaran8,
  JamPelajaran9,
  JamPelajaran10,
  JamPelajaran11,
  JamPelajaran12,
  JamPelajaran13,
  JamPelajaran14,
  JamPelajaran15,
  Masuk,
  Upacara,
  Istirahat,
  Istirahat1,
  Istirahat2,
  Istirahat3,
  SelesaiIstirahat,
  Kepramukaan,
  Khusus,
  Pulang,
  PulangJumat,
  PulangSabtu,
  Musik1,
  Musik2,
  Musik3,
  Musik4,
  Musik5,
  Musik6,
  Hadits1,
  Hadits2,
  Hadits3,
  Hadits4,
  Hadits5,
  Hadits6,
};
enum PengaturanAndroid
{
  cekAses,
  pengaturanJadwal,
  pengaturanWaktu,

};

char karakterMusik[8] = {
  0b00000,
  0b00100,
  0b00110,
  0b00101,
  0b00101,
  0b00100,
  0b11100,
  0b11100
};
byte karakterDetik1[8] = {
  0b00000,
  0b00000,
  0b00000,
  0b00100,
  0b00000,
  0b00000,
  0b00000,
  0b00000
};
byte karakterDetik2[8] = {
  0b00000,
  0b00000,
  0b00100,
  0b01010,
  0b00100,
  0b00000,
  0b00000,
  0b00000
};
byte karakterDetik3[8] = {
  0b00000,
  0b00100,
  0b01010,
  0b10001,
  0b01010,
  0b00100,
  0b00000,
  0b00000
};
byte karakterSetting[8] = {
  0b00100,
  0b00100,
  0b00100,
  0b01110,
  0b00100,
  0b10001,
  0b01010,
  0b00100
};

volatile bool interupsiDetik;
byte indexMataPelajaran;
RTC_DS3231 rtc;
DateTime now;
bool rtcValid;
byte indexPengaturanJadwal = 0;

#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

char namaHari[][7] = {"Minggu", "Senin", "Selasa", "Rabu", "Kamis", "Jum'at", "Sabtu"};
#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[40];
Waktu waktu;

char bufWaktu[40];
byte detikSebelumnya = 60;
byte tanggalSebelumnya = 0;
Waktu jadwalBerikutnya;
byte menitBel;
bool statusBel;
bool statusPengingat;

byte jadwalBerikutnyaKegiatan;


void setup() {
  digitalWrite(pinRelay, !relayOn);
  pinMode(pinRelay, OUTPUT);
  
  pinMode(SQWPin, INPUT_PULLUP);

  Serial.begin(9600);
  Serial.println(F("Bel Sekolah Dengan Kontrol Android"));
  Serial.println(F("https://www.semesin.com/project"));
  Serial.println();

  lcd.begin();

  lcd.command (0x40 | (0 << 3));
  for (byte i = 0; i < 8; i++)
    lcd.write (karakterDetik1[i]);

  lcd.command (0x40 | (1 << 3));
  for (byte i = 0; i < 8; i++)
    lcd.write (karakterDetik2[i]);

  lcd.command (0x40 | (2 << 3));
  for (byte i = 0; i < 8; i++)
    lcd.write (karakterDetik3[i]);

  lcd.command (0x40 | (3 << 3));
  for (byte i = 0; i < 8; i++)
    lcd.write (karakterDetik2[i]);

  lcd.command (0x40 | (4 << 3));
  for (byte i = 0; i < 8; i++)
    lcd.write (karakterMusik[i]);

  lcd.command (0x40 | (5 << 3));
  for (byte i = 0; i < 8; i++)
    lcd.write (karakterSetting[i]);


  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("Bel Sekolah");
  lcd.setCursor(0, 1);
  lcd.print(namaSekolah);


  mp3Serial.begin(9600);
  bluetooth.begin (9600);
  bluetooth.listen();

  mp3_set_serial (mp3Serial);
  mp3_set_volume (0x30);

  rtc.begin();

  if (rtc.lostPower()) 
  {
    Serial.println(F("RTC lost power, lets set the time!"));
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }
  
  rtc.writeSqwPinMode(DS3231_SquareWave1Hz);

  if (EEPROM.read(sizeof(jadwalBelajar)) != tokenEEPROM)
  {
    nilaiAwal();
    EEPROM.write(sizeof(jadwalBelajar), tokenEEPROM);
    Serial.println("setting awal");
  }
  
  EEPROM.get(0, jadwalBelajar);
  cekJadwalHariIni();

  delay(1000);

  lcd.clear();

  Serial.println(F("Sistem bel sekolah dimulai"));

}

void loop() {
  if (digitalRead(SQWPin))
  {
    if (rtcValid)
    {
      rtcValid = false;

      now = rtc.now();

      uint16_t unixJadwalBerikutnya = (jadwalBerikutnya.jam * 60) + jadwalBerikutnya.menit;
      uint16_t unixWaktu = (now.jam * 60) + now.menit;

      if (!now.detik)
      {
        if (jadwalBerikutnyaKegiatan && (jadwalBerikutnya.jam == now.jam) && (jadwalBerikutnya.menit == now.menit))
        {
          lcd.setCursor(6, 1);
          lcd.print((char)4);
          lcd.setCursor(0, 0);
          lcd.print((__FlashStringHelper *)kegiatanText[jadwalBerikutnyaKegiatan]);

          mp3_play (jadwalBerikutnyaKegiatan);
          Serial.println((__FlashStringHelper *)kegiatanText[jadwalBerikutnyaKegiatan]);
          menitBel = jadwalBerikutnya.menit;
          statusBel = true;
          statusPengingat = false;
        }
        else if (jadwalBerikutnyaKegiatan && (unixWaktu == unixJadwalBerikutnya - 1))
        {
          statusPengingat = true;
          digitalWrite(pinRelay, relayOn);
          Serial.println("Pengingat bel masuk 1 menit lagi");
        }
      }

      if (menitBel != now.menit)
      {
        if (statusBel)
        {
          lcd.setCursor(6, 1);
          lcd.print(' ');

          digitalWrite(pinRelay, !relayOn);

          cariJadwal();
          statusBel = false;
          tanggalSebelumnya = 0;
        }
      }

      //tampilan
      if (statusPengingat)
      {
        lcd.setCursor(1, 1);
        if (now.detik % 2)
        {
          sprintf(bufWaktu, "%02d:%02d", jadwalBerikutnya.jam, jadwalBerikutnya.menit);
          lcd.print(bufWaktu);
        }
        else
        {
          lcd.print("     ");
        }
      }

      if (detikSebelumnya != now.detik)
      {
        sprintf(bufWaktu, "%02d:%02d:%02d", now.jam, now.menit, now.detik);
        lcd.setCursor(8, 1);
        lcd.print(bufWaktu);
        lcd.setCursor(0, 1);
        lcd.print((char)(now.detik % 4));

        sprintf(bufWaktu, "%02d:%02d:%02d %s, %02d/%02d/%02d", now.jam, now.menit, now.detik, namaHari[now.hari - 1], now.tanggal, now.bulan, now.tahun - 2000);
        Serial.println(bufWaktu);
      }

      if (tanggalSebelumnya != now.tanggal)
      {
        tanggalSebelumnya = now.tanggal;
        lcd.clear();
        lcd.print(namaHari[now.hari - 1]);
        lcd.print(',');
        sprintf(bufWaktu, "%02d/%02d/%02d", now.tanggal, now.bulan, now.tahun - 2000);
        lcd.setCursor(8, 0);
        lcd.print(bufWaktu);

        cariJadwal();
      }
    }
  }
  else
  {
    rtcValid = true;
  }
  cekBluetooth();
}

void cekBluetooth()
{
  uint8_t tokenMulai;
  uint8_t perintah;
  uint8_t parameter;
  uint8_t panjang1;
  uint8_t panjang2;
  char c;
  uint8_t i, j;
  uint8_t tokenSelesai;
  byte bufferSerial[100];
  byte *alamat;

  if (bluetooth.available())
  {
    tokenMulai = bluetoothRead();
    if (tokenMulai == 0xFD)
    {
      panjang1 = bluetoothRead();
      panjang2 = bluetoothRead();

      if (panjang2 == 254 - panjang1)
      {
        if (panjang1 >= sizeof(bufferSerial))
        {
          panjang1 = sizeof(bufferSerial);
        }

        uint16_t timeOut = 0xFFF;
        i = 0;
        do
        {
          if (bluetooth.available())
          {
            c = bluetoothRead();
            bufferSerial[i++] = c;
          }
        } while ((i < panjang1 + 3) && (timeOut--));

        perintah = bufferSerial[0];
        parameter = bufferSerial[1];

        tokenSelesai = bufferSerial[i - 1];
        if (tokenSelesai == 0x00)
        {
          delay(10);
          bluetooth.write(254);
          switch (perintah)
          {
            case cekAses:
              bluetooth.write(1);
              bluetooth.write(254);
              break;
            case pengaturanJadwal:
              lcd.setCursor(6, 1);
              lcd.print((char)5);

              memcpy((byte*)&jadwalBelajar[parameter], bufferSerial + 2, sizeof(TabelMataPelajaran));
              if (parameter == (sizeof(jadwalBelajar) / sizeof(TabelMataPelajaran)) - 1)
              {
                EEPROM.put(0, jadwalBelajar);
                Serial.println("Jadwal diterima");

                lcd.setCursor(6, 1);
                lcd.print(' ');

                tanggalSebelumnya = 0;
              }
              break;
            case pengaturanWaktu:
              memcpy((byte*)&now, bufferSerial + 2, sizeof(DateTime));
              rtc.adjust(now);
              tanggalSebelumnya = 0;
              Serial.println("Setting waktu diterima");
              break;
          }
        }
        else
        {
          bluetooth.write(252);//data tidak benar
        }
      }
    }
  }
}
byte bluetoothRead()
{
  uint16_t timeOut = 0xFFF;
  while (!bluetooth.available() && timeOut--);
  return bluetooth.read();
}



void nilaiAwal()
{
  byte i = 0;
  jadwalBelajar[i++] = {Aktif, _waktu(  6, 45 ), hariAktifSenin                 , _mingguAktif(1, 0, 0, 0, 0), Upacara};
  jadwalBelajar[i++] = {Aktif, _waktu(  6, 45 ), hariAktifSenin                 , _mingguAktif(0, 1, 1, 1, 1), JamPelajaran1};
  jadwalBelajar[i++] = {Aktif, _waktu(  6, 45 ), _hariAktif(0, 1, 1, 1, 1, 0, 0), _mingguAktif(1, 1, 1, 1, 1), JamPelajaran1};

  jadwalBelajar[i++] = {Aktif, _waktu(  7, 30 ), _hariAktif(1, 1, 1, 1, 0, 0, 0), _mingguAktif(1, 1, 1, 1, 1), JamPelajaran2};
  jadwalBelajar[i++] = {Aktif, _waktu(  8, 15 ), _hariAktif(1, 1, 1, 1, 0, 0, 0), _mingguAktif(1, 1, 1, 1, 1), JamPelajaran3};
  jadwalBelajar[i++] = {Aktif, _waktu(  9, 0  ), _hariAktif(1, 1, 1, 1, 0, 0, 0), _mingguAktif(1, 1, 1, 1, 1), JamPelajaran4};
  jadwalBelajar[i++] = {Aktif, _waktu(  9, 45 ), _hariAktif(1, 1, 1, 1, 0, 0, 0), _mingguAktif(1, 1, 1, 1, 1), Istirahat};
  jadwalBelajar[i++] = {Aktif, _waktu( 10, 15 ), _hariAktif(1, 1, 1, 1, 0, 0, 0), _mingguAktif(1, 1, 1, 1, 1), JamPelajaran5};
  jadwalBelajar[i++] = {Aktif, _waktu( 11, 0  ), _hariAktif(1, 1, 1, 1, 0, 0, 0), _mingguAktif(1, 1, 1, 1, 1), JamPelajaran6};
  jadwalBelajar[i++] = {Aktif, _waktu( 11, 45 ), _hariAktif(1, 1, 1, 1, 0, 0, 0), _mingguAktif(1, 1, 1, 1, 1), Istirahat};
  jadwalBelajar[i++] = {Aktif, _waktu( 12, 30 ), _hariAktif(1, 1, 1, 1, 0, 0, 0), _mingguAktif(1, 1, 1, 1, 1), JamPelajaran7};
  jadwalBelajar[i++] = {Aktif, _waktu( 13, 15 ), _hariAktif(1, 1, 1, 1, 0, 0, 0), _mingguAktif(1, 1, 1, 1, 1), JamPelajaran8};

  jadwalBelajar[i++] = {Aktif, _waktu( 14, 0  ), _hariAktif(1, 1, 1, 0, 0, 0, 0), _mingguAktif(1, 1, 1, 1, 1), JamPelajaran9};
  jadwalBelajar[i++] = {Aktif, _waktu( 14, 45 ), _hariAktif(1, 1, 1, 0, 0, 0, 0), _mingguAktif(1, 1, 1, 1, 1), JamPelajaran10};

  jadwalBelajar[i++] = {Aktif, _waktu( 14, 0  ), hariAktifKamis,            _mingguAktif(1, 1, 1, 1, 1), Kepramukaan};
  jadwalBelajar[i++] = {Aktif, _waktu( 14, 45 ), hariAktifKamis,            _mingguAktif(1, 1, 1, 1, 1), Khusus};

  jadwalBelajar[i++] = {Aktif, _waktu( 15, 30 ), _hariAktif(1, 1, 1, 1, 0, 0, 0), _mingguAktif(1, 1, 1, 1, 1), Pulang};

  jadwalBelajar[i++] = {Aktif, _waktu(  7, 25 ), hariAktifJumat,            _mingguAktif(1, 1, 1, 1, 1), JamPelajaran2};
  jadwalBelajar[i++] = {Aktif, _waktu(  8, 5  ), hariAktifJumat,            _mingguAktif(1, 1, 1, 1, 1), JamPelajaran3};
  jadwalBelajar[i++] = {Aktif, _waktu(  8, 45 ), hariAktifJumat,            _mingguAktif(1, 1, 1, 1, 1), JamPelajaran4};
  jadwalBelajar[i++] = {Aktif, _waktu(  9, 25 ), hariAktifJumat,            _mingguAktif(1, 1, 1, 1, 1), Istirahat};
  jadwalBelajar[i++] = {Aktif, _waktu(  9, 55 ), hariAktifJumat,            _mingguAktif(1, 1, 1, 1, 1), JamPelajaran5};
  jadwalBelajar[i++] = {Aktif, _waktu( 10, 35 ), hariAktifJumat,            _mingguAktif(1, 1, 1, 1, 1), JamPelajaran6};
  jadwalBelajar[i++] = {Aktif, _waktu( 11, 15 ), hariAktifJumat,            _mingguAktif(1, 1, 1, 1, 1), PulangJumat};

  EEPROM.put(0, jadwalBelajar);
}

void cekJadwalHariIni()
{
  Serial.println("Jadwal hari ini");
  for (byte i = 0; i < sizeof(jadwalBelajar) / sizeof(TabelMataPelajaran) ; i++)
  {
    Serial.print(jadwalBelajar[i].aktif);
    Serial.print('\t');
    Serial.print(jadwalBelajar[i].waktu.jam);
    Serial.print('\t');
    Serial.print(jadwalBelajar[i].waktu.menit);
    Serial.print('\t');
    Serial.print(jadwalBelajar[i].hariAktif, HEX);
    Serial.print('\t');
    Serial.print(jadwalBelajar[i].mingguAktif, HEX);
    Serial.print('\t');
    Serial.print(jadwalBelajar[i].kegiatan);
    Serial.print('\t');
    char buf[20];
    memcpy_P(buf, kegiatanText[jadwalBelajar[i].kegiatan], sizeof(kegiatanText[0]));
    Serial.print(buf);
    Serial.println();
  }

}

void cariJadwal()
{
  uint16_t unixWaktu = (now.jam * 60) + now.menit;
  byte hariKeDiTanggal1 = ((now.hari + 7  - (now.tanggal % 7)) % 7) + 1;
  byte SeninKe = ((now.tanggal + ((hariKeDiTanggal1 + 4) % 7)) / 7); //senin pertama
  byte mingguKe = ((now.tanggal + hariKeDiTanggal1 + 6) / 7);

  Serial.print("SeninKe = ");
  Serial.println(SeninKe);
  Serial.print("mingguKe = ");
  Serial.println(mingguKe);


  uint16_t unixTerkecil = UINT16_MAX;
  jadwalBerikutnyaKegiatan = 0;
  Waktu waktuTerkecil;

  for (byte i = 0; i < sizeof(jadwalBelajar) / sizeof(TabelMataPelajaran); i++)
  {
    if (
      (jadwalBelajar[i].aktif) &&
      (jadwalBelajar[i].hariAktif & (1 << (8 - now.hari))) &&
      (jadwalBelajar[i].mingguAktif & (1 << (8 - mingguKe)))
    )
    {
      uint16_t unixJadwal = (jadwalBelajar[i].waktu.jam * 60) + jadwalBelajar[i].waktu.menit;
      if (unixWaktu < unixJadwal)
      {
        if (unixTerkecil > unixJadwal)
        {
          unixTerkecil = unixJadwal;
          jadwalBerikutnya.jam = jadwalBelajar[i].waktu.jam;
          jadwalBerikutnya.menit = jadwalBelajar[i].waktu.menit;
          jadwalBerikutnyaKegiatan = jadwalBelajar[i].kegiatan;
        }
      }
    }
  }
  if (jadwalBerikutnyaKegiatan)
  {
    Serial.print("Bel berikutnya : ");
    Serial.print((__FlashStringHelper *)kegiatanText[jadwalBerikutnyaKegiatan]);
    Serial.print(" ");
    Serial.print(jadwalBerikutnya.jam);
    Serial.print(":");
    Serial.println(jadwalBerikutnya.menit);

    lcd.setCursor(1, 1);
    sprintf(bufWaktu, "%02d:%02d", jadwalBerikutnya.jam, jadwalBerikutnya.menit);
    lcd.print(bufWaktu);
  }
  else
  {
    lcd.setCursor(1, 1);
    lcd.print("--:--");
  }


}

library arduino bel sekolah dengan bluetooth dan aplikasi android yang digunakan :

Suara mp3 bel sekolah arduino dengan bluetooth:

mp3.zip

aplikasi apk android untuk bel sekolah arduino (evaluasi):

Bel_sekolah_v1_Evaluasi.apk

cara penggunaan :

  1. Buat rangkaian arduino seperti skema dan upload sketch yang diberikan.
  2. Masukkan file suara dalam kartu memori/SD card (file mp3 dan folder mp3).
  3. install aplikasi bel sekolah v1 evaluasi di android (evaluasi = 10 jadwal yang aktif).

Suara Arduino

Arduino merupakan platform elektronik yang dirancang untuk memudahkan pengontrolan berbagai perangkat.

Hardware arduino mikrokontroller yang memiliki port masukan (input)  dan port keluaran (output). Perangkat keras arduino juga dilengkapi dengan fitur-fitur bawaan chip mikrokontroler atau diprogram secara software, seperti komunikasi serial, SPI, I2C, ADC, TIMER.

Sebagai perangkat digital, arduino juga mampu berperilaku sebagai perangkat multimedia terbatas, yakni hanya sebagai pengontrol melalui protokol yang disediakan. Salah satu perangkat multimedia yang mampu ditangani oleh arduino adalah suara.

Arduino audio / suara bisa dihasilkan dalam 2 metode, yaitu arduino sebagai pembangkit suara dan arduino sebagai pengontrol modul suara.

Suara PWM arduino

Port output arduino mampu melewatkan arus 40mA setiap pinnya, artinya arduno masih mampu membangkitkan suara untuk keperluan headset. Selain keuntungan itu, arduino juga memiliki memory walaupun kapasitasnya kecil, seperti pada arduino uno mampu menampung kurang dari 8detik data PCM 8bit 8KHz yang membutuhkan 8.000 byte flash memory setiap detiknya. Untuk efesiensi memory bisa dengan menurunkan sampling rate atau menggunakan sistem kompresi ADPCM.

prinsip kerja Suara PCM Arduino dengan PWM:

  1. Data suara disimpan dalam memory flash.
  2. Dibutuhkan dua timer, timer1 berfungsi mengatur waktu sampling (misalnya 8KHz, 16KHz dst), dan timer 2 yang berfungsi mengatur PWM Sesuai ukuran bit sampling (misalnya 8bit dan 16 bit).
  3. Data PWM berubah dan dikirim saat timer1 selesai 1 periode sampling.

Keterbatasan PCM arduino adalah : waktu * ukuran sampling tidak bisa melebihi besar clock arduino 16MHz.

Contoh rangkaian suara arduino langsung :

 

Modul Suara WTV020

 

Modul ini menggunakan format suara .ad4 yang disimpan dalam kartu memory microSD (kapasitas terbatas). Pengontrolan menggunakan pin-pin kontrol dengan mode operasi yang tersedia:

  1. MP3 mode
  2. Key mode(3 group of voice)
  3. Key mode(5 group of voice)
  4. Loop play mode
  5. Two line serial mode

Modul suara ISD

Modul ISD menggunakan chip yang memiliki fitur rekam dan membangkitkan suara. terdiri dari beberapa seri dan kapasitas.

Modul mini MP3 TF Player

 

Mini Mp3 TF Player banyak disukai karena murah dan mudah dalam operasionalnya, mampu menggerakkan speaker 0.5Watt, dan menggunakan protokol Serial frame. Data suara disimpan dalam format MP3 / WAV dalam microSD.

Modul Suara VS1053

VS1053 merupakan chip audio player yang powerfull dengan kualitas suara yang bagus. Data suara dalam format MP3 yang disimpan dalam microSD.

Perbandingan modul suara arduino

Masih terdapat beberapa modul suara yang bisa disandingkan dengan arduino, yang disebutkan diatas bisa mewakili yang paling umum digunakan dalam perancangan perangkat multimedia berbasis arduino.

Kualitas suara yang dihasilkan menjadi alasan utama dari pemilihan modul audio untuk arduino, dan menurut penulis kualitas modul VS1053 paling baik dan layak digunakan sebagai media informasi. sedangkan modul lainnya efektif digunakan dalam pengembangan perangkat karena harganya relatif lebih murah.

Kualitas suara bisa ditingkatkan dengan memperhatikan hal berikut:

  1. Filter keluaran suara
  2. Power supply / catu daya yang cukup dan tidak saling menmpengaruhi dengan modu lainnya.
  3. Penggunaan speaker yang sesuai, kalau perlu gunakan box.
  4. Konversi suara mono ke stereo atau sebaliknya menggunakan cara koneksi yang benar.
  5. Konversi suara single supply ke balance double supply atau sebaliknya menggunakan cara konversi yang benar.

Memainkan suara 4-bit ADPCM langsung dari arduino

Rancangan bangun berbasis arduino kurang lengkap tanpa adanya suara. Fungsi suara tergantung kebutuhan, yang paling diutamakan adalah informasi audio. Perangkat audio arduino yang umum digunakan adalah mp3 shield, dan data suara mp3 disimpan dalam kartu memori/SDCard.

Untuk memainkan file suara dengan Arduino atau musik arduino memiliki permasalahan :

  1. Arduino memiliki memori flash yang kecil (Uno 32KB, Mega 256KB)
  2. Port yang hanya mampu mengeluarkan (source/sink) arus sebesar 40mA setiap pin.
  3. Kecepatan clock arduino yang hanya 16MHz, membatasi sampling rate dan ukuran sample.

Untuk menyimpan data suara lebih panjang kita bisa menggunakan data terkompresi, Salah satu sistem kompresi sederhana adalah 4-bit ADPCM (Adaptive differential pulse-code modulation), yaitu kompresi data suara kedalam 4-bit sehinggan file suara PCM yang umumnya 8-bit atau 16-bit bisa diperkecil menjadi 4-bit. Arduino adpcm juga bisa digunakan sebagai alternatif penggunaan modul suara WTV020SD yang juga bisa memainkan file dalam format 4-bit adpcm (.ad4)

Dalam contoh ini saya menggunakan sample rate 8KHz dan ukuran(size) sample 9 bit, alternatif yang disediakan 16KHz – 8 bit. Dengan properti 8KHz-9Bit, kompresi 4-bit ADPCM hanya menggunakan 4Kb setiap detiknya, sehingga uno mampu menyimpan 6 detik data suara (ruang memory lainnya digunakan oleh program), sedangkan mega mampu menampung 62 detik data suara.

untuk memaksimalkan arus port Arduino, saya menggunakan speaker 32Ohm.

Urusan memperhalus suara yang akan dihasilkan saya menggunakan metode bridge (tanpa kapasitor kopling) dengan menggunakan pin 9 dan 10 yang terhubung ke Timer1.

komponen:

  1. Arduino Uno
  2. Speaker 32ohm/head phone

skema:

Sketch / program :

 
#include "Selamat-datang-8000.h"
 
#define speakerA 9
#define speakerB 10
 
const int8_t IndexTable[16] = {
    -1, -1, -1, -1, 2, 4, 6, 8,
    -1, -1, -1, -1, 2, 4, 6, 8
};
int16_t StepSizeTable[89] = {
    7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
    19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
    50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
    130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
    337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
    876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
    2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
    5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
    15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
};
struct AD4Header
{
  byte ad4Code;
  char ad4Sign[4];
  uint16_t ad4SampleRate;
};
#define ad4DataOffset 6
 
long predsample;
int8_t index;
uint16_t panjangSuara;
uint16_t sampleCounter;
byte *dataSuara;
bool PWMUpdate;
bool swap;
AD4Header ad4Header;
bool suaraDimainkan;
 
void setup(void)
{
  pinMode(speakerA, OUTPUT);
  pinMode(speakerB, OUTPUT);
 
  Serial.begin(9600);
  Serial.println("Memainkan suara 4-bit ADPCM dengan arduino");
  Serial.println("https://www.semesin.com/project/");
}
 
void loop(void)
{
  if(!suaraDimainkan)
  {
    mainkanSuara(dataSuaraSelamatDatang8000, sizeof(dataSuaraSelamatDatang8000));
  }
  else
  {
    lanjutkanSuara();
  }
}
 
void mainkanSuara(const byte *fileSuara, uint16_t ukuranFileSuara)
{
  dataSuara = (byte*)fileSuara;
   
  ad4Header.ad4Code = pgm_read_byte_near(dataSuara + 0);
  ad4Header.ad4Sign[0] = pgm_read_byte_near(dataSuara + 1);
  ad4Header.ad4Sign[1] = pgm_read_byte_near(dataSuara + 2);
  ad4Header.ad4Sign[2] = pgm_read_byte_near(dataSuara + 3);
  ad4Header.ad4Sign[3] = 0;
  ad4Header.ad4SampleRate = pgm_read_word_near(dataSuara + 4);
 
  Serial.println();
  Serial.println("Memainkan file suara");
  Serial.print("Sample Rate : ");
  Serial.print(ad4Header.ad4SampleRate);
  Serial.println("Hz");
  Serial.print("Ukuran : ");
  Serial.println(ukuranFileSuara);
 
  if(ad4Header.ad4SampleRate == 16000)
  {
    ICR1 = 512;
  }
  else if(ad4Header.ad4SampleRate == 8000)
  {
    ICR1 = 1024;
  }
 
  TCCR1A = _BV(COM1A1) | _BV(COM1B1);
  TCCR1B = _BV(WGM13) | _BV(CS10);
 
  panjangSuara = ukuranFileSuara;
  sampleCounter = ad4DataOffset;
  predsample = 0;
  index = 0;
  swap = false;
  suaraDimainkan = true;
}
 
void lanjutkanSuara()
{
  if(TIFR1 & _BV(TOV1))
  {
    TIFR1 |= _BV(TOV1);
    if (sampleCounter > panjangSuara)
    {
      stopPlayback();
    }
    else
    {
      byte data = pgm_read_byte_near(dataSuara + sampleCounter);
      if(!swap)
      {
        data >>= 4;
      }
      else
      {
        sampleCounter++;  
      }
      swap = !swap;
   
      int16_t sample;
      if(ad4Header.ad4SampleRate == 16000)
      {
        sample = (ADPCMDecoder(data & 0x0F)/128) + 256;
        OCR1B = 512 - sample;
      }
      else if(ad4Header.ad4SampleRate == 8000)
      {
        sample = (ADPCMDecoder(data & 0x0F)/64) + 512;
        OCR1B = 1024 - sample;
      }
      OCR1A = sample;    
    }            
  }
}
int16_t ADPCMDecoder(byte codeNibble)
{
  uint16_t sample;
  int16_t diffq;
  uint16_t step;
 
  step = StepSizeTable[index];
 
  diffq = step >> 3;
  if( codeNibble & 4 )
    diffq += step;
  if( codeNibble & 2 )
    diffq += step >> 1;
  if( codeNibble & 1 )
    diffq += step >> 2;
   
  if( codeNibble & 8 )
    predsample -= diffq;
  else
    predsample += diffq;
 
  index += IndexTable[codeNibble];
 
  if( index < 0 )
    index = 0;
  if( index > 88 )
    index = 88;
 
  if( predsample > 32767 )
    predsample = 32767;
  else if( predsample < -32768 )
    predsample = -32768;
 
  return predsample;
}
 
void stopPlayback()
{
  TIMSK1 &= ~_BV(OCIE1A);
  TCCR1B &= ~_BV(CS10);
  if(ad4Header.ad4SampleRate == 16000)
  {
    OCR1A = 256;
    OCR1B = 256;
  }
  else if(ad4Header.ad4SampleRate == 8000)
  {
    OCR1A = 512;
    OCR1B = 512;
  }
  digitalWrite(speakerA, LOW);
  digitalWrite(speakerB, LOW);
 
  suaraDimainkan = false;
}

contoh file suara (copy-kan ke folder sketch arduino)

Selamat datang 8000.h

untuk mengkonversi file .wav atau .mp3 ke file .ad4 bisa menggunakan software 4D-SOMO-Tool (tidak direkomendasikan menggunakan ad4Converter karena software ini tidak menyertakan header). kemudian file .ad4 tersebut dijadikan .h dengan software bin2c.

suara bilangan hingga 999.999 dengan arduino

Modul suara arduino yang ada sudah memenuhi kebutuhan perancangan multimedia saat ini, seperti modul suara WTV020SD, mini TF MP3 player, MP3 shield dan lain-lain. Suara arduino bisa digunakan sebagai alarm peringatan, pengisi suara, suara latar, pemberitahuan dan keperluan lainnya.

Dalam perancangam suara dengan arduino kali ini diperuntukkan sebagai pembilang angka dan bisa diterapkan dalam berbagai proyek arduino. Angka/bilangan berasal dari pembacaan sensor dan dikirim ke modul suara.

Pada modul suara sudah disimpan dalam memorinya (microSD) berbagai macam kemungkinan suara angka dengan urutan tertentu. Arduino berfungsi sebagai pengatur suara angka yang akan diputar.

Suara pembilang arduino dimulai dengan kata pembuka contohnya “nomor antrian”, kemudian diikuti suara deret angka dan terakhir satuannya misalnya “di loket 1”.

Suara bilangan sampai 999.999 dengan komponen :

  1. arduino mega 2560
  2. MP3 DFPlayer
  3. Ampli modul LM386 (bila ada)

Bisa dikombinasikan sebagai pemberi suara :

  1. Mesin timbangan yang menginformasikan berat terukur
  2. Pemberi tahu bila jarak terlalu dekat pada sistem keamanan parkir
  3. Pengingat suhu dan kelembaban dengan sensor humidity
  4. Informasi kecepatan kendaraan kecepatan
  5. Suara antrian pada mesin antrian di perkantoran
  6. Pembilang total belanja
  7. dll

Video:

skema suara informasi arduino:

sketch/program:


#include <miniMP3.h>

#define belas 12 //belas.mp3
#define puluh 13 //puluh.mp3
#define seratus 14 //seratus.mp3
#define ratus 15 //ratus.mp3
#define seribu 16 //seribu.mp3
#define ribu 17 //ribu.mp3
#define koma 18 //Koma.mp3

#define berat 110 //berat.mp3
#define gram 111 //gram.mp3
#define kiloGram 112 //kilogram.mp3
#define jarak 120 //jarak.mp3
#define sentiMeter 121 //sentimeter.mp3
#define meter 122 //meter.mp3
#define suhu 130 //suhu.mp3
#define derajat 131 //derajat_celsius.mp3
#define ph 140 //P_H.mp3
#define kelembaban 150 //Kelembaban.mp3
#define persen 151 //Persen.mp3
#define kecepatan 160 //kecepatan.mp3
#define meterPerDetik 161 //meter_per_detik.mp3
#define kilometerPerJam 162 //kilometer_per_jam.mp3
#define nomorantrian 170 //nomor antrian.mp3
#define totalBelanja 180 //total belanja.mp3
#define rupiah 181 //rupiah.mp3

void setup() {
  mp3_set_serial (Serial1, 17);
  mp3_set_volume(30);

  uint32_t beratTimbangan = 0;
  
  mp3_play(berat);
  suaraBilangan(beratTimbangan);
  mp3_play(gram);
}

void loop() {

}

void suaraBilangan(uint32_t Bilangan)
{
  if(Bilangan < 100)
  {
    suaraPuluhan(Bilangan);
  }
  else if(Bilangan < 1000)
  {
    suaraRatusan(Bilangan);
  }
  else
  {
    suaraRibuan(Bilangan);
  }
}
void suaraPuluhan(uint8_t Bilangan)
{
  if(Bilangan < 12)
  {
    mp3_play(Bilangan);
  }
  else if(Bilangan < 20)
  {
    mp3_play(Bilangan - 10);
    mp3_play(belas);
  }
  else
  {
    uint8_t puluhan = Bilangan/10;
    mp3_play(puluhan);
    mp3_play(puluh);

    puluhan *= 10;
    if(Bilangan - puluhan != 0)
    {
      mp3_play((Bilangan - puluhan));
    }
  }
}
void suaraRatusan(uint16_t Bilangan)
{
  uint8_t ratusan = (uint8_t)(Bilangan/100);
  if(ratusan == 1)
  {
    mp3_play(seratus);
  }
  else
  {
    mp3_play(ratusan);
    mp3_play(ratus);
  }
  if(Bilangan % 100)
  {
    suaraPuluhan(Bilangan - (ratusan*100));
  }
}
void suaraRibuan(uint32_t Bilangan)
{
  uint16_t ribuan= (uint16_t)(Bilangan/1000);
  if(ribuan == 1)
  {
    mp3_play(seribu);
  }
  else if(ribuan < 100)
  {
    suaraPuluhan(ribuan);
    mp3_play(ribu);   
  }
  else
  {
    suaraRatusan(ribuan);
    mp3_play(ribu);   
  }
  if(Bilangan % 1000)
  {
    suaraRatusan(Bilangan - (ribuan*1000));
  }
}

file pendukung:
Suara : Suara bilangan mp3
Library : miniMP3