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

  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

Tombol cerdas cermat +sesi diskualifikasi menggunakan arduino

Cerdas cermat adalah pertandingan yang mengandalkan kecerdasan serta kecepatan. Untuk memberikan keadilan bagi seluruh group peserta, maka perangkat pendukung harus memiliki kriteria berikut :

  1. waktu scanning
    metode yang sering digunakan adalah interupsi dan scanning tombol, dalam hal penggunaan arduino uno (yang memiliki 2 external interrupt dan 23 pin change interrupt) masing-masing memiliki kelemahan dan kelebihan :

    • metode interruptpenggunaan external interrupt adalah metode yang paling baik, namun arduino uno hanya memiliki 2 external interrupt (hanya untuk 2 group) sehingga kurang efektif. Jika menggunakan 23 jalur external interrupt lebih banyak akan tetapi jenis interupsi ini di arduino uno terpisah dalam 3 kelompok, sehingga, seandainya 2 group cerdas cermat dalam satu kelompok interupsi menekan tombol (dalam waktu¬† scanning-nya) naka harus diambil salah satu group cerdas cermat saja, dan masalahnya pengambilan keputusan ini akan menjadi masalah keadilan bagi peserta.
    • metode scanning tombol
      metode ini bisa diistilahkan ‘tombol yang tepat di waktu yang tepat’ karena jika tombol cerdas cermat ditekan bersamaan, maka yang akan terpilih adalah tombol yang sedang di scanning. Namun sebetulnya waktu scanning ini sangatlah cepat, dan letak keadilannya ditentukan oleh ‘waktu’
  2.  interlock tombol
    • Ketika group yang paling cepat di sahkan, maka tombol group lain tidak berfungsi.
    • seluruh tombol group cerdas cermat hanya bisa di tekan pada saat yang ditentukan (misalkan setelah pertanyaan selesai dibacakan) jika mendahului waktu tersebut, maka tombolnya tidak berfungsi (diskualifikasi sesi pertanyaan) dengan cara menahan [tombol reset] dan melepas-nya ketika pertanyaan selesai di bacakan

blok diagram cerdas cermat menggunakan arduino:

 

skema mesin cerdas cermat berbasis arduino:

 

koding bel cerdas cermat berbasis arduino:

#define pinGroup1               2
#define pinGroup2               3
#define pinGroup3               4
#define pinGroup4               5

#define pinGroup1Indikator      A0
#define pinGroup2Indikator      A1
#define pinGroup3Indikator      A2
#define pinGroup4Indikator      A3

#define pinReset                8
#define pinBel                  9

#define relayAktif              LOW
#define jumlahGroup             4
#define waktuBel                3000

byte pinGroup[jumlahGroup] = {pinGroup1, pinGroup2, pinGroup3, pinGroup4};
byte pinGroupIndikator[jumlahGroup] = {pinGroup1Indikator, pinGroup2Indikator, pinGroup3Indikator, pinGroup4Indikator};

byte groupAktif;
byte groupScan;
byte tombolAktif;
long millisBel;
bool statusTombol;
bool statusSesi;
bool sesi[jumlahGroup];

// the setup routine runs once when you press reset:
void setup() {
  Serial.begin(9600);
  Serial.println(F("Tombol cerdas cermat berbasis arduino"));
  Serial.println(F("https://www.semesin.com/project"));
  Serial.println();

  for (int i = 0; i < sizeof(pinGroup); i++)
  {
    pinMode(pinGroup[i], INPUT_PULLUP);
    pinMode(pinGroupIndikator[i], OUTPUT);
  }

  pinMode(pinReset, INPUT_PULLUP);

  digitalWrite(pinBel, !relayAktif);
  pinMode(pinBel, OUTPUT);

  memset(sesi, 1, 4);
}

// the loop routine runs over and over again forever:
void loop() {

  groupScan = (groupScan + 1) % jumlahGroup;
  if (!digitalRead(pinGroup[groupScan]))
  {
    if (tombolAktif)
    {
      if (sesi[groupScan])
      {
        groupAktif = groupScan + 1;
        statusTombol = true;
        statusSesi = true;
      }
    }
    else if (!statusSesi)
    {
      if (sesi[groupScan])
      {
        sesi[groupScan] = false;
        Serial.print("Diskualifikasi : ");
        Serial.println(groupScan + 1);
      }
    }
  }

  if (!digitalRead(pinReset))
  {
    delay(50);

    if (!digitalRead(pinReset))
    {
      tombolAktif = false;
      if (groupAktif)
      {
        digitalWrite(pinGroupIndikator[groupAktif - 1], LOW);
        digitalWrite(pinBel, !relayAktif);
        groupAktif = 0;
        Serial.println("Reset");
        statusSesi = false;
        memset(sesi, 1, 4);
      }
    }
  }
  else if (groupAktif)
  {
    if (statusTombol)
    {
      Serial.print("Group : ");
      Serial.println(groupAktif);

      millisBel = millis() + waktuBel;
      digitalWrite(pinBel, relayAktif);

      digitalWrite(pinGroupIndikator[groupScan], HIGH);
      statusTombol = false;
      tombolAktif = false;
    }
  }
  else if (!tombolAktif)
  {
    Serial.println("Sesi mulai");

    tombolAktif = true;
  }

  if (millisBel < millis())
  {
    digitalWrite(pinBel, !relayAktif);
  }
}

 

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 >= 24)
              {
                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:

Pengunci nilai batas (Bandgap interlock) pada arduino

Sistem interlock pada pemograman digunakan untuk mengunci suatu blok program agar dijalankan hanya satu kali. Penguncian dapat dilakukan dengan flag/bendera, jadi sebelum masuk suatu blok program nilai flag penguncinya diuji dan hanya bisa dilewati jika nilainya cocok. pada arduino algoritma flag arduino (pengunci nilai arduino / interlock arduino) biasanya dideklarasikan sebagai boolean/bool yang bernilai true dan false.

Contoh sketch berikut ini menggunakan sensor analog (bisa dikembangkan untuk sensor dengan basis komunikasi) sebagai input. Sedangkan alarm/buzzer berlaku sebagai output. Tombol berfungsi sebagai konfirmasi bahwa alarm telah disetujui.

Komponen yang digunakan :

  1. Arduino uno
  2. Sensor analog (potensio, LM35, water level, flex, dll)
  3. Buzzer
  4. Tombol push on

Skema pengujian sistem kunci arduino:

Sketch / koding contoh penggunaan flag pada arduino:
Fungsi utama:

  1. Alarm hanya hidup jika nilai diluar batas dan belum dikonfirmasi
  2. Alarm mati jika tombol konfirmasi sudah ditekan
  3. Sistem alarm dapat kembali berfungsi jika nilai sudah dalam batas
//Pin
#define pinSensor           A0
#define pinTombolKonfirmasi 2
#define pinAlarm            13

#define batasAtas 600
#define batasBawah 400

bool sistemNormal = true;

void setup() {
  pinMode(pinTombolKonfirmasi, INPUT_PULLUP);
  pinMode(pinAlarm, OUTPUT);

  Serial.begin(9600);
  Serial.println("Alarm pengunci nilai batas (Bandgap interlock) pada arduino");
  Serial.println("http://www.semesin.com/project/");
}

void loop() {
  int nilaiSensor = analogRead(pinSensor);
  Serial.print("Nilai pembacaan sensor : ");
  Serial.println(nilaiSensor);

  if((nilaiSensor <= batasBawah) || (nilaiSensor >= batasAtas))//Pembacaan diluar batas
  {
    if(sistemNormal)//alarm belum dikonfirmasi
    {
      Serial.println("Pembacaan sensor diluar batas.");
      digitalWrite(pinAlarm, HIGH);
      sistemNormal = false;
    }
  }
  else //Pembacaan dalam batas
  {
    sistemNormal = true;
  }

  if(!digitalRead(pinTombolKonfirmasi))
  {
    Serial.println("Alarm dikonfirmasi.");
    digitalWrite(pinAlarm, LOW);
  }

  delay(1000);
}

dalam bentuk lain:

//Pin
#define pinSensor           A0
#define pinTombolKonfirmasi 2
#define pinAlarm            13

#define batasAtas 600
#define batasBawah 400

bool Alarm;
bool telahKonfirmasi;
bool Konfirmasi;

void setup() {
  pinMode(pinTombolKonfirmasi, INPUT_PULLUP);
  pinMode(pinAlarm, OUTPUT);

  Serial.begin(9600);
  Serial.println("Alarm pengunci nilai batas (Bandgap interlock) pada arduino");
  Serial.println("http://www.semesin.com/project/");
}

void loop() {

  int nilaiSensor = analogRead(pinSensor);
  Serial.print("Nilai pembacaan sensor : ");
  Serial.println(nilaiSensor);

  bool sistemNormal = ((nilaiSensor >= batasBawah) && (nilaiSensor <= batasAtas));
  if(!telahKonfirmasi)
  {
    Konfirmasi = !digitalRead(pinTombolKonfirmasi);
  }

  if(sistemNormal && (!Alarm || (Alarm && Konfirmasi)))
  {
    Alarm = false;
    telahKonfirmasi = false;
    Serial.println("Status : Sistem normal");
  }
  else if(sistemNormal && Alarm)
  {
    Serial.println("Status : Sistem normal, belum dikonfirmasi");
  }
  else if(!sistemNormal && Konfirmasi)
  {
    Alarm = false;
    telahKonfirmasi = true;
    Serial.println("Status : Sistem tidak normal, telah dikonfirmasi");
  }
  else if(!sistemNormal && !telahKonfirmasi)
  {
    Alarm = true;
    Serial.println("Status : Sistem tidak normal");
  }
  digitalWrite(pinAlarm, Alarm);

  delay(1000);
}

Pengaturan alarm dengan arduino dan RTC DS1307 melalui 4 tombol

Alarm berfungsi sebagai pengingat atau pemberitahu baik melalui visual dan suara. Biasanya alarm diaktifkan pada waktu-waktu tertentu sesuai kebutuhan, adakalanya dalam satu hari ada beberapa waktu alarm diaktifkan.

Dalam desain ini saya hanya menggunakan satu entri waktu alarm yang bisa diatur dengan 4 (empat) tombol, fungsi masing-masing tombol adalah:

  1. tombol kiri (M) untuk menu, tekan pertama untuk pengaturan jam, kedua untuk menit, ketiga untuk detik dan ke-empat untuk kembali.
  2. tombol kanan (E) untuk exit/langsung kembali jika sudah dalam menu.
  3. tombol atas untuk tambah
  4. tombol bawah untuk kurang

breadboard:

komponen yang digunakan:

  1. Arduino Uno
  2. LCD matrik 16×2
  3. I2C to LCD PCF8574
  4. RTC DS1307
  5. Buzzer
  6. Tombol 4bh

sketch/program:

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

//pin
byte tombolUp = 9;
byte tombolDn = 10;
byte tombolMinus = 11;
byte tombolPlus = 8;
byte buzzer = 13;

LiquidCrystal_I2C  lcd(0x3F,16,2);
byte detikTerakhir = 60;

int alarmJamAddr = 0;
int alarmMenitAddr = 1;
int alarmDetikAddr = 2;

byte alarmJam;
byte alarmMenit;
byte alarmDetik;

bool alarmStatus = false;
unsigned long millisMulai;
unsigned long millisAlarmMulai;

bool buzzStatus;

uint16_t jedaBuzzer = 1000;
uint16_t waktuAlarm = 10000;//Alarm 10 detik

byte menu = 0;
byte menuLCDPos = 8;
byte temp;

void setup()
{
  Serial.begin(9600);
  Serial.println("Setting alarm menggunakan Arduino dan RTC1307 melalui 4 push button");
  Serial.println("http://www.semesin.com/project");

  pinMode(buzzer, OUTPUT);
  pinMode(tombolUp, INPUT_PULLUP);
  pinMode(tombolDn, INPUT_PULLUP);
  pinMode(tombolMinus, INPUT_PULLUP);
  pinMode(tombolPlus, INPUT_PULLUP);
  
  Wire.begin();
  Wire.beginTransmission(0x3F);
  if (Wire.endTransmission())
  {
    lcd = LiquidCrystal_I2C(0x27, 16, 2);
  }
  lcd.begin();
  lcd.setBacklightPin(3,POSITIVE);
  lcd.setBacklight(HIGH);

  lcd.setCursor (0,0);
  lcd.print("Waktu:    :  :  ");
  lcd.setCursor(0,1);
  lcd.print("Alarm:    :  :  ");

  readEEPROMDataWaktu();

  lcd.setCursor(8,1);
  if(alarmJam < 10)lcd.print('0');
  lcd.print(alarmJam);
  lcd.setCursor(11,1);
  if(alarmMenit < 10)lcd.print('0');
  lcd.print(alarmMenit);
  lcd.setCursor(14,1);
  if(alarmDetik < 10)lcd.print('0');
  lcd.print(alarmDetik);
}

void loop()
{
  tmElements_t tm;

  do
  {
    lcd.setCursor(menuLCDPos, 1);
    switch(bacaTombol())
    {
      case '+':
        temp = EEPROM.read(menu - 1);
        if(((temp >= 23) && (menu == 1)) || ((temp >= 59) && (menu > 1)))
          temp = 0;
        else
          temp++;
        EEPROM.write(menu - 1, temp);
        if(temp < 10)lcd.print('0');
        lcd.print(temp);
        break;
      case '-':
        temp = EEPROM.read(menu - 1);
        if((temp == 0) && (menu == 1))
          temp = 23;
        else if((temp == 0) && (menu > 1))
          temp = 59;
        else
          temp--;
        EEPROM.write(menu - 1, temp);
        if(temp < 10)lcd.print('0');
        lcd.print(temp);
        break;
      case 'M':
        menu++;
        if(menu == 1)
        {
          menuLCDPos = 8;
          temp = alarmJam;
          lcd.blink();
        }
        else if(menu == 2)
        {
          menuLCDPos = 11;
        }
        else if(menu == 3)
        {
          menuLCDPos = 14;
        }
        if(menu == 4)
        {
          menu = 0;
          lcd.noBlink();
          readEEPROMDataWaktu();
        }
        break;
      case 'E':
        menu = 0;
        lcd.noBlink();
        readEEPROMDataWaktu();
        break;
    }
  }
  while (menu);

  if(alarmStatus)
  {
    if(millisMulai + jedaBuzzer < millis())
    {
      buzzStatus = !buzzStatus;
      digitalWrite(buzzer, buzzStatus);
      millisMulai = millis();
    }
    if(millisAlarmMulai + waktuAlarm < millis())
    {
      alarmStatus = false;
      digitalWrite(buzzer, LOW);
    }
  }

  if (RTC.read(tm)) {
    if(tm.Second != detikTerakhir)
    {
      lcd.setCursor(8,0);
      if(tm.Hour < 10)lcd.print('0');
      lcd.print(tm.Hour);
      lcd.setCursor(11,0);
      if(tm.Minute < 10)lcd.print('0');
      lcd.print(tm.Minute);
      lcd.setCursor(14,0);
      if(tm.Second < 10)lcd.print('0');
      lcd.print(tm.Second);

      if((alarmJam == tm.Hour) && (alarmMenit == tm.Minute) && (alarmDetik == tm.Second))
      {
        alarmStatus = true;
        millisMulai = millis();
        millisAlarmMulai = millisMulai;
      }

      detikTerakhir = tm.Second;
    }
  }
}

char bacaTombol()
{
  char tombol = ' ';
  if(!digitalRead(tombolUp))
  {
    tombol = '+';
  }
  else if(!digitalRead(tombolDn))
  {
    tombol = '-';
  }
  else if(!digitalRead(tombolMinus))
  {
    tombol = 'M';
  }
  else if(!digitalRead(tombolPlus))
  {
    tombol = 'E';//exit
  }
  while(!digitalRead(tombolUp));
  while(!digitalRead(tombolDn));
  while(!digitalRead(tombolMinus));
  while(!digitalRead(tombolPlus));
  delay(200);

  return tombol;
}

void readEEPROMDataWaktu()
{
  alarmJam = EEPROM.read(alarmJamAddr);
  alarmMenit = EEPROM.read(alarmMenitAddr);
  alarmDetik = EEPROM.read(alarmDetikAddr);
}

 

I2C scanner

apabila ditemui kesulitan dalam mencari alamat I2C dari PCF8574 (modul I2C ke LCD 16×2) gunakan I2C scanner berikut:

#include <Wire.h>
 
void setup()
{
  Wire.begin();
 
  Serial.begin(9600);
  Serial.println("\nI2C Scanner");
}
 
void loop()
{
  byte error, address;
  int nDevices;
 
  Serial.println("Scanning...");
 
  nDevices = 0;
  for(address = 1; address < 127; address++ )
  {
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
 
    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.print(address,HEX);
      
      byte addressFull = address << 1;
      Serial.print("(");
      if (addressFull<16)
        Serial.print("0");
      Serial.print(addressFull,HEX);
      Serial.println(")");
 
      nDevices++;
    }
    else if (error==4)
    {
      Serial.print("Unknown error at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");
 
  delay(5000);
}

alamat tulis I2C yang umum:

  • DS1307 = 0xD0
  • AT24C32 = 0xA0 – oxAE

Library: