Mengatur waktu rtc ds3231 dengan library RTCLib

Pengaturan waktu atau adjust rtc ds3231 bisa dilakukan dengan cara berikut :
1. Pengaturan langsung
a. Parameter jumlah detik sejak 1 Januari 1970 (UTC)

1
rtc.adjust(DateTime(1740199920));

angka 1740199920 adalah nilai utc pada 22 Februari 2025 11:52:00

b. Parameter tanggal wan waktu

1
rtc.adjust(DateTime(2025, 2, 22, 11, 52, 0));

parameter yang di inputkan masing-masing adalah tahun,bulan, tanggal, jam, menit dan detik.

c. Parameter string tanggal dan string waktu

1
rtc.adjust(DateTime("Feb 22 2025", "11:52:00"));

d. Paramter string ISO

1
rtc.adjust(DateTime("2025-02-22T11:52:00"));

2. Pengaturan otomatis sesuai waktu compile.

1
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));

__DATE__ dan __TIME__ adalah macro preprocessor yang memiliki nilai string tanggal dan waktu pada saat compile, preprocessor lainnya seperti __FILE__, __LINE__, __TIMESTAMP__

3. Pengaturan dengan entry nilai
Untuk flexibilitas, pengaturan waktu rtc bisa dilakukan dengan entry melalui tombol, keypad, android, serial dll. Berikut ini adalah contoh pengaturan melalui tiga tombol:
Skema Pengaturan waktu modul rtc ds3231 meun tombol:

Koding arduino adjust rtc ds3231:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#define menuPin       8
#define plusPin       9
#define minusPin      10
 
#include <Wire.h>;
#include <LCD_I2C.h>;
#include <RTClib.h>;
 
LCD_I2C lcd(0x27, 16, 2);
RTC_DS3231 rtc;
DateTime now;
DateTime rtcSet;
 
enum menuMode {
  settingStandby,
  settingJam,
  settingMenit,
  settingDetik,
  settingTanggal,
  settingBulan,
  settingTahun,
  jumlahMenuMode,
};
 
char buffer[20];
byte menuIndex;
byte detikSebelumnya;
 
void setup() {
  pinMode(menuPin, INPUT_PULLUP);
  pinMode(plusPin, INPUT_PULLUP);
  pinMode(minusPin, INPUT_PULLUP);
 
  Serial.begin(9600);
  Serial.println(F("Mengatur waktu rtc ds3231 dengan library RTCLib"));
  Serial.println(F("https://www.semesin.com/project"));
  Serial.println();
 
  Wire.begin();
  Wire.beginTransmission(0x27);
  if (Wire.endTransmission())
  {
    lcd = LCD_I2C(0x3F, 16, 2);
  }
  lcd.begin();
 
  //  if (rtc.lostPower())
  //  {
  //  1a
  //  rtc.adjust(DateTime(1740199920));
  //
  //  1b
  //  rtc.adjust(DateTime(2025, 2, 22, 11, 52, 0));
  //
  //  1c
  //  rtc.adjust(DateTime("Feb 22 2025", "11:52:00"));
  //
  //  1d
  //  rtc.adjust(DateTime("2025-02-22T11:52:00"));
  //
  //  2
  //  rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  //}
 
  lcd.backlight();
  lcd.print("Adjust RTC");
  lcd.setCursor(0, 1);
  lcd.print("semesin.com");
  delay(3000);
 
  lcd.clear();
 
}
 
void loop() {
  now = rtc.now();
 
  if (detikSebelumnya != now.second())
  {
    detikSebelumnya = now.second();
 
    if (menuIndex == settingStandby) {
      tampilanWaktu(now);
    }
  }
 
  if (!digitalRead(menuPin)) {
    delay(50);
    if (!digitalRead(menuPin)) {
      if (menuIndex == settingStandby) {
        rtcSet = DateTime(now);
      }
 
      menuIndex++;
      menuIndex %= jumlahMenuMode;
 
      if (menuIndex == settingStandby) {
        rtc.adjust(DateTime(rtcSet));
      }
      tampilanMenu();
      while (!digitalRead(menuPin));
    }
  }
 
  if (!digitalRead(plusPin)) {
    delay(50);
    if (!digitalRead(plusPin)) {
      plusNilai();
      tampilanMenu();
      while (!digitalRead(plusPin));
    }
  }
 
  if (!digitalRead(minusPin)) {
    delay(50);
    if (!digitalRead(minusPin)) {
      minusNilai();
      tampilanMenu();
      while (!digitalRead(minusPin));
    }
  }
}
 
void tampilanMenu() {
  tampilanWaktu(rtcSet);
  switch (menuIndex) {
    case settingStandby:
      lcd.noBlink();
      break;
    case settingJam:
      lcd.setCursor(4, 1);
      lcd.blink();
      break;
    case settingMenit:
      lcd.setCursor(7, 1);
      break;
    case settingDetik:
      lcd.setCursor(10, 1);
      break;
    case settingTanggal:
      lcd.setCursor(3, 0);
      break;
    case settingBulan:
      lcd.setCursor(6, 0);
      break;
    case settingTahun:
      lcd.setCursor(9, 0);
      break;
  }
}
 
void tampilanWaktu(DateTime datetime) {
  sprintf(buffer, "%02d/%02d/%04d", datetime.day(), datetime.month(), datetime.year());
  lcd.setCursor(3, 0);
  lcd.print(buffer);
  sprintf(buffer, "%02d:%02d:%02d", datetime.hour(), datetime.minute(), datetime.second());
  lcd.setCursor(4, 1);
  lcd.print(buffer);
}
 
void plusNilai() {
  switch (menuIndex) {
    case settingStandby:
      break;
    case settingJam:
      rtcSet = rtcSet + TimeSpan(0, 1, 0, 0);
      break;
    case settingMenit:
      rtcSet = rtcSet + TimeSpan(0, 0, 1, 0);
      break;
    case settingDetik:
      rtcSet = rtcSet + TimeSpan(0, 0, 0, 1);
      break;
    case settingTanggal:
      rtcSet = rtcSet + TimeSpan(1, 0, 0, 0);
      break;
    case settingBulan:
      rtcSet = DateTime(rtcSet.year(), rtcSet.month() == 12 ? 1 : rtcSet.month() + 1, rtcSet.day(), rtcSet.hour(), rtcSet.minute(), rtcSet.second());
      break;
    case settingTahun:
      rtcSet = DateTime(rtcSet.year() + 1, rtcSet.month(), rtcSet.day(), rtcSet.hour(), rtcSet.minute(), rtcSet.second());
      break;
  }
}
 
void minusNilai() {
  switch (menuIndex) {
    case settingStandby:
      break;
    case settingJam:
      rtcSet = rtcSet - TimeSpan(0, 1, 0, 0);
      break;
    case settingMenit:
      rtcSet = rtcSet - TimeSpan(0, 0, 1, 0);
      break;
    case settingDetik:
      rtcSet = rtcSet - TimeSpan(0, 0, 0, 1);
      break;
    case settingTanggal:
      rtcSet = rtcSet - TimeSpan(1, 0, 0, 0);
      break;
    case settingBulan:
      rtcSet = DateTime(rtcSet.year(), rtcSet.month() == 1 ? 12 : rtcSet.month() - 1, rtcSet.day(), rtcSet.hour(), rtcSet.minute(), rtcSet.second());
      break;
    case settingTahun:
      rtcSet = DateTime(rtcSet.year() - 1, rtcSet.month(), rtcSet.day(), rtcSet.hour(), rtcSet.minute(), rtcSet.second());
      break;
  }
}

Library:

1. LCD_I2C-2.3.0
2. RTClib-1.13.0

JWS Jammer dengan Database Jadwal Waktu Shalat Bulanan

Jammer merupakan alat pengacak/blokir sinyal handphone/hp dapat digunakan di tempat ibadah untuk me-nonaktifkan perangkat cellular sehingga tidak bisa dipanggil/memanggil dengan tujuan menjaga tempat ibadah dari kebisingan dering ponsel.

Penggunaan jammer/jamming/repeater sinyal hp bisa mengganggu hak orang lain dan berpotensi melanggar undang-undang telekomunikasi, gunakan dengan bijak

Jadwal Shalat

Jadwal shalat berubah-ubah setiap hari tergantung posisi matahari dan bulan, hal ini membuat perangkat digital harus mampu mengikuti perubahan ini. Beberapa metode penggunaan jadwal shalat shalat digital :

  1. Jadwal manual, yaitu jadwal rata-rata dari setiap waktu-waktu shalat
  2. Jadwal database, yaitu jadwal yang tersimpan dalam tabel, bisa mingguan, bulanan atau tahunan
  3. Jadwal Matahari, yaitu penghitungan waktu shalat menggunakan posisi peredaran matahari, dengan memasukkan variabel posisi lintang, bujur, dan tanggal.
  4. Jadwal online, dengan mengambil data dari server online setiap hari.

Skema JWS Jammer menggunakan arduino:

Komponen yang digunakan dalam JWS Database Jadwal Waktu Bulanan:

  1. Arduino Uno
  2. LCD 1602 I2C Backpack
  3. RTC DS3231
  4. Relay untuk jammer
  5. 3x LED
  6. 3x TOmbol

Koding/program JWS Jadwal Bulanan:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
#define pinLedMerah             5
#define pinLedHijau             6
#define pinLedBiru              7
 
#define pinTombolOtomatis       11
#define pinTombolManual         12
#define pinTombolJammer         13
 
#define pinJammer               4
#define relayOn                 LOW
 
#define waktuJammerShalat       20
#define waktuJammerShalatJumat  60
#define waktuJammerManual       20
 
#include <Wire.h>
#include "Sodaq_DS3231.h"
#include <LiquidCrystal_I2C.h>
 
LiquidCrystal_I2C lcd(0x3F, 16, 2);
 
struct waktu
{
  byte jam;
  byte menit;
};
 
 
const waktu jadwalShalat[][8] PROGMEM = {
  //Imsyak  Shubuh  Terbit  Dhuha Dzuhur  Ashr  Maghrib Isya
  {{ 4, 20}, { 4, 30}, { 5, 51}, { 6, 15}, {12, 7}, {15, 34}, {18, 20}, {19, 36}},
  {{ 4, 20}, { 4, 30}, { 5, 51}, { 6, 15}, {12, 8}, {15, 34}, {18, 20}, {19, 36}},
  {{ 4, 21}, { 4, 31}, { 5, 52}, { 6, 16}, {12, 8}, {15, 35}, {18, 21}, {19, 36}},
  {{ 4, 21}, { 4, 31}, { 5, 52}, { 6, 16}, {12, 9}, {15, 35}, {18, 21}, {19, 37}},
  {{ 4, 22}, { 4, 32}, { 5, 53}, { 6, 17}, {12, 9}, {15, 36}, {18, 21}, {19, 37}},
  {{ 4, 23}, { 4, 33}, { 5, 53}, { 6, 17}, {12, 9}, {15, 36}, {18, 22}, {19, 37}},
  {{ 4, 23}, { 4, 33}, { 5, 54}, { 6, 18}, {12, 10}, {15, 36}, {18, 22}, {19, 38}},
  {{ 4, 24}, { 4, 34}, { 5, 54}, { 6, 18}, {12, 10}, {15, 37}, {18, 23}, {19, 38}},
  {{ 4, 24}, { 4, 34}, { 5, 55}, { 6, 19}, {12, 11}, {15, 37}, {18, 23}, {19, 38}},
  {{ 4, 25}, { 4, 35}, { 5, 55}, { 6, 19}, {12, 11}, {15, 37}, {18, 23}, {19, 38}},
  {{ 4, 25}, { 4, 35}, { 5, 56}, { 6, 20}, {12, 12}, {15, 37}, {18, 24}, {19, 39}},
  {{ 4, 26}, { 4, 36}, { 5, 56}, { 6, 20}, {12, 12}, {15, 38}, {18, 24}, {19, 39}},
  {{ 4, 27}, { 4, 37}, { 5, 56}, { 6, 20}, {12, 12}, {15, 38}, {18, 24}, {19, 39}},
  {{ 4, 27}, { 4, 37}, { 5, 57}, { 6, 21}, {12, 13}, {15, 38}, {18, 25}, {19, 39}},
  {{ 4, 28}, { 4, 38}, { 5, 57}, { 6, 21}, {12, 13}, {15, 38}, {18, 25}, {19, 40}},
  {{ 4, 28}, { 4, 38}, { 5, 58}, { 6, 22}, {12, 13}, {15, 39}, {18, 25}, {19, 40}},
  {{ 4, 29}, { 4, 39}, { 5, 58}, { 6, 22}, {12, 14}, {15, 39}, {18, 25}, {19, 40}},
  {{ 4, 29}, { 4, 39}, { 5, 59}, { 6, 23}, {12, 14}, {15, 39}, {18, 26}, {19, 40}},
  {{ 4, 30}, { 4, 40}, { 5, 59}, { 6, 23}, {12, 14}, {15, 39}, {18, 26}, {19, 40}},
  {{ 4, 30}, { 4, 40}, { 5, 59}, { 6, 23}, {12, 15}, {15, 39}, {18, 26}, {19, 40}},
  {{ 4, 31}, { 4, 41}, { 6, 0}, { 6, 24}, {12, 15}, {15, 39}, {18, 26}, {19, 40}},
  {{ 4, 31}, { 4, 41}, { 6, 0}, { 6, 24}, {12, 15}, {15, 39}, {18, 26}, {19, 40}},
  {{ 4, 32}, { 4, 42}, { 6, 1}, { 6, 25}, {12, 16}, {15, 39}, {18, 27}, {19, 41}},
  {{ 4, 32}, { 4, 42}, { 6, 1}, { 6, 25}, {12, 16}, {15, 39}, {18, 27}, {19, 41}},
  {{ 4, 33}, { 4, 43}, { 6, 1}, { 6, 25}, {12, 16}, {15, 39}, {18, 27}, {19, 41}},
  {{ 4, 33}, { 4, 43}, { 6, 2}, { 6, 26}, {12, 16}, {15, 39}, {18, 27}, {19, 41}},
  {{ 4, 34}, { 4, 44}, { 6, 2}, { 6, 26}, {12, 17}, {15, 39}, {18, 27}, {19, 41}},
  {{ 4, 34}, { 4, 44}, { 6, 2}, { 6, 26}, {12, 17}, {15, 39}, {18, 27}, {19, 41}},
  {{ 4, 35}, { 4, 45}, { 6, 3}, { 6, 27}, {12, 17}, {15, 39}, {18, 27}, {19, 40}},
  {{ 4, 35}, { 4, 45}, { 6, 3}, { 6, 27}, {12, 17}, {15, 39}, {18, 27}, {19, 40}},
  {{ 4, 36}, { 4, 46}, { 6, 3}, { 6, 27}, {12, 17}, {15, 39}, {18, 27}, {19, 40}},
};
byte waktuUtama[] =  {1, 4, 5, 6, 7};
char namaHari[][8] = {"Minggu,", "Senin, ", "Selasa,", " Rabu, ", "Kamis, ", "Jumat, ", "Sabtu, "};
char namaWaktu[][16] = {"Imsyak", "Shubuh", "Terbit", "Dhuha", "Dzuhur", "Ashr", "Maghrib", "Isya"};
 
enum Mode
{
  otomatis,
  manual,
};
 
byte mode;
char buffer[32];
byte detikSebelumnya = 60;
byte menitSebelumnya = 60;
uint16_t unixRelay;
bool statusJammer;
DateTime now;
 
void setup()
{
  pinMode(pinLedMerah, OUTPUT);
  pinMode(pinLedHijau, OUTPUT);
  pinMode(pinLedBiru, OUTPUT);
  digitalWrite(pinJammer, !relayOn);
  pinMode(pinJammer, OUTPUT);
 
  pinMode(pinTombolOtomatis, INPUT_PULLUP);
  pinMode(pinTombolManual, INPUT_PULLUP);
  pinMode(pinTombolJammer, INPUT_PULLUP);
 
  Serial.begin(9600);
  Serial.println("JWS Jammer Sinyal HP dengan Jadwal Bulanan");
  Serial.println("https://www.project.semesin.com");
 
  Wire.begin();
  Wire.beginTransmission(0x3F);
  if (Wire.endTransmission())
  {
    lcd = LiquidCrystal_I2C(0x27, 16, 2);
  }
  lcd.begin();
 
  rtc.begin();
  now = rtc.now();
  if (now.year() == 2000)
  {
    //Waktu compiler
    char bulan[12];
    byte indexBulan;
    int jam, menit, detik, tanggal, tahun;
 
    char *namaBulan[12] = {
      "Jan", "Feb", "Mar", "Apr", "May", "Jun",
      "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
    };
    sscanf(__TIME__, "%d:%d:%d", &jam, &menit, &detik);
    sscanf(__DATE__, "%s %d %d", bulan, &tanggal, &tahun);
    for (indexBulan = 0; indexBulan < 12; indexBulan++) {
      if (strcmp(bulan, namaBulan[indexBulan]) == 0)
        break;
    }
    uint8_t wday = hariDariTanggal(tanggal, indexBulan + 1, tahun);
    DateTime dt(tahun, indexBulan + 1, tanggal, jam, menit, detik, wday);
    rtc.setDateTime(dt);
    Serial.println("RTC sudah otomatis di setting (Sekali saja)");
  }
 
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("JWS Bulanan");
  lcd.setCursor(0, 1);
  lcd.print("fitur : Jammer");
 
  delay(3000);
  lcd.clear();
 
  digitalWrite(pinLedHijau, HIGH);
  Serial.println("Sistem mulai");
 
}
 
void loop()
{
  now = rtc.now();
 
  uint16_t unixSekarang = now.hour() * 60 + now.minute();
  if (detikSebelumnya != now.second())
  {
 
    detikSebelumnya = now.second();
    if (!statusJammer)
    {
      sprintf(buffer, "%s %02d/%02d/%02d", namaHari[now.dayOfWeek() - 1], now.date(), now.month(), now.year() - 2000);
      lcd.setCursor(0, 0);
      lcd.print(buffer);
    }
    sprintf(buffer, "%02d:%02d:%02d", now.hour(), now.minute(), now.second());
    lcd.setCursor(4, 1);
    lcd.print(buffer);
  }
  if (menitSebelumnya != now.minute())
  {
    menitSebelumnya = now.minute();
    if (mode == otomatis)
    {
      for (byte i = 0; i < 5; i++)
      {
        if ((pgm_read_byte(&jadwalShalat[now.date() - 1][waktuUtama[i]].jam) == now.hour()) &&
            (pgm_read_byte(&jadwalShalat[now.date() - 1][waktuUtama[i]].menit) == now.minute()))
        {
          digitalWrite(pinLedMerah, HIGH);
          digitalWrite(pinJammer, relayOn);
 
          if ((i == 1) && (now.dayOfWeek() == 6)) //Dzuhur / jumatan
          {
            unixRelay = unixSekarang + waktuJammerShalatJumat;//menit
          }
          else
          {
            unixRelay = unixSekarang + waktuJammerShalat;//menit
          }
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("  J A M M E R   ");
          statusJammer = true;
 
          sprintf(buffer, "Waktu: %s", namaWaktu[waktuUtama[i]]);
          lcd.setCursor(0, 1);
          lcd.print(buffer);
 
          delay(5000);
          lcd.clear();
          lcd.setCursor(0, 0);
          lcd.print("  J A M M E R   ");
        }
      }
    }
    if (statusJammer)
    {
      if (unixSekarang == unixRelay)
      {
        statusJammer = false;
        digitalWrite(pinLedMerah, LOW);
        digitalWrite(pinJammer, !relayOn);
      }
    }
  }
 
 
  if (!digitalRead(pinTombolOtomatis))
  {
    delay(50);
    if (!digitalRead(pinTombolOtomatis))
    {
      mode = otomatis;
      digitalWrite(pinLedHijau, HIGH);
      digitalWrite(pinLedBiru, LOW);
      lcd.setCursor(0, 0);
      lcd.print("    M O D E     ");
      lcd.setCursor(0, 1);
      lcd.print("O T O M A T I S ");
      delay(3000);
      lcd.clear();
    }
  }
  if (!digitalRead(pinTombolManual))
  {
    delay(50);
    if (!digitalRead(pinTombolManual))
    {
      mode = manual;
      digitalWrite(pinLedHijau, LOW);
      digitalWrite(pinLedBiru, HIGH);
      lcd.setCursor(0, 0);
      lcd.print("    M O D E     ");
      lcd.setCursor(0, 1);
      lcd.print("  M A N U A L   ");
      delay(3000);
      lcd.clear();
    }
  }
  if (mode == manual)
  {
    if (!digitalRead(pinTombolJammer))
    {
      delay(50);
      if (!digitalRead(pinTombolJammer))
      {
        if (statusJammer)
        {
          digitalWrite(pinLedMerah, LOW);
          digitalWrite(pinJammer, !relayOn);
          statusJammer = false;
        }
        else
        {
          digitalWrite(pinLedMerah, HIGH);
          digitalWrite(pinJammer, relayOn);
          unixRelay = unixSekarang + waktuJammerManual;//menit
          statusJammer = true;
          lcd.setCursor(0, 0);
          lcd.print("  J A M M E R   ");
          lcd.setCursor(0, 1);
          lcd.print("  M A N U A L   ");
          delay(5000);
        }
        while (!digitalRead(pinTombolJammer));
        delay(50);
      }
    }
  }
}
byte hariDariTanggal(byte tanggal, byte bulan, uint16_t tahun)
{
  uint16_t jumlahHariPerBulanMasehi[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
  if (tahun >= 2000)
    tahun -= 2000;
 
  uint32_t jumlahHari = tahun * 365;
  uint16_t tahunKabisat = tahun / 4;
  for (byte i = 0; i < tahun; i++)
  {
    if (!(i % 4))
    {
      jumlahHari++;
    }
  }
  jumlahHari += jumlahHariPerBulanMasehi[bulan - 1];
  if ( (bulan >= 2) && !(tahun % 4))
  {
    jumlahHari++;
  }
  jumlahHari += tanggal;
  return ((jumlahHari + 5) % 7) + 1;
}

Library:

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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
#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

Pengisi galon otomatis menggunakan arduino

Depot pengisian air minum menggunakan galon sebagai tempat air. Tahap-tahap pengisian yang lazim di lakukan adalah: pembersihan, pengisian, pemasangan tutup dan perbersihan.

Dalam artikel ini hanya melakukan otomatisasi pada tahap pengisian, cara kerjanya sebagai berikut :

  1. Saat mulai, sensor ir/obstacle mendeteksi keberadaan galon diatas tempat pengisian galon. Jika ada galon maka sistem menginformasikan agar galon diambil terlebih dahulu.
  2. Sistem menunggu hingga galon kosong ditempatkan pada posisi pengisian galon.
  3. Sistem akan menghidupkan pompa air, kemudian menghidupkan solenoid.
  4. Sensor flow meter akan menghitung volume ait yang dialirkan kedalam galon.
  5. Jika volume telah mencukupi maka solenoid dan pompa dimatikan.
  6. Jika selama pengisian galon, posisi galon bergeser atau diambil, maka solenoid dan pompa akan dimatikan.
  7. Sistem akan menunggu galon diambil.
  8. Selesai.

Skema pengisian galon otomatis berbasis arduino:

Komponen yang digunakan dalam perancangan sistem pengisian galon arduino:

  1. Arduino uno
  2. LCD 16×2 lcd backpack
  3. sensor obstacle
  4. flow sensor
  5. solenoid
  6. pompa air
  7. relay 2 channel

Program pengisi galon menggunakan arduino:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#define kapasitasGalon      19//liter
#define pulsaPerLiter       450//sesuai spesifikasi sensor water flow
 
#define pinWaterFlow        2
#define pinSensorIR         A0
#define pinPompa            7
#define pinSelenoid         6
 
#define IRAktif             LOW
#define relayAktif          LOW
 
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <util/atomic.h>
 
LiquidCrystal_I2C lcd(0x3F, 16, 2);
volatile uint16_t pulseCount;
 
void setup() {
  digitalWrite(pinPompa, !relayAktif);
  digitalWrite(pinSelenoid, !relayAktif);
  pinMode(pinWaterFlow, INPUT);
  pinMode(pinSensorIR, INPUT);
  pinMode(pinPompa, OUTPUT);
  pinMode(pinSelenoid, OUTPUT);
 
  Serial.begin(9600);
  Serial.println(F("Pengisi galon otomatis"));
  Serial.println(F("https://www.project.semesin.com"));
 
 
  Wire.begin();
  Wire.beginTransmission(0x3F);
  if (Wire.endTransmission())
  {
    lcd = LiquidCrystal_I2C(0x27, 16, 2);
  }
  lcd.begin();
 
  lcd.backlight();
  lcd.print("Pengisi galon");
  lcd.setCursor(0, 1);
  lcd.print("Semesin.com");
  delay(3000);
 
 
  lcd.setCursor(0, 0);
  lcd.print("ambil Galon     ");
  while (digitalRead(pinSensorIR) == IRAktif); //deteksi awal : jika ada galon kosongkan dahulu
 
  attachInterrupt(digitalPinToInterrupt(pinWaterFlow), pulseCounter, FALLING);
}
 
void loop() {
  lcd.setCursor(0, 0);
  lcd.print("Letakkan Galon  ");
  while (digitalRead(pinSensorIR) == !IRAktif);
 
  delay(1000);//memastikan galon diletakkan
 
  if (digitalRead(pinSensorIR) == IRAktif)
  {
    lcd.setCursor(0, 0);
    lcd.print("Mengisi Galon...");
 
    pulseCount = 0;
    digitalWrite(pinPompa, relayAktif);
    delay(1000);
    digitalWrite(pinSelenoid, relayAktif);
 
    lcd.setCursor(0, 1);
    lcd.print("                ");
    uint16_t jumlahPulsa;
 
    while ((jumlahPulsa < kapasitasGalon * pulsaPerLiter) && (digitalRead(pinSensorIR) == IRAktif))
    {
      ATOMIC_BLOCK(ATOMIC_FORCEON)
      {
        jumlahPulsa = pulseCount;
      }
 
      lcd.setCursor(0, 1);
      lcd.print((1.0 * jumlahPulsa / pulsaPerLiter));
      lcd.print(" liter");
    }
 
    digitalWrite(pinSelenoid, !relayAktif);
    delay(100);
    digitalWrite(pinPompa, !relayAktif);
 
    lcd.setCursor(0, 0);
    if (jumlahPulsa >= kapasitasGalon * pulsaPerLiter)
    {
      lcd.print("Galon penuh     ");
    }
    else if (digitalRead(pinSensorIR) != IRAktif)
    {
      lcd.print("Galon tidak ada ");
    }
 
    delay(1000);
    lcd.setCursor(0, 0);
    lcd.print("silahkan ambil  ");
 
    while (digitalRead(pinSensorIR) == IRAktif);
    delay(1000);//memastikan galon sudah diambil
    while (digitalRead(pinSensorIR) == IRAktif);
  }
}
 
void pulseCounter()
{
  pulseCount++;
}

Library:

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 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
#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.project.semesin.com"));
  Serial.println();
   
  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("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

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 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
#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

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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#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 ”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#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

Bel sekolah dengan pengaturan melalui tombol

Bel sekolah merupakan pengingat waktu terjadwal yang menandai pergantian antar waktu pelajaran di sekolah. Ber sekolah juga memiliki penjawalan mingguan dan bulanan.

Perangkat bel sekolah otomatis bisa diaplikasikan menggunakan arduino sebagai unit prosesornya, tidak seperti bel sekolah digital berbasis komputer yang menyimpan jadwal dalam harddisk, bel sekolah digital arduino menyimpan data jadwal pelajaran didalam EEPROM. Data Jadwal disimpan dalam format/struktur berikut :

  • Aktif
  • Jam
  • Menit

Guna mengatur data jadwal tersebut, perangkat bel sekolah ini dilengkapi dengan tombol-tombol dengan fungsi [menu], [tambah], [kurang] dan [ok].

serta penggunaan LCD sebagai tampilan waktu sekarang dan tampilan jadwal apabila waktunya telah tepat.

skema bel sekolah dengan pengaturan melalui tombol/button:

komponen yang digunakan :

  1. Arduino uno
  2. RTC DS3231
  3. LCD i2C
  4. push button 4x

sketch/koding bel sekolah arduino :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
#define pinTombolMenu       5
#define pinTombolTambah     4
#define pinTombolKurang     3
#define pinTombolOk         2
 
#include <EEPROM.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SoftwareSerial.h>
#include "RTC.h"
 
LiquidCrystal_I2C lcd(0x3F, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display
RTC_DS3231 rtc;
char namaHari[][7] = {"Minggu", "Senin", "Selasa", " Rabu", "Kamis", "Jum'at", "Sabtu"};
char textMenuUtama[][17] = {
  "Bel masuk +pel 1",
  "Ganti pel 2     ",
  "Bel istirahat   ",
  "Bel masuk +pel 3",
  "Ganti pel 4     ",
  "Bel pulang      ",
  "Set Jam         ",
};
char textAktif[][6] = {"Mati ", "Aktif"};
 
char bufWaktu[40];
 
struct Jadwal
{
  bool aktif;
  byte jam;
  byte menit;
};
 
Jadwal jadwal[6] = {{0, 7, 0}, {0, 7, 0}, {0, 7, 0}, {0, 7, 0}, {0, 7, 0}, {0, 7, 0},} ;
Jadwal jadwalSet;
 
void setup()
{
  pinMode(pinTombolMenu, INPUT_PULLUP);
  pinMode(pinTombolTambah, INPUT_PULLUP);
  pinMode(pinTombolKurang, INPUT_PULLUP);
  pinMode(pinTombolOk, INPUT_PULLUP);
 
  Serial.begin (9600);
 
  rtc.begin();
 
  if (rtc.lostPower())
  {
    Serial.println(F("Waktu RTC di set ulang"));
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }
 
  Wire.beginTransmission(0x3F);
  if (Wire.endTransmission())
  {
    lcd = LiquidCrystal_I2C(0x27, 16, 2);
  }
  lcd.begin();
  // Print a message to the LCD.
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("Nama");
  lcd.setCursor(0, 1);
  lcd.print("Judul");
 
  //  delay(3000);
 
  if (EEPROM.read(0) != 0x48)
  {
    simpanJadwal();
    EEPROM.write(0, 0x48);
  }
  else
  {
    ambilJadwal();
  }
  Serial.println("Bel sekolah dimulai");
}
 
byte detikSebelumnya = 60;
byte menitSebelumnya = 60;
byte menuLevel = 0;
byte menuIndex[2];
DateTime setWaktu;
 
void loop()
{
  DateTime now = rtc.now();
  if (detikSebelumnya != now.detik)
  {
    detikSebelumnya = now.detik;
    if (!menuLevel)
    {
      sprintf(bufWaktu, "Pukul : %02d:%02d:%02d", now.jam, now.menit, now.detik);
      lcd.setCursor(0, 0);
      lcd.print(bufWaktu);
      sprintf(bufWaktu, "%s, %02d/%02d/%02d", namaHari[now.hari - 1], now.tanggal, now.bulan, now.tahun - 2000);
      lcd.setCursor(0, 1);
      lcd.print(bufWaktu);
 
    }
    if (menitSebelumnya != now.menit)
    {
      menitSebelumnya = now.menit;
      for (byte i = 0; i < 6; i++)
      {
        if (jadwal[i].aktif)
        {
          if ((jadwal[i].jam == now.jam) && (jadwal[i].menit == now.menit))
          {
            lcd.setCursor(0, 0);
            lcd.print("  Bel Sekolah   ");
            lcd.setCursor(0, 1);
            lcd.print(textMenuUtama[i]);
            delay(10000);
          }
        }
      }
    }
  }
 
  if (!digitalRead(pinTombolMenu))
  {
    delay(100);
    if (!digitalRead(pinTombolMenu))
    {
      if (menuLevel == 0)
      {
        menuLevel = 1;
        menuIndex[0] = 0;
      }
      else
      {
        menuLevel = 0;
        lcd.noBlink();
      }
      tampilanMenu();
      while (!digitalRead(pinTombolMenu));
    }
  }
  if (!digitalRead(pinTombolTambah))
  {
    delay(100);
    if (!digitalRead(pinTombolTambah))
    {
      if (menuLevel == 1)
      {
        menuIndex[0]++;
        if (menuIndex[0] >= sizeof(textMenuUtama) / sizeof(textMenuUtama[0]))
        {
          menuIndex[0] = 0;
        }
        tampilanMenu();
      }
      if (menuLevel == 2)
      {
        if (menuIndex[0] == 6)
        {
          switch (menuIndex[1])
          {
            case 0:
              setWaktu.jam++;
              if (setWaktu.jam >= 24)
              {
                setWaktu.jam = 0;
              }
              break;
            case 1:
              setWaktu.menit++;
              if (setWaktu.menit >= 60)
              {
                setWaktu.menit = 0;
              }
              break;
            case 2:
              setWaktu.detik++;
              if (setWaktu.detik >= 60)
              {
                setWaktu.detik = 0;
              }
              break;
          }
        }
        else
        {
          switch (menuIndex[1])
          {
            case 0:
              jadwalSet.aktif = !jadwalSet.aktif;
              break;
            case 1:
              jadwalSet.jam++;
              if (jadwalSet.jam >= 24)
              {
                jadwalSet.jam = 0;
              }
              break;
            case 2:
              jadwalSet.menit++;
              if (jadwalSet.menit >= 60)
              {
                jadwalSet.menit = 0;
              }
              break;
          }
        }
        tampilanMenu();
      }
      delay(100);
    }
  }
  if (!digitalRead(pinTombolKurang))
  {
    delay(100);
    if (!digitalRead(pinTombolKurang))
    {
      if (menuLevel == 1)
      {
        if (menuIndex[0] == 0)
        {
          menuIndex[0] = sizeof(textMenuUtama) / sizeof(textMenuUtama[0]) - 1;
        }
        else
        {
          menuIndex[0]--;
        }
        tampilanMenu();
      }
      if (menuLevel == 2)
      {
        if (menuIndex[0] == 6)
        {
          switch (menuIndex[1])
          {
            case 0:
              if (setWaktu.jam == 0)
              {
                setWaktu.jam = 23;
              }
              else
              {
                setWaktu.jam--;
              }
              break;
            case 1:
              if (setWaktu.menit == 0)
              {
                setWaktu.menit = 59;
              }
              else
              {
                setWaktu.menit--;
              }
              break;
            case 2:
              if (setWaktu.detik == 0)
              {
                setWaktu.detik = 59;
              }
              else
              {
                setWaktu.detik--;
              }
              break;
          }
        }
        else
        {
          switch (menuIndex[1])
          {
            case 0:
              jadwalSet.aktif = !jadwalSet.aktif;
              break;
            case 1:
              if (jadwalSet.jam == 0)
              {
                jadwalSet.jam = 23;
              }
              else
              {
                jadwalSet.jam--;
              }
              break;
            case 2:
              if (jadwalSet.menit == 0)
              {
                jadwalSet.menit = 59;
              }
              else
              {
                jadwalSet.menit--;
              }
              break;
          }
        }
        tampilanMenu();
      }
      delay(100);
    }
  }
  if (!digitalRead(pinTombolOk))
  {
    delay(100);
    if (!digitalRead(pinTombolOk))
    {
      if (menuLevel == 1)
      {
        menuLevel = 2;
        menuIndex[1] = 0;
        if (menuIndex[0] == 6)
        {
          setWaktu = rtc.now();
          tampilanMenu();
          lcd.setCursor(4, 1);
          lcd.blink();
        }
        else
        {
          jadwalSet.aktif = jadwal[menuIndex[0]].aktif;
          jadwalSet.jam = jadwal[menuIndex[0]].jam;
          jadwalSet.menit = jadwal[menuIndex[0]].menit;
          tampilanMenu();
          lcd.setCursor(2, 1);
          lcd.blink();
        }
      }
      else if (menuLevel == 2)
      {
        menuIndex[1]++;
        if (menuIndex[0] == 6)
        {
          switch (menuIndex[1])
          {
            case 1:
              tampilanMenu();
              lcd.setCursor(7, 1);
              lcd.blink();
              break;
            case 2:
              tampilanMenu();
              lcd.setCursor(10, 1);
              lcd.blink();
              break;
            case 3:
              menuLevel = 1;
              rtc.adjust(setWaktu);
              tampilanMenu();
              lcd.noBlink();
              break;
          }
        }
        else
        {
          switch (menuIndex[1])
          {
            case 1:
              tampilanMenu();
              lcd.setCursor(8, 1);
              lcd.blink();
              break;
            case 2:
              tampilanMenu();
              lcd.setCursor(11, 1);
              lcd.blink();
              break;
            case 3:
              menuLevel = 1;
              jadwal[menuIndex[0]].aktif = jadwalSet.aktif;
              jadwal[menuIndex[0]].jam = jadwalSet.jam;
              jadwal[menuIndex[0]].menit = jadwalSet.menit;
              simpanJadwal();
              lcd.noBlink();
              tampilanMenu();
              break;
          }
        }
        while (!digitalRead(pinTombolOk));
        delay(500);
      }
    }
  }
}
void tampilanMenu()
{
  if (menuLevel == 1)
  {
    lcd.setCursor(0, 0);
    lcd.print("   Menu Utama   ");
    lcd.setCursor(0, 1);
    lcd.print(textMenuUtama[menuIndex[0]]);
  }
  else if (menuLevel == 2)
  {
    if (menuIndex[0] == 6)
    {
      lcd.setCursor(0, 0);
      lcd.print(textMenuUtama[menuIndex[0]]);
      sprintf(bufWaktu, "    %02d:%02d:%02d    ", setWaktu.jam, setWaktu.menit, setWaktu.detik);
      lcd.setCursor(0, 1);
      lcd.print(bufWaktu);
    }
    else
    {
      lcd.setCursor(0, 0);
      lcd.print(textMenuUtama[menuIndex[0]]);
      sprintf(bufWaktu, "  %s %02d:%02d   ", textAktif[jadwalSet.aktif], jadwalSet.jam, jadwalSet.menit);
      lcd.setCursor(0, 1);
      lcd.print(bufWaktu);
    }
  }
}
 
void ambilJadwal()
{
  byte *alamat = (byte*)jadwal;
  for (byte i = 1; i < sizeof(jadwal) + 1; i++)
  {
    *alamat++ = EEPROM.read(i);
  }
}
void simpanJadwal()
{
  byte *alamat = (byte*)jadwal;
  for (byte i = 1; i < sizeof(jadwal) + 1; i++)
  {
    EEPROM.update(i, *alamat++);
  }
}

library yang digunakan:

Menu arduino dengan rotary encoder

Rotary encoder (shaft encoder) adalah komponen pengukuran arah putaran. Komponen ini memiliki dua pin keluaran yang menghasilkan sinyal pulsa yang diproses dahulu untuk mendapatkan arah putarannya.

Sinyal rotary encoder:

 

Rotary encoder tersedia dalam bermacam type, dan tipe yang digunakan dalam program ini ada type potensio rotary encoder.

Sinyal keluaran dari type ini terlihat dapat digambarkan sbb:

komponen aplikasi sketch menu rotary encoder berbasis arduino:

  1. Arduino Uno
  2. LCD 16×2 backpack I2C
  3. Momentary Rotary Encoder

Skema arduino menu menggunakan rotary encoder:

 

Sketch menu arduino ini menggunakan external interrupt. untuk arduino uno hanya bisa menggunakan pin 2 dan 3, sedangkan arduino mega bisa menggunakan pin 2, 3, 18, 19, 20 dan 21.

program/aplikasi arduino menu arduino dengan lcd I2c 16×2 menggunakan rotary encoder:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#define pinRotaryEncoderCLK     2
#define pinRotaryEncoderDT      3
#define pinRotaryEncoderSwitch  4
 
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
 
LiquidCrystal_I2C lcd(0x3f, 16, 2); // coba juga alamat 0x27 (tergantung seri back pack)
 
uint8_t maskSensorA;
uint8_t maskSensorB;
uint8_t *pinSensorA;
uint8_t *pinSensorB;
volatile bool encoderAFlag = 0;
volatile bool encoderBFlag = 0;
 
int8_t nilaiEncoder = 0;
int nilaiSetting[4];
byte setMode;
 
void setup() {
  Serial.begin(9600);
  Serial.println("Menu rotary encoder");
  Serial.println("https://www.project.semesin.com/");
  Serial.println();
 
  pinMode(pinRotaryEncoderCLK, INPUT_PULLUP);
  pinMode(pinRotaryEncoderDT, INPUT_PULLUP);
  pinMode(pinRotaryEncoderSwitch, INPUT_PULLUP);
 
  Wire.begin();
  Wire.beginTransmission(0x3F);
  if (Wire.endTransmission())
  {
    lcd = LiquidCrystal_I2C(0x27, 16, 2);
  }
  lcd.begin();
  lcd.backlight();
 
  attachInterrupt(digitalPinToInterrupt(pinRotaryEncoderCLK), encoderARising, RISING);
  attachInterrupt(digitalPinToInterrupt(pinRotaryEncoderDT), encoderBRising, RISING);
 
  maskSensorA  = digitalPinToBitMask(pinRotaryEncoderCLK);
  pinSensorA = portInputRegister(digitalPinToPort(pinRotaryEncoderCLK));
  maskSensorB  = digitalPinToBitMask(pinRotaryEncoderDT);
  pinSensorB = portInputRegister(digitalPinToPort(pinRotaryEncoderDT));
 
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("A:0     C:0");
  lcd.setCursor(0, 1);
  lcd.print("B:0     D:0");
}
 
void loop() {
  if (nilaiEncoder != 0)
  {
    Serial.println(nilaiEncoder);
    nilaiSetting[setMode] += nilaiEncoder;
    nilaiEncoder = 0;
 
    lcd.setCursor(((setMode / 2) * 8) + 2, setMode % 2);
    lcd.print(nilaiSetting[setMode]);
    lcd.print(" ");
  }
  if (!digitalRead(pinRotaryEncoderSwitch))
  {
    delay(50);
    setMode = (setMode + 1) % 4;
    while (!digitalRead(pinRotaryEncoderSwitch));
    Serial.println(setMode);
  }
}
void encoderARising() {
  if ((*pinSensorB & maskSensorB) && encoderAFlag)
  {
    nilaiEncoder = -1;
    encoderAFlag = false;
    encoderBFlag = false;
  }
  else
  {
    encoderBFlag = true;
  }
 
}
 
void encoderBRising() {
  if ((*pinSensorA & maskSensorA) && encoderBFlag)
  {
    nilaiEncoder = 1;
    encoderAFlag = false;
    encoderBFlag = false;
  }
  else
  {
    encoderAFlag = true;
  }
}

library yang digunakan:

penggunaan aplikasi sketch menu rotary encoder:

  1. tekan knob untuk memilih menu setting
  2. putar knob ke untuk mengganti nilai setting

Dokumentasi menu rotary encoder lcd i2c:

Input keyboard untuk LCD 16×2 menggunakan Arduino

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

PS2

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

AT Bus

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

USB Keyboard / mouse

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

Skema penggunaan keyboard dan mouse sebagai input

contoh sketch/program arduino menggunakan keyboard

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include <PS2_Semesin.h>
#include <LiquidCrystal_I2C.h>
#include <PS2Code.h>
 
#define keyboardDATAPIN   4
#define keyboardClockPIN  3
 
#define MAX_COL 16
#define MAX_ROW  2
int8_t cols = 0;
int8_t rows = 0;
 
LiquidCrystal_I2C lcd(0x3F, MAX_COL, MAX_ROW);
PS2 keyboard;
 
void setup()
{
  Serial.begin(9600);
  Serial.println("Keyboard arduino dengan tampilan I2C LCD");
  Serial.println("https://www.project.semesin.com/");
  Serial.println();
 
  Wire.begin();
  Wire.beginTransmission(0x3F);
  if (Wire.endTransmission())
  {
    lcd = LiquidCrystal_I2C(0x27, 16, 2);
  }
  lcd.begin();
  lcd.backlight();
 
  keyboard.begin( keyboardDATAPIN, keyboardClockPIN );
  keyboard.setNoBreak(1);
  keyboard.setNoRepeat( 1 );
}
 
 
void loop()
{
  if ( keyboard.available() )
  {
    char keyboardData = keyboard.read();
    if(keyboardData >= ' ' && keyboardData <= '~')
    {
      lcd.print(keyboardData);
      cols++;
      if ( cols >= MAX_COL )
      {
        cols = 0;
        rows++;
        if ( rows >= MAX_ROW )
        {
          rows = 0;
        }
      }
      lcd.setCursor( cols, rows );
      Serial.print(keyboardData);
    }
    else
    {
      Serial.println();
      Serial.print("Special char = ");
      Serial.println(keyboardData,HEX);
      switch ( keyboardData )
      {
        case PS2_KEY_ENTER:
        case PS2_KEY_KP_ENTER:
          cols = 0;
          rows++;
          if ( rows >= MAX_ROW )
            rows = 0;
          break;
        case PS2_KEY_PGDN:
          rows = MAX_ROW - 1;
          break;
        case PS2_KEY_PGUP:
          rows = 0;
          break;
        case PS2_KEY_L_ARROW:
          cols--;
          if ( cols < 0 )
          {
            cols = MAX_COL - 1;
            rows--;
            if ( rows < 0 )
              rows = MAX_ROW - 1;
          }
          break;
        case PS2_KEY_R_ARROW:
          cols++;
          if ( cols >= MAX_COL )
          {
            cols = 0;
            rows++;
            if ( rows >= MAX_ROW )
              rows = 0;
          }
          break;
        case PS2_KEY_UP_ARROW:
          rows--;
          if ( rows < 0 )
            rows = 0;
          break;
        case PS2_KEY_DN_ARROW:
          rows++;
          if ( rows >= MAX_ROW )
            rows = MAX_ROW - 1;
          break;
        case PS2_KEY_BS:
          cols--;
          if ( cols < 0 )
          {
            cols = MAX_COL - 1;
            rows--;
            if ( rows < 0 )
              rows = MAX_ROW - 1;
          }
          lcd.setCursor( cols, rows );
          lcd.write( ' ' );
          break;
        case PS2_KEY_HOME:
          cols = 0;
          rows = 0;
          break;
        case PS2_KEY_END:
          cols = MAX_COL - 1;
          rows = MAX_ROW - 1;
          break;
      }
      lcd.setCursor( cols, rows );
    }
  }
}

library LiquidCrystal-I2C.zip, PS2_Semesin.zip

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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
#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:

Pengaturan alarm dengan arduino dan RTC DS1307 melalui 4 tombol

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

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

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

breadboard:

komponen yang digunakan:

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

sketch/program:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <TimeLib.h>
#include <DS1307RTC.h>
#include <EEPROM.h>
 
//pin
byte tombolUp = 9;
byte tombolDn = 10;
byte tombolMinus = 11;
byte tombolPlus = 8;
byte buzzer = 13;
 
LiquidCrystal_I2C  lcd(0x3F, 16, 2);
byte detikTerakhir = 60;
 
int alarmJamAddr = 0;
int alarmMenitAddr = 1;
int alarmDetikAddr = 2;
 
byte alarmJam;
byte alarmMenit;
byte alarmDetik;
 
bool alarmStatus = false;
unsigned long millisMulai;
unsigned long millisAlarmMulai;
 
bool buzzStatus;
 
uint16_t jedaBuzzer = 1000;
uint16_t waktuAlarm = 10000;//Alarm 10 detik
 
byte menu = 0;
byte menuLCDPos = 8;
byte temp;
 
void setup()
{
  Serial.begin(9600);
  Serial.println("Setting alarm menggunakan Arduino dan RTC1307 melalui 4 push button");
  Serial.println("https://www.project.semesin.com");
 
  pinMode(buzzer, OUTPUT);
  pinMode(tombolUp, INPUT_PULLUP);
  pinMode(tombolDn, INPUT_PULLUP);
  pinMode(tombolMinus, INPUT_PULLUP);
  pinMode(tombolPlus, INPUT_PULLUP);
 
  Wire.begin();
  Wire.beginTransmission(0x3F);
  if (Wire.endTransmission())
  {
    lcd = LiquidCrystal_I2C(0x27, 16, 2);
  }
  lcd.begin();
  lcd.backlight();
  lcd.setBacklight(HIGH);
 
  lcd.setCursor (0, 0);
  lcd.print("Waktu:    :  :  ");
  lcd.setCursor(0, 1);
  lcd.print("Alarm:    :  :  ");
 
  readEEPROMDataWaktu();
 
  lcd.setCursor(8, 1);
  if (alarmJam < 10)lcd.print('0');
  lcd.print(alarmJam);
  lcd.setCursor(11, 1);
  if (alarmMenit < 10)lcd.print('0');
  lcd.print(alarmMenit);
  lcd.setCursor(14, 1);
  if (alarmDetik < 10)lcd.print('0');
  lcd.print(alarmDetik);
}
 
void loop()
{
  tmElements_t tm;
 
  do
  {
    lcd.setCursor(menuLCDPos, 1);
    switch (bacaTombol())
    {
      case '+':
        temp = EEPROM.read(menu - 1);
        if (((temp >= 23) && (menu == 1)) || ((temp >= 59) && (menu > 1)))
          temp = 0;
        else
          temp++;
        EEPROM.write(menu - 1, temp);
        if (temp < 10)lcd.print('0');
        lcd.print(temp);
        break;
      case '-':
        temp = EEPROM.read(menu - 1);
        if ((temp == 0) && (menu == 1))
          temp = 23;
        else if ((temp == 0) && (menu > 1))
          temp = 59;
        else
          temp--;
        EEPROM.write(menu - 1, temp);
        if (temp < 10)lcd.print('0');
        lcd.print(temp);
        break;
      case 'M':
        menu++;
        if (menu == 1)
        {
          menuLCDPos = 8;
          temp = alarmJam;
          lcd.blink();
        }
        else if (menu == 2)
        {
          menuLCDPos = 11;
        }
        else if (menu == 3)
        {
          menuLCDPos = 14;
        }
        if (menu == 4)
        {
          menu = 0;
          lcd.noBlink();
          readEEPROMDataWaktu();
        }
        break;
      case 'E':
        menu = 0;
        lcd.noBlink();
        readEEPROMDataWaktu();
        break;
    }
  }
  while (menu);
 
  if (alarmStatus)
  {
    if (millisMulai + jedaBuzzer < millis())
    {
      buzzStatus = !buzzStatus;
      digitalWrite(buzzer, buzzStatus);
      millisMulai = millis();
    }
    if (millisAlarmMulai + waktuAlarm < millis())
    {
      alarmStatus = false;
      digitalWrite(buzzer, LOW);
    }
  }
 
  if (RTC.read(tm)) {
    if (tm.Second != detikTerakhir)
    {
      lcd.setCursor(8, 0);
      if (tm.Hour < 10)lcd.print('0');
      lcd.print(tm.Hour);
      lcd.setCursor(11, 0);
      if (tm.Minute < 10)lcd.print('0');
      lcd.print(tm.Minute);
      lcd.setCursor(14, 0);
      if (tm.Second < 10)lcd.print('0');
      lcd.print(tm.Second);
 
      if ((alarmJam == tm.Hour) && (alarmMenit == tm.Minute) && (alarmDetik == tm.Second))
      {
        alarmStatus = true;
        millisMulai = millis();
        millisAlarmMulai = millisMulai;
      }
 
      detikTerakhir = tm.Second;
    }
  }
}
 
char bacaTombol()
{
  char tombol = ' ';
  if (!digitalRead(tombolUp))
  {
    tombol = '+';
  }
  else if (!digitalRead(tombolDn))
  {
    tombol = '-';
  }
  else if (!digitalRead(tombolMinus))
  {
    tombol = 'M';
  }
  else if (!digitalRead(tombolPlus))
  {
    tombol = 'E';//exit
  }
  while (!digitalRead(tombolUp));
  while (!digitalRead(tombolDn));
  while (!digitalRead(tombolMinus));
  while (!digitalRead(tombolPlus));
  delay(200);
 
  return tombol;
}
 
void readEEPROMDataWaktu()
{
  alarmJam = EEPROM.read(alarmJamAddr);
  alarmMenit = EEPROM.read(alarmMenitAddr);
  alarmDetik = EEPROM.read(alarmDetikAddr);
}

 

I2C scanner

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <Wire.h>
  
void setup()
{
  Wire.begin();
  
  Serial.begin(9600);
  Serial.println("\nI2C Scanner");
}
  
void loop()
{
  byte error, address;
  int nDevices;
  
  Serial.println("Scanning...");
  
  nDevices = 0;
  for(address = 1; address < 127; address++ )
  {
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
  
    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.print(address,HEX);
       
      byte addressFull = address << 1;
      Serial.print("(");
      if (addressFull<16)
        Serial.print("0");
      Serial.print(addressFull,HEX);
      Serial.println(")");
  
      nDevices++;
    }
    else if (error==4)
    {
      Serial.print("Unknown error at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.println(address,HEX);
    }   
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");
  
  delay(5000);
}

alamat tulis I2C yang umum:

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

Library: