Fungsi Waktu App Inventor

Data waktu pada App Inventor berupa tanggal dan waktu yang dinyatakan dalam orde milidetik dari 1 Januari 1970. Data waktu ini bisa digunakan untuk beberapa keperluan diantaranya hitung mundur dan durasi.

Data waktu Sekarang (now)

Interface / modul clock memiliki fungsi ‘now’ yang menyediakan data waktu serta fungsi format datetime guna mendapatkan text waktu yang diinginkan.

Block diatas akan mengganti text pada label1 dengan text waktu sekarang dalam format MM/dd/yyyy hh:mm:ss a. Penggantian dilakukan setiap interval dari clock1 (default 1 detik).

Ambil waktu sistem android

Untuk mengambil data waktu ketika tombol di tekan dengan format tertentu bisa menggunakan block berikut:

Ketika button1 ditekan, text pada label2 akan diganti dengan waktu sekarang dalam format hh:mm.

Edit data waktu dengan TimePicker

TimePicker berfungsi sebagai dialog pengedit waktu dengan nilai default waktu sekarang (now)

Ketika tombol [selesai] pada dialog timePicker ditekan, text pada tombol [TimePicker] akan diganti dengan hasil pengeditan jam dan menit.

Angka dua digit (time pattern) app inventor

Agar tampilan waktu jam:menit terlihat rapi dalam format waktu hh:mm, App inventor 2 belum mengakomodir text pattern (kecuali sensor clock), untuk itu bisa dikombinasikan dengan perhitungan matematis yakni apabila angka kecil dari 10 maka akan ditambahkan ‘0’ diawalnya.

Hitung mundur (Countdown)

Hitung mundur adalah metode penghitungan waktu tunda. Hitung mundur bisa dimanfaatkan untuk berbagai keperluan seperti aktifasi sebuah interface/screen dan sebagainya.

Hitung mundur dengan app inventor diaplikasikan dalam orde mili detik, agar lebih mudah waktu hitung mundur dikonversi menjadi detik dengan fungsi DurationToSeconds.

Untuk perancangan hitung mundur dengan app inventor dibutuhkan variabel waktu mulai dan durasi. Dengan bantuan ‘Clock’ penghitungan dideteksi setiap detik.

Hitung munder dengan metode time epoch ini bisa disetting dalam orde tahunan atau sesuai kebutuhan.

Menghitung durasi dengan app inventor

Durasi / selisih waktu adalah waktu yang dibutuhkan antara dua evenr/trigger, hasilnya diperoleh dengan formula waktu event2 dikurangi waktu event1.

Penghitungan durasi diukur dalam orde mili detik.

Block lengkap fungsi waktu menggunakan app inventor:

Design fungsi waktu dengan app inventor:

Tampilan app fungsi waktu memakai app inventor:

File apk fungsi waktu pada app inventor: FungsiWaktu.apk

Hitung mundur Arduino (volatile countdown)

Hitung mundur volatile (tidak menguap) adalah metode hitung mundur digital yang terus berlangsung walaupun catu daya (power supply) dimatikan. Jadi hitung mundur berlanjut sesuai waktu normal ketika catu daya aktif kembali.

Countdown arduino ini berfungsi sebagai penghitung mundur hingga jangka tahunan karena menggunakan metode epoch time. Waktu acuan yang digunakan adalah waktu RTC (DS1307/DS3231).

Waktu epoch adalah jumlah detik hingga saat ini dari tangga 1 Januari 1970.

Hitung mundur menggunakan Arduino dan RTC memanfaatkan EEPROM untuk menyimpan data-data berikut :

  1. Aktif
  2. Waktu mulai hitung mundur (epoch waktu)
  3. Waktu hitung mundur (dalam detik)

Karena perangkat ini memiliki fitur volatile maka dibutuhkan mekanisme pengujian/pengecekan data waktu yang disimpan yaitu :

  1. Apakah ada hitung mundur yang aktif
  2. Jika aktif apakah epoch waktu sekarang lebih besar dari epoch waktu hitung mundur mulai
  3. jika aktif apakan epoch waktu sekarang kecil dari jumlah epoch waktu mulai ditambah jumlah detik hitung mundur.

jika syarat ini di penuhi maka hitung mundur dengan arduino dilanjutkan.

berikut skema Arduino countdown (berlaku untuk DS1307/DS3231):

koding / sketch arduino hitung mundur:

#include <Wire.h>
#include <TimeLib.h>
#include <DS1307RTC.h>
#include <EEPROM.h>

#define alamatEEPROMCountDownAktif  0
#define alamatEEPROMCountDownMulai  1
#define alamatEEPROMCountDownDetik  5

byte countDownAktif;
uint32_t countDownMulai;
uint32_t countDownDetik;
uint32_t RTCEpoch;
byte detikSebelumnya = 60;

void setup() {
  Serial.begin(9600);
  Serial.println("Hitung mundur Arduino (volatile countdown)");
  Serial.println("https://www.project.semesin.com/");
  Serial.println("Entri waktu hitung mundur (dalam detik) :");
  Serial.println();

  countDownAktif = EEPROM.read(alamatEEPROMCountDownAktif);
  if(countDownAktif)
  {
    EEPROM.get(alamatEEPROMCountDownMulai, countDownMulai);
    EEPROM.get(alamatEEPROMCountDownDetik, countDownDetik);
    Serial.println("Hitung mundur aktif");
  }
  
}

void loop() {
  tmElements_t tm;

  if(Serial.available())
  {
    if (RTC.read(tm))
    {
      delay(200);
      countDownDetik = Serial.parseInt();
      countDownMulai = makeTime(tm);
      countDownAktif = true;
      EEPROM.write(alamatEEPROMCountDownAktif, countDownAktif);
      EEPROM.put(alamatEEPROMCountDownDetik, countDownDetik);
      EEPROM.put(alamatEEPROMCountDownMulai, countDownMulai);
      Serial.println("Waktu hitung mundur = " + String(countDownDetik) + " detik");
    }
    else
    {
      Serial.println("Gagal membaca RTC");
    }
  }
  
  if (RTC.read(tm)) 
  {
    if(detikSebelumnya != tm.Second)
    {
      if(countDownAktif)
      {
        RTCEpoch = makeTime(tm);
        uint32_t waktuCountDown = countDownDetik - (RTCEpoch - countDownMulai);
        Serial.println("Hitung mundur : " + String(waktuCountDown) + " detik");
  
        if(RTCEpoch < countDownMulai)
        {
          countDownAktif = false;
          EEPROM.write(alamatEEPROMCountDownAktif, countDownAktif);
          Serial.println("Hitung mundur di matikan karena Waktu RTC salah");
          Serial.println("Entri waktu hitung mundur (dalam detik) :");
        }
        else if(RTCEpoch > (countDownMulai + countDownDetik))
        {
          countDownAktif = false;
          EEPROM.write(alamatEEPROMCountDownAktif, countDownAktif);
          Serial.println("Hitung mundur kadaluarsa");
          Serial.println("Entri waktu hitung mundur (dalam detik) :");
        }
        else if(waktuCountDown == 0)
        {
          countDownAktif = false;
          EEPROM.write(alamatEEPROMCountDownAktif, countDownAktif);
          Serial.println("Hitung mundur berakhir");
          Serial.println("Entri waktu hitung mundur (dalam detik) :");
        }
      }
      detikSebelumnya = tm.Second;
    }
  }
  else
  {
    Serial.println("Gagal membaca RTC");
  }
  delay(100);
}

Keluaran serial monitor hitung mundur berbasis arduino:

Menu LCD Arduino dengan keypad

Aplikasi menu arduino memang menarik namun tidak mudah untuk dibuat. Arduino menggunakan menu merupakan aplikasi yang menampilkan sejumlah pilihan sehingga pengguna bisa memilih/merubah pilihannya.

Menu interaktif lebih cocok digunakan apabila sejumlah pilihan tidak bisa ditampilkan dalam satu halaman. Misalnya menampilkan menu pada LCD karakter 16×2 yang hanya bisa menampung 16 karakter setiap barisnya.

Salah satu menu yang sering digunakan adalah menu-menu makanan dan minuman pada penerapan restoran yang menggunakan sistem digital terkoneksi.

Kelebihan Menu I2C LCD Arduino ini adalah:

  1. Tampilan interaktif bergilir setiap 1 detik dan tampil 5 detik ketika hendak dipilih.
  2. Menggunakan keypad 4×4 sehingga lebih lega.

Video menu interaktif arduino:

Dalam perancangan berbasis arduino ini digunakan komponen berikut :

  1. Arduino Uno
  2. LCD 1602 + I2C
  3. Keypad 4×4

skema menu arduino LCD dan keypad:

koding/sketch menu keypad arduino:

#include <LiquidCrystal_I2C.h>
#include <Keypad.h>

const byte ROWS = 4; //four rows
const byte COLS = 4; //three columns
char keys[ROWS][COLS] = {
  {'1', '2', '3', 'A'},
  {'4', '5', '6', 'B'},
  {'7', '8', '9', 'C'},
  {'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {4, 5, 6, 7};
byte colPins[COLS] = {8, 9, 10, 11};

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );

LiquidCrystal_I2C lcd(0x3F, 16, 2);

struct daftarMenu {
  char strMenu[17];
  uint32_t harga;
  bool pilihan;
};

char menuUtama[][17] = {
  "0..9 - Pilih    ",
  "* - Pilih       ",
  "# - Batal       ",
  "A - Makanan     ",
  "B - Minuman     ",
  "C - Total/Pesan ",
  "D - Batal       ",
};
daftarMenu menuMakanan[] = {
  {"1 Nasi Goreng   ", 13000L, false},
  {"2 Mie Goreng    ", 8000L, false},
  {"3 Bihun Goreng  ", 8000L, false},
  {"4 Mie Rebus     ", 6000L, false},
  {"5 Gado-gado     ", 13000L, false},
  {"6 Soto Padang   ", 15000L, false},
  {"7 Sate Padang   ", 18000L, false},
};
daftarMenu menuMinuman[] = {
  {"1 Es Campur     ", 6000L, false},
  {"2 Es Tebak      ", 7500L, false},
  {"3 Es Kosong     ", 2000L, false},
  {"4 Jus Jeruk     ", 6000L, false},
  {"5 Jus Pokat     ", 6500L, false},
  {"6 Kopi          ", 4000L, false},
  {"7 Teh Panas     ", 4000L, false},
  {"8 Teh Telur     ", 8000L, false},
};

int8_t indexMenu = -1;
byte menuLevel = 0;
byte menuLevelSebelumnya = -1;

enum ModeMenu {
  modeMenuMakanan,
  modeMenuMinuman,
};
ModeMenu modeMenu;
#define standarWaktuTampil  1000L
#define LihatWaktuTampil    5000L
#define jumlahMakanan       sizeof(menuMakanan)/sizeof(menuMakanan[0])
#define jumlahMinuman       sizeof(menuMinuman)/sizeof(menuMinuman[0])

uint16_t waktuTampil;
unsigned long millisMulai;

void setup()
{
  Serial.begin(9600);
  Serial.println("Menu LCD Arduino dengan keypad");
  Serial.println("https://www.project.semesin.com/");

  Wire.begin();
  Wire.beginTransmission(0x3F);
  if (Wire.endTransmission())
  {
    lcd = LiquidCrystal_I2C(0x27, 16, 2);
  }
  lcd.begin ();
  lcd.backlight();
  //  tampilanDepan();
  millisMulai = millis();
  resetPilihan();
}

void loop()
{
  char key = keypad.getKey();

  if (key) {
    Serial.println(key);
    switch (key)
    {
      case 'A':
        menuLevel = 1;
        indexMenu = -1;
        modeMenu = modeMenuMakanan;
        break;
      case 'B':
        menuLevel = 1;
        indexMenu = -1;
        modeMenu = modeMenuMinuman;
        break;
      case 'C':
        menuLevel = 2;
        updateMenu();
        break;
      case 'D':
        resetPilihan();
        menuLevel = 0;
        indexMenu = -1;
        updateMenu();
        break;
      case '*':
        if (menuLevel == 2)
        {
          pesananMasuk();
        }
        else
        {
          if (waktuTampil == LihatWaktuTampil)
          {
            if (modeMenu == modeMenuMakanan)
            {
              menuMakanan[indexMenu].pilihan = true;
            }
            else if (modeMenu == modeMenuMinuman)
            {
              menuMinuman[indexMenu].pilihan = true;
            }
            updateMenu();
          }
          else
          {
            waktuTampil = LihatWaktuTampil;
            millisMulai = millis();
          }
        }
        break;
      case '#':
        if (menuLevel == 2)
        {
          menuLevel = 1;
        }
        else
        {
          if (waktuTampil == LihatWaktuTampil)
          {
            if (modeMenu == modeMenuMakanan)
            {
              menuMakanan[indexMenu].pilihan = false;
            }
            else if (modeMenu == modeMenuMinuman)
            {
              menuMinuman[indexMenu].pilihan = false;
            }
            updateMenu();
          }
          else
          {
            waktuTampil = LihatWaktuTampil;
            millisMulai = millis();
          }
        }
        break;
      default:
        indexMenu = key - '1';
        updateMenu();
        millisMulai = millis();
        waktuTampil = LihatWaktuTampil;
        break;
    }
  }

  if (millis() - millisMulai > waktuTampil)
  {
    millisMulai = millis();
    waktuTampil = standarWaktuTampil;
    indexMenu++;
    updateMenu();
    menuLevelSebelumnya = menuLevel;
  }
}
void pesananMasuk()
{
  //Aksi pesanan masuk
  lcd.setCursor(0, 0);
  lcd.println("  Terima Kasih  ");
  lcd.setCursor(0, 1);
  lcd.println("Silahkan tunggu ");
  delay(3000);
  Serial.println("Pesanan masuk!!!");
  menuLevel = 0;
  indexMenu = -1;
}
void updateMenu()
{
  if (menuLevel == 0)
  {
    if (indexMenu == sizeof(menuUtama) / sizeof(menuUtama[0]))
    {
      indexMenu = 0;
    }
    if (menuLevelSebelumnya != menuLevel)
    {
      lcd.clear();
      lcd.print("Selamat Datang");
    }
    tampilMenuUtama(indexMenu);
  }
  else if (menuLevel == 2)
  {
    lcd.setCursor(0, 0);
    lcd.print("Rp. ");
    formatStrHarga(totalPilihan());
    lcd.setCursor(0, 1);
    lcd.print("* Ya   # kembali");
  }
  else if (modeMenu == modeMenuMakanan)
  {
    if (indexMenu >= jumlahMakanan)
    {
      indexMenu = 0;
    }
    tampilMenuMakanan(indexMenu);
  }
  else if (modeMenu == modeMenuMinuman)
  {
    if (indexMenu >= jumlahMinuman)
    {
      indexMenu = 0;
    }
    tampilMenuMinuman(indexMenu);
  }
}
void resetPilihan()
{
  for (byte i = 0; i < jumlahMakanan; i++)
  {
    menuMakanan[i].pilihan = false;
  }
  for (byte i = 0; i < jumlahMinuman; i++)
  {
    menuMinuman[i].pilihan = false;
  }
}
uint32_t totalPilihan()
{
  uint32_t total = 0;
  for (byte i = 0; i < jumlahMakanan; i++)
  {
    if (menuMakanan[i].pilihan)
    {
      total += menuMakanan[i].harga;
    }
  }
  for (byte i = 0; i < jumlahMinuman; i++)
  {
    if (menuMinuman[i].pilihan)
    {
      total += menuMinuman[i].harga;
    }
  }
  return total;
}
void tampilMenuUtama(byte index)
{
  lcd.setCursor(0, 1);
  lcd.print(menuUtama[index]);
}
void tampilMenuMakanan(byte index)
{
  lcd.setCursor(0, 0);
  lcd.print(menuMakanan[index].strMenu);
  lcd.setCursor(0, 1);
  lcd.print("Rp. ");
  formatStrHarga(menuMakanan[index].harga);
  if (menuMakanan[index].pilihan)
  {
    lcd.setCursor(15, 1);
    lcd.print("*");
  }
}
void tampilMenuMinuman(byte index)
{
  lcd.setCursor(0, 0);
  lcd.print(menuMinuman[index].strMenu);
  lcd.setCursor(0, 1);
  lcd.print("Rp. ");
  formatStrHarga(menuMinuman[index].harga);
  if (menuMinuman[index].pilihan)
  {
    lcd.setCursor(15, 1);
    lcd.print("*");
  }
}
void formatStrHarga(uint32_t harga)
{
  String strHarga = String(harga);
  uint8_t panjangStr = strHarga.length();
  uint8_t offset = 3 - (panjangStr % 3);
  for (byte i = 0; i < strHarga.length(); i++)
  {
    lcd.print(strHarga[i]);
    if (!((strHarga.length() + i - offset + 1) % 3))
    {
      if (i != strHarga.length() - 1)
      {
        lcd.print('.');
      }
    }
  }
  for (byte i = 0; i < 16 - 5 - strHarga.length(); i++)
  {
    lcd.print(' ');
  }
}

Library:

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.

Simpan dan ambil data setting menggunakan metode list pada App Inventor

Database tinyDB

Cara menyimpan data input app inventor agar dapat ditampilkan kembali saat app dibuka kembali adalah dengan memanfaatkan media storage seperti TinyDB untuk menyimpan data tersebut. Data-data yang disimpan dalam database TinyDB diberi index/tag tertentu. Untuk mengambil data dari TinyDB dibutuhkan input/tag yang sesuai.

Kegunaan menyimpan data ke dalam database TinyDB adalah supaya data yang telah di entri tidak hilang setelah app ditutup.

List interface / object

Penggunaan interface dalam jumlah besar pada App Iventor sebaiknya menggunakan list, karena dengan list proses pengambilan dan penyimpanan hasil lebih mudah dan memperpendek block.

berikut keterangan block perancangan apk App Inventor:

Tahap awal penggunaan list adalah dengan menginisialisasi-nya sebagai list kosong (empty list) masing-masing kelompok interface (seperti checkbox dan textbox)

Kemudian list-list tersebut ditambahkan item yang bersesuaian, dalam contoh ini checkbox1, checkbox2, checkbox3 ditambahkan dalam list Array_checkbox. dan textbox1, textbox2, textbox3 ditambahkan dalam list Array_textbox.

Selanjutnya prosedur ambil_dari_database dipanggil untuk mengambil data-data yang tersimpan sebelumnya ke dalam masing-masing item list.

Prosedur ini menggunakan metode list dengan memecah item-item dalam variabel Array_checkbox dan Array_textbox.

Prosedur ambil data dari database akan melaksanakan fungsi mengambil data-data dari tinyDB dengan tag checkbox1, checkbox2, checkbox3 dan textbox1, textbox2, textbox3.

Prosedur Simpan_ke_database berfungsi menyimpan data-data yang telah di entry  kedalam database dengan tag/index tertentu.

Contoh penggunaan prosedur simpan_ke_database adalah saat pengguna / user menekan tombol back. Sebelum keluar dari app, terlebih dahulu dipanggil prosedur Simpan_ke_database untuk menyimpan data-data entri interface untuk digunakan kembali saat app dibuka selanjutnya.

blok app Inventor cara menyimpan data dan cara menggunakan list yang digunakan :

Design screen app inventor dengan banyak interface serupa yang di kelompokkan kedalam list yang berguna mempersingkat perulangan block.

dan apk cara menggunakan database app Inventor yang dipakai dalam contoh ini:

SimpanDanAmbilDataSetting.apk

Tampilan seven segment dengan metode scanning menggunakan arduino

Seven segment banyak digunakan sebagai tampilan dari sebuah perangkat, terutama tampilan angka. Seven segment telah tersedia dalam berbagai macam teknologi serta kelebihan masing-masing. Seven segment jenis LED memiliki kelebihan mampu menghasilkan cahaya sendiri sehingga terlihat lebih terang. Sedangkan seven segmen LCD hanya membutuhkan daya kecil untuk operasi-nya.

Setiap segment dari 7segment memiliki paling kurang 8 pin yaitu 7 pin untuk digit, dan 1 pin untuk CA/CC. Untuk membentuk deret angka seven segment digabungkan menjadi beberapa digit. Untuk mengontrol banyak digit seven segment biasanya digunakan metode scanning. Melalui metode scanning ini penggunaan pin menjadi lebih efisien.

Cara menghubungkan seven segment dengan arduino bisa menggunakan transistor array dan BCD to seven segment. Apabila menggunakan seven segment ukuran kecil misalnya ukuran 0.5″, bisa saja seven segment-nya dihubungkan langsung ke arduino seperti contoh berikut:

skema rangkaian seven segment menggunakan arduino:

tata letak seven segment:

sketch atau program scanning seven segment menggunakan arduino:

#include <TimerOne.h>

#define CCorCA            1//0 = CC, 1 = CA
#define jumlah7Segment    4

#define pin1    A0
#define pin2    A1
#define pin3    A2
#define pin4    A3

#define pinA    4
#define pinB    5
#define pinC    6
#define pinD    7
#define pinE    8
#define pinF    9
#define pinG    10
#define pinDot  11

byte pin7Segment[] = {pinA, pinB, pinC, pinD, pinE, pinF, pinG};
byte pin7SegmentCommon[] = {pin1, pin2, pin3, pin4};

const char angka[] = {
  0b00111111,
  0b00000110,
  0b01011011,
  0b01001111,
  0b01100110,
  0b01101101,
  0b01111100,
  0b00000111,
  0b01111111,
  0b01100111,
  0b00000000,//blank
  0b01000000,//strip
  0b01101101,//S
  0b00000100,//i
  0b01011111,//a
  0b01110011,//p

};
#define Seg_blank 10
#define Seg_stip 11
#define Seg_S 12
#define Seg_i 13
#define Seg_a 14
#define Seg_p 15

#define dotBlank 6
#define dotAll   5

volatile byte nilai7Segment[4];
volatile byte lastScanIndex = 0;
volatile byte index7Segment = 0;
volatile byte posisiTitik;

void setup() {
  Serial.begin(9600);
  Serial.println("Tampilan 7 Segment metode scanning menggunakan arduino");
  Serial.println("https://www.project.semesin.com/");
  Serial.println();

  pinMode(pin1, OUTPUT);
  pinMode(pin2, OUTPUT);
  pinMode(pin3, OUTPUT);
  pinMode(pin4, OUTPUT);

  pinMode(pinA, OUTPUT);
  pinMode(pinB, OUTPUT);
  pinMode(pinC, OUTPUT);
  pinMode(pinD, OUTPUT);
  pinMode(pinE, OUTPUT);
  pinMode(pinF, OUTPUT);
  pinMode(pinG, OUTPUT);
  pinMode(pinDot, OUTPUT);

  Timer1.initialize(2000);
  Timer1.attachInterrupt( timerIsr );

  nilai7Segment [3] = Seg_S;
  nilai7Segment [2] = Seg_i;
  nilai7Segment [1] = Seg_a;
  nilai7Segment [0] = Seg_p;
  posisiTitik = dotBlank;
  delay(1000);
}

void loop() {
  for (uint16_t i = 0; i < 10000; i++)//0 .. 99.99
  {
    uint32_t BCD = Convert_IntToBCD32(i);
    nilai7Segment [0] = (BCD >> 0) & 0x0F;
    nilai7Segment [1] = (BCD >> 4) & 0x0F;
    nilai7Segment [2] = (BCD >> 8) & 0x0F;
    nilai7Segment [3] = (BCD >> 12) & 0x0F;
    posisiTitik = 2;
    delay(100);
  }
}

void timerIsr()
{
  digitalWrite(pin7SegmentCommon[lastScanIndex], CCorCA ? LOW : HIGH);
  drive7Segment(nilai7Segment[index7Segment]);
  if (posisiTitik == dotAll)
  {
    digitalWrite(pinDot, CCorCA ? LOW : HIGH);
  }
  else if (posisiTitik == dotBlank)
  {
    digitalWrite(pinDot, CCorCA ? HIGH : LOW);
  }
  else
  {
    digitalWrite(pinDot, (index7Segment == posisiTitik) ? CCorCA ? LOW : HIGH : CCorCA ? HIGH : LOW);
  }
  digitalWrite(pin7SegmentCommon[index7Segment], CCorCA ? HIGH : LOW);
  lastScanIndex = index7Segment++;
  if (index7Segment >= jumlah7Segment)index7Segment = 0;
}
void drive7Segment(byte nilai)
{
  byte nilai7Segment = CCorCA ? ~angka[nilai] : angka[nilai];
  for (byte i = 0; i < sizeof(pin7Segment); i++)
  {
    digitalWrite(pin7Segment[i], nilai7Segment & 0x01);
    nilai7Segment >>= 1;
  }
}
uint32_t Convert_IntToBCD32(uint32_t DecimalValue)
{
  uint32_t returnValue = 0;
  //uint32_t LSB_L = DecimalValue;

  while (DecimalValue >= 10000000L)
  {
    DecimalValue -= 10000000L;
    returnValue += 0x10000000;
  }
  while (DecimalValue >= 1000000L)
  {
    DecimalValue -= 1000000L;
    returnValue += 0x01000000;
  }
  while (DecimalValue >= 100000L)
  {
    DecimalValue -= 100000L;
    returnValue += 0x00100000;
  }
  while (DecimalValue >= 10000)
  {
    DecimalValue -= 10000;
    returnValue += 0x00010000;
  }
  while (DecimalValue >= 1000L)
  {
    DecimalValue -= 1000L;
    returnValue += 0x00001000;
  }
  while (DecimalValue >= 100)
  {
    DecimalValue -= 100;
    returnValue += 0x00000100;
  }
  while (DecimalValue >= 10)
  {
    DecimalValue -= 10;
    returnValue += 0x00000010;
  }
  return returnValue + DecimalValue;
}

Library : TimerOne.zip

Kalibrasi sensor loadcell interaktif dengan Serial USB TTL Arduino

Sebelum digunakan, timbangan wajib ditera atau di kalibrasi. Proses kalibrasi timbangan dilakukan dengan membandingkan hasil terukurnya dengan berat diketahui sebuah beban pengkalibrasinya.

Loadcell digunakan sebagai sensor berat digital. Proses kalibrasi loadcell dengan arduino menggunakan metode dua beban menggunakan formula :

cara mengkalibrasi loadcell dengan metode dua beban ini menghasilkan dua variabel yaitu skala dan ofset.

Timbangan digital dengan sensor loadcell memiliki karakteristik akurasi berikut :

  1. Skala
  2. Ofset
  3. Linearitas
  4. Diferensial linearitas
  5. Kuantisasi
  6. Transisi akurasi

Setiap loadcell memiliki karakteristik yang berbeda-beda. cara memperoleh nilai skala dan offset yang baik adalah dengan menetapkan nilai beban pengkalibrasi antara 25% – 75% dari kapasitas loadcell.

skema / rangkaian kalibrasi loadcell arduino:

Setting kalibrasi ini akan disimpan di EEPROM, dan akan diambil kembali saat perangkat mulai dihidupkan.

koding /program kalibrasi loadcell menggunakan arduino:

#include "HX711.h"
#include <EEPROM.h>

#define alamatKalibrasiM 0
#define alamatKalibrasiC 4

//pin
HX711 scale(A0, A1); // (DT, SCK)

byte modeKalibrasi = 0;
uint16_t beratKalibrasi1Tera;
uint16_t beratKalibrasi2Tera;
long beratKalibrasi1;
long beratKalibrasi2;

long lastMillis;

void setup() {
  Serial.begin(9600);
  Serial.println("Kalibrasi Loadcell");
  Serial.println("https://www.project.semesin.com/");
  Serial.println();
  
  float m,c;
  EEPROM.get(alamatKalibrasiM, m);
  EEPROM.get(alamatKalibrasiC, c);
  scale.power_up();
  scale.set_scale(m);
  scale.set_offset(c);
  scale.power_down();

  lastMillis = millis();
}

void loop() {
  if(Serial.available())
  {
    if(modeKalibrasi == 0)
    {
      if(toupper(Serial.read()) == 'K')
      {
        Serial.println("Masukkan beban kalibrasi pertama (gram) :");
        modeKalibrasi = 1;
      }
    }
    else if (modeKalibrasi == 1)
    {
      scale.power_up();
      delay(100);
      beratKalibrasi1Tera = Serial.parseInt();
      beratKalibrasi1 = scale.read_average(10);
      Serial.println("Beban = " + String(beratKalibrasi1Tera) + " gram, terukur = " + String(beratKalibrasi1) + " unit");
      Serial.println("Masukkan beban kalibrasi kedua yang lebih besar (gram) :");
      modeKalibrasi = 2;
      scale.power_down();
    }
    else if (modeKalibrasi == 2)
    {
      scale.power_up();
      delay(100);
      beratKalibrasi2Tera = Serial.parseInt();
      beratKalibrasi2 = scale.read_average(10);
      Serial.println("Beban = " + String(beratKalibrasi2Tera) + " gram, terukur = " + String(beratKalibrasi2) + " unit");
      
      float m = 1.0 * (beratKalibrasi2 - beratKalibrasi1) / ( beratKalibrasi2Tera - beratKalibrasi1Tera);
      float c = beratKalibrasi2 - (1.0 * m * beratKalibrasi2Tera);

      scale.set_scale(m);
      scale.set_offset(c);
      EEPROM.put(alamatKalibrasiM, m);
      EEPROM.put(alamatKalibrasiC, c);

      Serial.print("Skala = ");
      Serial.println(m);
      Serial.print("Ofset = ");
      Serial.println(c);

      scale.power_down();
      Serial.println("Kalibrasi berhasil.");
      
      modeKalibrasi = 0;
    }
  }

  if(!modeKalibrasi)
  {
    if(millis() - lastMillis > 100)
    {
      scale.power_up();
      delay(10);
      float berat = scale.get_units(10);
      scale.power_down();
      Serial.print("Berat : ");
      Serial.println(berat);
      lastMillis = millis();
    }
  }
}

Cara kalibrasi loadcell melalui serial monitor:

Prosedur kalibrasi loadcell dengan arduino melalui serial monitor:

  1. Input ‘K’ atau ‘k’ untuk masuk mode kalibrasi.
  2. Naikkan beban pengkalibrasi pertama
  3. Inputkan berat tera beban pengkalibrasi pertama – Enter
  4. Naikkan beban pengkalibrasi kedua
  5. Inputkan berat tera beban pengkalibrasi kedua – Enter
  6. Selesai

Library : HX711.zip

Seting waktu RTC otomatis dengan arduino

DS1307 dan DS3231 merupakan RTC (real time clock) yang umum digunakan dalam perancangan arduino. kedua RTC ini saling kompatibel untuk register waktunya, sedangkan register kontrol memiliki alamat berbeda. Selain itu DS3231 memiliki kelebihan dua alarm yang tidak dimiliki oleh DS1307.

Penggunaan RTC pertama kali, RTC harus disetting terlebih dahulu, cara setting DS3231 adalah dengan memberi nilai pada register waktunya, juga register kontrol atau register alarm (khusus DS3231).

Cara menyetting RTC DS3231 dan DS1307 umumnya membutuhkan dua sketch untuk menggunakan RTC ini yaitu setTime dan program utama. Program ‘set waktu’ harus dipisah untuk menghindari program me-‘set waktu’ setiap kali arduino reset.

Otomatisasi setting RTC bertujuan untuk membuat setting waktu berada dalam sketch utama sehingga lebih praktis terutama jika sketch akan bagikan ke publik atau pengguna lain.

Untuk mengetahui apakah RTC sudah disetting atau belum, digunakan 1 byte EEPROM untuk menyimpan status (dibaca tokenRTC), jika RTC sudah disetting maka sketch akan menulis dialamat alamatEEPROMCekToken pada EEPROM dengan nilai tokenRTC.

Ketika program dijalankan sketch akan menguji nilai tokenRTC, jika sama maka sketch tidak lagi melakukan setting waktu RTC.

Skema tulis waktu rtc otomatis (kompatibel DS1307):

sketch/program Atur waktu RTC otomatis (bisa digunakan langsung untuk DS1307 dan DS3231 tanpa library):

#include <EEPROM.h>
#include <Wire.h>
#include <Sodaq_DS3231.h>

#define alamatRTC 0x68
#define alamatEEPROMCekToken 0
#define tokenRTC 0xAA //<== rubah token jika ingin nilai baru

void setup() {
  Serial.begin(9600);
  Serial.println("Set waktu RTC otomatis dengan arduino");
  Serial.println("https://www.project.semesin.com/");
  Serial.println();

  Wire.begin();
  if (EEPROM.read(alamatEEPROMCekToken) != tokenRTC)
  {
    //Waktu compiler
    char bulan[12];
    byte indexBulan;
    int jam, menit, detik, tanggal, tahun;

    char *namaBulan[12] = {
      "Jan", "Feb", "Mar", "Apr", "May", "Jun",
      "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
    };
    sscanf(__TIME__, "%d:%d:%d", &jam, &menit, &detik);
    sscanf(__DATE__, "%s %d %d", bulan, &tanggal, &tahun);
    for (indexBulan = 0; indexBulan < 12; indexBulan++) {
      if (strcmp(bulan, namaBulan[indexBulan]) == 0)
        break;
    }
    uint8_t wday = hariDariTanggal(tanggal, indexBulan + 1, tahun);
    DateTime dt(tahun, indexBulan + 1, tanggal, jam, menit, detik, wday);
    rtc.setDateTime(dt);
    EEPROM.write(alamatEEPROMCekToken, tokenRTC);
    Serial.println("RTC sudah otomatis di setting (Sekali saja)");
  }
}

uint32_t old_ts;
void loop() {
  String strNamaHari[] = {"Minggu", "Senin", "Selasa", "Rabu", "Kamis", "Jum'at", "Sabtu"};
  DateTime now = rtc.now(); //get the current date-time
  Serial.print(now.year(), DEC);
  Serial.print('/');
  Serial.print(now.month(), DEC);
  Serial.print('/');
  Serial.print(now.date(), DEC);
  Serial.print(' ');
  Serial.print(now.hour(), DEC);
  Serial.print(':');
  Serial.print(now.minute(), DEC);
  Serial.print(':');
  Serial.print(now.second(), DEC);
  Serial.print(' ');
  Serial.print(strNamaHari[now.dayOfWeek()-1]);
  Serial.println();

  while (1);
}
byte hariDariTanggal(byte tanggal, byte bulan, uint16_t tahun)
{
  uint16_t jumlahHariPerBulanMasehi[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
  if (tahun >= 2000)
    tahun -= 2000;

  uint32_t jumlahHari = tahun * 365;
  uint16_t tahunKabisat = tahun / 4;
  for (byte i = 0; i < tahun; i++)
  {
    if (!(i % 4))
    {
      jumlahHari++;
    }
  }
  jumlahHari += jumlahHariPerBulanMasehi[bulan - 1];
  if ( (bulan >= 2) && !(tahun % 4))
  {
    jumlahHari++;
  }
  jumlahHari += tanggal;
  return ((jumlahHari + 5) % 7) + 1;
}

Library: Sodaq_DS3231.zip
Versi tanpa library : set_otomatis_rtc.ino

Konversi sistem bilangan biner ke BCD

Bilangan biner adalah angka berbasis 2 yang hanya memiliki numerik ‘0’ dan ‘1’. Dalam ilmu komputer satu numerik bilangan biner disebut “bit”, apabila bilangan ini dikelompokkan kedalam 8 bit disebut dengan byte, Satu byte bisa menyimpan kombinasi hingga 2^8 atau 256 kombinasi.

Dalam ilmu komputer juga dikenal bilangan hex (hexadesimal) yaitu angka berbasis 16 dengan numerik 0-9 dan A-F, bilangan ini merepresentasikan 4-bit bilangan biner (binary number).

Bilangan biner atau bilangan hex juga bilangan byte umum digunakan dalam perhitungan digital dan komputer, namun bilangan ini sulit dicerna oleh manusia yang menggunakan bilangan desimal (basis 10),

Bilangan BCD (binary coded decimal) adalah bilangan hex dalam bentuk desimal yang lebih familier dan bisa terbaca oleh manusia dalam bentuk desimal.

byte 8-bit binary ke BCD

//max hex 0x63 / bcd 0x99
uint8_t Convert_IntToBCD(uint8_t DecimalValue)
{
	return DecimalValue + 6 * (DecimalValue / 10);
}

atau

//max hex 0x63 / bcd 0x99
uint8_t Convert_IntToBCD(uint8_t DecimalValue)
{
	uint8_t MSB = 0;
	uint8_t LSB = DecimalValue;

	while (LSB >= 10)
	{
		LSB -= 10;
		MSB += 0x10;
	}
	return MSB + LSB;
}

word 16-bit binary ke BCD

//max hex 0x270F / bcd 0x9999
uint16_t Convert_IntToBCD16(uint16_t DecimalValue)
{
	uint16_t returnValue = 0;
	//uint16_t LSB_L = DecimalValue;

	while (DecimalValue >= 1000)
	{
		DecimalValue -= 1000;
		returnValue += 0x1000;
	}
	while (DecimalValue >= 100)
	{
		DecimalValue -= 100;
		returnValue += 0x0100;
	}
	while (DecimalValue >= 10)
	{
		DecimalValue -= 10;
		returnValue += 0x0010;
	}
	return returnValue + DecimalValue;
}

integer 32-bit binary ke BCD

//max hex 0x5F5E0FF / bcd 0x99999999
uint32_t Convert_IntToBCD32(uint32_t DecimalValue)
{
	uint32_t returnValue = 0;
	//uint32_t LSB_L = DecimalValue;

	while (DecimalValue >= 10000000L)
	{
		DecimalValue -= 10000000L;
		returnValue += 0x10000000;
	}
	while (DecimalValue >= 1000000L)
	{
		DecimalValue -= 1000000L;
		returnValue += 0x01000000;
	}
	while (DecimalValue >= 100000L)
	{
		DecimalValue -= 100000L;
		returnValue += 0x00100000;
	}
	while (DecimalValue >= 10000)
	{
		DecimalValue -= 10000;
		returnValue += 0x00010000;
	}
	while (DecimalValue >= 1000L)
	{
		DecimalValue -= 1000L;
		returnValue += 0x00001000;
	}
	while (DecimalValue >= 100)
	{
		DecimalValue -= 100;
		returnValue += 0x00000100;
	}
	while (DecimalValue >= 10)
	{
		DecimalValue -= 10;
		returnValue += 0x00000010;
	}
	return returnValue + DecimalValue;
}

Jadwal Waktu Shalat (JWS) 2 & 3 Panel P10 Arduino Uno dengan kontroller Android melalui Bluetooth

Rancangan displai jadwal waktu sholat / JWS menggunakan arduino ini memanfaatkan I2C EEPROM 24C32 sebagai penyimpan data tampilan Infomasi text yang mampu menampung 4096 karakter. Chip 24C32 umumnya disertakan pada modul RTC DS1307 / DS3231 dengan jalur komunikasi yang sama dan alamat yang berbeda. Karena komunikasi I2C dikategorikan lambat, maka akses pembacaan memori ini diminimalisir dengan metode read on demand.

Display Jadwal Sholat Arduino

Perancangan JWS menggunakan Arduino atau JWS dengan kontroller running text harus mampu menangani hal-hal berikut :

  1. Waktu sholat berdasarkan perjalanan matahari yang berubah-ubah sepanjang tahun, sehingga dibutuhkan perhitungan khusus untuk menentukan posisi matahari secara matematis. Formula yang digunakan berasal dari islamicity, dengan penambahan variabel sudut-sudut matahari.
  2. Pengaturan yang komplek namun fleksibel mengharuskan JWS didesain mampu menyesuaikan tugasnya dengan beberapa parameter yang bisa di monitor atau diganti berkala. Seperti adanya kegiatan-kegiatan khusus sehingga JWS bisa beralih fungsi.

Kapasitas memory flash arduino uno (ATMega328) yang 32Kb masih menyisakan ruang untuk 3 set font diamping 1 font angka. Font-font ini berfungsi memberikan efek tulisan sehingga memungkinkan adanya penekanan informasi.

Efek JWS Arduino

Efek-efek tampilan diperlukan supaya kehadiran JWS lebih menghiasi dinding, bukan hanya sebagai papan informasi. efek yang di tambahkan :

  1. Wipe in – wipe out
  2. Marque
  3. Lukis gambar

JWS Bluetooth

Fasilitas pengaturan JWS dengan bluetooth:

  1. 10 teks informasi yang disimpan dalam memory 24C32 yang mampu menyimpan 4096 karakter.
  2. Font informasi bisa diatur terpisah (System Font 5×7,Arial 14,Arial Black 16) pada uno, dan bisa ditambahkan pada board yang memiliki memori lebih besar.
  3. Waktu padam dan nyala.
  4. Perhitungan waktu sholat dengan metode sudut matahari.
  5. Tampilan tanggal hijriah (bisa diatur dan dinonaktifkan).
  6. Efek wipe untuk tampilan waktu-waktu sholat.
  7. Efek tulisan gambar.
  8. Pengaturan bluetooth meliputi kecerahan DMD panel, kecepatan scroll.
  9. Token aplikasi apk, untuk mengantisipasi apabila ada komunikasi bluetooth yang tidak diinginkan yang mungkin akan merubah setting.
  10. Konfirmasi data setting diterima dan waktu padam/nyala ke apk android.
  11. Data yang diketik di apk disimpan dalam database android, jadi saat aplikasi ditutup data yang diketik tetap akan tampil saat aplikasi dibuka kembali.

Komponen yang digunakan dalam JWS Arduino bluetooth:

  1. Arduino Uno (Gunakan Arduino mega untuk memory yang lebih besar).
  2. RTC DS3231 (termasuk 24C32) kompatibel DS1307 (beda address)
  3. Bluetooth HC-05
  4. Panel P10 (2 panel)

Jika ingin upload sketch dari arduino ide, lepaskan dahulu pin ‘0’ / pin RX jika menggunakan bluetooth hardware serial.

Skema arduino JWS bluetooth:

Video bluetooth arduino JWS:

 

JWS Android

Screenshoot JWS Android bluetooth:

JWS bluetooth android ini menggunakan hardware SPI sebagai pengirim data ke running text, meskipun mengorbankan pin 12 (MISO) yang tidak bisa digunakan karena dikontrol oleh SPI.

Pengaturan JWS dengan arduino yang dibutuhkan :

  1. #define modeDemo pada baris atas digunakan jika ingin menjalankan JWS demo, hapus baris ini jika JWS digunakan normal.
  2. Pin Kontrol DMD hardware SPI : pinOE  harus dipasangkan pada pin PWM sebagai pengatur kecerahan. Sedangkan pinA, pinB, dan pinSCK bisa ditempatkan dimana saja.
  3. Jumlah panel.
  4. Perancangan ini dibuat dengan DS3231, jika menggunakan DS1307 harap diganti bagian alamat I2C-nya.
  5. Pin SQW (DS3231) diset sebagai penghasil pulsa dengan frekuensi 1 HZ sebagai interupsi bagi JWS bahwa detik telah berubah. dalam perancangan JWS arduino ini dihubungkan ke pin A3 namun bisa dipindahkan kemana saja.
  6. Jenis font bisa disesuaikan dengan kebutuhan, (#include-kan juga library font-nya). dengan merubah variabel berikut:
    #define fontWaktu               angka6x13
    #define fontInformasi           SystemFont5x7Ramping
    #define fontTanggal             SystemFont5x7Ramping
    #define fontNamaSholat          SystemFont5x7Ramping
    #define fontWaktuSholat         SystemFont5x7Ramping
    #define fontWaktuMasuk          SystemFont5x7Ramping
    #define fontAdzan               SystemFont5x7Ramping
    #define fontIqomah              SystemFont5x7Ramping
    #define fontMatikanHP           Arial14
    
  7. JWS ini dilengkapi sistem token, untuk RTC dan komunikasi bluetooth, apabila token yang digunakan cocok maka perintah untuk RTC dan bluetooth (setting variabel) akan dijalankan.

Sketch/koding header dan setup android bluetooth JWS:

#define modeDemo                0    //<<==================================== DEMO prinsip kerja 0 / 1

#define selisihImsak            10

//defenisi pin
#define pinA                    6
#define pinB                    7
#define pinOE                   9
#define pinSCK                  8

#define alarm                   5
#define RTCDetikIRQ             A3

//variabel Setting
#define jumlahKolomPanel        2  //panel
#define jumlahBarisPanel        1  //panel

#define lamaTampilWaktuSholat   10 // * 100 milidetik
#define lamaTampilInformasiJam  100 // * 100 milidetik

#define fontWaktu               angka6x13
#define fontInformasi           SystemFont5x7Ramping
#define fontTanggal             SystemFont5x7Ramping
#define fontJadwalSholat        SystemFont5x7Ramping
#define fontWaktuSholat         SystemFont5x7Ramping
#define fontWaktuMasuk          SystemFont5x7Ramping
#define fontAdzan               SystemFont5x7Ramping
#define fontIqomah              SystemFont5x7Ramping
#define fontMatikanHP           Arial14

#define RTC_ADDRESS             0x68
#define I2CEEPROM_ADDRESS       0x57  //Perhatikan alamat I2CEEPROM 0x50(ds1307 .. 0x57(ds3231)
#define RTC_CONTROL_REG         0x0E  //0x07 ds1307, 0x0E ds3231 


#include <Wire.h>
#include <SPI.h>
#include <avr/sleep.h>
#include <avr/pgmspace.h>
#include <EEPROM.h>
#include <SoftwareSerial.h>

#include <DMD2.h>

#include "fungsi.h"
#include "definisi.h"
#include "konstanta.h"
#include "rtc.h"
#include "prayer.h"
#include "i2cUmum.h"
#include "trigonometri.h"

#include <fonts/SystemFont5x7Ramping.h>
#include <fonts/Arial14.h>
#include <fonts/Arial_Black_16.h>
#include <fonts/angka6x13.h>
#include <fonts/AllahMuhammad.h>

const uint16_t alamatFont[] = {&SystemFont5x7Ramping, &Arial14, &Arial_Black_16};

struct Setting
{
  int8_t koreksiHijriah;
  int8_t jumlahAlarm;
  int8_t lamaAdzan;
  int8_t lamaIqomah[5];
  int8_t ulangMatikanHP;
  int8_t lamaSholat[5];
  int8_t lamaSholatJumat;
  int8_t kecepatanJalanInfoText;
  int8_t kecerahanJWS;
  int8_t padamJam;
  int8_t padamMenit;
  int8_t nyalaJam;
  int8_t nyalaMenit;
  int8_t tampilanHijriah;
  int8_t tampilanImsak;
  int8_t tampilanTerbit;
  int8_t tampilanDhuha;
  int8_t tampilanTerbenam;
  int8_t JumlahInfoTextAktif;
};

#if modeDemo
  Setting setting = {0, 5, 1, {5, 5, 5, 5, 5}, 1, {5, 5, 5, 5, 5}, 2, 50, 20, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1};
  char namaMesjid[panjangString] = "Musholla ...\0   ";
#else
  Setting setting;
  char namaMesjid[panjangString];
#endif

//variabel
const char strWaktu[] PROGMEM = "Waktu";
const char strSholat[] PROGMEM = "Sholat";
char strWaktuInformasi[9];
JamDanMenit waktuSholat[9];

EfekMarqueHorizontalkeKiri marqueKiri;
EfekTulis efekTulis;
uint8_t efekScrollOutDanWipeIn;

uint8_t marqueOut;
bool marqueTampilan;
uint8_t wipeInTampilan;
uint8_t wipeOutTampilan;
uint8_t efekTulisTampilan;


uint8_t indexNamaSholat;
uint16_t hitungMundurSholat;
uint16_t hitungMundurPesanSebelumSholat;
uint16_t hitungMundurIqomah;
uint16_t hitungMundurAdzan;
uint8_t hitungMundurAlarm;
uint16_t hitungMudurAlarmIqomah;

byte modeOperasi;
byte modeOperasiSebelumnya;

uint8_t menitSebelumnya = 60;
uint8_t hariSebelumnya = 32;

bool statusAlarm;

bool tampilkanMenit;
bool infoWaktu;
byte infoWaktuTop;
uint16_t lamaTampil = 0;
uint16_t indekTampilan;

char textWaktuJam[6];
char textTanggalHijriah[sizeof(strNamaHari[0]) + 2 + 3 + sizeof(strNamaBulanHijriah[0]) + 3 - 2];

uint8_t bluetoothData[32];
uint16_t indexParseSerial = 0;

byte indexInformasi = 1;
long mulaiMillis;
uint16_t AlamatI2CEEPROM;

int8_t indexSetting = 0;
byte indexSettingInfo;
bool tokenValid = false;
bool RTCValid = true;

byte tanggalHijriah;
byte bulanHijriah;
uint16_t tahunHijriah;

uint16_t AlamatI2CEEPROMSebelumnya;
bool nextEEPROMData = false;
byte EEPROMDataCounter;

bool modeSambungSebelumnya = false;

tanggalDanWaktu now;
tanggalDanWaktu settingWaktu;
byte settingWaktuIndex;

//Class variabel
#define l jumlahKolomPanel * 32
#define t jumlahBarisPanel * 16
SPIDMD dmd(jumlahKolomPanel, jumlahBarisPanel, pinOE, pinA, pinB, pinSCK);
DMDFrame dmdEfek(l, t);

DMD_TextBox boxKolom1(dmd, 0, 0, l / 2, t);
DMD_TextBox boxKolom2(dmd, l / 2, 0, l / 2, t);
DMD_TextBox boxBaris1(dmd, 0, 0, l, (t / 2) - 1);
DMD_TextBox boxBaris2(dmd, 0, t / 2, l, t / 2);

DMD_TextBox boxKolom2Baris1(dmd, l / 2, 0, l / 2, t / 2);
DMD_TextBox boxKolom2Baris2(dmd, l / 2, t / 2, l / 2, t / 2);

//Eeprom24C32_64 I2CEEPROM(EEPROM_ADDRESS);
HardwareSerial *bluetooth;

#define tokenRTC 0xA9
#define tokenBluetooth 0x4C
#define tokenSetInformasi "225654"
#define tokenSetSetting "963215"

void setup() {
  Serial.begin(9600);
  Serial.println("JWS Bluetooth");
  Serial.println("https://www.project.semesin.com/");
  Serial.println();

  bluetooth = &Serial;

  pinMode(alarm, OUTPUT);
  pinMode(RTCDetikIRQ, INPUT_PULLUP);

  //Interupsi setiap 1 detik
  Wire.begin();
  Wire.beginTransmission(RTC_ADDRESS);
  Wire.write(RTC_CONTROL_REG);
  Wire.write(0x00);//SQW freq, 1Hz
  Wire.endTransmission();

#if modeDemo
  prayerData = { -1576, 27343, 1792, 5120, 213, -1152, 1024, 4608, 0, 0, 0,0,0};
  settingWaktu = {50, 29, 4, 5, 7, 5, 2018};
  simpanRTC(RTC_ADDRESS, settingWaktu);
#endif

  if (EEPROM.read(alamatTokenRTC) != tokenRTC)
  {
    //Waktu compiler
    char Month[12];
    int Day, Year;
    uint8_t monthIndex;
    int Hour, Min, Sec;
    char *monthName[12] = {
      "Jan", "Feb", "Mar", "Apr", "May", "Jun",
      "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
    };
    sscanf(__TIME__, "%d:%d:%d", &Hour, &Min, &Sec);
    sscanf(__DATE__, "%s %d %d", Month, &Day, &Year);
    for (monthIndex = 0; monthIndex < 12; monthIndex++) {
      if (strcmp(Month, monthName[monthIndex]) == 0) break;
    }
    uint8_t wday = hariDariTanggal(Day, monthIndex + 1, Year);
    settingWaktu = {Sec, Min, Hour, wday, Day, monthIndex + 1, Year};
    simpanRTC(RTC_ADDRESS, settingWaktu);
    EEPROM.write(alamatTokenRTC, tokenRTC);
  }

#if !modeDemo
  if (EEPROM.read(alamatTokenBluetooth) == tokenBluetooth)
  {
    ambilSetting();
  }
#endif
  ambilHijriah();
  dmd.begin();

  set_sleep_mode(SLEEP_MODE_IDLE);
  sleep_enable();

  mulaiMillis = millis();
  modeOperasi = tampilWaktuSholat;

  while (!digitalRead(RTCDetikIRQ));
}

 

File-file yang digunakan dalam JWS android :

  1. definisi.h
  2. fungsi.h
  3. i2cUmum.h
  4. JWS_Semesin.ino
  5. konstanta.h
  6. prayer.h
  7. rtc.h
  8. trigonometri.h
  9. JWS_Bluetooth.apk
  10. file lengkap (.zip)

Rekomendasi Perakitan JWS Bluetooth Android:

  1. unzip JWS Bluetooth + apk – Semesin.zip (adalah folder sketch arduino beserta file pendukung dalam satu folder)
  2. copy isi folder libraries ke Document/Arduino/libraries/
  3. Buka JWS_Semesin.ino dengan arduino IDE (pengujian dengan versi 1.8.5)
  4. Lepas tx Bluetooth
  5. Upload ke arduino
  6. Hubungkan tx Bluetooth
  7. Buka app JWS Bluetooth klik setting dan kirim pengaturan
  8. Selesai.

antisipasi masalah:

  1. Data EEPROM sebelumnya mungkin berpengaruh pada settingan, set dengan apk via bluetooth atau hapus dahulu dengan examples->EEPROM->eeprom_clear.
  2. #define modeDemo 1 untuk test / 0 untuk running
  3. Pastikan daya mencukupi (kalo tidak punya 5V > 5A hubungkan saja GND DMD ke GND Arduino tapi tidak Vcc +5V-nya)

nb: V1.0 -> Versi2.0

  1. Karakter informasi yang akan ditampilkan langsung diambil dari I2CEEPROM
  2. Penambahan pengaturan sudut-sudut waktu sholat.
  3. Penambahan efek grafis

catatan:

  • koordinat dalam mode derajat-menit –±dd° mm’–(menit = pecahan derajat*60/100)
    contohnya :
    lintang -6.78 -> -6-46′
    bujur 110.38 -> 110-22′
  • jika koordinat sudah sesuai, namun masih ada perbedaan waktu dengan jadwal yang diinginkan (mis: jadwal depag), maka geser bujur (ditambah/dikurang)
  • Jika sebagian jadwal shalat tidak akurat, maka geser derajat masing-masing jadwal shalat yang belum akurat
  • JWS ini belum menggunakan ikhtiyath, untuk mengantisipasinya bisa dengan menggeser derajat-menit bujur ±2 menit)

Hasil percobaan

by: Priadi Amfi

Hasil percobaan

by: Catur cahya

Hasil percobaan

by: Ochoy Thea