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.project.semesin.com"));
  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;
char buf[17];

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

 

Library pemberi pakan ikan otomatis :

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