JWS Universal (Jadwal Waktu Shalat) 1 – 8 panel

Jadwal Waktu Shalat (JWS) adalah media informasi di rumah ibadah Masjid/Mushalla/Surau yang menampilkan informasi waktu-waktu Shalat.

Dalam perkembangannya Jam Waktu Shalat berfungsi sebagai :

  1. Menampilkan Jadwal / Waktu Shalat wajib dan sunat
  2. Menampilkan informasi tanggal Masehi, Hijriah, Pasaran Jawa, dan penanggalan khusus seperti penanggalan Minang
  3. Menampilkan Ayat Al-Quran, Doa
  4. Informasi Tartil, Tarhim, Azan, Iqamah
  5. Pengingat / alarm waktu masuk Shalat dan selesai Iqamah
  6. Memutar Suara/Musik Tartil, Tarhim disertai kontrol hidup/mati amplifier
  7. Perhitungan jadwal berdasarkan posisi matahari, masukan manual, data jadwal online harian.

Diagram alir Jawdal waktu-waktu Shalat :

 

Skema Jam waktu shalat universal:

 

Tampilan aplikasi (apk) JWS Semesin Universal:

 

contoh tampilan jadwal shalat 3 panel :

 

Koding / sketch JWS semesin:

/*
   JWS Semesin 1 - 8 panel

   Fitur yang tidak aktif
   1. Tampilan tanggal Hijriah
   2. Tampilan tanggal Jawa
   3. Tampilan tanggal Minang
   4. Pesan selama tartil
   5. Pesan selama tarhim
   6. Pesan selama Iqamah

*/

#define serialDebug                       false
#define modeDemo                          false

#define namaMesjid                        "JWS"

//defenisi pin
#define pinMP3Busy                        2
#define pinRelayAmpli                     3
#define pinBuzzer                         4
#define RTCDetikIRQ                       A3

#define relayOn                           LOW

#define I2CEEPROM_ADDRESS                 0x57

//setting
#define periodaAlarmWaktuShalatMasuk      100//milidetik
#define periodaAlarmWaktuAkhirIqamah      300//milidetik

#define pixelLebarPanel                   32
#define pixelTinggiPanel                  16

//variabel Setting
#define kecepatanMinimal                  10
#define skalaKecepatan                    10

#define tokenSetting                      32
#define lamaAksesApk                      10L * 60 * 1000

#define jumlahNyalaPadam                  5
#define jumlahTextInformasi               10

#define fontNamaMesjid                    Arial14
#define fontJamDanMenitUtama              angka6x14
#define fontSimbolGambar                  simbolGambar

#include <Wire.h>
#include <EEPROM.h>
#include <DMD_Semesin.h>
#include <RTC_Semesin.h>
#include <DFPlayer_Mini_Mp3.h>
#include <BluetoothApk.h>

#include <fonts/angka6x14.h>
#include <fonts/SystemFont5x7Ramping.h>
#include <fonts/Arial14.h>
#include <fonts/simbolGambar.h>

#include "fungsi.h"
#include "definisi.h"
#include "konstanta.h"
#include "setting.h"
#include "WaktuShalat.h"

const uint8_t *alamatFont[] = {
  Arial14,
  SystemFont5x7Ramping,
};

SPIDMD dmd(8, 1);//max jumlah panel = 8
RTC_DS3231 rtc;
DateTime now;

//Status
bool RTCValid = true;
byte modeOperasi = modeInformasi;
bool statusAlarm;
bool tampilJamMenitDetik = false;
long millisRunningText;
uint8_t kecepatanRunningText;
uint8_t kecepatanRunningEfek;

uint16_t hitungMundurTartil;
uint16_t hitungMundurTarhim;
uint16_t hitungMundurAzan;//terhitung sejak waktu masuk
uint16_t hitungMundurIqamah;//terhitung sejak selesai azan

bool pesanSetelahAzan;
bool pesanSebelumShalat;
uint16_t hitungMundurPeringatanSimbol;
uint16_t hitungMundurShalat;

bool initHitungMundurTartil;
bool initHitungMundurTarhim;
bool initHitungMundurAzan;
bool initHitungMundurIqamah;
bool initHitungMundurPeringatanSimbol;
bool initHitungMundurShalat;

uint8_t hitungMundurAlarmIqamah;//kali

int8_t indexWaktuIbadah;
int8_t indekInformasi;

//efek
uint16_t lamaTampilText;
bool initTampil;

bool tampilanInformasiSambung;

byte indekTampilan = jumlahInformasi;
EfekMarque efekMarque;

uint16_t lebarText;
uint8_t tinggiText;

byte detikSebelumnya = 60;
byte menitSebelumnya = 60;
byte tanggalSebelumnya = 0;

long millisAlarm;

bool status;

BluetoothApk bluetoothApk(&Serial, "JWS2 SEMESIN.COM");
long millisAksesApk;
bool aksesApk;

