Keamanan berlapis akses pintu menggunakan sandi keypad dan sidik jari menggunakan Code Vision

Sistem keamanan merupakan bagian sistem yang bertugas memberikan akses terhadap bagian-bagian yang dilindunginya. Jika unit yang dilindungi memiliki fungsi sangat vital yang hanya di boleh diakses oleh orang tertentu maka sistem keamanannya dibuat berlapis.

Infrastruktur sistem keamanan sudah sangat berkembang, beberapa yang sering digunakan pada aplikasi mikrokontroller diantaranya :

  1. Kata sandi dengan tombol/keypad/remot tv
  2. Kartu akses dengan RFID reader
  3. Sidik jari
  4. suara dengan voice recognition

Dalam perancangan dini menggunakan 2 lapis sistem keamanan yaitu kata sandi menggunakan keypad serta sidik jari.

Komponen yang digunakan:

  1. ATMega8535
  2. Keypad membrane 4×4
  3. Fingerprint dy50
  4. LCD I2c 16×2
  5. Solenoid doorlock
  6. Buzzer

Skema perancangan sistem keamanan berlapis (password dan fingerprint):
 

program code vision (cvavr) sistem keamanan menggunakan finger print dan keypad:

#include <mega8535.h>
#include <stdbool.h>
#include "fingerprint.h"
#include "lcdi2c.h"

// Declare your global variables here
#define password    "1234"
#define pinBuzzer   PORTD.3
#define pinKunci    PORTD.2

char buf[10];
uint8_t respon;

uint16_t timingFingerprintAktif;
uint16_t i;

char keypad;
char keypadBuffer[10];
bool statusPassword;
uint8_t keypadCnt;


#define DATA_REGISTER_EMPTY (1<<UDRE)
#define RX_COMPLETE (1<<RXC)
#define FRAMING_ERROR (1<<FE)
#define PARITY_ERROR (1<<UPE)
#define DATA_OVERRUN (1<<DOR)

// USART Receiver buffer
#define RX_BUFFER_SIZE 20
char rx_buffer[RX_BUFFER_SIZE];

#if RX_BUFFER_SIZE <= 256
unsigned char rx_wr_index=0,rx_rd_index=0;
#else
unsigned int rx_wr_index=0,rx_rd_index=0;
#endif

#if RX_BUFFER_SIZE < 256
unsigned char rx_counter=0;
#else
unsigned int rx_counter=0;
#endif

// This flag is set on USART Receiver buffer overflow
bit rx_buffer_overflow;

// USART Receiver interrupt service routine
interrupt [USART_RXC] void usart_rx_isr(void)
{
char status,data;
status=UCSRA;
data=UDR;
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))==0)
   {
   rx_buffer[rx_wr_index++]=data;
#if RX_BUFFER_SIZE == 256
   // special case for receiver buffer size=256
   if (++rx_counter == 0) rx_buffer_overflow=1;
#else
   if (rx_wr_index == RX_BUFFER_SIZE) rx_wr_index=0;
   if (++rx_counter == RX_BUFFER_SIZE)
      {
      rx_counter=0;
      rx_buffer_overflow=1;
      }
#endif
   }
}

#ifndef _DEBUG_TERMINAL_IO_
// Get a character from the USART Receiver buffer
#define _ALTERNATE_GETCHAR_
#pragma used+
char getchar(void)
{
char data;
while (rx_counter==0);
data=rx_buffer[rx_rd_index++];
#if RX_BUFFER_SIZE != 256
if (rx_rd_index == RX_BUFFER_SIZE) rx_rd_index=0;
#endif
#asm("cli")
--rx_counter;
#asm("sei")
return data;
}
#pragma used-
#endif


