Input keyboard untuk LCD 16×2 menggunakan Arduino

Keyboard dan mouse merupakan perangkat PC (personal computer) yang berfungsi sebagai interface atau perantara antara pengguna dan pc. Perangkat ini umumnya terhubung menggunakan interface usb, akan tetapi umumnya keyboard dan mouse juga memiliki interface PS2 dan AT Bus.

PS2

PS2 atau Personal System/2 adalah salah satu protokol komunikasi antara komputer dan perangkat lain yang dikembangkan pada tahun 1987. Untuk keyboard dan mouse standar soket PS2-nya berbentuk seperti ini :

AT Bus

AT atau advanced technology bus dikembangkan pada tahun 1984. Standar interface AT Bus untuk keyboad berbentuk seperti ini:

USB Keyboard / mouse

Saat sekarang keyboad dan mouse dengan interface PS2 dan AT bus sudah tidak ditemukan yang digantikan dengan soket dengan interface USB. Namun kebanyakan keyboard dan mouse masih mendukung interface PS2 dengan kombinasi sebagai berikut :

Skema penggunaan keyboard dan mouse sebagai input

contoh sketch/program arduino menggunakan keyboard

#include <PS2_Semesin.h>
#include <LiquidCrystal_I2C.h>
#include <PS2Code.h>

#define keyboardDATAPIN   4
#define keyboardClockPIN  3

#define MAX_COL 16
#define MAX_ROW  2
int8_t cols = 0;
int8_t rows = 0;

LiquidCrystal_I2C lcd(0x3F, MAX_COL, MAX_ROW);
PS2 keyboard;

void setup()
{
  Serial.begin(9600);
  Serial.println("Keyboard arduino dengan tampilan I2C LCD");
  Serial.println("https://www.project.semesin.com/");
  Serial.println();

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

  keyboard.begin( keyboardDATAPIN, keyboardClockPIN );
  keyboard.setNoBreak(1);
  keyboard.setNoRepeat( 1 );
}


void loop()
{
  if ( keyboard.available() )
  {
    char keyboardData = keyboard.read();
    if(keyboardData >= ' ' && keyboardData <= '~')
    {
      lcd.print(keyboardData);
      cols++;
      if ( cols >= MAX_COL )
      {
        cols = 0;
        rows++;
        if ( rows >= MAX_ROW )
        {
          rows = 0;
        }
      }
      lcd.setCursor( cols, rows );
      Serial.print(keyboardData);
    }
    else
    {
      Serial.println();
      Serial.print("Special char = ");
      Serial.println(keyboardData,HEX);
      switch ( keyboardData )
      {
        case PS2_KEY_ENTER:
        case PS2_KEY_KP_ENTER:
          cols = 0;
          rows++;
          if ( rows >= MAX_ROW )
            rows = 0;
          break;
        case PS2_KEY_PGDN:
          rows = MAX_ROW - 1;
          break;
        case PS2_KEY_PGUP:
          rows = 0;
          break;
        case PS2_KEY_L_ARROW:
          cols--;
          if ( cols < 0 )
          {
            cols = MAX_COL - 1;
            rows--;
            if ( rows < 0 )
              rows = MAX_ROW - 1;
          }
          break;
        case PS2_KEY_R_ARROW:
          cols++;
          if ( cols >= MAX_COL )
          {
            cols = 0;
            rows++;
            if ( rows >= MAX_ROW )
              rows = 0;
          }
          break;
        case PS2_KEY_UP_ARROW:
          rows--;
          if ( rows < 0 )
            rows = 0;
          break;
        case PS2_KEY_DN_ARROW:
          rows++;
          if ( rows >= MAX_ROW )
            rows = MAX_ROW - 1;
          break;
        case PS2_KEY_BS:
          cols--;
          if ( cols < 0 )
          {
            cols = MAX_COL - 1;
            rows--;
            if ( rows < 0 )
              rows = MAX_ROW - 1;
          }
          lcd.setCursor( cols, rows );
          lcd.write( ' ' );
          break;
        case PS2_KEY_HOME:
          cols = 0;
          rows = 0;
          break;
        case PS2_KEY_END:
          cols = MAX_COL - 1;
          rows = MAX_ROW - 1;
          break;
      }
      lcd.setCursor( cols, rows );
    }
  }
}

library LiquidCrystal-I2C.zip, PS2_Semesin.zip

Pengontrolan tegangan menggunakan PWM pada arduino