uint16_t counterAlamat = 0;
uint16_t counterAlamatSebelumnya = 0;
uint16_t parameterSebelumnya = 0;

byte lebarJamUtama = 32;

byte lebarJadwalShalat = 32;
byte modeTampilanJadwal;
char buffer[72];
uint16_t offsetJadwalEEPROM;
bool runningTextAktif;

JamDanMenitJadwal jadwalBerikutnya;
JamDanMenitAlarm alarmBerikutnya;
int8_t hitungMundurAlarm;
bool initHitungMundurAlarm;
bool statusRelayAmpli;

void setup() {

  pinMode(pinBuzzer, OUTPUT);
  digitalWrite(pinRelayAmpli, !relayOn);
  pinMode(pinRelayAmpli, OUTPUT);
  pinMode(pinMP3Busy, INPUT_PULLUP);

  Serial.begin(9600);
  Serial.println(F("JWS Semesin 1-8 panel"));
  Serial.println(F("https://www.project.semesin.com"));

  mp3_set_serial (Serial);
  mp3_set_volume (15);


#if serialDebug
  Serial.println(F("Inisialisasi"));
#endif

  rtc.begin();

  if (rtc.lostPower())
  {
#if serialDebug
    Serial.println(F("RTC tidak jalan"));
#endif
    write_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG, 0x00);
  }
  write_i2c_register(DS3231_ADDRESS, DS3231_CONTROL, DS3231_SquareWave1Hz);

  if (EEPROM.read(offsetof(Setting, token)) != tokenSetting)
  {
    pengaturanAwal();
  }

  updateUkuranTampilan();
  dmd.waitInterruptOver = false;
  dmd.begin();
  dmd.clearScreen();
  dmd.setBrightness(25.5 * EEPROM.read(offsetof(Setting, kecerahanStandar)));

  kecepatanRunningEfek = skala2kecepatanRunning(EEPROM.read(offsetof(Setting, kecepatanEfek)));

#if serialDebug
  Serial.println(F("Sistem mulai"));
#endif

  dmd.selectFont(fontNamaMesjid);
  dmd.drawString(1, 1, namaMesjid);

  delay(3000);
  dmd.clearScreen();

  statusRelayAmpli = digitalRead(pinMP3Busy);
}


void loop() {

....... file lengkap bisa didownload melalui link dibawah

file JWS universal:

JWS Semesin v2.1

catatan:
* untuk RTC DS3231, pin-SQW harus terpasang pada pin-A3 (arduino)
* jika menggunakan pcb jws (versi manapun) ada kemungkinan tidak cocok dan perlu modifikasi

DMD Jam, Timer, Countdown dengan arduino

Jam, timer/stopwatch, countdown seringkali di kombinasikan dalam sebuah perangkat, karena fitur2 ini memiliki kemiripan fungsi.

Fitur tampilan dapat dipilih melalui satu tombol, setiap tombol ditekan maka mode waktu akan berubah yaitu Watch – Timer – Countdown, fungsi masing-masing adalah :

Watch (Jam)

Ditandai dengan Karakter ‘W’ (watch) pada sudut kiri atas, berfungsi menampilan waktu rtc saat ini dalam format “hh:mm:dd” atau jam:menit:detik.

Timer (Hitung maju)

Ditandai dengan karakter ‘T’ (Timer) pada sudut kiri atas. Dalam mode ini pewaktu memulai hitungan dari 00:00:00 dan akan terus bertambah setiap detik. Apabila hitungan maju ini telah mencapai 86.400 detik atau 23:59:59 atau 1 hari penuh, maka hitungan akan dimulai lagi dari 0.

Countdown (Hitung mundur)

Ditandai dengan karakter ‘C’ (Count down) pada sudut kiri atas.berfungsi menampilkan waktu tersisa dari batas aawal yang bisa diatur dengan memodifikasi variabel ‘waktuHitungMundur’ seperti contoh :


#define waktuHitungMundur 5 * 60// 5 menit

Waktu hitung mungdur dapat diisi angka 1 – 86400 dalam satuan detik.

Apabila hitungan habis atau mencapai 0 (00:00:00) maka tampilan akan berubah ke mode watch dan menampilkan waktu rtc saat ini.

Komponen yang digunakan dalam perancangan jam, counter, countdown:

  1. Arduino uno
  2. 2x Panel P10 hub12
  3. RTC DS3231

berikut skema rakitan tampilan waktu, hitung maju dan hitung mundur:

Koding/sketch arduino tampilan jam, penghitung mundur dan pewaktu maju:

#define waktuHitungMundur     5 * 60// 5 menit

#define pinTombol             A0


#include "Sodaq_DS3231.h"
#include <DMD2.h>
#include <fonts/angka6x14.h>
#include <fonts/System_Min5x7.h>

enum Mode
{
  modeJam,
  modeHitungMaju,
  modeHitungMundur,
  jumlahMode,
};

DateTime now;
uint32_t hitungMundur;
uint32_t hitungMaju;
byte mode;
char buffer[10];
byte jam, menit, detik;
byte detikSebelumnya;

SPIDMD dmd(2, 1);

void setup() {

  pinMode(pinTombol, INPUT_PULLUP);

  Serial.begin(9600);
  Serial.println("Jam, Hitung maju, Hitung mundur (Watch, Timer, Count down)");
  Serial.println("https://www.project.semesin.com");

  rtc.begin();

  //Set rtc untuk keperluan testing
  DateTime dt(2020, 2, 20, 15, 30, 0, 1);
  rtc.setDateTime(dt);

  dmd.begin();

  setMode();
}

void loop() {
  now = rtc.now();
  if (detikSebelumnya != now.second())
  {
    detikSebelumnya = now.second();

    switch (mode)
    {
      case modeJam:
        sprintf(buffer, "%02d%s%02d%s%02d", now.hour(), now.second() % 2 ? ":" : " ", now.minute(), now.second() % 2 ? ":" : " ", now.second());
        dmd.drawString(8, 1, buffer);
        break;

      case modeHitungMaju:
        jam = hitungMaju / (3600L);
        menit = (hitungMaju % (3600L)) / 60;
        detik = hitungMaju % 60;
        sprintf(buffer, "%02d%s%02d%s%02d", jam, now.second() % 2 ? ":" : " ", menit, now.second() % 2 ? ":" : " ", detik);
        dmd.drawString(8, 1, buffer);
        hitungMaju++;
        if(hitungMaju == 86400L)
        {
          hitungMaju = 0; 
        }
        
        break;

      case modeHitungMundur:
        jam = hitungMundur / (3600L);
        menit = (hitungMundur % (3600L)) / 60;
        detik = hitungMundur % 60;
        sprintf(buffer, "%02d%s%02d%s%02d", jam, now.second() % 2 ? ":" : " ", menit, now.second() % 2 ? ":" : " ", detik);
        dmd.drawString(8, 1, buffer);

        hitungMundur--;
        if (!hitungMundur)
        {
          mode = modeJam;
          setMode();
        }
        break;
    }
  }
  if (!digitalRead(pinTombol))
  {
    delay(100);
    if (!digitalRead(pinTombol))
    {
      mode++;
      mode %= jumlahMode;
      setMode();

      while (!digitalRead(pinTombol));
    }
  }
}

void setMode()
{
  dmd.selectFont(System_Min5x7);
  switch (mode)
  {
    case modeJam:
      dmd.drawString(0, 0, "W");
      break;

    case modeHitungMaju:
      dmd.drawString(0, 0, "T");
      hitungMaju = 0;
      break;

    case modeHitungMundur:
      dmd.drawString(0, 0, "C");
      hitungMundur = waktuHitungMundur;
      break;
  }
  dmd.selectFont(angka6x14);
  dmd.fontHeader.fixedWidth = 2;
}

library :

Mesin antrian dmd dilengkapi suara dengan arduino

Mesin antrian adalah sistem informasi antara meja layanan dan pengunjung untuk mengatur waktu pelayanan terhadap pengunjung sesuai urutan kedatangan. Sistem ini terdiri atas media, dan tombol panggil, bisa juga ditambahkan dengan tombol tiket (dengan cetak tiket). Media informasi seperti seven segment, running text (dmd), monitor, suara yang diletakkan di ruang tunggu yang terlihat/terdengar di kursi pengunjung yang sedang antri.

Mesin antrian dalam proyek ini memiliki fitur berikut :

  1. Tombol panggil 4 buah dengan fitur cascade yaitu masing-masing tombol dapat ditekan bersamaan tanpa harus menunggu proses panggilan meja operator lain.
  2. Tombol tiket 1 buah dan dilengkapi cetak tiket
  3. Tombol reset untuk mengembalikan ke keadaan awal
  4. Media dot matik P10 sebagai papan informasi.
  5. Suara panggil mp3 berupa nomor antrian dan nomor loket

Skema Mesin antrian arduino :

Komponen yang digunakan dalam membuat mesin antrian menggunakan dmd (dot matrix display) berbasis arduino :

  1. Arduino uno
  2. DMD P10
  3. Printer thermal
  4. DF Player mini mp3, speaker, resistor
  5. Tombol

Sketch / koding sistem antrian arduino :

#define pinTombolPanggil1   A0
#define pinTombolPanggil2   A1
#define pinTombolPanggil3   A2
#define pinTombolPanggil4   A3

#define pinTombolReset      A4
#define pinTombolTiket      A5

#define pinMP3Busy          2

#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 antrianNomor        101
#define silahkanKeCS        102

#include <SPI.h>
#include <DMD_Semesin.h>
#include <fonts/angka6x14ABCD.h>
#include <DFPlayer_Mini_Mp3.h>
#include "Adafruit_Thermal.h"


byte nomorAntrianDaftar;
byte nomorAntrianPanggil;
byte nomorCSPanggil;

SPIDMD dmd(1, 1);
SoftwareSerial serialPrinter(4, 5);
Adafruit_Thermal printer(&serialPrinter);

struct DataAntrian
{
  uint16_t counterTiket;
  uint16_t counterPanggil;
  uint8_t CS;
  bool dataTombolTekan[4];
};

DataAntrian dataAntrian;
byte pinTombolPanggil[] = {pinTombolPanggil1, pinTombolPanggil2, pinTombolPanggil3, pinTombolPanggil4};
char buffer[20];

bool statusTombolTiket;
byte statusTombolPanggil[4];


void setup() {
  pinMode(pinTombolPanggil1, INPUT_PULLUP);
  pinMode(pinTombolPanggil2, INPUT_PULLUP);
  pinMode(pinTombolPanggil3, INPUT_PULLUP);
  pinMode(pinTombolPanggil4, INPUT_PULLUP);

  pinMode(pinTombolReset, INPUT_PULLUP);
  pinMode(pinTombolTiket, INPUT_PULLUP);

  Serial.begin(9600);

  Serial.println(F("Mesin antrian arduino"));
  Serial.println(F("https://www.project.semesin.com"));

  mp3_set_serial (Serial);
  mp3_set_volume(30);
  Serial.println();

  serialPrinter.begin(9600);
  printer.begin();
  printer.sleep();

  dmd.clearScreen();
  dmd.setBrightness(255);
  dmd.selectFont(angka6x14ABCD);
  dmd.begin();
}

void loop() {

  bacaTombol();

  if (!digitalRead(pinTombolReset))
  {
    delay(100);
    if (!digitalRead(pinTombolReset))
    {
      dataAntrian.counterTiket = 0;
      dataAntrian.counterPanggil = 0;
      dataAntrian.CS = 0;
      dataAntrian.dataTombolTekan[0] = 0;
      dataAntrian.dataTombolTekan[1] = 0;
      dataAntrian.dataTombolTekan[2] = 0;
      dataAntrian.dataTombolTekan[3] = 0;

      dmd.clearScreen();
      Serial.println("Reset");
      while (!digitalRead(pinTombolReset));
    }
  }

  for (byte i = 0; i < sizeof(pinTombolPanggil); i++)
  {
    if (dataAntrian.counterTiket > dataAntrian.counterPanggil)
    {
      if (dataAntrian.dataTombolTekan[i])
      {
        dataAntrian.counterPanggil++;
        dataAntrian.CS = i + 1;

        sprintf(buffer, "%02d>%1d", dataAntrian.counterPanggil, dataAntrian.CS);
        dmd.drawString(2, 1, buffer);

        Serial.print("call=");
        Serial.println(dataAntrian.counterPanggil);
        Serial.print("cs=");
        Serial.println(dataAntrian.CS);

        mp3_play_and_wait(antrianNomor);
        suaraBilangan(dataAntrian.counterPanggil);
        mp3_play_and_wait(silahkanKeCS);
        suaraBilangan(dataAntrian.CS);

        Serial.println();
        dataAntrian.dataTombolTekan[i] = false;
      }
    }
  }
}

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_and_wait(Bilangan);
  }
  else if (Bilangan < 20)
  {
    mp3_play_and_wait(Bilangan - 10);
    mp3_play_and_wait(belas);
  }
  else
  {
    uint8_t puluhan = Bilangan / 10;
    mp3_play_and_wait(puluhan);
    mp3_play_and_wait(puluh);

    puluhan *= 10;
    if (Bilangan - puluhan != 0)
    {
      mp3_play_and_wait((Bilangan - puluhan));
    }
  }
}
void suaraRatusan(uint16_t Bilangan)
{
  uint8_t ratusan = (uint8_t)(Bilangan / 100);
  if (ratusan == 1)
  {
    mp3_play_and_wait(seratus);
  }
  else
  {
    mp3_play_and_wait(ratusan);
    mp3_play_and_wait(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_and_wait(seribu);
  }
  else if (ribuan < 100)
  {
    suaraPuluhan(ribuan);
    mp3_play_and_wait(ribu);
  }
  else
  {
    suaraRatusan(ribuan);
    mp3_play_and_wait(ribu);
  }
  if (Bilangan % 1000)
  {
    suaraRatusan(Bilangan - (ribuan * 1000));
  }
}

void mp3_play_and_wait(uint16_t num) {
  mp3_play (num);
  delay(200);
  while (!digitalRead(pinMP3Busy))
  {
    bacaTombol();
  }
}

void bacaTombol()
{
  if (!digitalRead(pinTombolTiket))
  {
    if (!statusTombolTiket)
    {
      delay(100);
      if (!digitalRead(pinTombolTiket))
      {
        dataAntrian.counterTiket++;
        printer.wake();
        printer.setDefault();

        printer.justify('C');
        printer.println("Nomor Antrian");
        printer.doubleHeightOn();
        printer.println(dataAntrian.counterTiket);
        printer.doubleHeightOff();
        printer.println("Terima kasih");
        printer.feed(2);
        printer.sleep();

        Serial.print("ambil tiket : ");
        Serial.println(dataAntrian.counterTiket);

        statusTombolTiket = true;
      }
    }
  }
  else
  {
    statusTombolTiket = false;
  }

  for (byte i = 0; i < sizeof(pinTombolPanggil); i++)
  {
    if (!digitalRead(pinTombolPanggil[i]))
    {
      if (!statusTombolPanggil[i])
      {
        delay(100);
        if (!digitalRead(pinTombolPanggil[i]))
        {
          dataAntrian.dataTombolTekan[i] = true;
          statusTombolPanggil[i] = true;

          Serial.print("TombolPanggil:");
          Serial.println(i);
        }
      }
    }
    else
    {
      statusTombolPanggil[i] = false;
    }
  }
}

library :

suara mp3

  1. mp3 mesin antrian arduino.zip

Papan skor arduino 3 panel P10 dengan kontrol android

Papan skor (score board) adalah papan tempat informasi dan hasil pertandingan yang dapat dilihat oleh semua orang yang berada di arena pertandingan dan penonton.

Papan skor dengan dot matrix (dmd) dengan kontrol android melalui bluetooth ini memiliki fitur :

  1. Tambah-kurang point, skor, waktu, dan ronde pertandingan serta reset point.
  2. Informasi running text yang bisa tampil di tengah pertandingan.
  3. Master reset untuk menginisialisasi semua informasi pertandingan.

Skema papan skor arduino

lepas ‘pin 0’ arduino – bluetooth saat upload sketch:

komponen papan skor bluetooth

  1. Arduino Uno
  2. 3 buah DMD Panel P10
  3. Bluetooth HC-05
  4. Android

Sketch/koding scoring board arduino dengan android melalui bluetooth

#include <SoftwareSerial.h>
#include <DMD_Semesin.h>
#include <fonts/Arial16.h>
#include <fonts/Arial_Black_16.h>
#include <fonts/SystemFont5x7.h>
#include <fonts/SystemFont5x7Gemuk.h>
#include <Wire.h>

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

#define DISPLAYS_WIDE 3
#define DISPLAYS_HIGH 1

#define fontPembuka     Arial16
#define fontSkor        Arial_Black_16
#define fontInformasi   SystemFont5x7
#define fontWaktu       SystemFont5x7
#define fontRonde       SystemFont5x7Gemuk

SPIDMD dmd(DISPLAYS_WIDE, DISPLAYS_HIGH);

//SoftwareSerial bluetooth(2, 3);
#define bluetooth     Serial

byte pointA, pointB, skorA, skorB, ronde = 0;
uint16_t waktu = 0;
byte Arial14TengahY;
char strInformasi[200] = "Selamat Datang";
char bufferBluetooth[200];
bool pertandinganBerjalan;
long millisDetik;
long millisEfek;
byte detikSebelumnya = 60;
bool modeInformasi;

EfekMarque efekMarque;

enum perintah {
  initPerangkat,
  pointAplus,
  pointAminus,
  pointBplus,
  pointBminus,
  skorAplus,
  skorAminus,
  skorBplus,
  skorBminus,
  rondePlus,
  rondeMinus,
  menitPlus,
  menitMinus,
  text,
  resetPoint,
  resetSemua,
  mulai,
};

DMD_TextBox boxSkorA(dmd, 0, 0, 28, 16);
DMD_TextBox boxSkorB(dmd, 68, 0, 28, 16);

void setup() {
  Serial.begin(9600);
  bluetooth.begin(9600);

  Serial.println(F("Papan skor arduino 3 panel P10 dengan kontrol android"));
  Serial.println(F("https://www.project.semesin.com"));


  dmd.setBrightness(128);
  dmd.selectFont(fontPembuka);
  dmd.clearScreen();
  dmd.begin();
  dmd.drawString(0, 0, F("Papan Skor bluetooth"));
  delay(1000);
  dmd.clearScreen();

  efekMarque.mode = nonAktif;
  efekMarque.sumber = sumberRAM;
  efekMarque.font = fontInformasi;
  efekMarque.kiri = 28;
  efekMarque.atas = 0;
  efekMarque.tinggi = 8;
  efekMarque.lebar = 40;
  efekMarque.step = 1;
  efekMarque.skip = 0;

  tampilanUtama();

  Serial.println("Sistem dimulai");

  millisDetik = millis();
}

void loop() {
  if (millisDetik != millis() / 1000L)
  {
    millisDetik = millis() / 1000L;
    if (pertandinganBerjalan)
    {
      waktu++;

      if (!modeInformasi)
      {
        tampilanUtama();
      }
    }
  }

  if (millisEfek < millis() - 100)
  {
    millisEfek = millis();
    if (efekMarque.mode == XMinus)
    {
      dmd.marqueeXMinus(&efekMarque);
    }
    else
    {
      modeInformasi = false;
      tampilanUtama();
    }
  }

  if (bluetooth.available())
  {
    byte tokenMulai = bluetooth.read();
    Serial.println(tokenMulai, HEX);
    if (tokenMulai == 0xFE)
    {
      delay(2);
      byte perintah = bluetooth.read();
      delay(2);
      byte panjang = bluetooth.read();

      for (uint16_t i = 0; i < panjang; i++)
      {
        delay(2);
        char c = bluetooth.read();
        bufferBluetooth[i] = c;
      }
      delay(2);
      byte tokenSelesai = bluetooth.read();
      if (tokenSelesai == 0xFF)
      {
        uint16_t i;
        switch (perintah)
        {
          case initPerangkat:
            bluetooth.write(237);
            break;
          case pointAplus:
            pointA++;
            break;
          case pointAminus:
            pointA--;
            break;
          case pointBplus:
            pointB++;
            break;
          case pointBminus:
            pointB--;
            break;
          case skorAplus:
            skorA++;
            break;
          case skorAminus:
            skorA--;
            break;
          case skorBplus:
            skorB++;
            break;
          case skorBminus:
            skorB--;
            break;
          case rondePlus:
            ronde++;
            break;
          case rondeMinus:
            ronde--;
            break;
          case menitPlus:
            waktu += 60 ;
            break;
          case menitMinus:
            if (waktu > 60)
              waktu -= 60;
            else
              waktu = 0;
            break;
          case resetPoint:
            pointA = 0;
            pointB = 0;
            break;
          case resetSemua:
            pointA = 0;
            pointB = 0;
            skorA = 0;
            skorB = 0;
            ronde = 0;
            waktu = 0;
            break;
          case mulai:
            pertandinganBerjalan = !pertandinganBerjalan;
            break;
          case text:
            for (i = 0; i < panjang; i++)
            {
              strInformasi[i] = bufferBluetooth[i];
            }
            strInformasi[i] = 0;
            dmd.drawFilledBox(28, 0, 67, 7, GRAPHICS_OFF);
            efekMarque.init = true;
            efekMarque.alamat = strInformasi;
            efekMarque.mode = XMinus;
            efekMarque.clear = 40;
            modeInformasi = true;

            millisEfek = millis();
            break;
        }
        if (pointA == 255)
          pointA = 0;
        if (pointB == 255)
          pointB = 0;
        if (skorA == 255)
          skorA = 0;
        if (skorB == 255)
          skorB = 0;
        if (ronde == 255)
          ronde = 0;
        if (waktu == 3600)
          waktu = 0;

        if (!modeInformasi)
        {
          tampilanUtama();
        }
      }
    }
  }
}
byte bin2bcd(byte val)
{
  return val + 6 * (val / 10);
}

void tampilanUtama()
{
  byte lebarText;
  dmd.selectFont(fontSkor);
  Arial14TengahY = (dmd.height - dmd.fontHeader.height) / 2;

  boxSkorA.clear();
  boxSkorB.clear();
  lebarText = dmd.stringWidth(String(pointA));
  dmd.drawString((28 - lebarText) / 2 + 0, Arial14TengahY, String(pointA));
  lebarText = dmd.stringWidth(String(pointB));
  dmd.drawString((28 - lebarText) / 2 + 68, Arial14TengahY, String(pointB));


  dmd.selectFont(fontWaktu);
  char waktuStr[] = "00:00";
  byte menitBCD = bin2bcd(waktu / 60);
  byte detikBCD = bin2bcd(waktu % 60);
  waktuStr[0] = (menitBCD >> 4) + 0x30;
  waktuStr[1] = (menitBCD & 0x0F) + 0x30;
  waktuStr[3] = (detikBCD >> 4) + 0x30;
  waktuStr[4] = (detikBCD & 0x0F) + 0x30;
  lebarText = dmd.stringWidth(waktuStr);
  dmd.drawString((dmd.width - lebarText) / 2, 0, waktuStr);

  dmd.selectFont(fontRonde);

  dmd.drawString(28, 8, String(skorA));
  lebarText = dmd.stringWidth(String(skorB));
  dmd.drawString((68 - lebarText), 8, String(skorB));

  lebarText = dmd.stringWidth(String(ronde));
  dmd.drawString((dmd.width - lebarText) / 2, 8, String(ronde));
}

screenshot apk papan skor

File papan skor android

 

Konversi font dmd ke gfx (c font vertikal ke horizontal)

Metode menyimpanan data font memiliki perbedaan antara vendor library.

Font Library DMD

DMD, DMD2, DMD3 menggunakan font dengan metode vertikal seperti ditunjukkan dalam diagram berikut:

Font library GFX

Font yang dikembangkan oleh adafruit dalam GFX menggunakan metode mendatar seperti diagram berikut :

Untuk keperluan konversi font dari dmd ke gfx bisa dilakukan dengan metode invert.

Coding berikut ditulis dengan bahasa php, jadi harus menggunakan web server seperti xampp:

<? php
$fontHorizontal = "";
$fontVertikal = "";
$tinggi = 0;
$lebar = 0;
$charCount = 0;
if (isset($_GET['konversiKeHorizontal']))
{
  $fontVertikal = $_GET['fontVertikal'];
  $tinggi = $_GET['tinggi'];
  $lebar = $_GET['lebar'];
  $charCount = $_GET['jumlahKarakter'];


  $verticalHex = str_getcsv ($fontVertikal, ',');
  for ($i = 0; $i < sizeof($verticalHex); $i++)
  {
    $verticalByte[$i] = hexDec($verticalHex[$i]);
  }

  for ($cc = 0; $cc < $charCount; $cc++)
  {
    $horizontalByte = array();
    for ($i = 0; $i < ($tinggi*$lebar / 8); $i++)
    {
      array_push($horizontalByte, 0);
    }

    $bit = 0;
    $byte = 0;
    $indexHorizontal = 0;
    $byteMask = 1;

    for ($x = 0; $x < $lebar; $x++)
    {
      for ($y = 0; $y < $tinggi; $y++)
      {
        $x2 = $x;
        $y2 = $y;
        if ($y >= 8)
        {
          $x2 += ((int)($y / 8) * $lebar);
          $y2 = $y % 8;
        }
        $indexVertical = ($x2 * 8) + $y2 + ($cc*$lebar*$tinggi);

        $indexVerticalByte = (int)($indexVertical / 8);
        $indexVerticalBit = $indexVertical % 8;


        $indexHorizontal = ($y * $lebar ) + $x;
        $indexHorizontalByte = (int)($indexHorizontal / 8);
        $indexHorizontalBit = $indexHorizontal % 8;

        $verticalBit = $verticalByte[$indexVerticalByte] & pow(2, $indexVerticalBit);
        if ($verticalBit)
        {
          $horizontalByte[$indexHorizontalByte] |= pow(2, 7 - $indexHorizontalBit);
        }
      }
    }
    for ($i = 0; $i < sizeof($horizontalByte); $i++)
    {
      $fontHorizontal . = "0x";
      if ($horizontalByte[$i] < 0x10)
      {
        $fontHorizontal . = '0';
      }

      $fontHorizontal . = decHex($horizontalByte[$i]);
      $fontHorizontal . = ', ';
    }
    $fontHorizontal . = '&#13;&#10;';
  }
}
?>

<html>
  <head><title>font Invert ( vertical to horizontal) - semesin.com</title>
  </head>
  <body>
    <h4>Konversi font DMD menjadi font GFX</h4><br>
    <a href="https://www.project.semesin.com/">https://www.project.semesin.com/</a>
    <form action = "" method = "get">
      Font vertikal : <br><textarea name = "fontVertikal" rows = "10" cols = "100%"> <? php echo $fontVertikal ?> < / textarea > <br>
      Tinggi : <input type = "text" name = "tinggi" value = "<?php echo $tinggi ?>"><br>
      Lebar : <input type = "text" name = "lebar" value = "<?php echo $lebar; ?>"><br>
      Jumlah : <input type = "text" name = "jumlahKarakter" value = "<?php echo $charCount; ?>"><br>
      <input type = "submit" name = "konversiKeHorizontal" value = "Konversi ke Horizontal">
    </form>
    Font horizontal : <br><textarea rows = "10" cols = "100%"> <? php echo $fontHorizontal ?> < / textarea > <br>
  </body >
</html >

 

tampilan konversi font dmd ke gfx:

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

running text anti flicker (improved DMD) dengan arduino

DMD (dot matrix display) yang dikontrol dengan arduino dengan segala keterbatasannya memiliki permasalahan saat panel DMD disusun dalam lebih dari 4 panel. Flicker terjadi karena proses pengiriman data serial dari arduino harus mengantri sekian lama sehingga pergantian aktifasi baris per baris tertangkap oleh mata seperti berayun (berkedip) dan tentu membuat mata tidak nyaman.

Untuk itu saya melakukan improvisasi terhadap library arduino –DMD2– dengan prinsip kerja satu clock untuk lebih dari satu baris. contohnya untuk ukuran panel 4 kolom 2 baris kelompok DMD dibagi menjadi 2 bagian (baris 1 dan baris 2) dengan entri data yang sama setiap clock-nya.

Kelebihan alat DMD2 arduino:

  1. Sensor DHT11 untuk memantau keadaan suhu dan kelembaban sekitar
  2. Database waktu sholat 5 waktu (statis) dan dilengkapi buzzer yang menandakan waktu sholat telah masuk.

 

Komponen yang dibutuhkan :

  1. 8 Panel P10
  2. Arduino Mega 2560
  3. RTC DS1307
  4. DHT11
  5. Buzzer

DS1307 dapat diganti dengan DS3231 untuk keperluan presisi RTC.

berikut skema-nya :

berserta sketch atau program nya:

 

#include <DMD2.h>
#include <fonts/SystemFont5x7.h>
#include <fonts/Arial14.h>
#include <TimeLib.h>
#include <DS1307RTC.h>
#include "DHT.h"

byte DataPins[2] = {33, 35}; //pin jalur out
SoftDMD dmd(4, 2, 23, 25, 27, 31, 29, 2, DataPins); //kolom, baris, OE, A, B, SCK, CLK, jumlah jalur out, pin jalur out
//SoftDMD dmd(4,2,23,25,27,31,29,33); //standard

DMD_TextBox box(dmd, 0, 0, 78, 32);

DHT dht(A0, DHT11);
String namaSholat[] = {"  Subuh", "  Zuhur", "   Asar", " Maghrib", "   Isya"};
byte waktuSholat[][2] = {{5, 12},
                        {12, 32},
                        {15, 45},
                        {18, 35},
                        {19, 44}
};

#define waktunyaSholat 1
#define pesanSMS 2

int n = 123;
byte lastSecond = 60;
byte lastDay = 32;
byte lastH = 60;
byte lastT = 32;
String Sholat;
String pesanDisplay;
byte pesan;
int buzzer = 8;
bool buzz;
byte buzzCounter;

void setup() {
  Serial.begin(9600);
  Serial.println("Running text dengan Arduino bebas kedip");
  Serial.println("https://www.project.semesin.com");
  dht.begin();
  dmd.setBrightness(255);
  dmd.begin();

  pesan = pesanSMS;
  pesanDisplay = "  Selamat\n  datang";
  dmd.selectFont(Arial14);
  box.print(pesanDisplay);
}

void loop()
{
  tmElements_t tm;
  byte h = (byte)dht.readHumidity();
  byte t = (byte)dht.readTemperature();
  RTC.read(tm);

  if (pesan == waktunyaSholat)
  {
    buzzCounter++;
    if (!(buzzCounter % 32))
    {
      buzz = !buzz;
      digitalWrite(buzzer, buzz);
      pinMode(buzzer, OUTPUT);
    }
  }

  if (tm.Second != lastSecond)
  {
    String waktu = "";
    if (tm.Hour < 10)
      waktu += "0";
    waktu += tm.Hour;
    waktu += ":";
    if (tm.Minute < 10)
      waktu += "0";
    waktu += tm.Minute;
    waktu += ":";
    if (tm.Second < 10)
      waktu += "0";
    waktu += tm.Second;
    lastSecond = tm.Second;

    dmd.selectFont(SystemFont5x7);
    dmd.drawString(80, 0, waktu);

    if ((pesan == waktunyaSholat) && (tm.Second >= 58))
    {
      box.clear();
      dmd.selectFont(Arial14);
      box.print(pesanDisplay);
      pesan = pesanSMS;
      digitalWrite(buzzer, LOW);
    }
    else if (tm.Second <= 1)
    {
      for (byte i = 0; i < 5; i++)
      {
        if ((waktuSholat[i][0] == tm.Hour) && (waktuSholat[i][1] == tm.Minute))
        {
          Sholat = namaSholat[i];
          box.clear();
          dmd.selectFont(Arial14);
          box.println("  Sholat");
          box.print(Sholat);
          pesan = waktunyaSholat;
        }
      }
    }
  }
  if (tm.Day != lastDay)
  {
    String tanggal = "";
    if (tm.Day < 10)
      tanggal += "0";
    tanggal += tm.Day;
    tanggal += "/";
    if (tm.Month < 10)
      tanggal += "0";
    tanggal += tm.Month;
    tanggal += "/";
    if (tmYearToCalendar(tm.Year) < 10)
      tanggal += "0";
    tanggal += tmYearToCalendar(tm.Year);
    lastDay = tm.Day;

    dmd.selectFont(SystemFont5x7);
    dmd.drawString(80, 8, tanggal);
  }
  if ((h != lastH) || (t != lastT))
  {
    String suhu = "";
    if (t < 10)
      suhu += "0";
    suhu += t;
    suhu += "'C ";
    if (h < 10)
      suhu += "0";
    suhu += h;
    suhu += "%";

    lastT = t;
    lastH = h;

    dmd.selectFont(SystemFont5x7);
    dmd.drawString(80, 16, suhu);
  }
}

dokumentasi Galeri DMD arduino anti flicker

Library yang sudah dimodifikasi: DMD-GL

Jika menginginkan jadwal sholat yang dinamis (waktu matahari) bisa menggunakan library “PrayerTimes.h”.