Kompresi citra dengan metode DCT-Kuantisasi-Huffman

Citra merupakan informasi multimedia dengan jumlah data yang sangat besar di mana kualitasnya sering dikaitkan dengan resolusi citra. Resolusi citra berarti ukuran panjang dan lebar dari sebuah citra dalam satuan pikel. Kedalaman intensitas warna berarti banyaknya bit yang digunakan untuk tiap kode warna yang dinyatakan dalam satuan bit/piksel. Semakin tinggi resolusi citra, semakin banyak jumlah piksel dan kedalaman intensitas warna sehingga mengakibatkan semakin baik kualitas citranya. Tingginya resolusi citra dan kedalaman intensitas warna berarti jumlah bit yang ada semakin banyak sehingga mentransmisikan citra dengan resolusi yang tinggi membutuhkan penyimpanan data citra untuk jumlah bit yang ditransmisikan. Oleh karena itu, untuk meminimalkan jumlah bit yang ditransmisikan, digunakan suatu algoritma kompresi citra.

Kompresi citra dapat dilakukan dalam domain spasial maupun domain frekuensi. Pada kompresi citra dalam domain spasial, redundansi data yang relatif tinggi dalam citra dikodekan dengan menggunakan bit yang lebih kecil. Redundansi berarti banyaknya piksel dari citra memiliki kesamaan secara visual atau kesamaan nilai. Sementara pada kompresi citra dalam domain frekuensi, perlu dilakukan proses transformasi dari domain spasial ke domain frekuensi. Merode transformasi yang digunakan pada penelitian ini yaitu Discrete Cosine Transform (DCT) yang digunakan dalam kompresi JPEG 2000.

Kompresi citra terbagi menjadi dua teknik, yaitu lossy dan loseless. Teknik kompresi citra loseless bekerja dengan membuat kapasitas file dari citra sekecil mungkin yaitu dengan mengoptimalkan teknik pengkodean data redundan yang terdapat pada citra asli. Dalam hal tersebut, kompresi loseless terjadi tanpa ada perubahan data. Salah satu metode yang menerapkan teknik kompresi loseless yaitu metode Huffman. Teknik kompresi citra lossy bekerja dengan mengurangi jumlah bit pada informasi detil citra seperti luminance dan chrominance (warna). Salah satu metode yang menerapkan teknik kompresi lossy yaitu DCT.

Discrete Cosine Transform (DCT)

Metode Discrete Cosine Transform (DCT) mengubah data citra masukan ke dalam format yang dapat mengurangi redundansi piksel. Untuk memetakan nilai piksel ke dalam satu set koefisien, teknik perubahan pengkodean menggunakan reversibel dan linier matematika transformasi. Proses selanjutnya dibutuhkan proses kuantisasi dan pengkodean. Transformasi 2D-DCT dinyatakan dalam persamaan berikut:

Kuantisasi

Pada tahap kuantisasi, koefisien DCT yang tidak penting dihilangkan guna merekontruksi citra yang baru. Proses kuantisasi menggunakan teknik lossy dengan menyeleksi frekuensi yang tinggi untuk dihilangkan.

Pengkodean Huffman

Prinsip pengkodean Huffman yaitu mengkodekan koefisien hasil proses DCT dengan mengeliminasi nilai-nilai matriks bernilai nol sehingga kelebihan dari keluaran kuantisasi hilang secara zigzag sehingga dihasilkan citra yang sudah terkompresi atau dilakukan kompresi citra.

Program matlab kompresi DCT  – Quantization – Huffman

clear all
close all
clc

I=imread('football.jpg');

qy50 = [16 11 10 16 24 40 51 61;
    12 12 14 19 26 58 60 55;
    14 13 16 24 40 57 69 56;
    14 17 22 29 51 87 80 62;
    18 22 37 56 68 109 103 77;
    24 35 55 64 81 104 113 92;
    49 64 78 87 103 121 120 101;
    72 92 95 98 112 100 103 99];

qc50 = [ 17 18 24 47 99 99 99 99;
    18 21 26 66  99 99 99 99;
    24 26 56 99 99 99 99 99;
    47 66 99 99 99 99 99 99;
    99 99 99 99 99 99 99 99;
    99 99 99 99 99 99 99 99;
    99 99 99 99 99 99 99 99;
    99 99 99 99 99 99 99 99;];

zz =[1 2 6 7 15 16 28 29;
    3 5 8 14 17 27 30 43;
    4 9 13 18 26 31 42 44;
    10 12 19 25 32 41 45 54;
    11 20 24 33 40 46 53 55;
    21 23 34 39 47 52 56 61;
    22 35 38 48 51 57 60 62;
    36 37 49 50 58 59 63 64;];


% Konversi Warna Image RGB ke YCbCr
Iycbcr=rgb2ycbcr(I);
[MI,NI,~]=size(Iycbcr);
mb=mod(MI,8);
nb=mod(NI,8);
if nb>0
    Iycbcr(:,NI+1:NI+(8-nb),:)=0;
end
if mb>0
    Iycbcr(MI+1:MI+(8-mb),:,:)=0;
end
[m,n,o] = size(Iycbcr);

% Blok Citra
Imycbcr=Iycbcr;

ImDouble = double(Imycbcr);

% DCT
ImDCT = dct(ImDouble);

% Kuantisasi
yDCT = ImDCT(:,:,1);
cbDCT = ImDCT(:,:,2);
crDCT = ImDCT(:,:,3);

y_kuantisasiBlock  = @(block_struct) round(block_struct.data ./ qy50) ;
c_kuantisasiBlock  = @(block_struct) round(block_struct.data ./ qc50) ;
y_kuantisasi =  blockproc(yDCT ,[8 8] , y_kuantisasiBlock) ;
cb_kuantisasi =  blockproc(cbDCT ,[8 8] , c_kuantisasiBlock) ;
cr_kuantisasi =  blockproc(crDCT ,[8 8] , c_kuantisasiBlock) ;

% Zig-Zag encoding
y_ZigZag = zeros(m*n,1);
cb_ZigZag = zeros(m*n,1);
cr_ZigZag = zeros(m*n,1);
idx = 0;
for i=1:8:m
    for j=1:8:n
        y_ZigZag(zz+idx) = y_kuantisasi(i:i+7, j:j+7);
        cb_ZigZag(zz+idx) = cb_kuantisasi(i:i+7, j:j+7);
        cr_ZigZag(zz+idx) = cr_kuantisasi(i:i+7, j:j+7);
        idx = idx + (8*8);
    end
end

zigZagCoding = [y_ZigZag; cb_ZigZag; cr_ZigZag];

% Huffman encoding
minDinput=min(zigZagCoding);
if minDinput<=0
    faktor=minDinput*-1+1;
else
    faktor=0;
end
zigZagCoding=zigZagCoding+faktor;
Hist=zeros(1,max(zigZagCoding));
L=length(zigZagCoding);
DinputNum=zeros(1,L);

for i=1:L
    DinputNum(i)=zigZagCoding(i);
    Hist(DinputNum(i))=Hist(DinputNum(i))+1;
end
PHist=Hist/L;
[PHist, symbols]=sort(PHist,'descend');
eobi=max(find(PHist~=0));
PHist=PHist(1:eobi);
symbols=symbols(1:eobi);

% Proses Coding
dict=huffmandict(symbols,PHist);
ImHuffmanEncoder=huffmanenco(zigZagCoding,dict);

imKirim = ImHuffmanEncoder;

%% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

imTerima = imKirim;

%Huffman decoding
ImHuffmanDecoder=huffmandeco(imTerima,dict) - faktor;

ImDecoder = reshape(ImHuffmanDecoder, m, n, o);

y = ImDecoder(:,:,1);
cb = ImDecoder(:,:,2);
cr = ImDecoder(:,:,3);

% Zig-Zag decoding
y_DeZigZag = zeros(m,n);
cb_DeZigZag = zeros(m,n);
cr_DeZigZag = zeros(m,n);
idx = 0;
for i=1:8:m
    for j=1:8:n
        y_DeZigZag(i:i+7, j:j+7) = y(zz+idx);
        cb_DeZigZag(i:i+7, j:j+7) = cb(zz+idx);
        cr_DeZigZag(i:i+7, j:j+7) = cr(zz+idx);
        idx = idx + (8*8);
    end
end


% De Kuantisasi
y_DekuantisasiBlock  = @(block_struct) round(block_struct.data .* qy50) ;
c_DekuantisasiBlock  = @(block_struct) round(block_struct.data .* qc50) ;
y_Dekuantisasi =  blockproc(y_DeZigZag ,[8 8] , y_DekuantisasiBlock) ;
cb_Dekuantisasi =  blockproc(cb_DeZigZag ,[8 8] , c_DekuantisasiBlock) ;
cr_Dekuantisasi =  blockproc(cr_DeZigZag ,[8 8] , c_DekuantisasiBlock) ;

ImDeKuantisasi = cat(3, y_Dekuantisasi, cb_Dekuantisasi, cr_Dekuantisasi);

% De DCT
ImDeDCT = idct(ImDeKuantisasi);
ImDeDouble = uint8(ImDeDCT);
IDeycbcr = ycbcr2rgb(ImDeDouble);

figure('name',['SNR=',num2str(1)]);
subplot(1,2,1);
imshow(I);
title('citra yang dikirim')

subplot(1,2,2);
imshow(IDeycbcr);
title('citra yang diterima')

hasil kompres-dekompres dengan metode DCT Kuantisasi Zigzag Huffman :

 

Antar muka (interface) kalibrasi sensor PH melalui serial monitor Arduino

Sensor PH adalah instrumen untuk mengukur konsentrasi hidrogen dalam sebuah larutan. Baik sensor pH untuk air maupun untuk tanah perlu dikalibrasi berkala agar ke-akuratannya terjamin.

Untuk menjamin keakuratan sensor ph, diperlukan bahan buffer solution dengan pH diketahui dan akurat. buffer solution yang digunakan umumnya adalah dengan pH 4.0 dan pH 7.0.

Beberapa produsen sensor pH juga menyertakan instrumen untuk melakukan kalibrasi secara manual. Namun jika dihubungkan dengan arduino maka, arduino (instrumen baca) juga perlu dikalibrasi. Dalam atikel ini disertakan program interface kalibrasi sensor pH melalui serial monitor, yang merupakan pengembangan dari library sensor pH yang ada. Hasil kalibrasi akan tersimpan dalam EEPROM untuk digunakan dalam pengukuran normal.

Skema mengkalibrasi sensor pH dengan arduino:

Sktech program pengkalibrasian sensor ph pada arduino :

#define pinPH               A1
#define suhuPengukuran      25

#include "DFRobot_PH.h"

DFRobot_PH ph;

float voltagePH;
float phValue;

long millisBacaSensor;

void setup()
{
  Serial.begin(9600);
  Serial.println("Kalibrasi sensor PH melalui serial monitor");
  Serial.println("Buka serial monitor dan kirim (send) sebarang karakter");
  Serial.println("https://www.semesin.com/project");
  Serial.println();

  ph.begin();
}

void loop()
{
  if (millisBacaSensor < millis())
  {
    millisBacaSensor = millis() + 3000;

    voltagePH = analogRead(pinPH) / 1024.0 * 5000;          // read the ph voltage
    phValue    = ph.readPH(voltagePH, suhuPengukuran);      // convert voltage to pH with temperature compensation

    byte PH = round(phValue);

    Serial.println();
    Serial.print("voltagePH = ");
    Serial.println(voltagePH);
    Serial.print("phValue = ");
    Serial.println(phValue);
    Serial.print("PH = ");
    Serial.println(PH);
  }

  if (Serial.available())
  {
    Serial.readString();

    Serial.println();
    Serial.println("Proses kalibrasi, ikuti petunjuk di serial monitor");
    
    ph.calibration(voltagePH, suhuPengukuran, "ENTERPH");

    while (!Serial.available());
    Serial.readString();
    
    voltagePH = analogRead(pinPH) / 1024.0 * 5000;      // read the ph voltage
    ph.calibration(voltagePH, suhuPengukuran, "CALPH");

    ph.calibration(voltagePH, suhuPengukuran, "EXITPH");
  }
}

library : DFRobot_PH.zip

 

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.semesin.com/project"));
  Serial.println();
  
  Wire.begin();
  rtc.begin();
  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

Remot kontrol android untuk mobil arduino melalui bluetooth

Remot kontrol adalah instrumen jarak jauh (remot) yang mengendalikan perangkat untuk melaksanakan fungsi-fungsi sesuai perintah. Komunikasi antara remot kontrol dan perangkat (rtu) bisa menggunakan kabel atau tanpa kabel (bluetooth, wifi, radio).

Android bisa dimanfatkan sebagai remot kontrol dengan memanfatkan fasilitas sensor-sensor yang dimilikinya. Dalam contoh ini (pengontrolan mobil arduino) memanfatkan fitur berikut :

  1. Bluetooth
  2. Sensor orientasi/kemiringan
  3. Touch screen

Pengendalian remot kontrol bisa dilakukan dalam 2 mode yaitu mode steer dan mode sensor orientasi.

Prototipe mobil arduino dibuat dari komponen berikut :

  1. Arduino uno
  2. Driver motor L298
  3. Motor DC
  4. Bluetooth HC-05 dan resistor pembagi tegangan
  5. Rangka miniatur mobil

Fokus dalam perancangan mobil arduino ini adalah pengendalian kecepatan motor kiri dan kanan sehingga diperoleh gerakan yang mulus/smooth. jadi tidak seperti kendali steer mobil pada umumnya yang menggunakan metode putaran poros roda untuk melakukan belokan. Untuk itu digunakan formula gerakan menggunakan pwm (pulse width modulation) dan pengaturan kecepatan roda kiri dan kanan sehingga dihasilkan gerakan yang halus.

berikut skema pengendalian gerakan mobil-mobilan arduino melalui android :

sketch arduino untuk mobil remot dengan gerakan yang halus:

#include <SoftwareSerial.h>

#define pinMotorKiriPlus            5
#define pinMotorKiriMinus           6
#define pinMotorKananPlus           10
#define pinMotorKananMinus          11

SoftwareSerial bluetooth(2, 3);

int x = 128;
int y = 128;
byte kiri;
byte kanan;
char buffer[32];
bool statusBerhenti;

void setup() {
  pinMode(pinMotorKiriPlus, OUTPUT);
  pinMode(pinMotorKiriMinus, OUTPUT);
  pinMode(pinMotorKananPlus, OUTPUT);
  pinMode(pinMotorKananMinus, OUTPUT);

  Serial.begin(9600);
  Serial.println(F("Remot kontrol android untuk mobil arduino melalui bluetooth"));
  Serial.println(F("https://www.semesin.com/project"));
  Serial.println();
  
  bluetooth.begin(9600);

  Serial.println("Sistem mulai");

}

void loop() {

  while (bluetooth.available())
  {
    char c = bluetooth.read();
    switch (c)
    {
      case 'x':
        x = bluetooth.parseInt();
        break;
      case 'y':
        y = bluetooth.parseInt();
        break;
    }
  }

  if ((y > 96) && (y < 160))
  {
    if (!statusBerhenti)
    {
      digitalWrite(pinMotorKiriPlus, LOW);
      digitalWrite(pinMotorKiriMinus, LOW);
      digitalWrite(pinMotorKananPlus, LOW);
      digitalWrite(pinMotorKananMinus, LOW);
      Serial.println("berhenti");
      statusBerhenti = true;
    }

  }
  else
  {
    float rasioKiri = 1.0 * x / 255;
    float rasioKanan = 1.0 * (255 - x) / 255;
    byte kecepatan = abs(y - 128) * 2;

    if (rasioKiri > rasioKanan)
    {
      rasioKanan += 1 - rasioKiri;
      rasioKiri = 1;
    }
    else
    {
      rasioKiri += 1 - rasioKanan;
      rasioKanan = 1;
    }

    kiri = constrain(rasioKiri * kecepatan, 0 , 255);
    kanan = constrain(rasioKanan * kecepatan, 0 , 255);

    sprintf(buffer, "%s : kiri: %d, kanan: %d", y < 128 ? "Maju" : "mundur", kiri, kanan);
    Serial.println(buffer);

    if (y < 128)
    {
      analogWrite(pinMotorKiriPlus, kiri);
      analogWrite(pinMotorKananPlus, kanan);
      digitalWrite(pinMotorKiriMinus, LOW);
      digitalWrite(pinMotorKananMinus, LOW);
    }
    else
    {
      analogWrite(pinMotorKiriMinus, kiri);
      analogWrite(pinMotorKananMinus, kanan);
      digitalWrite(pinMotorKiriPlus, LOW);
      digitalWrite(pinMotorKananPlus, LOW);
    }
    statusBerhenti = false;
  }
}

block app inventor remot kontrol android:

screenshoot Remot kontrol arduino pengendali mobil-mobilan:

File app inventor remot kontrol:

1. Setir_Android.apk
2. Setir_Android.aia

Sistem kontrol PID close loop – stabilizer tegangan – menggunakan arduino melalui simulink matlab

Sistem kontrol PID (Proportional–Integral–Derivative controller) bertujuan memperoleh hasil optimum yang menggunakan mekanisme umpan balik (sistem tertutup / close loop). sistem kontrol PID juga bisa diterapkan pada arduino. Untuk menambah kemampuan numerik pada arduino, bisa dikombinasikan dengan program matlab.

Program Matlab (Matrix Laboratory) yang memiliki fitur simulink dapat dapat digunakan untuk memprogram arduino, dan dengan kelebihan matlab bisa dengan mudah mengembangkan sistem kontrol (dan keperluan numerikal lain) kedepannya.

Untuk pemrograman arduino menggunakan matlab, diperlukan add-ons matlab berikut ini:

  1.  Simulink Support Package for Arduino Hardware
  2. MATLAB Support for MinGW-w64 C/C++ Compiler

Dalam contoh ini menggunakan plant pengatur tegangan keluaran pwm dengan beban kapasitor.

Skema / plant / rangkaian percobaan sistem kontrol pid loop tertutup berbasis arduino:

Model simulink matlab sistem kontrol tegangan

respon keluaran pengontrolan tegangan dengan arduino dan simulink

file simulink pengontrolan pid tegangan pwm:

pidArduino.slx

 

 

Input string melalui keypad menggunakan arduino

Keypad (dalam konteks arduino) sama halnya dengan keypad pada handphone lawas (tuts) yang terdiri dari setidaknya 12 tombol berupa angka 0 hingga 9 serta karakter * dan karakter #. Untuk menuliskan karakter huruf, maka tuts keypad harus ditekan beberapa kali hingga karakter yang diinginkan muncul.

String / text terdiri atas karakter-karakter penyusunnya, penggunaan keypad 3×4 (numerik) membutuhkan trik khusus dan terdapat bermacam-macam metode, dalam contoh ini menggunakan metode entry deret.

 

aturan pemakaian umum:

  1. Masing-masing tuts memiliki beberapa karakter, untuk memilih karakter maka tuts yang sama ditekan berulang-ulang hingga karakter yang diinginkan tampil.
  2. Jika tuts/tombol tidak ditekan selama 3 detik, maka karakter sebelumnya dimasukkan dalam memory dan sistem lanjut ke karakter berikutnya.
  3. Jika tuts yang ditekan berbeda dengan tuts sebelumnya, maka karakter terakhir akan dimasukkan dalam memory.
  4. tuts * berfungsi untuk menghapus karakter terakhir
  5. jika tuts * pada saat belum ada karakter yang dimasukkan, maka sistem akan kembali ke sistem normal (dalam contoh ini kembali ke keadaan awal).
  6. tuts # berfungsi seperti ‘enter’ untuk menyimpan string dan kembali ke sistem normal (dalam contoh ini kembali ke keadaan awal).

skema pemanfaatan keypad sebagai entry teks:

koding/sketch masukan keypad sebagai string / teks :

#define periodaKeypad         3000

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

LiquidCrystal_I2C lcd(0x3F, 16, 2);

const byte ROWS = 4;
const byte COLS = 3;
char keys[ROWS][COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};
byte rowPins[ROWS] = {11, 10, 9, 8};
byte colPins[COLS] = {7, 6, 5};
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );


char pad[11][11] = {
  "0 ",
  "1?!*#:=/+-",
  "2AaBbCc",
  "3DdEeFf",
  "4GgHhIi",
  "5JjKkLl",
  "6MmNnOo",
  "7PpQqRrSs",
  "8TtUuVvWw",
  "9XxYyZz",
};

byte padCounter;
char padChar;
bool padDitekan;
byte charCounter;
byte keySebelumnya;
char bufferKeypad[17];
char *bufferKeypadPtr;

long millisKeypad;

void setup() {
  Serial.begin(9600);
  Serial.println(F("Input string malalui keypad menggunakan arduino"));
  Serial.println(F("https://www.semesin.com/project"));
  Serial.println();

  lcd.begin();

  resetInput();
}

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

  if (key) {
    switch (key)
    {
      case '0':
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':

        millisKeypad = millis() + periodaKeypad;
        if ((key == keySebelumnya) || (keySebelumnya == 0))
        {
          padChar = pad[key - '0'][charCounter];
          keySebelumnya = key;
        }
        else if ((padDitekan) && (padCounter < sizeof(bufferKeypad) - 1))
        {
          *bufferKeypadPtr++ = padChar;
          keySebelumnya = key;
          charCounter = 0;
          padCounter++;
          padChar = pad[key - '0'][charCounter];
        }

        padDitekan = true;

        lcd.setCursor(padCounter, 1);
        lcd.print(padChar);
        lcd.setCursor(padCounter, 1);

        charCounter++;
        if (!pad[key - '0'][charCounter])
        {
          charCounter = 0;
        }
        break;

      case '*':
        if (padCounter)
        {
          if (keySebelumnya)
          {
            keySebelumnya = 0;
          }
          lcd.setCursor(padCounter, 1);
          lcd.print(' ');
          charCounter = 0;
          padCounter--;
          bufferKeypadPtr--;
          padChar = *bufferKeypadPtr;

          lcd.setCursor(padCounter, 1);
        }
        else
        {
          resetInput();
        }
        break;
      case '#':
        if ((padDitekan) && (padCounter < sizeof(bufferKeypad) - 1))
        {
          *bufferKeypadPtr++ = padChar;
        }
        *bufferKeypadPtr = 0;

        Serial.print("String input = ");
        Serial.println(bufferKeypad);

        lcd.clear();
        lcd.noBlink();
        lcd.setCursor(0, 0);
        lcd.print("String input = ");
        lcd.setCursor(0, 1);
        lcd.print(bufferKeypad);
        delay(3000);

        resetInput();
        break;
    }
  }

  if ((padDitekan) && (padCounter < sizeof(bufferKeypad) - 1))
  {
    if (millisKeypad < millis())
    {
      *bufferKeypadPtr++ = padChar;
      keySebelumnya = key;
      charCounter = 0;
      padCounter++;
      padDitekan = false;

      lcd.setCursor(padCounter, 1);
      lcd.print(' ');
      lcd.setCursor(padCounter, 1);
    }
  }
}

void resetInput()
{
  bufferKeypadPtr = bufferKeypad;
  charCounter = 0;
  padCounter = 0;
  keySebelumnya = 0;
  padDitekan = false;

  lcd.clear();
  lcd.print("Masukkan string");
  lcd.setCursor(padCounter, 1);
  lcd.blink();
}

library entry teks melalui keypad berbasis arduino :
LiquidCrystal-I2C.zip
Keypad.zip

Komunikasi Modbus dengan arduino sebagai master (read input register tanpa library)

Modbus adalah sebuah protokol komunikasi antar perangkat. Modbus tergolong sebagai komunikasi serial dengan kelebihan mampu berkomunikasi dalam bus data (lalu lintas data),  jadi dalam sebuah jaringan modbus bisa menghubungkan lebih dari 2 alat (hingga 254 alat/perangkat). Contoh penggunaan protokol modbus adalah programmable logic controllers (PLCs) serta supervisory control and data acquisition (SCADA).

Dalam protokol modbus terdapat fungsi-fungsi diantaranya :

  • Coils (1 bit) baca/tulis
  • Discrete Inputs: (1 bit) hanya baca
  • Input Registers: (2 byte) hanya baca
  • Holding Registers: (2 byte) baca/tulis

Komunikasi antara perangkat dalam jaringan modbus digambarkan dalam diagram berikut :

RS485

rs485 adalah perangkat elektronika pengirim dan penerima data (serial) umumnya menggunakan dua kabel dengan karakteristik sinyal yang seimbang. rs485 juga mampu menghubungkan lebih dari 2 perangkat komunikasi (multipoint).

rs485 sering dimanfaatkan sebagai perangkat tambahan dalam komunikasi modbus.

Pembacaan modul PZEM modbus dengan arduino sebagai master

modul pzem dikenal sebagai modul pembaca tegangan, arus, daya, energi, frekuensi dari listrik. beberapa diantaranya mendukung protokol modbus. dalam contoh ini digunakan modul pzem 003 yaitu modul pengukuran dc.

skema komunikasi modbus berbasis arduino:

komponen yang digunakan :

  1. Arduino uno
  2. modul serial rs485

sketch/program arduino untuk pembacaan sensor pzem :

#define pinModBusTX         4

#include <SoftwareSerial.h>

SoftwareSerial pzem(2, 3); // RX, TX

byte perintah[] = {0x01, 0x04, 0x00, 0x00, 0x00, 0x08};//readInputRegisters
byte bufferDataModbus[100];
byte *ptr;

void setup() {
  pinMode(pinModBusTX, OUTPUT);

  Serial.begin(9600);
  Serial.println(F("Komunikasi Modbus dengan arduino sebagai master (read input register tanpa library)"));
  Serial.println(F("https://www.semesin.com/project"));
  Serial.println();

  pzem.begin(9600);
  ptr = bufferDataModbus;
}

void loop()
{
  uint16_t crc = calcCRC(perintah, sizeof(perintah));

  digitalWrite(pinModBusTX, HIGH);
  delay(1);
  pzem.write(perintah, sizeof(perintah));
  pzem.write(lowByte(crc));
  pzem.write(highByte(crc));
  delay(10);
  digitalWrite(pinModBusTX, LOW);

  long millisResponModbus = millis() + 1000;
  while (!pzem.available())
  {
    if (millisResponModbus < millis())
    {
      break;//timeout
    }
  }

  while (pzem.available())
  {
    byte b = pzem.read();
    *ptr++ = b;
    delay(2);
  }

  if (memcmp(bufferDataModbus, perintah, 2) == 0)
  {
    ptr = bufferDataModbus;

    float tegangan      = ((ptr[0 + 3] << 8) + ptr[1 + 3]) * 0.01;
    float arus          = ((ptr[2 + 3] << 8) + ptr[3 + 3]) * 0.01;
    float daya          = ((ptr[4 + 3] << 24) + (ptr[5 + 3] << 16) + (ptr[6 + 3] << 8) + ptr[7 + 3]) * 0.1;
    float energi        = ((ptr[8 + 3] << 24) + (ptr[9 + 3] << 16) + (ptr[10 + 3] << 8) + ptr[11 + 3]) * 0.1;
    int16_t alarmHigh  = ((ptr[12 + 3] * 256) + ptr[13 + 3]);
    int16_t alarmLow   = ((ptr[14 + 3] * 256) + ptr[15 + 3]);

    memset(bufferDataModbus, 0x00, sizeof(bufferDataModbus));

    Serial.println("==========");
    Serial.print("tegangan      = ");
    Serial.println(tegangan);
    Serial.print("arus          = ");
    Serial.println(arus);
    Serial.print("daya          = ");
    Serial.println(daya);
    Serial.print("energi        = ");
    Serial.println(energi);
    Serial.print("alarmHigh     = ");
    Serial.println(alarmHigh);
    Serial.print("alarmLow      = ");
    Serial.println(alarmLow);
  }

  Serial.println();
  delay(1000);
}

uint16_t calcCRC(byte *data, byte panjang)
{
  int i;
  uint16_t crc = 0xFFFF;
  for (byte p = 0; p < panjang; p++)
  {
    crc ^= data[p];
    for (i = 0; i < 8; ++i)
    {
      if (crc & 1)
        crc = (crc >> 1) ^ 0xA001;
      else
        crc = (crc >> 1);
    }
  }
  return crc;
}

 

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);
  }
}

 

Kontrol motor servo dengan delphi melalui port parallel lpt

Motor servo berputar ke posisi sudut tertentu berdasarkan lebar pulsa yang diberikan padanya. Pada umumnya lebar pulsa yang dibutuhkan adalah 1ms – 2ms, dengan perida 20ms seperti diagram berikut :

Membangkitkan sinyal pulsa ini menjadi masalah tersendiri jika menggunakan pc melalui port paralel, karena disisi komputer cara ini (akses langsung ke perangkat) dianggap tidak aman.

Beberapa metode/trik bisa dilakukan untuk menggerakkan motor servo melalui lpt port seperti kode berikut :


for i:=1 to 10 do
begin
Out32($378, $01);
delay(1);
Out32($378, $00);
delay(19);
end;

cara ini menjadi tidak efektif karena fungsi ‘delay()’ tidak bisa menjamin timingnya. contohnya jika delay(1) tidak ada garansi akan tepat 1ms. Maka yang terjadi adalah servo agak bergerak tidak beraturan.

jadi kunci memitar motor servo tepat pada posisinya adalah timing yang pas dan tepat. untuk itu digunakan fungsi ‘QueryPerformanceCounter(lastTick);’ yang lebih presisi pewaktuannya.

skema simulasi gerak servo untuk membuka pintu menggunakan port parallel:

 

program delphi penggerak motor servo, simulasi buka tutup:

 

unit servo;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    ButtonBuka: TButton;
    ButtonTutup: TButton;
    Label1: TLabel;
    Label2: TLabel;
    procedure ButtonBukaClick(Sender: TObject);
    procedure ButtonTutupClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  nilaiPort : byte;

const
  //cek alamat resource lpt port melalui device manager
  baseRegister = $DC00;
  dataRegister = baseRegister + 0;
  statusRegister = baseRegister + 1;
  controlRegister = baseRegister + 2;

  sudutBuka = 180;
  sudutTutup = 0;
  maskPinServo = $01;


implementation

{$R *.dfm}

function Inp32(PortAdr: word): byte; stdcall; external 'inpout32.dll';
function Out32(PortAdr: word; Data: byte): byte; stdcall; external 'inpout32.dll';

procedure gerakServo(maskPort : byte; sudut : byte);
var
	lastTick, tick : Int64;
	lastTick20 : Int64;
	mikroDetik : integer;
	Frequency : Int64;
	i : integer;
begin
	QueryPerformanceFrequency(Frequency);
	mikroDetik := 500 + (Round(sudut/180) * 2000);

	for i := 1 to 20 do
	begin
		nilaiPort := nilaiPort or maskPort;
		Out32(dataRegister, nilaiPort);

		QueryPerformanceCounter(lastTick);
		lastTick20 := lastTick + round((20000 / 1000000) * Frequency);
		lastTick := lastTick + round((mikroDetik / 1000000) * Frequency);

		while true do
		begin
			QueryPerformanceCounter(tick);
			if tick > lastTick then
				break;
		end;

		nilaiPort := nilaiPort and (not maskPort);
		Out32(dataRegister, nilaiPort);

		while true do
		begin
			QueryPerformanceCounter(tick);
			if tick > lastTick20 then
				break;
		end;
	end;
end;

procedure TForm1.ButtonBukaClick(Sender: TObject);
begin
	gerakServo(maskPinServo, sudutBuka);
end;

procedure TForm1.ButtonTutupClick(Sender: TObject);
begin
	gerakServo(maskPinServo, sudutTutup);
end;

end.

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;

void setup() {
  Serial.begin(9600);
  Serial.println("Pemberi pakan ikan otomatis");
  Serial.println("https://www.semesin.com/project");
  
  servoMakanIkan.attach(pinServoMakanan);
  servoMakanIkan.write(servoTutup);

  Wire.begin();
  rtc.begin();

  lcd.begin();
  lcd.backlight();

  lcd.print("Pemberi ");
  lcd.setCursor(0, 1);
  lcd.print("pakan ikan");
  delay(3000);
  lcd.clear();

  Serial.println("Sistem mulai");
}

void loop() {

  DateTime now = rtc.now();
  if (detikSebelumnya != now.second())
  {
    char buf[17];
    sprintf(buf, "%02d:%02d:%02d", now.hour(), now.minute(), now.second());
    lcd.setCursor(4, 0);
    lcd.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);

      servoMakanIkan.write(servoBuka);
      delay(waktuBukaServo);
      servoMakanIkan.write(servoTutup);

    }
  }
}

 

Library pemberi pakan ikan otomatis :

Input angka menggunakan keypad pada Arduino

Keypad untuk arduino terdiri atas numerik 0-9 serta ‘*’ dan ‘#’ berfungsi sebagai input bagi arduino. Arduino membaca keypad (type membrane) dengan metode scanning 7 kabel (untuk keypad 3×4), atau adc satu kabel. Dengan menggunakan library keypad, nilai input yang diterima arduino sudah berupa karakter ‘0’ – ‘9’, ‘*’ dan ‘#’, nilai ini bisa baca langsung sebagai perintah seperti contoh berikut ”

 
void loop(){
  char key = keypad.getKey();
  
  if (key){
    Serial.println(key);
    switch(key)
    {
      case '0':
        digitalWrite(2, HIGH);
        break;
      case '1':
        digitalWrite(3, HIGH);
        break;
      case '*'://reset
        digitalWrite(2, LOW);
        digitalWrite(3, LOW);
        break;
    }
  }
}

Input deret angka

Supaya keypad berfungsi sebagai input nilai angka (misal 0-1000) seperti untuk keperluan input variabel ‘setting batas sensor analog’, maka keypad dibaca beberapa kali dengan ketentuan:

  • karakter ‘0’ – ‘9’ sebagai input numerik
  • karakter ‘*’ berfungsi sebagai reset (kembali ke 0)
  • karakter ‘#’ berfungsi sebagai enter layaknya keybboard laptop dan menyimpan pembacaan keypad sebagai nilai variabel

berikut skema yang digunakan untuk pembacaan keypad dengan arduino:

koding input nilai variabel dari keypad :

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

const byte ROWS = 4;
const byte COLS = 3;
char keys[ROWS][COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};
byte rowPins[ROWS] = {8, 7, 6, 5};
byte colPins[COLS] = {4, 3, 2};

Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );
LiquidCrystal_I2C lcd(0x3F, 16, 2);//coba juga 0x27

char stringAngka[17];
int indexKeypad = 0;

void setup() {
  Serial.begin(9600);
  Serial.println("Input angka menggunakan keypad");
  Serial.println("https://www.semesin.com/project/");
  Serial.println();

  lcd.begin();
  lcd.backlight();
  lcd.print("Input angka");
}

void loop() {


  char key = keypad.getKey();

  if (key) {
    Serial.println(key);
    switch (key)
    {
      case '0':
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
        if (!indexKeypad)
        {
          lcd.clear();
        }
        stringAngka[indexKeypad++] = key;
        lcd.print(key);
        break;
      case '*'://reset
        lcd.clear();
        indexKeypad = 0;
        break;
      case '#':
        stringAngka[indexKeypad] = 0;
        lcd.setCursor(0, 1);

        int nilaiAngka = atoi(stringAngka);
        lcd.print(nilaiAngka);

        indexKeypad = 0;
        break;
    }
  }
}

contoh penggunaan keypad sebagai masukan variabel integer:

Jpeg

Pin mapping board ESP8266

Board ESP8266 yang ada dipasaran membawa standar penamaan sendiri-sendiri, berikut tabel persamaannya:

Generik Alias D1 D1 mini Espectro Inven tone Node MCU Oak Wifi slot Wifi duino Wifinfo Wifio
0 D8 D3 D2 D3 P2 PIN_A1 D3 D3 E0
1 TX D1 TX TX/TX0 TX D10 P4 D1/TX D10 E1
2 TX1 D9 D4 TX1 D4 D4 P0 D2 D4 E2
3 RX D0 RX RX/RX0 RX D9 P3 PIN_A0 D0/RX D9 E3
4 SDA D4/D14 D2 D6 D2 P5 PIN_A6 D4 D2 E4
5 SCL D3/D15 D1 D5 D1 P1 PIN_A4 D5 D1 E5
12 MISO D6/D12 D6 D8 D6 P8 PIN_A7 D8/D12 D6 E12
13 MOSI D7/D11 D7 D7 D7 P7 PIN_A3 D9/D11 D7 E13
14 SCK D5/D13 D5 D3 D5 P9 PIN_A5 D7/D13 D5 E14
15 SS D10 D8 D1 D8 P6 D10 D8 E15
16 D2 D0 D9 D0 P10 PIN_A2 D6 D0 E16

Sedangkan aksesoris seperti LED dan button terpasa seperti tabel berikut:

Board LED Button
Adafruit 0
Arduino SPI 2
Arduino UART 14
D1 2
D1 mini 2
ESP8285 1
Espectro 15 0/2
Espino 2/4/5 0
Espinotee 16
Espresso lite v1 16
Espresso lite v2 2
Inventone 2
Modwifi 1
NodeMCU 16
Oak 5
phoenix v1 16
phoenix v2 2
Thing 5
Wifi slot 2
Wifiduino 2
Wifinfo 12
Wifio 2
Wiolink 2
Xinabox 5/12/13