Pengontrolan tegangan berfungsi untuk menjaga kestabilan tegangan keluaran ke beban sehingga beban bisa bekerja semestinya. Contohnya jika beban lampu yang intensitas cahayanya bergantung kepada tegangan, maka dengan tegangan yang stabil akan mengeluarkan cahaya yang stabil pula.

Hal yang menyebabkan ketidakstabilan tegangan diantaranya :

  1. Perubahan beban (penambahan dan pengurangan)
  2. Perubahan nilai masukan (input)
  3. Faktor luar seperti interferensi.

Faktor yang mempengaruhi keandalan pengontrolan tegangan :

  1. Kecepatan respon dari pengontrol tegangan terhadap perubahan yang terjadi, semakin cepat semakin baik.
  2. Sistem koreksi yang digunakan, seperti PID, fuzzy
  3. Karakteristik sensor dan beban yang digunakan

Pengontrolan tegangan dengan arduino

Pengendalian tegangan harus memiliki masukan sensor tegangan dan aktuator kontrol tegangan. Pada aplikasi arduino pembacaan tegangan menggunakan ADC dan aktuasi kontrol tegangan menggunakan PWM.

Dalam contoh ini, sistim koreksi tegangan menggunakan metode proporsional, yaitu semakin besar selisih tegangan dan input maka akan semakin besar pula penambahan nilai PWM.

skema sistem kontrol tegangan mengguakan arduino:

Sketch / koding Penngendalian Tegangan dengan PWM:

#define pinSensorTegangan     0
#define pinOutputPWM          9
#define setTegangan           2.5//volt
#define faktorProporsional    0.1

float keluaran;

void setup() {
  pinMode(pinOutputPWM, OUTPUT);
  
  Serial.begin(9600);
  Serial.println("Sumber tegangan stabil (automatic voltage regulator) menggunakan kontrol proporsional");
  Serial.println("https://www.project.semesin.com/");
  Serial.println();

  keluaran = setTegangan;
}

void loop() {
  uint16_t adc = analogRead(pinSensorTegangan);
  float tegangan = map(adc, 0, 1024, 0, 500)/100.0;
  float selisih = setTegangan - tegangan;
  float proporsional = faktorProporsional * selisih;
  
  keluaran += proporsional;
  keluaran = constrain(keluaran, 0, 5);
  byte keluaranPWM = map(keluaran*100, 0, 5*100, 0, 255);
  analogWrite(pinOutputPWM, keluaranPWM);

  //Plot serial, hapus untuk menambah kecepatan
  Serial.print(tegangan);
  Serial.print(", ");
  Serial.print(keluaranPWM);
  Serial.println();
  delay(10);
}

Hasil Plot sinyal PWM (merah) dan tegangan keluaran (biru) terhadap perubahan beban.

Tombol power otomatis arduino

tombol pengunci (self-latching)

Rangkaian kunci tombol otomatis bisa diterapkan dengan bermacam komponen utama, yang umum digunakan adalah dengan menggunakan relay, transistor, mosfet dan SCR.

Penggrendel tombol dengan relay

Dalam sistem listrik rangkaian ini dikenal sebagai DOL (direct on line). Jika tombol ‘nyala’ ditekan maka tegangan akan masuk ke relay melalui tombol ‘padam’, kemudian relay akan aktif dan NO dalam keadaan kontak dan mengunci tegangan tetap masuk ke coil relai dan mengunci posisi relay aktif.

Jika tombol ‘padam’ ditekan dalam keadaan rangkaian aktif, maka suplai  kunci akan terputus dan relay kembali nonaktif.

Pengancing tombol dengan SCR

Masih menggunakan interface yang sama tetapi menggunakan SCR/thyristor 2P4M sebagai penguncinya. Jika tombol ‘nyala ditekan, akan mengalirkan arus ‘gate trigger’ melalui resistor 330 ohmm dan menjadikan SCR dalam keadaan on-state yang selalu aktif walaupun tombol ‘nyala dilepaskan’.

Jika tombol ‘padam’ ditekan, maka suplay arus ke SCR melalui beban outpun akan hilang dan otomatis akan mematikan operasi SCR.

Tombol Vcc otomatis pada arduino menggunakan MOSFET

Tombol power dan arduino bisa dikombinasikan (saling melengkapi) antara pemberi sumber, dan pengunci sumber.

Cara kerjanya adalah pada saat tombol power ditekan, gate pada mosfet akan diberi tegangan 5V, dan menjadikan mosfet menghantarkan GND arduino ke ground sumber.

