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 :

JWS Jammer dengan Database Jadwal Waktu Shalat Bulanan

Jammer merupakan alat pengacak/blokir sinyal handphone/hp dapat digunakan di tempat ibadah untuk me-nonaktifkan perangkat cellular sehingga tidak bisa dipanggil/memanggil dengan tujuan menjaga tempat ibadah dari kebisingan dering ponsel.

Penggunaan jammer/jamming/repeater sinyal hp bisa mengganggu hak orang lain dan berpotensi melanggar undang-undang telekomunikasi, gunakan dengan bijak

Jadwal Shalat

Jadwal shalat berubah-ubah setiap hari tergantung posisi matahari dan bulan, hal ini membuat perangkat digital harus mampu mengikuti perubahan ini. Beberapa metode penggunaan jadwal shalat shalat digital :

  1. Jadwal manual, yaitu jadwal rata-rata dari setiap waktu-waktu shalat
  2. Jadwal database, yaitu jadwal yang tersimpan dalam tabel, bisa mingguan, bulanan atau tahunan
  3. Jadwal Matahari, yaitu penghitungan waktu shalat menggunakan posisi peredaran matahari, dengan memasukkan variabel posisi lintang, bujur, dan tanggal.
  4. Jadwal online, dengan mengambil data dari server online setiap hari.

Skema JWS Jammer menggunakan arduino:

Komponen yang digunakan dalam JWS Database Jadwal Waktu Bulanan:

  1. Arduino Uno
  2. LCD 1602 I2C Backpack
  3. RTC DS3231
  4. Relay untuk jammer
  5. 3x LED
  6. 3x TOmbol

Koding/program JWS Jadwal Bulanan:

#define pinLedMerah             5
#define pinLedHijau             6
#define pinLedBiru              7

#define pinTombolOtomatis       11
#define pinTombolManual         12
#define pinTombolJammer         13

#define pinJammer               4
#define relayOn                 LOW

#define waktuJammerShalat       20
#define waktuJammerShalatJumat  60
#define waktuJammerManual       20

#include <Wire.h>
#include "Sodaq_DS3231.h"
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x3F, 16, 2);

struct waktu
{
  byte jam;
  byte menit;
};


const waktu jadwalShalat[][8] PROGMEM = {
  //Imsyak  Shubuh  Terbit  Dhuha Dzuhur  Ashr  Maghrib Isya
  {{ 4, 20}, { 4, 30}, { 5, 51}, { 6, 15}, {12, 7}, {15, 34}, {18, 20}, {19, 36}},
  {{ 4, 20}, { 4, 30}, { 5, 51}, { 6, 15}, {12, 8}, {15, 34}, {18, 20}, {19, 36}},
  {{ 4, 21}, { 4, 31}, { 5, 52}, { 6, 16}, {12, 8}, {15, 35}, {18, 21}, {19, 36}},
  {{ 4, 21}, { 4, 31}, { 5, 52}, { 6, 16}, {12, 9}, {15, 35}, {18, 21}, {19, 37}},
  {{ 4, 22}, { 4, 32}, { 5, 53}, { 6, 17}, {12, 9}, {15, 36}, {18, 21}, {19, 37}},
  {{ 4, 23}, { 4, 33}, { 5, 53}, { 6, 17}, {12, 9}, {15, 36}, {18, 22}, {19, 37}},
  {{ 4, 23}, { 4, 33}, { 5, 54}, { 6, 18}, {12, 10}, {15, 36}, {18, 22}, {19, 38}},
  {{ 4, 24}, { 4, 34}, { 5, 54}, { 6, 18}, {12, 10}, {15, 37}, {18, 23}, {19, 38}},
  {{ 4, 24}, { 4, 34}, { 5, 55}, { 6, 19}, {12, 11}, {15, 37}, {18, 23}, {19, 38}},
  {{ 4, 25}, { 4, 35}, { 5, 55}, { 6, 19}, {12, 11}, {15, 37}, {18, 23}, {19, 38}},
  {{ 4, 25}, { 4, 35}, { 5, 56}, { 6, 20}, {12, 12}, {15, 37}, {18, 24}, {19, 39}},
  {{ 4, 26}, { 4, 36}, { 5, 56}, { 6, 20}, {12, 12}, {15, 38}, {18, 24}, {19, 39}},
  {{ 4, 27}, { 4, 37}, { 5, 56}, { 6, 20}, {12, 12}, {15, 38}, {18, 24}, {19, 39}},
  {{ 4, 27}, { 4, 37}, { 5, 57}, { 6, 21}, {12, 13}, {15, 38}, {18, 25}, {19, 39}},
  {{ 4, 28}, { 4, 38}, { 5, 57}, { 6, 21}, {12, 13}, {15, 38}, {18, 25}, {19, 40}},
  {{ 4, 28}, { 4, 38}, { 5, 58}, { 6, 22}, {12, 13}, {15, 39}, {18, 25}, {19, 40}},
  {{ 4, 29}, { 4, 39}, { 5, 58}, { 6, 22}, {12, 14}, {15, 39}, {18, 25}, {19, 40}},
  {{ 4, 29}, { 4, 39}, { 5, 59}, { 6, 23}, {12, 14}, {15, 39}, {18, 26}, {19, 40}},
  {{ 4, 30}, { 4, 40}, { 5, 59}, { 6, 23}, {12, 14}, {15, 39}, {18, 26}, {19, 40}},
  {{ 4, 30}, { 4, 40}, { 5, 59}, { 6, 23}, {12, 15}, {15, 39}, {18, 26}, {19, 40}},
  {{ 4, 31}, { 4, 41}, { 6, 0}, { 6, 24}, {12, 15}, {15, 39}, {18, 26}, {19, 40}},
  {{ 4, 31}, { 4, 41}, { 6, 0}, { 6, 24}, {12, 15}, {15, 39}, {18, 26}, {19, 40}},
  {{ 4, 32}, { 4, 42}, { 6, 1}, { 6, 25}, {12, 16}, {15, 39}, {18, 27}, {19, 41}},
  {{ 4, 32}, { 4, 42}, { 6, 1}, { 6, 25}, {12, 16}, {15, 39}, {18, 27}, {19, 41}},
  {{ 4, 33}, { 4, 43}, { 6, 1}, { 6, 25}, {12, 16}, {15, 39}, {18, 27}, {19, 41}},
  {{ 4, 33}, { 4, 43}, { 6, 2}, { 6, 26}, {12, 16}, {15, 39}, {18, 27}, {19, 41}},
  {{ 4, 34}, { 4, 44}, { 6, 2}, { 6, 26}, {12, 17}, {15, 39}, {18, 27}, {19, 41}},
  {{ 4, 34}, { 4, 44}, { 6, 2}, { 6, 26}, {12, 17}, {15, 39}, {18, 27}, {19, 41}},
  {{ 4, 35}, { 4, 45}, { 6, 3}, { 6, 27}, {12, 17}, {15, 39}, {18, 27}, {19, 40}},
  {{ 4, 35}, { 4, 45}, { 6, 3}, { 6, 27}, {12, 17}, {15, 39}, {18, 27}, {19, 40}},
  {{ 4, 36}, { 4, 46}, { 6, 3}, { 6, 27}, {12, 17}, {15, 39}, {18, 27}, {19, 40}},
};
byte waktuUtama[] =  {1, 4, 5, 6, 7};
char namaHari[][8] = {"Minggu,", "Senin, ", "Selasa,", " Rabu, ", "Kamis, ", "Jumat, ", "Sabtu, "};
char namaWaktu[][16] = {"Imsyak", "Shubuh", "Terbit", "Dhuha", "Dzuhur", "Ashr", "Maghrib", "Isya"};

enum Mode
{
  otomatis,
  manual,
};

byte mode;
char buffer[32];
byte detikSebelumnya = 60;
byte menitSebelumnya = 60;
uint16_t unixRelay;
bool statusJammer;
DateTime now;

void setup()
{
  pinMode(pinLedMerah, OUTPUT);
  pinMode(pinLedHijau, OUTPUT);
  pinMode(pinLedBiru, OUTPUT);
  digitalWrite(pinJammer, !relayOn);
  pinMode(pinJammer, OUTPUT);

  pinMode(pinTombolOtomatis, INPUT_PULLUP);
  pinMode(pinTombolManual, INPUT_PULLUP);
  pinMode(pinTombolJammer, INPUT_PULLUP);

  Serial.begin(9600);
  Serial.println("JWS Jammer Sinyal HP dengan Jadwal Bulanan");
  Serial.println("https://www.project.semesin.com");

  Wire.begin();
  Wire.beginTransmission(0x3F);
  if (Wire.endTransmission())
  {
    lcd = LiquidCrystal_I2C(0x27, 16, 2);
  }
  lcd.begin();

  rtc.begin();
  now = rtc.now();
  if (now.year() == 2000)
  {
    //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);
    Serial.println("RTC sudah otomatis di setting (Sekali saja)");
  }

  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("JWS Bulanan");
  lcd.setCursor(0, 1);
  lcd.print("fitur : Jammer");

  delay(3000);
  lcd.clear();

  digitalWrite(pinLedHijau, HIGH);
  Serial.println("Sistem mulai");

}

void loop()
{
  now = rtc.now();

  uint16_t unixSekarang = now.hour() * 60 + now.minute();
  if (detikSebelumnya != now.second())
  {

    detikSebelumnya = now.second();
    if (!statusJammer)
    {
      sprintf(buffer, "%s %02d/%02d/%02d", namaHari[now.dayOfWeek() - 1], now.date(), now.month(), now.year() - 2000);
      lcd.setCursor(0, 0);
      lcd.print(buffer);
    }
    sprintf(buffer, "%02d:%02d:%02d", now.hour(), now.minute(), now.second());
    lcd.setCursor(4, 1);
    lcd.print(buffer);
  }
  if (menitSebelumnya != now.minute())
  {
    menitSebelumnya = now.minute();
    if (mode == otomatis)
    {
      for (byte i = 0; i < 5; i++)
      {
        if ((pgm_read_byte(&jadwalShalat[now.date() - 1][waktuUtama[i]].jam) == now.hour()) &&
            (pgm_read_byte(&jadwalShalat[now.date() - 1][waktuUtama[i]].menit) == now.minute()))
        {
          digitalWrite(pinLedMerah, HIGH);
          digitalWrite(pinJammer, relayOn);

          if ((i == 1) && (now.dayOfWeek() == 6)) //Dzuhur / jumatan
          {
            unixRelay = unixSekarang + waktuJammerShalatJumat;//menit
          }
          else
          {
            unixRelay = unixSekarang + waktuJammerShalat;//menit
          }
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("  J A M M E R   ");
          statusJammer = true;

          sprintf(buffer, "Waktu: %s", namaWaktu[waktuUtama[i]]);
          lcd.setCursor(0, 1);
          lcd.print(buffer);

          delay(5000);
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("  J A M M E R   ");
        }
      }
    }
    if (statusJammer)
    {
      if (unixSekarang == unixRelay)
      {
        statusJammer = false;
        digitalWrite(pinLedMerah, LOW);
        digitalWrite(pinJammer, !relayOn);
      }
    }
  }


  if (!digitalRead(pinTombolOtomatis))
  {
    delay(50);
    if (!digitalRead(pinTombolOtomatis))
    {
      mode = otomatis;
      digitalWrite(pinLedHijau, HIGH);
      digitalWrite(pinLedBiru, LOW);
      lcd.setCursor(0, 0);
      lcd.print("    M O D E     ");
      lcd.setCursor(0, 1);
      lcd.print("O T O M A T I S ");
      delay(3000);
      lcd.clear();
    }
  }
  if (!digitalRead(pinTombolManual))
  {
    delay(50);
    if (!digitalRead(pinTombolManual))
    {
      mode = manual;
      digitalWrite(pinLedHijau, LOW);
      digitalWrite(pinLedBiru, HIGH);
      lcd.setCursor(0, 0);
      lcd.print("    M O D E     ");
      lcd.setCursor(0, 1);
      lcd.print("  M A N U A L   ");
      delay(3000);
      lcd.clear();
    }
  }
  if (mode == manual)
  {
    if (!digitalRead(pinTombolJammer))
    {
      delay(50);
      if (!digitalRead(pinTombolJammer))
      {
        if (statusJammer)
        {
          digitalWrite(pinLedMerah, LOW);
          digitalWrite(pinJammer, !relayOn);
          statusJammer = false;
        }
        else
        {
          digitalWrite(pinLedMerah, HIGH);
          digitalWrite(pinJammer, relayOn);
          unixRelay = unixSekarang + waktuJammerManual;//menit
          statusJammer = true;
          lcd.setCursor(0, 0);
          lcd.print("  J A M M E R   ");
          lcd.setCursor(0, 1);
          lcd.print("  M A N U A L   ");
          delay(5000);
        }
        while (!digitalRead(pinTombolJammer));
        delay(50);
      }
    }
  }
}
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:

Penjadwalan dan durasi aktif relay dengan setting melalui tombol berbasis arduino

Pengontrolan waktu hidup dan mati peralatan sebagai otomasi yang mengurangi ketergantungan dari kontrol operator, bisa dilakukan dengan penjadwalan beban/peralatan. Contohnya dalam pengaturan beban dalam rumah tangga, misalkan terdapat beban yang akan dikontrol seperti berikut :

  1. lampu teras
  2. lampu taman
  3. pompa pengisi air tandon
  4. kran/solenoid Penyiram tanaman
  5. electric water heater

adalah beban-beban listrik yang biasanya hidup dan mati-nya terjadwal.

Untuk mengatur jadwalnya, pada contoh ini menggunakan 3 tombol yaitu set, up dan down. adapun komponen yang digunakan adalah :

  1. Arduino uno
  2. rtc ds3231
  3. lcd 16×02 i2c
  4. relay 8 channel

Skema penjadwalan relay menggunakan arduino :

koding arduino penjadwalan relay :


#define pinTombolSet        A0
#define pinTombolUp         A1
#define pinTombolDown       A2

#define pinRelay1           2
#define pinRelay2           3
#define pinRelay3           4
#define pinRelay4           5
#define pinRelay5           6
#define pinRelay6           7
#define pinRelay7           8
#define pinRelay8           9

#define relayOn             LOW
#define jumlahRelay         8

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

LiquidCrystal_I2C lcd(0x3F, 16, 2);//coba juga 0x27

byte setting[jumlahRelay * 4];
byte menu = 0;
char buf[32];
DateTime now;
byte detikSebelumnya = 60;
byte pinRelay[] = {pinRelay1, pinRelay2, pinRelay3, pinRelay4, pinRelay5, pinRelay6, pinRelay7, pinRelay8};

void setup()
{
  pinMode(pinTombolSet, INPUT_PULLUP);
  pinMode(pinTombolUp, INPUT_PULLUP);
  pinMode(pinTombolDown, INPUT_PULLUP);

  for (byte i = 0; i < jumlahRelay; i++)
  {
    digitalWrite(pinRelay[i], !relayOn);
    pinMode(pinRelay[i], OUTPUT);
  }

  Serial.begin(9600);
  Serial.println(F("Penjadwalan dan durasi aktif relay dengan setting melalui tombol berbasis arduino"));
  Serial.println(F("https://www.project.semesin.com"));
  Serial.println();
  
  Wire.begin();
  rtc.begin();
  DateTime dt(2011, 11, 10, 15, 18, 0, 5); // set tanggal dan waktu (format): tahun, bulan tanggal, jam, menit, detik, hari (1=minggu, 7=sabtu)
  rtc.setDateTime(dt);

  Wire.beginTransmission(0x3F);
  if (Wire.endTransmission())
  {
    lcd = LiquidCrystal_I2C(0x27, 16, 2);
  }
  lcd.begin();

  lcd.backlight();
  lcd.print("Jadwal relay");
  lcd.setCursor(0, 1);
  lcd.print("www.Semesin.com");
  delay(3000);

  lcd.clear();

  if (EEPROM.read(0) != 12)
  {
    EEPROM.update(0, 12);
    for (byte i = 0; i < jumlahRelay * 4; i++)
    {
      setting[i] = 0;
    }
    EEPROM.put(1, setting);
  }
  EEPROM.get(1, setting);

  Serial.println("Sistem mulai");

}


void loop()
{
  now = rtc.now();
  if (detikSebelumnya != now.second())
  {
    detikSebelumnya = now.second();
    if (now.second() == 0)
    {
      for (byte i = 0; i < jumlahRelay; i++)
      {
        uint16_t unixNow = (now.hour() * 60) +  now.minute();
        uint16_t unixWaktu = ((setting[(i * 4) + 0] * 60) +  setting[(i * 4) + 1]);
        uint16_t unixDurasi = ((setting[(i * 4) + 2] * 60) +  setting[(i * 4) + 3]);
        if (unixNow == unixWaktu)
        {
          digitalWrite(pinRelay[i], LOW);
          Serial.print("Relay ");
          Serial.print(i + 1);
          Serial.println(" aktif");
        }
        if (unixNow == unixWaktu + unixDurasi)
        {
          digitalWrite(pinRelay[i], HIGH);
          Serial.print("Relay ");
          Serial.print(i + 1);
          Serial.println(" tidak aktif");
        }
      }
    }
    if (!menu)
    {
      sprintf(buf, "%02d/%02d/%04d", now.date(), now.month(), now.year());
      lcd.setCursor(3, 0);
      lcd.print(buf);
      sprintf(buf, "%02d:%02d:%02d", now.hour(), now.minute(), now.second());
      lcd.setCursor(4, 1);
      lcd.print(buf);
    }
  }

  if (menu)
  {
    if (!digitalRead(pinTombolUp))
    {
      delay(50);
      while (!digitalRead(pinTombolUp))
      {
        setting[menu - 1]++;
        if ((menu - 1) % 2)
        {
          if (setting[menu - 1] >= 60)
          {
            setting[menu - 1] = 0;
          }
        }
        else
        {
          if (setting[menu - 1] >= 24)
          {
            setting[menu - 1] = 0;
          }
        }

        tampilanMenu();
        delay(100);
      }
    }
    if (!digitalRead(pinTombolDown))
    {
      delay(50);
      while (!digitalRead(pinTombolDown))
      {

        if ((menu - 1) % 2)
        {
          if (setting[menu - 1] == 0)
          {
            setting[menu - 1] = 59;
          }
          else
          {
            setting[menu - 1]--;
          }
        }
        else
        {
          if (setting[menu - 1] == 0)
          {
            setting[menu - 1] = 23;
          }
          else
          {
            setting[menu - 1]--;
          }
        }

        tampilanMenu();
        delay(100);
      }
    }
  }

  if (!digitalRead(pinTombolSet))
  {
    delay(50);
    if (!digitalRead(pinTombolSet))
    {
      menu++;

      if (menu == jumlahRelay * 4 + 1)
      {
        menu = 0;
        lcd.clear();
        lcd.noCursor();
        EEPROM.put(1, setting);
      }
      else
      {
        lcd.clear();
        lcd.setCursor(2, 0);
        lcd.print("Set Relay ");
        lcd.print(((menu - 1) / 4) + 1);
        tampilanMenu();
      }
      
      long miliisTekanPanjang = millis() + 3000;
      while (!digitalRead(pinTombolSet))
      {
        if (miliisTekanPanjang < millis())
        {
          menu = 0;
          lcd.clear();
          lcd.noCursor();
          EEPROM.put(1, setting);

        }
      }
    }
  }
}
void tampilanMenu()
{
  sprintf(buf, "%s : %02d:%02d", ((menu - 1) % 4) / 2 ? "Durasi" : "Waktu ", setting[(menu - 1) & 0xFE], setting[((menu - 1) & 0xFE) + 1]);
  lcd.setCursor(0, 1);
  lcd.print(buf);

  lcd.setCursor(((menu - 1) % 2) ? 12 : 9, 1);
  lcd.cursor();
}
  1. LiquidCrystal-I2C.zip
  2. Sodaq_DS3231.zip

Pewaktu otomatis dengan arduino (aplikasi pemberi pakan ikan)

Pewaktu otomatis adalah perangkat bekerja menggunakan real time clock (RTC) sebagai basis waktu dan menghasilkan output aksi tepat pada waktu yang ditentukan.

setting waktu alarm

program ini akan setiap detik menmbandingkan/mencek apakah waktu alarm sama sama dengan waktu saat ini, untuk menentukan waktu alarm dalam contoh ini menggunakan 2 waktu alarm dengan cara mengatur variabel pada bagian ini :


#define waktuMakan1 DateTime(0, 1, 1, 8, 0, 0, 0)//jam 8 pagi
#define waktuMakan2 DateTime(0, 1, 1, 17, 0, 0, 0)//jam 5 sore

kelas date time diisi nilai tahun, bulan, tanggal, jam, menit, detik, hari.
namun untuk pengplikasian di sketch pemberi makanan ikan ini hanya diset bagian jam, menit dan detik dengan tujuan nilai waktu ini berulang setiap hari.

Waktu makan ikan

Pada contoh ini perangkat akan menggerakkan servo pemberi makan ikan pada jam 8 pagi dan jam 5 sore.

skema pemberi makan ikan menggunakan arduino :

 

koding/program feeder ikan berbasis arduino:

#define pinServoMakanan               A0
  
#define waktuBukaServo                1000//milidetik
#define servoBuka                     20//derajat
#define servoTutup                    60//derajat
  
#define waktuMakan1                   DateTime(0, 1, 1,  8, 0, 0, 0)//jam 8 pagi
#define waktuMakan2                   DateTime(0, 1, 1, 17, 0, 0, 0)//jam 5 sore
  
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "Sodaq_DS3231.h"
#include <Servo.h>
  
LiquidCrystal_I2C lcd(0x3F, 16, 2);//coba juga 0x27
Servo servoMakanIkan;
  
byte detikSebelumnya;
char buf[17];

  
void setup() {
  Serial.begin(9600);
  Serial.println("Pemberi pakan ikan otomatis");
  Serial.println("https://www.project.semesin.com");
    
  servoMakanIkan.attach(pinServoMakanan);
  servoMakanIkan.write(servoTutup);
  
  Wire.begin();
  rtc.begin();
  //DateTime dt(2011, 11, 10, 15, 18, 0, 5); // set tanggal dan waktu (format): tahun, bulan tanggal, jam, menit, detik, hari (1=minggu, 7=sabtu)
  //rtc.setDateTime(dt);
  
  Wire.beginTransmission(0x3F);
  if (Wire.endTransmission())
  {
    lcd = LiquidCrystal_I2C(0x27, 16, 2);
  }
  lcd.begin();
  
  lcd.backlight();
  
  lcd.print("Pemberi ");
  lcd.setCursor(0, 1);
  lcd.print("pakan ikan");
  delay(3000);
  lcd.clear();
  
  Serial.println("Sistem mulai");
  sprintf(buf, "Set waktu 1 = %02d:%02d (%lu)", waktuMakan1.hour(), waktuMakan1.minute(), waktuMakan1.get());
  Serial.println(buf);
  sprintf(buf, "Set waktu 2 = %02d:%02d (%lu)", waktuMakan2.hour(), waktuMakan2.minute(), waktuMakan2.get());
  Serial.println(buf);
}
  
void loop() {
  
  DateTime now = rtc.now();
  if (detikSebelumnya != now.second())
  {
    sprintf(buf, "%02d:%02d:%02d", now.hour(), now.minute(), now.second());
    lcd.setCursor(4, 0);
    lcd.print(buf);
    Serial.print(buf);
  
    detikSebelumnya = now.second();
  
    uint32_t epoch = now.get() % 86400;//hanya jam menit detik
  
    if ((epoch == waktuMakan1.get()) ||
        (epoch == waktuMakan2.get()))
    {
      char buf[17];
      sprintf(buf, "Pakan = %02d:%02d", now.hour(), now.minute());
      lcd.setCursor(0, 1);
      lcd.print(buf);
      Serial.println(buf);
  
      servoMakanIkan.write(servoBuka);
      delay(waktuBukaServo);
      servoMakanIkan.write(servoTutup);
  
    }
  }
}

 

Library pemberi pakan ikan otomatis :

Bel sekolah dengan pengaturan melalui tombol

Bel sekolah merupakan pengingat waktu terjadwal yang menandai pergantian antar waktu pelajaran di sekolah. Ber sekolah juga memiliki penjawalan mingguan dan bulanan.

Perangkat bel sekolah otomatis bisa diaplikasikan menggunakan arduino sebagai unit prosesornya, tidak seperti bel sekolah digital berbasis komputer yang menyimpan jadwal dalam harddisk, bel sekolah digital arduino menyimpan data jadwal pelajaran didalam EEPROM. Data Jadwal disimpan dalam format/struktur berikut :

  • Aktif
  • Jam
  • Menit

Guna mengatur data jadwal tersebut, perangkat bel sekolah ini dilengkapi dengan tombol-tombol dengan fungsi [menu], [tambah], [kurang] dan [ok].

serta penggunaan LCD sebagai tampilan waktu sekarang dan tampilan jadwal apabila waktunya telah tepat.

skema bel sekolah dengan pengaturan melalui tombol/button:

komponen yang digunakan :

  1. Arduino uno
  2. RTC DS3231
  3. LCD i2C
  4. push button 4x

sketch/koding bel sekolah arduino :

#define pinTombolMenu       5
#define pinTombolTambah     4
#define pinTombolKurang     3
#define pinTombolOk         2

#include <EEPROM.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SoftwareSerial.h>
#include "RTC.h"

LiquidCrystal_I2C lcd(0x3F, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display
RTC_DS3231 rtc;
char namaHari[][7] = {"Minggu", "Senin", "Selasa", " Rabu", "Kamis", "Jum'at", "Sabtu"};
char textMenuUtama[][17] = {
  "Bel masuk +pel 1",
  "Ganti pel 2     ",
  "Bel istirahat   ",
  "Bel masuk +pel 3",
  "Ganti pel 4     ",
  "Bel pulang      ",
  "Set Jam         ",
};
char textAktif[][6] = {"Mati ", "Aktif"};

char bufWaktu[40];

struct Jadwal
{
  bool aktif;
  byte jam;
  byte menit;
};

Jadwal jadwal[6] = {{0, 7, 0}, {0, 7, 0}, {0, 7, 0}, {0, 7, 0}, {0, 7, 0}, {0, 7, 0},} ;
Jadwal jadwalSet;

void setup()
{
  pinMode(pinTombolMenu, INPUT_PULLUP);
  pinMode(pinTombolTambah, INPUT_PULLUP);
  pinMode(pinTombolKurang, INPUT_PULLUP);
  pinMode(pinTombolOk, INPUT_PULLUP);

  Serial.begin (9600);

  rtc.begin();

  if (rtc.lostPower())
  {
    Serial.println(F("Waktu RTC di set ulang"));
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }

  Wire.beginTransmission(0x3F);
  if (Wire.endTransmission())
  {
    lcd = LiquidCrystal_I2C(0x27, 16, 2);
  }
  lcd.begin();
  // Print a message to the LCD.
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("Nama");
  lcd.setCursor(0, 1);
  lcd.print("Judul");

  //  delay(3000);

  if (EEPROM.read(0) != 0x48)
  {
    simpanJadwal();
    EEPROM.write(0, 0x48);
  }
  else
  {
    ambilJadwal();
  }
  Serial.println("Bel sekolah dimulai");
}

byte detikSebelumnya = 60;
byte menitSebelumnya = 60;
byte menuLevel = 0;
byte menuIndex[2];
DateTime setWaktu;

void loop()
{
  DateTime now = rtc.now();
  if (detikSebelumnya != now.detik)
  {
    detikSebelumnya = now.detik;
    if (!menuLevel)
    {
      sprintf(bufWaktu, "Pukul : %02d:%02d:%02d", now.jam, now.menit, now.detik);
      lcd.setCursor(0, 0);
      lcd.print(bufWaktu);
      sprintf(bufWaktu, "%s, %02d/%02d/%02d", namaHari[now.hari - 1], now.tanggal, now.bulan, now.tahun - 2000);
      lcd.setCursor(0, 1);
      lcd.print(bufWaktu);

    }
    if (menitSebelumnya != now.menit)
    {
      menitSebelumnya = now.menit;
      for (byte i = 0; i < 6; i++)
      {
        if (jadwal[i].aktif)
        {
          if ((jadwal[i].jam == now.jam) && (jadwal[i].menit == now.menit))
          {
            lcd.setCursor(0, 0);
            lcd.print("  Bel Sekolah   ");
            lcd.setCursor(0, 1);
            lcd.print(textMenuUtama[i]);
            delay(10000);
          }
        }
      }
    }
  }

  if (!digitalRead(pinTombolMenu))
  {
    delay(100);
    if (!digitalRead(pinTombolMenu))
    {
      if (menuLevel == 0)
      {
        menuLevel = 1;
        menuIndex[0] = 0;
      }
      else
      {
        menuLevel = 0;
        lcd.noBlink();
      }
      tampilanMenu();
      while (!digitalRead(pinTombolMenu));
    }
  }
  if (!digitalRead(pinTombolTambah))
  {
    delay(100);
    if (!digitalRead(pinTombolTambah))
    {
      if (menuLevel == 1)
      {
        menuIndex[0]++;
        if (menuIndex[0] >= sizeof(textMenuUtama) / sizeof(textMenuUtama[0]))
        {
          menuIndex[0] = 0;
        }
        tampilanMenu();
      }
      if (menuLevel == 2)
      {
        if (menuIndex[0] == 6)
        {
          switch (menuIndex[1])
          {
            case 0:
              setWaktu.jam++;
              if (setWaktu.jam >= 24)
              {
                setWaktu.jam = 0;
              }
              break;
            case 1:
              setWaktu.menit++;
              if (setWaktu.menit >= 60)
              {
                setWaktu.menit = 0;
              }
              break;
            case 2:
              setWaktu.detik++;
              if (setWaktu.detik >= 60)
              {
                setWaktu.detik = 0;
              }
              break;
          }
        }
        else
        {
          switch (menuIndex[1])
          {
            case 0:
              jadwalSet.aktif = !jadwalSet.aktif;
              break;
            case 1:
              jadwalSet.jam++;
              if (jadwalSet.jam >= 24)
              {
                jadwalSet.jam = 0;
              }
              break;
            case 2:
              jadwalSet.menit++;
              if (jadwalSet.menit >= 60)
              {
                jadwalSet.menit = 0;
              }
              break;
          }
        }
        tampilanMenu();
      }
      delay(100);
    }
  }
  if (!digitalRead(pinTombolKurang))
  {
    delay(100);
    if (!digitalRead(pinTombolKurang))
    {
      if (menuLevel == 1)
      {
        if (menuIndex[0] == 0)
        {
          menuIndex[0] = sizeof(textMenuUtama) / sizeof(textMenuUtama[0]) - 1;
        }
        else
        {
          menuIndex[0]--;
        }
        tampilanMenu();
      }
      if (menuLevel == 2)
      {
        if (menuIndex[0] == 6)
        {
          switch (menuIndex[1])
          {
            case 0:
              if (setWaktu.jam == 0)
              {
                setWaktu.jam = 23;
              }
              else
              {
                setWaktu.jam--;
              }
              break;
            case 1:
              if (setWaktu.menit == 0)
              {
                setWaktu.menit = 59;
              }
              else
              {
                setWaktu.menit--;
              }
              break;
            case 2:
              if (setWaktu.detik == 0)
              {
                setWaktu.detik = 59;
              }
              else
              {
                setWaktu.detik--;
              }
              break;
          }
        }
        else
        {
          switch (menuIndex[1])
          {
            case 0:
              jadwalSet.aktif = !jadwalSet.aktif;
              break;
            case 1:
              if (jadwalSet.jam == 0)
              {
                jadwalSet.jam = 23;
              }
              else
              {
                jadwalSet.jam--;
              }
              break;
            case 2:
              if (jadwalSet.menit == 0)
              {
                jadwalSet.menit = 59;
              }
              else
              {
                jadwalSet.menit--;
              }
              break;
          }
        }
        tampilanMenu();
      }
      delay(100);
    }
  }
  if (!digitalRead(pinTombolOk))
  {
    delay(100);
    if (!digitalRead(pinTombolOk))
    {
      if (menuLevel == 1)
      {
        menuLevel = 2;
        menuIndex[1] = 0;
        if (menuIndex[0] == 6)
        {
          setWaktu = rtc.now();
          tampilanMenu();
          lcd.setCursor(4, 1);
          lcd.blink();
        }
        else
        {
          jadwalSet.aktif = jadwal[menuIndex[0]].aktif;
          jadwalSet.jam = jadwal[menuIndex[0]].jam;
          jadwalSet.menit = jadwal[menuIndex[0]].menit;
          tampilanMenu();
          lcd.setCursor(2, 1);
          lcd.blink();
        }
      }
      else if (menuLevel == 2)
      {
        menuIndex[1]++;
        if (menuIndex[0] == 6)
        {
          switch (menuIndex[1])
          {
            case 1:
              tampilanMenu();
              lcd.setCursor(7, 1);
              lcd.blink();
              break;
            case 2:
              tampilanMenu();
              lcd.setCursor(10, 1);
              lcd.blink();
              break;
            case 3:
              menuLevel = 1;
              rtc.adjust(setWaktu);
              tampilanMenu();
              lcd.noBlink();
              break;
          }
        }
        else
        {
          switch (menuIndex[1])
          {
            case 1:
              tampilanMenu();
              lcd.setCursor(8, 1);
              lcd.blink();
              break;
            case 2:
              tampilanMenu();
              lcd.setCursor(11, 1);
              lcd.blink();
              break;
            case 3:
              menuLevel = 1;
              jadwal[menuIndex[0]].aktif = jadwalSet.aktif;
              jadwal[menuIndex[0]].jam = jadwalSet.jam;
              jadwal[menuIndex[0]].menit = jadwalSet.menit;
              simpanJadwal();
              lcd.noBlink();
              tampilanMenu();
              break;
          }
        }
        while (!digitalRead(pinTombolOk));
        delay(500);
      }
    }
  }
}
void tampilanMenu()
{
  if (menuLevel == 1)
  {
    lcd.setCursor(0, 0);
    lcd.print("   Menu Utama   ");
    lcd.setCursor(0, 1);
    lcd.print(textMenuUtama[menuIndex[0]]);
  }
  else if (menuLevel == 2)
  {
    if (menuIndex[0] == 6)
    {
      lcd.setCursor(0, 0);
      lcd.print(textMenuUtama[menuIndex[0]]);
      sprintf(bufWaktu, "    %02d:%02d:%02d    ", setWaktu.jam, setWaktu.menit, setWaktu.detik);
      lcd.setCursor(0, 1);
      lcd.print(bufWaktu);
    }
    else
    {
      lcd.setCursor(0, 0);
      lcd.print(textMenuUtama[menuIndex[0]]);
      sprintf(bufWaktu, "  %s %02d:%02d   ", textAktif[jadwalSet.aktif], jadwalSet.jam, jadwalSet.menit);
      lcd.setCursor(0, 1);
      lcd.print(bufWaktu);
    }
  }
}

void ambilJadwal()
{
  byte *alamat = (byte*)jadwal;
  for (byte i = 1; i < sizeof(jadwal) + 1; i++)
  {
    *alamat++ = EEPROM.read(i);
  }
}
void simpanJadwal()
{
  byte *alamat = (byte*)jadwal;
  for (byte i = 1; i < sizeof(jadwal) + 1; i++)
  {
    EEPROM.update(i, *alamat++);
  }
}

library yang digunakan:

Bel sekolah arduino dengan kontrol android 2 (upgrade lcd)

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

Bel sekolah digital bisa di aplikasikan dalam bentuk:

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

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

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

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

Skema bel sekolah otomatis dengan kontrol android:

komponen bel sekolah arduino control android:

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

tampilan Aplikasi bel sekolah android :

sketch/aplikasi bel sekolah bluettoth android :

#define namaSekolah   "Nama Sekolah"

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

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

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

struct Waktu
{
  byte jam;
  byte menit;
};

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

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

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

};

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

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

#define hariAktifSenin 1<<6
#define hariAktifSelasa 1<<5
#define hariAktifRabu 1<<4
#define hariAktifKamis 1<<3
#define hariAktifJumat 1<<2
#define hariAktifSabtu 1<<1
#define hariAktifMinggu 1<<7

char namaHari[][7] = {"Minggu", "Senin", "Selasa", "Rabu", "Kamis", "Jum'at", "Sabtu"};
#define _hariAktif(Sen,Sel,Rab,Kam,Jum,Sab,Mgu) (Mgu<<7)|(Sen<<6)|(Sel<<5)|(Rab<<4)|(Kam<<3)|(Jum<<2)|(Sab<<1)
#define _mingguAktif(Mgu1,Mgu2,Mgu3,Mgu4,Mgu5,Mgu6) (Mgu1<<7)|(Mgu2<<6)|(Mgu3<<5)|(Mgu4<<4)|(Mgu5<<3)|(Mgu6<<2)
#define _waktu(Jam, Menit) {Jam, Menit}
#define Aktif 1
#define TidakAktif 0

TabelMataPelajaran jadwalBelajar[40];
Waktu waktu;

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

byte jadwalBerikutnyaKegiatan;


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

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

  Wire.begin();
  Wire.beginTransmission(0x3F);
  if (Wire.endTransmission())
  {
    lcd = LiquidCrystal_I2C(0x27, 16, 2);
  }
  lcd.begin();

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

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

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

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

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

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


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


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

  mp3_set_serial (mp3Serial);
  mp3_set_volume (15);//full volume 0x30

  rtc.begin();

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

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

  delay(1000);

  lcd.clear();

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

}

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

      now = rtc.now();

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

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

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

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

          digitalWrite(pinRelay, !relayOn);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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



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

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

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

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

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

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

  EEPROM.put(0, jadwalBelajar);
}

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

}

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

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


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

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

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


}

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

Suara mp3 bel sekolah arduino dengan bluetooth:

mp3.zip

aplikasi apk android untuk bel sekolah arduino (evaluasi):

Bel_sekolah_v1_Evaluasi.apk

cara penggunaan :

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

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

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

Bel Sekolah menggunakan tabel database fleksibel berbasis Arduino

Bel sekolah digital dimanfaatkan untuk menentukan waktu pertukaran kegiatan di sekolah-sekolah. Jadwal untuk sebuah sekolah berbeda dengan sekolah lainnya, baik perbedaan tingkat sekolah maupun zona waktunya. Selain itu terdapat juga perbedaan jadwal untuk masing masing hari, seperti senin pertama setiap bulan untuk upacara dan hari lainnya yang mempunyai kekhususan waktu. Bel sekolah digital berbasis arduino atau mikrokontroller lain memiliki kemampuan penjadwalan jam pelajaran tersebut. selain itu bel sekolah digital arduino juga mudah dalam pengembangan nantinya.

Dalam perancangan bel sekolah arduino ini dibatasi hanya sampai pengaplikasian tabel database arduino fleksibel yang bisa disesuaikan dengan kebutuhan. Bel sekolah berbasis arduino ini hanya berupa penerapan dasar saja yang bisa dikombinasikan dengan aplikasi Bel Sekolah fungsional lainnya.

Untuk pengembangannya bisa saja perangkat bel sekolah otomatis berbasis arduino ini ditambahkan sistem entri data dari bluetooth, wifi, PC dll. juga bisa ditambahkan sistem output multimedia seperti alarm, suara, running text, DMD dan lain-lain.

Kelebihan perancangan ini adalah:

  1. Tabel database jadwal fleksibel
  2. Pembacaan RTC dengan interupsi sehingga menghemat resource
  3. Pemanfaatan sleep mode

Komponen yang digunakan:

  1. Arduino Uno
  2. RTC DS3231

berikut skema / rangkaian bel sekolah dengan arduino:

dan program/sketch Arduino:

#include <DS3232RTC.h>
#include <avr/sleep.h>

#define SQWPin 12

struct Waktu
{ 
  byte jam; 
  byte menit; 
};

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

enum _kegiatan
{
  JamPelajaran1,
  JamPelajaran2,
  JamPelajaran3,
  JamPelajaran4,
  JamPelajaran5,
  JamPelajaran6,
  JamPelajaran7,
  JamPelajaran8,
  JamPelajaran9,
  JamPelajaran10,
  JamPelajaran11,
  JamPelajaran12,
  JamPelajaran13,
  JamPelajaran14,
  JamPelajaran15,
  Masuk,
  Upacara,
  Istirahat,
  SelesaiIstirahat,
  Kepramukaan,
  Khusus,
  Pulang,
  PulangJumat,
  PulangSabtu
};

volatile bool interupsiDetik;
byte indexMataPelajaran;

#define hariAktifSenin 1<<6
#define hariAktifSelasa 1<<5
#define hariAktifRabu 1<<4
#define hariAktifKamis 1<<3
#define hariAktifJumat 1<<2
#define hariAktifSabtu 1<<1
#define hariAktifMinggu 1<<7

String namaHari[] = {"Minggu","Senin","Selasa","Rabu","Kamis","Jum;at","Sabtu"};
#define _hariAktif(Sen,Sel,Rab,Kam,Jum,Sab,Mgu) (Mgu<<7)|(Sen<<6)|(Sel<<5)|(Rab<<4)|(Kam<<3)|(Jum<<2)|(Sab<<1)
#define _mingguAktif(Mgu1,Mgu2,Mgu3,Mgu4,Mgu5) (Mgu1<<7)|(Mgu2<<6)|(Mgu3<<5)|(Mgu4<<4)|(Mgu5<<3)
#define _waktu(Jam, Menit) {Jam, Menit}
#define Aktif 1
#define TidakAktif 0



TabelMataPelajaran jadwalBelajar[35];
Waktu waktu;
tmElements_t tm;

void setup() {
  byte i = 0;

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

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

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

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

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

  indexMataPelajaran = i;

  Serial.begin(9600);
  Serial.println("Bel Sekolah menggunakan tabel database flexibel berbaasis Arduino");
  Serial.println("Bisa ditambahkan input bluetooth, wifi, PC, komputer dll");
  Serial.println("Bisa ditambahkan output multimedia seperti suara, alarm, running text, dmd dll");
  Serial.println("https://www.project.semesin.com");
  
  byte ControlRegister;
  RTC.readRTC(0x0E,&ControlRegister,1);
  ControlRegister &= ~(0x07<<2);
  RTC.writeRTC(0x0E, &ControlRegister,1);

  *digitalPinToPCMSK(SQWPin) |= bit (digitalPinToPCMSKbit(SQWPin));
  PCIFR  |= bit (digitalPinToPCICRbit(SQWPin));
  PCICR  |= bit (digitalPinToPCICRbit(SQWPin));
 
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();

////Set waktu sekali saja
//  tm.Day = 1;
//  tm.Month = 4;
//  tm.Year = CalendarYrToTm(2018);
//  tm.Hour = 15;
//  tm.Minute = 24;
//  tm.Second = 00;
//
//  time_t t = makeTime(tm);
//  tm.Wday = dayOfWeek(t);
//  RTC.write(tm);
//  TampilkanWaktu();
}

ISR (PCINT0_vect)
{
  if(digitalRead(SQWPin))
  {
    interupsiDetik = true;
  }
}  

void loop() {
  
  
  if(interupsiDetik)
  {
    interupsiDetik = false;
    RTC.read(tm);
    
    if(tm.Second == 0)
    {
      TampilkanWaktu();//***
      
      byte hariKeDiTanggal1 = (((tm.Wday + 8)  - (tm.Day % 7)) % 7);
      byte SeninKe = ((tm.Day + 7 - hariKeDiTanggal1) / 7);
      byte mingguKe = ((tm.Day + 8 - hariKeDiTanggal1) / 7) + 1;
      
      for(byte i=0; i<indexMataPelajaran ;i++)
      {
        if(jadwalBelajar[i].aktif)
        {
          if((jadwalBelajar[i].waktu.jam == tm.Hour) && 
          (jadwalBelajar[i].waktu.menit == tm.Minute) && 
          (jadwalBelajar[i].hariAktif & (1<<(8-tm.Wday))) &&
          (jadwalBelajar[i].mingguAktif & (1<<(8-SeninKe))))
          {
            TampilkanWaktu();
            //Bisa ditambahkan sistem output
            switch(jadwalBelajar[i].kegiatan)
            {
              case JamPelajaran1:
                Serial.println("Jam Pelajaran 1");
                break;
              case JamPelajaran2:
                Serial.println("Jam Pelajaran 2");
                break;
              case JamPelajaran3:
                Serial.println("Jam Pelajaran 3");
                break;
              case JamPelajaran4:
                Serial.println("Jam Pelajaran 4");
                break;
              case JamPelajaran5:
                Serial.println("Jam Pelajaran 5");
                break;
              case JamPelajaran6:
                Serial.println("Jam Pelajaran 6");
                break;
              case JamPelajaran7:
                Serial.println("Jam Pelajaran 7");
                break;
              case JamPelajaran8:
                Serial.println("Jam Pelajaran 8");
                break;
              case JamPelajaran9:
                Serial.println("Jam Pelajaran 9");
                break;
              case JamPelajaran10:
                Serial.println("Jam Pelajaran 10");
                break;
              case JamPelajaran11:
                Serial.println("Jam Pelajaran 11");
                break;
              case JamPelajaran12:
                Serial.println("Jam Pelajaran 12");
                break;
              case JamPelajaran13:
                Serial.println("Jam Pelajaran 13");
                break;
              case JamPelajaran14:
                Serial.println("Jam Pelajaran 14");
                break;
              case JamPelajaran15:
                Serial.println("Jam Pelajaran 15");
                break;
              case Masuk:
                Serial.println("Masuk");
                break;
              case Upacara:
                Serial.println("Upacara");
                break;
              case Istirahat:
                Serial.println("Istirahat");
                break;
              case SelesaiIstirahat:
                Serial.println("Selesai istirahat");
                break;
              case Kepramukaan:
                Serial.println("Kepramukaan");
                break;
              case Khusus:
                Serial.println("Khusus");
                break;
              case Pulang:
                Serial.println("Jam pelajaran telah selesai, sampai jumpa esok hari");
                break;
              case PulangJumat:
                Serial.println("Jam pelajaran telah selesai, sampai jumpa minggu depan");
                break;
              case PulangSabtu:
                Serial.println("Jam pelajaran telah selesai, sampai jumpa minggu depan");
                break;
              default:
                Serial.println("Lainnya");
                break;
            }
          }
        }
      }
    }
  }
  delay(100);//Selesaikan Serial nge print, hapus saja jika tidak diperlukan
  sleep_mode();
}
void TampilkanWaktu()
{
  Serial.print("Waktu = ");
  print2digits(tm.Hour);
  Serial.write(':');
  print2digits(tm.Minute);
  Serial.write(':');
  print2digits(tm.Second);
  Serial.print(", Tanggal = ");
  Serial.print(namaHari[tm.Wday-1]);
  Serial.write(' ');
  Serial.print(tm.Day);
  Serial.write('/');
  Serial.print(tm.Month);
  Serial.write('/');
  Serial.print(tmYearToCalendar(tm.Year));
  Serial.println();
}

void print2digits(int number) {
  if (number >= 0 && number < 10) {
    Serial.write('0');
  }
  Serial.print(number);
}

contoh Bel Sekolah Arduino Uno dengan output modul mini MP3 DFPlayer (library DFPlayer_Mini_Mp3.h) dan software serial : Bel_Sekolah_tanpa_interupsi.ino

Bel sekolah bluetooth dengan kontrol android : disini