char scanning_keypad()
{
    PORTB = 0b01111111;
    delay_ms(20);
    if(PINB.0 == 0){while(PINB.0 == 0);return 'A';}
    if(PINB.1 == 0){while(PINB.1 == 0);return 'B';}
    if(PINB.2 == 0){while(PINB.2 == 0);return 'C';}
    if(PINB.3 == 0){while(PINB.3 == 0);return 'D';}
     
    PORTB = 0b10111111;
    delay_ms(20);
    if(PINB.0 == 0){while(PINB.0 == 0);return '3';}
    if(PINB.1 == 0){while(PINB.1 == 0);return '6';}
    if(PINB.2 == 0){while(PINB.2 == 0);return '9';}
    if(PINB.3 == 0){while(PINB.3 == 0);return '#';}
     
    PORTB = 0b11011111;
    delay_ms(20);
    if(PINB.0 == 0){while(PINB.0 == 0);return '2';}
    if(PINB.1 == 0){while(PINB.1 == 0);return '5';}
    if(PINB.2 == 0){while(PINB.2 == 0);return '8';}
    if(PINB.3 == 0){while(PINB.3 == 0);return '0';}
     
    PORTB = 0b11101111;
    delay_ms(20);
    if(PINB.0 == 0){while(PINB.0 == 0);return '1';}
    if(PINB.1 == 0){while(PINB.1 == 0);return '4';}
    if(PINB.2 == 0){while(PINB.2 == 0);return '7';}
    if(PINB.3 == 0){while(PINB.3 == 0);return '*';}    
    
    return 0;
     
}


// Standard Input/Output functions
#include <stdio.h>

void main(void)
{
// Declare your local variables here

// Input/Output Ports initialization
// Port A initialization
// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In 
DDRA=(0<<DDA7) | (0<<DDA6) | (0<<DDA5) | (0<<DDA4) | (0<<DDA3) | (0<<DDA2) | (0<<DDA1) | (0<<DDA0);
// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T 
PORTA=(0<<PORTA7) | (0<<PORTA6) | (0<<PORTA5) | (0<<PORTA4) | (0<<PORTA3) | (0<<PORTA2) | (0<<PORTA1) | (0<<PORTA0);

// Port B initialization
// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In 
DDRB=(1<<DDB7) | (1<<DDB6) | (1<<DDB5) | (1<<DDB4) | (0<<DDB3) | (0<<DDB2) | (0<<DDB1) | (0<<DDB0);
// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T 
PORTB=(0<<PORTB7) | (0<<PORTB6) | (0<<PORTB5) | (0<<PORTB4) | (1<<PORTB3) | (1<<PORTB2) | (1<<PORTB1) | (1<<PORTB0);

// Port C initialization
// Function: Bit7=In Bit6=In Bit5=In Bit4=Out Bit3=In Bit2=In Bit1=In Bit0=In 
DDRC=(0<<DDC7) | (0<<DDC6) | (0<<DDC5) | (1<<DDC4) | (0<<DDC3) | (0<<DDC2) | (0<<DDC1) | (0<<DDC0);
// State: Bit7=T Bit6=T Bit5=T Bit4=0 Bit3=T Bit2=T Bit1=T Bit0=T 
PORTC=(0<<PORTC7) | (0<<PORTC6) | (0<<PORTC5) | (0<<PORTC4) | (0<<PORTC3) | (0<<PORTC2) | (0<<PORTC1) | (0<<PORTC0);

// Port D initialization
// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In 
DDRD=(0<<DDD7) | (0<<DDD6) | (0<<DDD5) | (0<<DDD4) | (1<<DDD3) | (1<<DDD2) | (0<<DDD1) | (0<<DDD0);
// State: Bit7=T Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T 
PORTD=(0<<PORTD7) | (0<<PORTD6) | (0<<PORTD5) | (0<<PORTD4) | (0<<PORTD3) | (0<<PORTD2) | (0<<PORTD1) | (0<<PORTD0);

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Normal top=0xFF
// OC0 output: Disconnected
TCCR0=(0<<WGM00) | (0<<COM01) | (0<<COM00) | (0<<WGM01) | (0<<CS02) | (0<<CS01) | (0<<CS00);
TCNT0=0x00;
OCR0=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: Timer1 Stopped
// Mode: Normal top=0xFFFF
// OC1A output: Disconnected
// OC1B output: Disconnected
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=(0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10);
TCCR1B=(0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (0<<CS11) | (0<<CS10);
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer2 Stopped
// Mode: Normal top=0xFF
// OC2 output: Disconnected
ASSR=0<<AS2;
TCCR2=(0<<WGM20) | (0<<COM21) | (0<<COM20) | (0<<WGM21) | (0<<CS22) | (0<<CS21) | (0<<CS20);
TCNT2=0x00;
OCR2=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=(0<<OCIE2) | (0<<TOIE2) | (0<<TICIE1) | (0<<OCIE1A) | (0<<OCIE1B) | (0<<TOIE1) | (0<<OCIE0) | (0<<TOIE0);

// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// INT2: Off
MCUCR=(0<<ISC11) | (0<<ISC10) | (0<<ISC01) | (0<<ISC00);
MCUCSR=(0<<ISC2);

// USART initialization
// Communication Parameters: 8 Data, 1 Stop, No Parity
// USART Receiver: On
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 57600
UCSRA=(0<<RXC) | (0<<TXC) | (0<<UDRE) | (0<<FE) | (0<<DOR) | (0<<UPE) | (0<<U2X) | (0<<MPCM);
UCSRB=(1<<RXCIE) | (0<<TXCIE) | (0<<UDRIE) | (1<<RXEN) | (1<<TXEN) | (0<<UCSZ2) | (0<<RXB8) | (0<<TXB8);
UCSRC=(1<<URSEL) | (0<<UMSEL) | (0<<UPM1) | (0<<UPM0) | (0<<USBS) | (1<<UCSZ1) | (1<<UCSZ0) | (0<<UCPOL);
UBRRH=0x00;
UBRRL=0x08;

// Analog Comparator initialization
// Analog Comparator: Off
// The Analog Comparator's positive input is
// connected to the AIN0 pin
// The Analog Comparator's negative input is
// connected to the AIN1 pin
ACSR=(1<<ACD) | (0<<ACBG) | (0<<ACO) | (0<<ACI) | (0<<ACIE) | (0<<ACIC) | (0<<ACIS1) | (0<<ACIS0);
SFIOR=(0<<ACME);

// ADC initialization
// ADC disabled
ADCSRA=(0<<ADEN) | (0<<ADSC) | (0<<ADATE) | (0<<ADIF) | (0<<ADIE) | (0<<ADPS2) | (0<<ADPS1) | (0<<ADPS0);

// SPI initialization
// SPI disabled
SPCR=(0<<SPIE) | (0<<SPE) | (0<<DORD) | (0<<MSTR) | (0<<CPOL) | (0<<CPHA) | (0<<SPR1) | (0<<SPR0);

// TWI initialization
// TWI disabled
TWCR=(0<<TWEA) | (0<<TWSTA) | (0<<TWSTO) | (0<<TWEN) | (0<<TWIE);

// Global enable interrupts
#asm("sei")

i2c_begin();
lcd_begin(0x27,16,2); // alamat lcd i2c
lcd_clear();
lcd_puts("Sistem Keamanan");
lcd_gotoxy(0,1);
lcd_puts("www.semesin.com");
delay_ms(3000);

lcd_clear();
//rx_wr_index = 15;
fingerPrintBegin((uint8_t*)&rx_buffer, &rx_wr_index);
respon = checkPassword();
//sprintf(buf, "%2X", respon);
lcd_gotoxy(0,0);
lcd_puts("Akses terbatas  ");

delay_ms(2000);

keypadCnt = 0;

while (1)
      {
      // Place your code here
            while(1)
            {      
                if(!statusPassword)
                {
                    keypad = scanning_keypad();
                    if(keypad)
                    {
                        if(keypad == '#')
                        {           
                            keypadBuffer[keypadCnt] = 0; 
                                         
                            lcd_clear();              
                            lcd_gotoxy(0,0);
                            if(strcmp(keypadBuffer, password) == 0)
                            {
                                statusPassword = 1;          
                                timingFingerprintAktif = 30000;
                                lcd_puts("Tempel sidikjari");
                            }
                            else    
                            {
                                statusPassword = 0;
                                lcd_puts("Password salah  ");
                                for(i=0;i<3;i++)
                                {
                                    pinBuzzer = 1;
                                    delay_ms(1000);
                                    pinBuzzer = 0;
                                    delay_ms(1000);
                                }
                                lcd_clear();
                                lcd_puts("Akses terbatas  ");
                                
                            }                      
                            keypadCnt = 0;
                    		
                        }
                        if((keypad >= '0') &&(keypad <= '9')) 
                        {            
                            if(keypadCnt == 0)
                            {
                                lcd_gotoxy(0,0);
                                lcd_puts("Password :       ");
                            }                     
                            if(keypadCnt < 4)
                            {
                                lcd_gotoxy(keypadCnt,1);
                                lcd_send_data(keypad);          
                                keypadBuffer[keypadCnt] = keypad;
                                keypadCnt++;
                            }  
                    	
                        }
                    	
                    }          
                }
                else
                {
                    delay_ms(1);
                    timingFingerprintAktif--;
                    if(!timingFingerprintAktif)
                    {
                        statusPassword = 0;
                        pinBuzzer = 1;
                        delay_ms(1000);
                        pinBuzzer = 0;    
                        lcd_clear();
                        lcd_puts("Panel           ");  
                        
                    }   
                    lcd_gotoxy(0,1);  
                    lcd_puts("Tempelkan jari  ");
                    respon = getImage();
                    if(respon != FINGERPRINT_OK)
                    {
                        break;
                    }  

                    lcd_gotoxy(0,1);  
                    lcd_puts("Konversi gambar ");
                    respon = image2Tz(1);
                    if(respon != FINGERPRINT_OK)
                    {
                        break;
                    }  
                    
                    lcd_gotoxy(0,1);  
                    lcd_puts("Mencari id      ");
                    respon = fingerFastSearch();
                    if(respon != FINGERPRINT_OK)
                    {
                        break;
                    }                     
                    lcd_clear();
                    sprintf(buf, "id = %2d", fingerID);
                    lcd_gotoxy(0,1);  
                    lcd_puts(buf);
                    lcd_gotoxy(0,0);
                    lcd_puts("Panel");
                                        
                    pinKunci = 1;
                    delay_ms(5000);
                    pinKunci = 0; 
                }
            }
      }
}

library:

  1. fingerprint.h
  2. lcdi2c.h

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

  Wire.begin();
  Wire.beginTransmission(0x3F);
  if (Wire.endTransmission())
  {
    lcd = LiquidCrystal_I2C(0x27, 16, 2);
  }
  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

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

  Wire.begin();
  Wire.beginTransmission(0x3F);
  if (Wire.endTransmission())
  {
    lcd = LiquidCrystal_I2C(0x27, 16, 2);
  }
  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

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:

Dinamik menu dan submenu dengan keypad dan lcd 16×2 menggunakan Arduino

Dalam perancangan perangkat berbasis arduino yang mudah beradaptasi dengan kondisi baru haruslah memiliki sistem setingan variabel yang dinamis. Untuk keperluan setting variabel dinamis ini perangkat bisa dilengkapi panel potensio atau sistem menu yang bisa melakukan setting variabel interaktif. Membuat menu arduino bisa diterapkan secara dinamik dengan menggunakan database / tabel menu. Database menu dibuat fleksibel sehingga pengaturan variabel bisa dikelompokkan dalam sub menu.

Kelebihan database menu dinamis dengan arduino:

  1. Template menu arduino yang fleksibel, bisa ditambah/kurang/edit dengan mudah
  2. Sub-menu yang tak terbatas
  3. Akses alamat variabel yang dinamis sehingga mampu menjangkau ratusan variabel
  4. Tampilan skroll texk bagi item-menu
  5. Respon cepat
  6. Nilai variabel langsung bisa di potong dalam batas min dan max
  7. Menu interaktif arduino

Video submenu Arduino dinamis:

Membuat Menu arduino serta submenu-nya membutuhkan komponen :

  1. Arduino Mega
  2. Membrane keypad 3×4
  3. LCD 16×2/1602

skema arduino menu:

Sebelum digunakan sistem menu fleksibel ini dengan mudah dapat dikonfigurasi sesuai kebutuhan, terutama menu utama dan submenu-submenunya. Kolom text, tipe, alamat variabel, nilai minimal variabel, minai maksimum variabel, alamat submenu dan ukuran submenu harus dikonfigurasi dengan benar.

Struktur menu dibuat fleksibel sehingga bisa menukar urutan/pindah posisi dengan mudah, selain itu juga mudah untuk diedit, dihapus, disisip.

Sistem menu di buat dinamik sehingga cocok digunakan untuk semua perangkat. untuk membangun sebuah menu bisa mengisi item-item berikut:


//text                          tipe            variabel          nilaiMin nilaiMax submenu      jumlahBaris
const Menu menuUtama[] = 
{
  {"1.Aktif         "         , textDropDown  , &aktif            , false , true  , &aktifText   , 2 },   //"1.Aktif         ",
  {"2.Suhu /\xDF\x43      "   , UInt8         , &suhu             , 28    , 36    , 0            , 0 },   //"2.Suhu          ",celcius
  {"3.Kelembapan /% "         , UInt8         , &kelembapan       , 50    , 100   , 0            , 0 },   //"3.Kelembapan    ",%
  {"4.Int Cahaya /lm"         , UInt16        , &intensitasCahaya , 5     , 300   , 0            , 0 },   //"4.Inten. Cahaya ",lm
  {"5.Aliran udara  "         , UInt8         , &aliranUdara      , 0     , 5     , 0            , 0 },   //"5.Aliran udara  ",m/s
  {"6.Level suara/db"         , UInt16        , &levelSuara       , 30    , 120   , 0            , 0 },   //"6.Level suara   ",db tangisan
  {"7.Warna lampu   "         , textDropDown  , &warnaLampu       , 1     , 3     , &WarnaLampu  , 4 },   //"7.Warna lampu   ",
  {"8.Alarm        >"         , subMenu       , 0                 , 1     , 3     , &menuWaktu   , 3 },   //"7.Setting waktu  ",
};

penjelasan item menu:

  1. Text, yaitu teks yang akan ditampilkan oleh lcd
  2. Tipe, adalah jenis data/submenu antara lain : UInt8, UInt16, textDropDown, subMenu
  3. variabel, menyimpan alamat variabel yang akan disetting
  4. nilaiMin, merupakan nilai minimum variabel
  5. nilaiMax, merupakan nilai maksimum variabel
  6. Submenu, diisi jika item ini bertipe sub-menu yang diisi dengan alamat menu yang akan dijadikan submenu
  7. jumlahBaris merupakan jumlah baris dari submenu yang berkaitan

berikut koding/sketch lengkapnya:

#include <Keypad.h>
#include <LiquidCrystal.h>

const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] = {
  {'1','2','3'},
  {'4','5','6'},
  {'7','8','9'},
  {'*','0','#'}
};

//========================================================
//pin 
byte rowPins[ROWS] = {23, 25, 27, 29};
byte colPins[COLS] = {31, 33, 35};

LiquidCrystal lcd(53, 51, 49, 47, 45, 43);

//Variabel lcd dan menu
#define lebarTextLCD 16 + 1//lebar LCD + 1 null terminated
#define menuLevel 2
//========================================================

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

enum mode 
{
  UInt8,
  UInt16,
  textDropDown,
  subMenu
};

struct Menu
{
  char text[lebarTextLCD];
  byte tipe;
  void *variabel;
  uint16_t nilaiMin;
  uint16_t nilaiMax;
  void *subMenu;
  byte jumlahBaris;
};

struct MenuIndex
{
  byte index;
  Menu *menu;
  byte menuLength;
  char *dropDown;
  byte dropDownLength;
};

//========================================================
//variabel
bool aktif;
byte suhu;
byte kelembapan;
uint16_t intensitasCahaya;
uint16_t aliranUdara;
uint16_t levelSuara;
uint16_t warnaLampu;

byte alarmJam;
byte alarmMenit;
byte alarmDetik;

//Dropdown menu
const char aktifText[][lebarTextLCD]  = 
{
  "0. Tidak        ",
  "1. Ya           ",
};
const char WarnaLampu[][lebarTextLCD]  = 
{
  "1. Mati         ",
  "2. Dingin       ",
  "3. Putih        ",
  "4. Hangat       ",
};

//Sub menu
//text                          tipe            variabel          nilaiMin nilaiMax submenu      jumlahBaris
const Menu menuWaktu[] = 
{
  {"1. Jam          "         , UInt8         , &alarmJam         , 1     , 24    , 0            , 0 },
  {"2. Menit        "         , UInt8         , &alarmMenit       , 0     , 59    , 0            , 0 },
  {"3. Detik        "         , UInt8         , &alarmDetik       , 0     , 59    , 0            , 0 },
};

//Menu utama
const Menu menuUtama[] = 
{
  {"1.Aktif         "         , textDropDown  , &aktif            , false , true  , &aktifText   , 2 },   //"1.Aktif         ",
  {"2.Suhu /\xDF\x43      "   , UInt8         , &suhu             , 28    , 36    , 0            , 0 },   //"2.Suhu          ",celcius
  {"3.Kelembapan /% "         , UInt8         , &kelembapan       , 50    , 100   , 0            , 0 },   //"3.Kelembapan    ",%
  {"4.Int Cahaya /lm"         , UInt16        , &intensitasCahaya , 5     , 300   , 0            , 0 },   //"4.Inten. Cahaya ",lm
  {"5.Aliran udara  "         , UInt8         , &aliranUdara      , 0     , 5     , 0            , 0 },   //"5.Aliran udara  ",m/s
  {"6.Level suara/db"         , UInt16        , &levelSuara       , 30    , 120   , 0            , 0 },   //"6.Level suara   ",db tangisan
  {"7.Warna lampu   "         , textDropDown  , &warnaLampu       , 1     , 3     , &WarnaLampu  , 4 },   //"7.Warna lampu   ",
  {"8.Alarm        >"         , subMenu       , 0                 , 1     , 3     , &menuWaktu   , 3 },   //"7.Setting waktu  ",
};
//========================================================

MenuIndex menuIndex[menuLevel];

long millismenuText;
String menuEntriNilai;
int8_t levelMenu = -1;
bool entriNilai;
byte menuTextIndex;
char *judulMenu;
byte judulMenuTampil;
byte lcdEntriPos;


void setup() 
{
  Serial.begin(9600);
  Serial.println("Dinamik menu tak terbatas sub-menu dengan keypad 3x4 dan arduino");
  Serial.println("(Aplikasi Inkubator)");
  Serial.println("entri/kirim 'h' untuk melihat nilai variabel");
  Serial.println("https://www.project.semesin.com/");

  lcd.begin(16, 2);
  menuIdle();

  millismenuText = millis();
}

void menuIdle()
{
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Tekan * untuk");
  lcd.setCursor(0, 1);
  lcd.print("masuk ke menu");
}

void loop() 
{
  cekMenu();
  
  if(Serial.available())
  {
    if(toupper(Serial.read()) == 'H')
    {
      Serial.println("--------------------------");
      Serial.print("aktif = ");
      Serial.println(aktif);
      Serial.print("suhu = ");
      Serial.println(suhu);
      Serial.print("kelembapan = ");
      Serial.println(kelembapan);
      Serial.print("intensitasCahaya = ");
      Serial.println(intensitasCahaya);
      Serial.print("aliranUdara = ");
      Serial.println(aliranUdara);
      Serial.print("levelSuara = ");
      Serial.println(levelSuara);
      Serial.print("warnaLampu = ");
      Serial.println(warnaLampu);

      Serial.print("alarmJam = ");
      Serial.println(alarmJam);
      Serial.print("alarmMenit = ");
      Serial.println(alarmMenit);
      Serial.print("alarmDetik = ");
      Serial.println(alarmDetik);
      Serial.println("--------------------------");
      Serial.println();
    }
  }
}

void cekMenu()
{
  char key = keypad.getKey();
  if (key)
  {
    if(key == '*')
    {
      if(entriNilai)
      {
        uint16_t nilaiBaru = menuEntriNilai.toInt();

        if((nilaiBaru >= menuIndex[levelMenu].menu[menuIndex[levelMenu].index].nilaiMin) && (nilaiBaru <= menuIndex[levelMenu].menu[menuIndex[levelMenu].index].nilaiMax))
        {
          switch(menuIndex[levelMenu].menu[menuIndex[levelMenu].index].tipe)
          {
            case UInt8:
              *(uint8_t*)menuIndex[levelMenu].menu[menuIndex[levelMenu].index].variabel = nilaiBaru;
              break;
            case UInt16:
              *(uint16_t*)menuIndex[levelMenu].menu[menuIndex[levelMenu].index].variabel = nilaiBaru;
              break;
            case textDropDown:
              menuIndex[levelMenu].dropDownLength = 0;
              *(byte*)menuIndex[levelMenu].menu[menuIndex[levelMenu].index].variabel = nilaiBaru;
              menuTextIndex = 0;
              break;
          }
          lcd.clear();
          lcd.print(judulMenu);
          lcd.setCursor(0, 1);
          lcd.print(nilaiBaru);
          lcd.print(" disimpan");
          delay(1000);
        }
        entriNilai = false;
      }
      else if(levelMenu == -1)
      {
        levelMenu = 0;
      }
      else
      {
        levelMenu--;
      }
      displayMenu();
    }
    else if(key == '#')
    {
      if(entriNilai)
      {
        entriNilai = false;
        displayMenu();
      }
      else if(levelMenu >= 0)
      {
        levelMenu--;
        displayMenu();
      }
    }
    else if((key >= '0') || (key <= '9') )
    {
      if(entriNilai)
      {
          menuEntriNilai += key;
          lcd.setCursor(lcdEntriPos++, 1);
          lcd.print(key);
      }
      else if((key != '0') && (key - '0' <= menuIndex[levelMenu].menuLength))//pilihan menu
      {
        menuIndex[levelMenu].index = key - '1';
        judulMenu = menuIndex[levelMenu].menu[menuIndex[levelMenu].index].text;
        lcd.clear();
        lcd.print(judulMenu);
        lcd.setCursor(0, 1);
        lcdEntriPos = 8;
        judulMenuTampil = 0;

        uint16_t nilaiUInt8;
        uint16_t nilaiUInt16;
        uint16_t nilaiUInt32;
        int16_t nilaiFloat;

        menuEntriNilai = "";
        entriNilai = true;

        switch(menuIndex[levelMenu].menu[menuIndex[levelMenu].index].tipe)
        {
          case UInt8:
            lcd.print(*(byte*)menuIndex[levelMenu].menu[menuIndex[levelMenu].index].variabel);
            lcd.print(" ==> ");
            break;
          case UInt16:
            lcd.print(*(uint16_t*)menuIndex[levelMenu].menu[menuIndex[levelMenu].index].variabel);
            lcd.print(" ==> ");
            break;
          case textDropDown:
            menuIndex[levelMenu].dropDownLength = menuIndex[levelMenu].menu[menuIndex[levelMenu].index].jumlahBaris;
            menuIndex[levelMenu].dropDown = menuIndex[levelMenu].menu[menuIndex[levelMenu].index].subMenu;
            menuTextIndex = 0;
            lcd.print(*(uint8_t*)menuIndex[levelMenu].menu[menuIndex[levelMenu].index].variabel);
            lcd.print(" ==> ");
            delay(1000);
            break;
          case subMenu:
            levelMenu++;
            menuIndex[levelMenu].index = 0;
            menuIndex[levelMenu].menu = menuIndex[levelMenu-1].menu[menuIndex[levelMenu-1].index].subMenu;
            menuIndex[levelMenu].menuLength = menuIndex[levelMenu-1].menu[menuIndex[levelMenu-1].index].jumlahBaris;
            menuIndex[levelMenu].dropDownLength = 0;
            menuTextIndex = 0;
            entriNilai = false;
            break;
        }
      }
    }
  }
  if(millis() - millismenuText > 1000)
  {
    millismenuText = millis();
    
    if(menuIndex[levelMenu].dropDownLength != 0)
    {
      if(menuTextIndex >= menuIndex[levelMenu].dropDownLength)
      {
        menuTextIndex = 0;
      }
      lcd.setCursor(0, 1);
      lcd.print(menuIndex[levelMenu].dropDown + (menuTextIndex++ * (lebarTextLCD)));
    }
    if(entriNilai)
    {
      lcd.setCursor(0, 0);
      if((judulMenuTampil % 3) == 0)
      {
        lcd.print(judulMenu);
      }
      else if((judulMenuTampil % 3) == 1)
      {
        lcd.print("* untuk simpan  ");
      }
      else
      {
        lcd.print("# untuk batal   ");
      }
      judulMenuTampil++;
    }
    else if(levelMenu != -1)  
    {
      if(menuTextIndex >= menuIndex[levelMenu].menuLength)
      {
        menuTextIndex = 0;
      }
      lcd.setCursor(0, 1);
      lcd.print(menuIndex[levelMenu].menu[menuTextIndex++].text);
    }
  }
}

void displayMenu()
{
  if(levelMenu == -1)
  {
    menuIdle();
    menuIndex[levelMenu].dropDownLength = 0;
  }
  else if(levelMenu == 0)
  {
    menuIndex[levelMenu].index = 0;
    menuIndex[levelMenu].menu = menuUtama;
    menuIndex[levelMenu].menuLength = sizeof(menuUtama)/sizeof(menuUtama[0]);
    menuIndex[levelMenu].dropDownLength = 0;
    menuTextIndex = 0;

    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Pilih [1..");
    lcd.print(sizeof(menuUtama)/sizeof(menuUtama[0]));
    lcd.print("]");
  }
  else
  {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print(menuIndex[levelMenu-1].menu[menuIndex[levelMenu-1].index].text);
    menuIndex[levelMenu].dropDownLength = 0;
  }
}

Library yang digunakan dalam sketch Arduino menu:

  1. Keypad.zip

Pengujian menu dinamik Arduino:

  1. tekan ‘*’ untuk masuk ke menu
  2. tekan ‘*’ pada saat menu aktif berfungsi untuk simpan dan kembali
  3. tekan ‘#’ untuk kembali ke level menu diatasnya
  4. Jika entri nilai valid akan muncul pesan ‘disimpan’

Timbangan beras otomatis dengan arduino

Timbangan beras digital ini merupakan timbangan beras pintar yang akan memberitahukan kapasitas beras tersisa dalam silo/tampungan beras ke apk Android melalui bluetooth sehingga pengguna dapat mengatur ketersiaan stok beras dengan mudah. Disamping itu timbangan beras berbasis arduino ini juga akan mengingatkan pengguna melalui suara apabila beras hampir habis.

Memiliki dua timbangan yaitu timbangan beras di silo dan timbangan beras yang akan dikeluarkan melalui slot beras. Beras yang ingin diambil dapat dipilih melalui panel keypad 1.000gr hingga 10.000 gram. Jika slot beras telah terisi sesuai berat yang diminta perangkat akan mengeluarkan peringatan melalui suara.

album : Galeri timbangan beras arduino android