Sesaat setelah menerima power dari sumber/baterai melalui mosfet, arduino akan menjalankan perintah untuk mengunci kondisi mosfet tetap aktif.

Untuk menonaktifkan mosfetm, cukup dengan menjadikan pin Gate bernilai LOW.

contoh sketch Sumber baterai dengan tombol otomais:

#define pinPower A0
#define pinLED   13

void setup() {
  Serial.begin(9600);
  Serial.println("Power arduino otomatis menggunakan MOSFET");
  Serial.println("https://www.project.semesin.com/");
  Serial.println();
  Serial.println("Jangan beri power supply / catu daya USB");
  Serial.println("Akan dimatikan dalam 10 detik");
  Serial.println();
  
  pinMode(pinPower, OUTPUT);
  pinMode(pinLED, OUTPUT);
  digitalWrite(pinPower, HIGH);
  digitalWrite(pinLED, LOW);

  delay(7000);
  digitalWrite(pinLED, HIGH);//Tanda arduino akan dimatikan 3 detik lagi
  delay(3000);

  //Fungsi mematikan power Vcc
  digitalWrite(pinPower, LOW);
  
}

void loop() {

}

Tombol power otomatis pada arduino menggunakan SCR (hemat energi)

Prinsip kerja power otomatis pada arduino ini adalah ketika tombol ‘power’ ditekan, maka gate dari scr akan diberi trigger untuk mengaktifkan SCR, setelah tombol dilepaskan SCR akan tetap aktif tanpa sumber arus lain. Tidak seperti menggunakan transistor atau mosfet dimana arus dan tegangan harus disuplai dari arduino.

Untuk mematikan power ini, cukup dengan meng-ground-kan / logika LOW pada pin gate.

contoh sketch kunci tombol power otomatis:

#define pinPower A0
#define pinLED   13

void setup() {
  Serial.begin(9600);
  Serial.println("Power arduino otomatis ");
  Serial.println("https://www.project.semesin.com/");
  Serial.println();
  Serial.println("Jangan beri power supply / catu daya USB");
  Serial.println("Akan dimatikan dalam 10 detik");
  Serial.println();
  
  pinMode(pinLED, OUTPUT);
  digitalWrite(pinLED, LOW);

  delay(7000);
  digitalWrite(pinLED, HIGH);//Tanda arduino akan dimatikan 3 detik lagi
  delay(3000);

  //Fungsi mematikan power Vcc
  digitalWrite(pinPower, LOW);
  pinMode(pinPower, OUTPUT);
  
}

void loop() {

}

Hitung mundur Arduino (volatile countdown)

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

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

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

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

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

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

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

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

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

koding / sketch arduino hitung mundur:

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

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

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

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

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

void loop() {
  tmElements_t tm;

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

Keluaran serial monitor hitung mundur berbasis arduino:

Menu LCD Arduino dengan keypad

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

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

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

Kelebihan Menu I2C LCD Arduino ini adalah:

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

Video menu interaktif arduino:

Dalam perancangan berbasis arduino ini digunakan komponen berikut :

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

skema menu arduino LCD dan keypad:

koding/sketch menu keypad arduino:

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

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

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

LiquidCrystal_I2C lcd(0x3F, 16, 2);

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

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

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

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

uint16_t waktuTampil;
unsigned long millisMulai;

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

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

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

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

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

Library:

Tampilan seven segment dengan metode scanning menggunakan arduino

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

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

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

skema rangkaian seven segment menggunakan arduino:

tata letak seven segment:

sketch atau program scanning seven segment menggunakan arduino:

#include <TimerOne.h>

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

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

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

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

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

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

#define dotBlank 6
#define dotAll   5

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

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

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

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

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

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

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

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

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

Library : TimerOne.zip

Kalibrasi sensor loadcell interaktif dengan Serial USB TTL Arduino

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

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

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

Timbangan digital dengan sensor loadcell memiliki karakteristik akurasi berikut :

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

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

skema / rangkaian kalibrasi loadcell arduino:

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

koding /program kalibrasi loadcell menggunakan arduino:

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

#define alamatKalibrasiM 0
#define alamatKalibrasiC 4

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

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

long lastMillis;

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

  lastMillis = millis();
}

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

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

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

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

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

Cara kalibrasi loadcell melalui serial monitor:

Prosedur kalibrasi loadcell dengan arduino melalui serial monitor:

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

Library : HX711.zip

Seting waktu RTC otomatis dengan arduino

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

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

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

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

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

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

Skema tulis waktu rtc otomatis (kompatibel DS1307):

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

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

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

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

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

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

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

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

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

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

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

Dimmer PWM arduino

Dimmer adalah rangkaian elektronik yang memodifikasi bentuk sinyal ac murni menjadi sinyal terpotong-potong sehingga daya keluaran bisa diatur. Pemotongan sinyal ac ini berguna sebagai peredup lampu, memperlambat motor, mengatur pemanasan dan lainnya.

Dimmer yang lebih komplek menggunakan PWM sebagai pengendalinya. PWM bisa dihasilkan oleh rangkaian SCR, chip/IC PWM atau mikrokontroller. Dimmer PWM ini mampu menghasilkan tingkatan daya yang kecil, sehingga pengontrolan menjadi lebih presisi.

Dimmer PWM bisa dikategorikan menjadi dua macam yaitu :

  1. Penyalaan berdasarkan titik nol.
  2. Penyalaan bebas.

Penyalaan berdasarkan titik nol

Waktu penyalaan bergantung pada saat sinya menyentuh nilai nol. Maka dibutuhkan mekanisme untuk mendeteksi waktu sinyal tersebut bernilai 0.

Komponen SCR memiliki sifat forward blocking, forward conduction, dan reverse blocking, maka komponen ini cocok digunakan sebagai dimmer elektronik.

Rangkaian dimmer lampu ac yang memanfatkan sifat SCR:

Pada aplikasi dimmer digital, perlintasan titik nol harus dideteksi terlebih dahulu sebelum melakukan menyalaan, Pendeteksian nilai nol bisa dilakukan dengan rangkaian zero crossing detector / ZCD berikut :

Perancangan dimmer PWM mengikuti kaidah berikut:

  1. Waktu penyalaan, sinyal bolak-balik (AC) senantiasa bergerak naik dan turun, maka sinyal pengontrol PWM haruslah dimulai saat sinyal AC meninggalkan nilai nol
  2. Frekuensi AC, Sinyal pengontrol PWM juga harus memiliki frekuensi tepat dengan frekuensi sinyal AC (listrik)

Kendala membuat dimmer metode zero cross adalah :

  1. frekuensi ac 220v dari penyedia listrik seperti PLN bisa saja berubah-ubah. pada contoh dimmer lampu 220v, intensitas cahaya menjadi tidak konsisten. Untuk mengantisipasi ini sebaiknya dilakukan pengukuran frekuensi secara berkala.
  2. Sulit untuk sinkronisasi frekuensi jala listrik dengan frekuensi pengontrol, karena keterbatasan perhitungan digital, misalnya faktor pergeseran frekuensi akibat pembagian bilangan yang tidak sempurna. Sebagai contoh perangkat digital akan sulit mencapai frekuensi 50,00019 Hz.
  3. Memakai resources mikrokontroller seperti arduino untuk mendeteksi ZCD terus menerus.
  4. Jika ada kesalahan setting waktu penyalaan (program diinterupsi) maka beban seperti lampu akan berkedip.
  5. Pada duty cycle rendah, untuk dimmer lampu akan terlihat flicker karena perbandingan waktu on  sangat kecil dibandingkan waktu off.

Rangkaian dimmer arduino dengan beban lampu:

Penampakan modul dimmer lampu:

Penghasil sinyal PWM yang favorit adalah arduino, karena mampu menghitung frekuensi dan melakukan penyesuaian apabila ada pergeseran frekuensi:

Sketch / koding dimmer lampu arduino
fitur:

  1. input zcd dari semua pin (tidak harus pin int0/pin 9 dan int1/pin 10)
  2. input kontrol berupa duty cycle (rentang 0.0 – 100.0 %)
#define PWM         9  //!!!Mega hanya pin 10-13. 50-53, 14-15, A8-A15
#define ZCD         10 // A0 = 14, A5 = 19
#define frekuensi   50 //50 Hz
#define inputSerial 0
  
volatile uint16_t dutyCycle;
#define maxDutyCycle    ((16000000L / (2 * 1024L *  frekuensi)) - 1)
  
volatile intptr_t *portPWM;
volatile uint32_t millisZCDSebelumnya;
byte bitPWM;
  
void setup() {
  Serial.begin(9600);
  Serial.println("Dimmer arduino");
  Serial.println("https://www.project.semesin.com/");
  Serial.println();
  
  dutyCycle = 0;
  TCCR2A = _BV(WGM21);
  TCCR2B = _BV(CS22) | _BV(CS21) | _BV(CS20);
  OCR2A = maxDutyCycle;
  OCR2B = setDutyCycle(dutyCycle);
  TIMSK2 = _BV(OCIE2B);
  
  *digitalPinToPCMSK(ZCD) |= bit (digitalPinToPCMSKbit(ZCD));
  PCIFR  |= bit (digitalPinToPCICRbit(ZCD));
  PCICR  |= bit (digitalPinToPCICRbit(ZCD));
  
  portPWM = (volatile intptr_t *) portOutputRegister(digitalPinToPort(PWM));
  bitPWM = digitalPinToBitMask(PWM);
  
  pinMode(PWM, OUTPUT);
}
  
void loop() {
#if inputSerial
  
  if (Serial.available())
  {
    int data = Serial.parseInt();
    dutyCycle = setDutyCycle(data);

    while(Serial.available())
    {
      delay(2);
      Serial.read();
    }
  }
    
#else
  
  for (byte i = 20; i <= 100; i++)
  {
    dutyCycle = setDutyCycle(i);
    delay(20);
  }
  for (byte i = 99; i != 20; i--)
  {
    dutyCycle = setDutyCycle(i);
    delay(20);
  }
    
#endif
  
}
uint16_t setDutyCycle(uint8_t dutyCycle)
{
  return maxDutyCycle - (1.0 * dutyCycle / 100 * (maxDutyCycle - 1)) + 1;
}
  
#if defined(__AVR_ATmega328P__)
#  if ((ZCD >= 0) & (ZCD <= 7))
ISR (PCINT2_vect)
#  elif ((ZCD >= 8) & (ZCD <= 13))
ISR (PCINT0_vect)
#  elif ((ZCD >= 14) & (ZCD <= 19))
ISR (PCINT1_vect)
#  endif
#elif  defined(__AVR_ATmega2560__)
#  if ((ZCD >= 50) & (ZCD <= 53)) || ((ZCD >= 10) & (ZCD <= 13))
ISR (PCINT0_vect)
#  elif ((ZCD >= 14) & (ZCD <= 15))
ISR (PCINT1_vect)
#  elif ((ZCD >= A8) & (ZCD <= A15))
ISR (PCINT2_vect)
#  endif
#endif
{
  if(millisZCDSebelumnya < millis())
  {
    millisZCDSebelumnya = millis() + 7;
    OCR2B = dutyCycle;
    TCNT2 = 0;
  }
}
  
ISR (TIMER2_COMPB_vect)
{
  *portPWM |= bitPWM;
  delayMicroseconds(50);
  *portPWM &= ~bitPWM;
}

Penyalaan bebas

Waktu penyalaan dimmer tidak dipengaruhi oleh nilai nol,

Rangkaian dimmer ac sederhana :

Sirkit melalui dioda disebut juga penyearah setengah gelombang, yang menghasilkan kondisi dimmer setengah terang. Rangkaian ini biasanya digunakan pada solder, heatgun untuk pemanasan awal.

Pengaturan dimmer PWM lebih diutamakan pada frekuensi PWM-nya. Dimmer lampu akan terlihat berkedip jika frekuensi tidak sama. Untuk mengatasi pemasalahan tersebut rangkaian peredup lampu (Dimmer) didesain dengan penggunaan frekuensi yang lebih tinggi dari frekuensi sinyal AC tanpa memperhatikan waktu nol dan nilai frekuensinya.

Sinyal PWM bisa diperoleh dari rangkaian pembangkit PWM (PWM generator) atau dari mikrokontroller seperti arduino. Aplikasi rangkaian dimmer lampu arduino (rangkaian dimmer arduino) bisa menggunakan perintah analogWrite().

Berikut komponen elektronika yang digunakan dalam perancangan dimmer PWM lampu 220v:

  1. Dioda 1N5408 4 buah
  2. Dioda 1N4007
  3. Dioda zener 10V
  4. Resistor 220 ohm 2 buah
  5. Resistor 330 ohm
  6. Resistor 68 Kohm
  7. Kapasitor 2.2 uH
  8. Optocoupler 4N35
  9. Mosfet IRF 830
  10. Lampu dan Fitting

Berikut skema rangkaian dimmer lampu dc/ac yang dikontrol PWM: