Sensor suara KY-037 3 pin Analog out

Sensor suara KY-037 pcb merah dan pcb biru memiliki perbedaan pada pin analog out.
Gambar KY-037 pcb merah:

Skema KY-037 pcb merah:

Gambar KY-037 pcb biru:

Output analog out pada prinsipnya adalah output mic setelah pre-amp. maka pada pcb biru yang tidak ada pin analog outnya bisa diambil pada titik berikut:


Jumper analog out:


Langkah kalibrasi koding arduino:

  1. Kondisikan lokasi hening/minim suara
  2. Baca adc dan tampilkan di serial monitor
  3. Tentukan rata-rata adc dan masukkan sebagai offset (tengah) dari sinyal analog suara

Contoh koding arduino uno untuk kalibrasi sensor ky037 pcb biru yang mengambil output analog out dari jumper sebelum comparator (jumper analog out ke pin A0 arduino uno):

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
#define pinSensor     A0
 
int analogOffset;
 
int bacaSensor() {
#define faktorTrim        0.2 //20%
#define jumlahSampel      100
 
  int buf[jumlahSampel];
  int  temp;
  int rataRata;
 
  for (int i = 0; i < jumlahSampel; i++)
  {
    buf[i] = analogRead(pinSensor);
    delay(10);
  }
 
  //proses pengurutan (sorting)
  for (int i = 0; i < jumlahSampel - 1; i++)
  {
    for (int j = i + 1; j < jumlahSampel; j++)
    {
      if (buf[i] > buf[j])
      {
        temp = buf[i];
        buf[i] = buf[j];
        buf[j] = temp;
      }
    }
  }
 
  //rata-rata (trimmed mean)
  rataRata = 0;
  for (int i = jumlahSampel * faktorTrim; i < jumlahSampel * (1 - faktorTrim); i++)
  {
    rataRata += buf[i];
  }
 
  rataRata /= jumlahSampel * (1 - (faktorTrim * 2));
 
  return rataRata;
}
 
void setup() {
 
  Serial.begin(9600);
  Serial.println(F("Sensor suara KY-037 3 pin Analog out"));
  Serial.println(F("https://www.semesin.com/project"));
  Serial.println();
 
  //Kalibrasi
  analogOffset = bacaSensor();
 
  Serial.print("analogOffset = ");
  Serial.println(analogOffset);
}
 
void loop() {
 
  int analogOut = bacaSensor() - analogOffset;
 
  Serial.print("analogOut = ");
  Serial.println(analogOut);
 
  delay(100)
}

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

Aplikasi android koneksi classic bluetooth HC-05 dengan RAD Studio (Delphi)

Transfer data classic bluetooth bersifat half duplex (satu arah dalam satu waktu) namun terlihat full duplex karena kecepatannya. Dalam beberapa kasus/contoh penggunaan aplikasi android seringkali proses ReadData/ReceiveData/pembacaan bluetooth, memaksa bluetooth dalam kondisi ‘penerima’/client terus menerus sehingga tidak ada/kecil waktu yang tersedia bagi proses sendData/kirim.

Pada software Rad Studio (Delphi) khususnya target android, disediakan fungsi readdata() dan receivedata(), yang apabila dijalankan tanpa parameter maka secara default akan menahan modul bluetooth (HC-05) dalam posisi penerima selama waktu setting timeout, baik pada metode thread atau timer hal ini menyebabkan proses write/kirim harus menunggu hingga jalur komunikasi mode receive selesai.

Untuk memberikan kesempatan lebih untuk proses baca, seharusnya proses terima data bluetooth dibuat tidak terlalu lama karena dalam RX/TX android sendiri ada mekanisme buffer sebagai tampungan data yang masuk.

Berikut ini adalah contoh pemograman APK Android menggunakan Rad Studio untuk kirim/terima data bluetoth klasik:

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
procedure TForm1.ButtonLedOnClick(Sender: TObject);
begin
  if LSockect.Connected then
  begin
    LSockect.SendData(TEncoding.UTF8.GetBytes('@'));
  end;
end;
 
procedure TForm1.ButtonLedOffClick(Sender: TObject);
begin
  if LSockect.Connected then
  begin
    LSockect.SendData(TEncoding.UTF8.GetBytes('#'));
  end;
end;
 
procedure TForm1.Timer1Timer(Sender: TObject);
var
  buffer : TBytes;
  dataString : String;
  I: Integer;
begin
  if (LSockect &lt;&gt; nil) and (LSockect.Connected) then
  begin
    buffer := LSockect.ReceiveData(100);
 
    if Length(buffer) &gt; 0 then
    begin
      Insert(buffer, bufferBluetooth, Length(bufferBluetooth));
 
      dataString := TEncoding.UTF8.GetString(bufferBluetooth);
      if dataString.Contains(#13#10) then
      begin
        LabelData.Text := dataString;
        SetLength(bufferBluetooth, 0);
      end;
    end;
  end;
end;

Skema modul hc-05 bluetooth dengan arduino sebagai client:


Sedangkan contoh/sampel koding arduino untuk berkomunikasi dengan apk android berbasis delphi (rad studio):

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
#define led1Pin 7
 
#include &lt;SPI.h&gt;
#include &lt;SoftwareSerial.h&gt;
 
SoftwareSerial serialBluetooth(2, 3); // RX, TX
uint32_t kirimMillis;
int counter = 0;
 
void setup() {
  pinMode(led1Pin, OUTPUT);
 
  Serial.begin(9600);
  Serial.println(F("Aplikasi android koneksi classic bluetooth HC-05 dengan RAD Studio (Delphi)"));
  Serial.println(F("https://www.semesin.com/project"));
  Serial.println();
 
  serialBluetooth.begin(9600);
}
 
void loop() {
 
  if (serialBluetooth.available()) {
    char c = serialBluetooth.read();
    Serial.print(c);
    if (c == '@') {
      digitalWrite(led1Pin, HIGH);
      Serial.println(" : Led on");
    }
    else if (c == '#') {
      digitalWrite(led1Pin, LOW);
      Serial.println(" : Led off");
    }
  }
 
  if (kirimMillis &lt; millis()) {
    kirimMillis = millis() + 1000;
    serialBluetooth.println(counter);
    counter++;
  }
}

Link koding aplikasi android dengan rad studio serta koding arduino:

  1. Koding APK Rad studio (delphi)

Dimmable LED bulb

Pencahayaan merupakan aspek kebutuhan yang bisa di optimasi sehingga memberikan kenyamanan, ketelitian, keakuratan dan seterusnya. Bola lampu (bulb) merupakan sumber cahaya yang disediakan pabrikan dalam bermacam ukuran, secara awam diberikan dalam satuan Watt. Namun dalam pencahayaan, dibutuhkan besaran lumen yang mampu di hasilkan oleh titik bola lampu. Apabila bola lampu digunakan untuk menerangi bisang di depannya, maka rata-rata kecerahan bidang tersebut adalah jumlah lumen di bagi luas area yang terpapar dalam satuan lux.

Standar pencahayaan menetapkan beberapa ukuran yang diperlukan untuk menerangi area, diantaranya :

Ruangan Tingkat Pencahayaan
Teras 60
Ruang tamu 120 ̴ 150
Ruang makan 120 ̴ 250
Ruang kerja 120 ̴ 250
Kamar tidur 120 ̴ 250
Kamar mandi 250
Dapur 250
Garasi 60

Dalam beberapa aplikasi pencahayaan diperlukan kecerahan yang akurat, untuk keperluan itu dibutuhkan bola lampu yang bisa diatur keluaran intensitas cahaya/lumen-nya. Selain itu keuntungan lainnya menggunakan dimmer seperti bisa diatur tingkat kesilauan, rendering warna, panas, daya.

Projek kali ini akan mencoba membuat bola lampu LED yang bisa diredupkan. Karena jenis bola lampu ini tidak banyak dijual atau jarang tersedia di toko listrik, kita bisa memodifikasi bola lampu led biasa menjadi bola lampu yang bisa di redupkan/dimmable.

Komponen yang diperlukan adalah :

  • Bola lampu LED yang punya cukup ruang bebas di dalamnya
  • Transformator, ukuran ampere dan tegangannya disesuaikan
  • Dioda bridge
  • kapasitor

rakit komponen tersebut menurut skema berikut:

Rangkaian ini berupa penyearah pada umumnya yang dihubungkan dengan led pada bola lampu. Pada percobaan ini led-led dikelompokkan dalam 3 led seri dan dihubungkan dengan sumber tegangan dari trafo 12v–6v (~18v ac) disesuaikan dengan spesifikasi komponen yang digunakan.

berikut adalah contoh pemasangan lampu led dimmable:

 

Dimmer LED bulb ini bisa di kontrol dengan arduino menggunakan skema berikut:

 

Gunakan koding dimmer bola lampu led ini untuk menguji modifikasi lampu led yang dapat diredupkan:

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 pinPWM          3
#define pinZCD          2
#define frekuensi       50 //50 Hz
#define inputSerial     false
 
#define fCPU            16e6
#define prescaler       1024
#define lebarZCD        500e-6//s
#define freqDutyCycle   (fCPU / (1.0 * prescaler * 2 * frekuensi))
#define minTrigger      ((lebarZCD/2) / (prescaler / fCPU)) + 1
#define maxTrigger      (freqDutyCycle * 0.85)
 
volatile uint16_t dutyCycle;
volatile intptr_t *portPWM;
volatile byte bitPWM;
 
void setup() {
  Serial.begin(9600);
  Serial.println("Dimmer LED arduino");
  Serial.println("https://www.project.semesin.com/");
  Serial.println();
 
  pinMode(pinPWM, OUTPUT);
 
  dutyCycle = setDutyCycle(0);
 
  TCCR2A = _BV(WGM21);
  TCCR2B = _BV(CS22) | _BV(CS21) | _BV(CS20);// clk/1024
  OCR2A = maxTrigger - 1;
  OCR2B = dutyCycle;
  TIMSK2 = _BV(OCIE2B);
 
  portPWM = (volatile intptr_t *) portOutputRegister(digitalPinToPort(pinPWM));
  bitPWM = digitalPinToBitMask(pinPWM);
 
  attachInterrupt(digitalPinToInterrupt(pinZCD), zcdChange, RISING);
 
  Serial.print("minTrigger=");
  Serial.println((int)minTrigger);
  Serial.print("maxTrigger=");
  Serial.println((int)maxTrigger);
}
 
void loop() {
#if inputSerial
 
  if (Serial.available())
  {
    int data = Serial.parseInt();
    dutyCycle = setDutyCycle(data);
 
    while (Serial.available())
    {
      Serial.read();
      delay(2);
    }
  }
 
#else
 
  for (byte i = 1; i <= 100; i++)
  {
    dutyCycle = setDutyCycle(i);
    delay(20);
  }
  for (int8_t i = 99; i >= 0; i--)
  {
    dutyCycle = setDutyCycle(i);
    delay(20);
  }
  delay(1000);
 
#endif
 
}
uint16_t setDutyCycle(uint8_t dutyCycle)
{
  uint8_t trigger = map(dutyCycle, 0, 100, maxTrigger, minTrigger);
 
  //  Serial.print("dutyCycle=");
  //  Serial.print(dutyCycle);
  //  Serial.print(" trigger=");
  //  Serial.println(trigger);
 
  return trigger;
}
 
void zcdChange()
{
  TCNT2 = 0;
  OCR2B = dutyCycle;
}
 
ISR (TIMER2_COMPB_vect)
{
  *portPWM |= bitPWM;
  delayMicroseconds(10);
  *portPWM &= ~bitPWM;
}

Traffic lights (UK sequence) dengan arduino

Urutan traffic lights standar Inggris mengandung arti sebagai berikut :

  1. Lampu merah,
    Setiap kendaraan wajib berhenti tidak lebih dari garis batas
  2. Lampu merah dan lampu kuning,
    Setiap kendaraan wajib berhenti namun bersiap untuk melanjutkan perjalanan
  3. Lampu hijau,
    Boleh melintasi traffic lights
  4. Lampu kuning,
    Bersiap untuk berhenti di belakang garis batas, tetapi jika sudah melewati garis batas masih di perbolehkan jalan.

Jumlah keseluruhan lampu yang dibutuhkan untuk 4 simpang adalah 12 buah, untuk menghemat jalur pin arduino, maka bisa diterapkan sistem scan yang menggunakan 3 jalur lampu, (untuk merah, kuning, hijau), serta 4 jalur untuk masing-masing posisi trafic led, sehingga untuk 4 simpang diperlukan 7 jalur pengontrolan saja.

skema traffic lights berbasis arduino:

program Urutan traffic lights 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
#define jumlahTrafficLight    4
 
byte pinDigit[] = {7, 6, 5, 4};
byte pinRYG[] = {10, 9, 8};
 
#define lampuMerah    (1 << 2)
#define lampuKuning   (1 << 1)
#define lampuHijau    (1 << 0)
 
byte hijauSekarang;
byte hijauSelanjutnya;
byte timingTraffic;
 
struct traffic {
  byte lampu;
  byte lampuSelanjutnya;
  uint32_t waktu;
};
 
traffic skemaTraffic[] = {
  {lampuHijau  , lampuMerah               , 5000},
  {lampuKuning , lampuMerah               , 1000},
  {lampuMerah  , lampuMerah | lampuKuning , 1000},
};
 
byte lampuTraffic[jumlahTrafficLight];
byte indexTraffic;
byte indexScan;
uint32_t millisTraffic;
byte jalurDarurat;
 
void setup() {
 
  for (byte i = 0; i < jumlahTrafficLight; i++)
  {
    pinMode(pinDigit[i], OUTPUT);
  }
  for (byte i = 0; i < 3; i++)
  {
    pinMode(pinRYG[i], OUTPUT);
  }
 
  Serial.begin(9600);
 
  for (byte i = 0 ; i < jumlahTrafficLight; i++)
  {
    lampuTraffic[i] = skemaTraffic[2].lampu;
  }
  hijauSekarang = 0;
  hijauSelanjutnya = 1;
 
}
 
void loop() {
 
  if (millisTraffic < millis())
  {
    lampuTraffic[hijauSekarang] = skemaTraffic[indexTraffic].lampu;
    lampuTraffic[hijauSelanjutnya] = skemaTraffic[indexTraffic].lampuSelanjutnya;
    millisTraffic += skemaTraffic[indexTraffic].waktu;
 
    indexTraffic++;
    if (indexTraffic == 3)
    {
      indexTraffic = 0;
      hijauSekarang = hijauSelanjutnya;
      hijauSelanjutnya = (hijauSekarang + 1) % jumlahTrafficLight;
    }
  }
 
  trafficScan();
}
 
void trafficScan()
{
  digitalWrite(pinDigit[indexScan], HIGH);
  indexScan++;
  indexScan %= jumlahTrafficLight;
  digitalWrite(pinRYG[0], lampuTraffic[indexScan] & lampuMerah);
  digitalWrite(pinRYG[1], lampuTraffic[indexScan] & lampuKuning);
  digitalWrite(pinRYG[2], lampuTraffic[indexScan] & lampuHijau);
  digitalWrite(pinDigit[indexScan], LOW);
 
}

 

 

SPWM fungsional tanpa tabel-sinusiodal dengan arduino

Sinusoidal Pulse width modulation (SPWM) adalah teknik membangkitkan sinyal sinusiodal dengan metode PWM (pulse width modulation). Sinyal PWM umum di gunakan pada perangkat digital,  sehingga memungkinkan perangkat digital untuk menghasilkan sinyal sinusiodal.

Metode SPWM yang umum digunakan diantaranya :

  1. Segitiga yaitu dengan membandingkan sinyal ramp dengan sinyal sinusiodal dan diperoleh deret duty cycle yang bisa di masukkan dalam tabel.
  2. delta, deret pwm dihasilkan melalui penggambaran slope dalam batas (atas dan bawah) sinyal sinusiodal target.
  3. delta sigma
  4. space vector
  5. direct torque
  6. time proportioning

kehandalan S-PWM di ukur berdasarkan spectrum, karena SPWM adalah sinyal digital yang menyerupai sinyal sinus, maka membutuhkann filter low-pass untuk mengurangi spectrum frekusnsi tinggi dari switching digital.

SPWM juga bisa digunakan sebagai regulator AC untuk keperluan pengontrolan tegangan output.

berikut tata letak pin yang digunakan :

H-bridge dalam skema adalah BTS7960, bisa di ganti dengan modul/rangkaian H-bridge lain

 

sketch program arduino spwm:

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
#define pinSPWM_A               9
#define pinSPWM_B               10
 
#define frekuensiOutput         50
#define frekuensiSPWM           1000
 
volatile byte indexSPWM;
volatile float output;
int limitOutput;
 
void setup() {
  pinMode(pinSPWM_A, OUTPUT);
  pinMode(pinSPWM_B, OUTPUT);
 
  Serial.begin(9600);
  Serial.println(F("SPWM fungsional dengan arduino"));
  Serial.println(F("https://www.project.semesin.com"));
  Serial.println();
 
  TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11);
 
  long cycles = (F_CPU / frekuensiSPWM / 2);
  uint8_t clockSelectBits;
 
  if      (cycles        < 0xFF) clockSelectBits = _BV(CS10);
  else if ((cycles >>= 3) < 0xFF) clockSelectBits = _BV(CS11);
  else if ((cycles >>= 3) < 0xFF) clockSelectBits = _BV(CS11) | _BV(CS10);
  else if ((cycles >>= 2) < 0xFF) clockSelectBits = _BV(CS12);
  else if ((cycles >>= 2) < 0xFF) clockSelectBits = _BV(CS12) | _BV(CS10);
  else     cycles = 0xFF - 1,    clockSelectBits = _BV(CS12) | _BV(CS10);
 
  TCCR1B = (1 << WGM13) | clockSelectBits;
  ICR1 = cycles;
  TIMSK1 = _BV(TOIE1);
  OCR1A = 0;
  OCR1B = 0;
 
  limitOutput = cycles;
}
 
void loop() {
 
  output = limitOutput / 2;
 
}
 
ISR(TIMER1_OVF_vect)
{
  int duty = 1.0 * sin(2.0 * PI * indexSPWM / (frekuensiSPWM / frekuensiOutput)) * output;
 
  if (duty >= 0)
  {
    OCR1AL = duty;
    OCR1BL = limitOutput + 1;
  }
  else
  {
    OCR1AL = limitOutput + 1;
    OCR1BL = 0 - duty;
  }
 
  indexSPWM++;
  indexSPWM %= frekuensiSPWM / frekuensiOutput;
}

output logic analyzer

Meningkatkan presisi pembacaan sensor analog dengan metode Trimmed Mean

Sensor-sensor analog dibaca oleh arduino melalui pin analog menggunakan adc. Agar pembacaan adc oleh arduino memiliki presisi yang baik diperlukan perlakuan (treatment) sisi hardware  diantaranya:

  1. Jika impedansi keluaran (output) sensor besar (>10 kΩ) maka perbesar sampling and hold time (s/h) dengan cara mengganti nilai ADCSRA,
  2. Gunakan tegangan referensi yang sesuai dengan tegangan maksimal keluaran sensor menggunakan perintah analogReference(),
  3. Gunakan kabel sependek mungkin antara pin output sensor dan pin adc arduino dan terselubung ground,
  4. Jauhkan kabel dan sensor dari komponen yang bisa menimbulkan interferensi elektromagnetik,
  5. Jika menggunakan tegangan referensi luar, tambakan dengan filter LC,
  6. Pin-pin analog yang tidak digunakan sebaiknya tidak dioperasikan saat proses pembacaan sensor.
  7. Tegangan power supply yang stabil dan terproteksi dari gangguan luar.

Pada sisi software bisa dilakukan peningkatan presisi diataranya menggunakan metode rata-rata seperti Mean, Trimmed Mean, Truncated mean, Winsorizing, Interquartile mean dan sebagainya.

Berikut contoh penggunaan metode Trimmed Mean untuk meningkatkan presisi pembacaan sensor analog :

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
#define faktorTrim        0.2 //20%
#define jumlahSampel      10
 
#define pinSensor         A0
 
int buffer[jumlahSampel], temp, rataRata;
 
void setup() {
  Serial.begin(9600);
  Serial.println(F("Meningkatkan presisi pembacaan sensor analog dengan metode Trimmed Mean"));
  Serial.println(F("https://www.project.semesin.com"));
  Serial.println();
}
 
void loop() {
  for (int i = 0; i < jumlahSampel; i++)
  {
    buffer[i] = analogRead(pinSensor);
    delay(10);
  }
 
  //proses pengurutan (sorting)
  for (int i = 0; i < jumlahSampel - 1; i++)
  {
    for (int j = i + 1; j < jumlahSampel; j++)
    {
      if (buffer[i] > buffer[j])
      {
        temp = buffer[i];
        buffer[i] = buffer[j];
        buffer[j] = temp;
      }
    }
  }
 
  //rata-rata (trimmed mean)
  rataRata = 0;
  for (int i = jumlahSampel * faktorTrim; i < jumlahSampel * (1 - faktorTrim); i++)
  {
    rataRata += buffer[i];
  }
 
  rataRata /= jumlahSampel * (1- (faktorTrim*2));
 
  Serial.print("sensor = ");
  Serial.println(rataRata);
 
  delay(500);
}

JWS Universal (Jadwal Waktu Shalat) 1 – 8 panel

Jadwal Waktu Shalat (JWS) adalah media informasi di rumah ibadah Masjid/Mushalla/Surau yang menampilkan informasi waktu-waktu Shalat.

Dalam perkembangannya Jam Waktu Shalat berfungsi sebagai :

  1. Menampilkan Jadwal / Waktu Shalat wajib dan sunat
  2. Menampilkan informasi tanggal Masehi, Hijriah, Pasaran Jawa, dan penanggalan khusus seperti penanggalan Minang
  3. Menampilkan Ayat Al-Quran, Doa
  4. Informasi Tartil, Tarhim, Azan, Iqamah
  5. Pengingat / alarm waktu masuk Shalat dan selesai Iqamah
  6. Memutar Suara/Musik Tartil, Tarhim disertai kontrol hidup/mati amplifier
  7. Perhitungan jadwal berdasarkan posisi matahari, masukan manual, data jadwal online harian.

Diagram alir Jawdal waktu-waktu Shalat :

 

Skema Jam waktu shalat universal:

 

Tampilan aplikasi (apk) JWS Semesin Universal:

 

contoh tampilan jadwal shalat 3 panel :

 

Koding / sketch JWS semesin:

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
/*
   JWS Semesin 1 - 8 panel
 
   Fitur yang tidak aktif
   1. Tampilan tanggal Hijriah
   2. Tampilan tanggal Jawa
   3. Tampilan tanggal Minang
   4. Pesan selama tartil
   5. Pesan selama tarhim
   6. Pesan selama Iqamah
 
*/
 
#define serialDebug                       false
#define modeDemo                          false
 
#define namaMesjid                        "JWS"
 
//defenisi pin
#define pinMP3Busy                        2
#define pinRelayAmpli                     3
#define pinBuzzer                         4
#define RTCDetikIRQ                       A3
 
#define relayOn                           LOW
 
#define I2CEEPROM_ADDRESS                 0x57
 
//setting
#define periodaAlarmWaktuShalatMasuk      100//milidetik
#define periodaAlarmWaktuAkhirIqamah      300//milidetik
 
#define pixelLebarPanel                   32
#define pixelTinggiPanel                  16
 
//variabel Setting
#define kecepatanMinimal                  10
#define skalaKecepatan                    10
 
#define tokenSetting                      32
#define lamaAksesApk                      10L * 60 * 1000
 
#define jumlahNyalaPadam                  5
#define jumlahTextInformasi               10
 
#define fontNamaMesjid                    Arial14
#define fontJamDanMenitUtama              angka6x14
#define fontSimbolGambar                  simbolGambar
 
#include <Wire.h>
#include <EEPROM.h>
#include <DMD_Semesin.h>
#include <RTC_Semesin.h>
#include <DFPlayer_Mini_Mp3.h>
#include <BluetoothApk.h>
 
#include <fonts/angka6x14.h>
#include <fonts/SystemFont5x7Ramping.h>
#include <fonts/Arial14.h>
#include <fonts/simbolGambar.h>
 
#include "fungsi.h"
#include "definisi.h"
#include "konstanta.h"
#include "setting.h"
#include "WaktuShalat.h"
 
const uint8_t *alamatFont[] = {
  Arial14,
  SystemFont5x7Ramping,
};
 
SPIDMD dmd(8, 1);//max jumlah panel = 8
RTC_DS3231 rtc;
DateTime now;
 
//Status
bool RTCValid = true;
byte modeOperasi = modeInformasi;
bool statusAlarm;
bool tampilJamMenitDetik = false;
long millisRunningText;
uint8_t kecepatanRunningText;
uint8_t kecepatanRunningEfek;
 
uint16_t hitungMundurTartil;
uint16_t hitungMundurTarhim;
uint16_t hitungMundurAzan;//terhitung sejak waktu masuk
uint16_t hitungMundurIqamah;//terhitung sejak selesai azan
 
bool pesanSetelahAzan;
bool pesanSebelumShalat;
uint16_t hitungMundurPeringatanSimbol;
uint16_t hitungMundurShalat;
 
bool initHitungMundurTartil;
bool initHitungMundurTarhim;
bool initHitungMundurAzan;
bool initHitungMundurIqamah;
bool initHitungMundurPeringatanSimbol;
bool initHitungMundurShalat;
 
uint8_t hitungMundurAlarmIqamah;//kali
 
int8_t indexWaktuIbadah;
int8_t indekInformasi;
 
//efek
uint16_t lamaTampilText;
bool initTampil;
 
bool tampilanInformasiSambung;
 
byte indekTampilan = jumlahInformasi;
EfekMarque efekMarque;
 
uint16_t lebarText;
uint8_t tinggiText;
 
byte detikSebelumnya = 60;
byte menitSebelumnya = 60;
byte tanggalSebelumnya = 0;
 
long millisAlarm;
 
bool status;
 
BluetoothApk bluetoothApk(&Serial, "JWS2 SEMESIN.COM");
long millisAksesApk;
bool aksesApk;
 
uint16_t counterAlamat = 0;
uint16_t counterAlamatSebelumnya = 0;
uint16_t parameterSebelumnya = 0;
 
byte lebarJamUtama = 32;
 
byte lebarJadwalShalat = 32;
byte modeTampilanJadwal;
char buffer[72];
uint16_t offsetJadwalEEPROM;
bool runningTextAktif;
 
JamDanMenitJadwal jadwalBerikutnya;
JamDanMenitAlarm alarmBerikutnya;
int8_t hitungMundurAlarm;
bool initHitungMundurAlarm;
bool statusRelayAmpli;
 
void setup() {
 
  pinMode(pinBuzzer, OUTPUT);
  digitalWrite(pinRelayAmpli, !relayOn);
  pinMode(pinRelayAmpli, OUTPUT);
  pinMode(pinMP3Busy, INPUT_PULLUP);
 
  Serial.begin(9600);
  Serial.println(F("JWS Semesin 1-8 panel"));
  Serial.println(F("https://www.project.semesin.com"));
 
  mp3_set_serial (Serial);
  mp3_set_volume (15);
 
 
#if serialDebug
  Serial.println(F("Inisialisasi"));
#endif
 
  rtc.begin();
 
  if (rtc.lostPower())
  {
#if serialDebug
    Serial.println(F("RTC tidak jalan"));
#endif
    write_i2c_register(DS3231_ADDRESS, DS3231_STATUSREG, 0x00);
  }
  write_i2c_register(DS3231_ADDRESS, DS3231_CONTROL, DS3231_SquareWave1Hz);
 
  if (EEPROM.read(offsetof(Setting, token)) != tokenSetting)
  {
    pengaturanAwal();
  }
 
  updateUkuranTampilan();
  dmd.waitInterruptOver = false;
  dmd.begin();
  dmd.clearScreen();
  dmd.setBrightness(25.5 * EEPROM.read(offsetof(Setting, kecerahanStandar)));
 
  kecepatanRunningEfek = skala2kecepatanRunning(EEPROM.read(offsetof(Setting, kecepatanEfek)));
 
#if serialDebug
  Serial.println(F("Sistem mulai"));
#endif
 
  dmd.selectFont(fontNamaMesjid);
  dmd.drawString(1, 1, namaMesjid);
 
  delay(3000);
  dmd.clearScreen();
 
  statusRelayAmpli = digitalRead(pinMP3Busy);
}
 
 
void loop() {
 
....... file lengkap bisa didownload melalui link dibawah

file JWS universal:

JWS Semesin v2.1

catatan:
* untuk RTC DS3231, pin-SQW harus terpasang pada pin-A3 (arduino)
* jika menggunakan pcb jws (versi manapun) ada kemungkinan tidak cocok dan perlu modifikasi

Mengirim data melalui jaringan Wifi menggunakan ESP01 dengan metode POST (kasus IOT ThingSpeak)

ESP8266 adalah modul Wi-Fi dengan fitur TCP/IP yang lengkap dan bisa dihubungkan dengan mikrokontroler melalui protokon AT-Command. TCP/IP (Transmission Control Protocol / Internet Protocol)  adalah protokol komunikasi antara dua perangkat yang terhubung dengan sebuah metode paket termasuk metode pengalamatan dan metode transmisi dalam jaringan internet.

Dalam komunikasi TCP/IP dikenal beberapa metode request/permintaan yaitu : HEAD, GET, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT, PATCH.

Metode POST  sering digunakan untuk mengirimkan data-data ter-enkripsi dan langsung ke server sehingga lebih menjamin kerahasiaan data. berbeda dengan metode GET yang mengirimkan requeat dalam bentuk URL.

Skematik ESP8266/ESP01 (+Arduino Uno) request metode post:

Sketch/koding pemrograman komunikasi ESP01 + arduino dengan server menggunakan metode POST :

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
char ssid[]             = "xxxx";            // your network SSID (name)
char pass[]             = "xxxxxxxx";        // your network password
 
char server[]           = "api.thingspeak.com";
byte port               = 80;
char APIKey[]           = "XXXXXXXXXXXXXX";
uint32_t periodeKirim   = 20000;
 
#include <WiFiEsp.h>
#include <SoftwareSerial.h>
 
SoftwareSerial SerialEsp(10, 11);
WiFiEspClient client;
int status = WL_IDLE_STATUS;     // the Wifi radio's status
uint32_t millisKirim;
bool statusKirim;
 
void setup()
{
  Serial.begin(9600);
  Serial.println("Mengirim data melalui jaringan Wifi menggunakan ESP01 dengan metode POST");
  Serial.println("https://www.project.semesin.com/");
  Serial.println();
 
  SerialEsp.begin(115200);
  SerialEsp.println("AT+UART_DEF=9600,8,1,0,0");
  delay(500);
  SerialEsp.begin(9600);
 
  WiFi.init(&SerialEsp);
 
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
  }
  millisKirim = millis();
}
 
void loop()
{
  if (millisKirim < millis())
  {
    millisKirim = millis() + periodeKirim;
     
    // hubungkan ke jaringan wifi jika belum tersambung atau terputus (auto reconnect)
    if (WiFi.status() != WL_CONNECTED)
    {
      Serial.print("Menghubungkan ke jaringan SSID: ");
      Serial.println(ssid);
      while (WiFi.status() != WL_CONNECTED)
      {
        WiFi.begin(ssid, pass);
        Serial.print(".");
        delay(5000);
      }
      printWifiStatus();
      Serial.println("Berhasil terhubung ke jaringan");
    }
 
 
    if (WiFi.status() == WL_CONNECTED)
    {
      Serial.println();
      Serial.println("Menghubungkan dengan server...");
      if (client.connect(server, port))
      {
        Serial.println();
        Serial.println("Terhubung dengan server.");
 
        char content[30];
        sprintf(content, "field1=%d", millis() % 100);
 
        client.println("POST /update HTTP/1.1");
        client.println("Host: api.thingspeak.com");
        client.println("User-Agent: tslib-arduino/1.5.0");
        client.print("X-THINGSPEAKAPIKEY: ");
        client.println(APIKey);
        client.println("Content-Type: application/x-www-form-urlencoded");
        client.print("Content-Length: ");
        client.println(strlen(content));
        client.println("Connection: close");
        client.println();
 
        client.print(content);
 
        statusKirim = true;
      }
    }
  }
 
  if (statusKirim)
  {
    while (client.available())
    {
      char c = client.read();
      Serial.write(c);
    }
 
    if (!client.connected())
    {
      Serial.println();
      Serial.println("Memutuskan hubungan dengan server...");
      delay(10);
      client.stop();
 
      statusKirim = false;
    }
  }
}
 
 
void printWifiStatus()
{
  // print the SSID of the network you're attached to
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());
 
  // print your WiFi shield's IP address
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);
 
  // print the received signal strength
  long rssi = WiFi.RSSI();
  Serial.print("Signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

Library :

 

Hex Serial Monitor dengan Visual C#

Serial monitor seperti pada putty, hyper terminal, arduino IDE sangat bermanfaat untuk memonitor atau mengontrol perangkat yang sedang dikembangkan/development. Serial monitor juga bisa digunakan untuk proses debug untuk mencari kesalahan algoritma, misalnya dengan memberikan informasi nilai variabel ataupun informasi step by step percabangan.

Penggunaan serial monitor untuk keperluan debug haruslah memberikan informasi detail. Proses debug perangkat digital sangat berhubungan dengan format hexadesimal (hex) dan komunikasi binary.

Fitur Hex Serial Monitor:

  1. Data Serial yang diterima di tampilkan dalam format tabel hexa, juga disertai string.
  2. Baris baru dengan pilihan 0x00 dan 0x0A
  3. Kirim data serial dalam format :
    • String
    • 2 karakter, contohnya 12AB34BC = 0x12, 0xAB, 0x34, 0xBC
    • separator spasi, contoh : 12 AB 34 BC
    • separator koma, contoh : 12, AB,34, BC
    • awalan 0x
    • awalan $, contoh : $12$AB $34  $BC

Fungsi utama software ini adalah untuk berkomunikasi melalui serial port dalam mode binary dan ditampilkan dalam format hexa desimal.

tampilan Hexadecimal serial monitor menggunakan c#:

 

Kode software visual c# hex serial monitor:

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
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
 
namespace Hex_serial_monitor
{
    public partial class Form1 : Form
    {
        public int baris = 0;
        public int kolom = 0;
        String strKolom;
 
 
        public Form1()
        {
            InitializeComponent();
        }
 
        public delegate void AddDataDelegate();
        public AddDataDelegate delegateSerial;
 
        private void Form1_Load(object sender, EventArgs e)
        {
            string[] ports = SerialPort.GetPortNames();
 
            comboBoxCOMPort.Items.Clear();
            foreach (string port in ports)
            {
                comboBoxCOMPort.Items.Add(port);
            }
            if (comboBoxCOMPort.Items.Count > 0)
            {
                comboBoxCOMPort.SelectedIndex = 0;
            }
 
            this.delegateSerial = new AddDataDelegate(updateSerial);
 
            dataGridView1.Rows.Clear();
            dataGridView1.Rows.Add();
            dataGridView1.Rows[baris].Cells[0].Value = baris.ToString("X2");
            strKolom = "";
 
            radioButtonAscii.Checked = true;
            //checkBox0.Checked = true;
 
        }
        private void updateSerial()
        {
            while (serialPort1.BytesToRead > 0)
            {
                int data = serialPort1.ReadByte();
                dataGridView1.Rows[baris].Cells[kolom + 1].Value = data.ToString("X2");
 
                if ((data >= ' ') && (data < 128))
                {
 
                    strKolom += (char)data;
                }
                else
                {
                    strKolom += ' ';
                }
 
 
                dataGridView1.Rows[baris].Cells[17].Value = strKolom;
 
                kolom++;
                if (((data == 0) && (checkBox0.Checked)) ||
                    ((data == 0x0A) && (checkBox0A.Checked)) ||
                    (kolom == 16))
                {
                    kolom = 0;
                    baris++;
                    dataGridView1.Rows.Add();
                    dataGridView1.Rows[baris].Cells[0].Value = baris.ToString("X2");
                    strKolom = "";
                }
                if (checkBoxAutoScroll.Checked)
                {
                    dataGridView1.FirstDisplayedScrollingRowIndex = dataGridView1.RowCount - 1;
                }
            }
            textBoxKirim.Focus();
        }
 
        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            dataGridView1.Invoke(this.delegateSerial, new Object[] { });
        }
 
        private void buttonClear_Click(object sender, EventArgs e)
        {
            dataGridView1.Rows.Clear();
            kolom = 0;
            baris = 0;
            dataGridView1.Rows.Add();
            dataGridView1.Rows[baris].Cells[0].Value = baris.ToString("X2");
            strKolom = "";
        }
 
        private void buttonConnect_Click(object sender, EventArgs e)
        {
            if (buttonConnect.Text == "Connect")
            {
                serialPort1.PortName = comboBoxCOMPort.Text;
                serialPort1.Open();
                if (serialPort1.IsOpen)
                {
                    buttonConnect.Text = "Disconnect";
                }
            }
            else
            {
                if (serialPort1.IsOpen)
                {
                    serialPort1.Close();
                    buttonConnect.Text = "Connect";
                }
 
            }
 
        }
 
        private void buttonKirim_Click(object sender, EventArgs e)
        {
            if (serialPort1.IsOpen)
            {
                if (radioButtonAscii.Checked)
                {
                    serialPort1.WriteLine(textBoxKirim.Text + "\r\n");
                }
                else if (radioButton2Character.Checked)
                {
                    if (textBoxKirim.Text.Length % 2 == 0)
                    {
                        int jumlahHex = textBoxKirim.Text.Length / 2;
                        byte[] hex = new byte[jumlahHex];
 
                        for (int i = 0; i < jumlahHex; i++)
                        {
                            String str2Hex = textBoxKirim.Text.Substring(i * 2, 2);
                            hex[i] = (byte)int.Parse(str2Hex, System.Globalization.NumberStyles.HexNumber);
 
                        }
                        serialPort1.Write(hex, 0, jumlahHex);
                    }
                }
                else if (radioButtonSpace.Checked)
                {
                    String[] strHexSplit = textBoxKirim.Text.Split(' ');
                    byte[] hex = new byte[strHexSplit.Length];
 
                    for (int i = 0; i < strHexSplit.Length; i++)
                    {
                        String strHex = strHexSplit[i].Substring(0, 2);
                        hex[i] = (byte)int.Parse(strHex, System.Globalization.NumberStyles.HexNumber);
                    }
                    serialPort1.Write(hex, 0, strHexSplit.Length);
                }
                else if (radioButtonComma.Checked)
                {
                    String[] strHexSplit = textBoxKirim.Text.Split(',');
                    byte[] hex = new byte[strHexSplit.Length];
 
                    for (int i = 0; i < strHexSplit.Length; i++)
                    {
                        String strHex = strHexSplit[i].Substring(0, 2);
                        hex[i] = (byte)int.Parse(strHex, System.Globalization.NumberStyles.HexNumber);
                    }
                    serialPort1.Write(hex, 0, strHexSplit.Length);
                }
                else if (radioButton0x.Checked)
                {
                    String[] strHexSplit = textBoxKirim.Text.Split('x');
                    byte[] hex = new byte[strHexSplit.Length];
 
                    for (int i = 0; i < strHexSplit.Length; i++)
                    {
                        String strHex = strHexSplit[i].Substring(0, 2);
                        hex[i] = (byte)int.Parse(strHex, System.Globalization.NumberStyles.HexNumber);
                    }
                    serialPort1.Write(hex, 0, strHexSplit.Length);
                }
                else if (radioButtonDollar.Checked)
                {
                    String[] strHexSplit = textBoxKirim.Text.Split('$');
                    byte[] hex = new byte[strHexSplit.Length];
 
                    for (int i = 0; i < strHexSplit.Length; i++)
                    {
                        String strHex = strHexSplit[i].Substring(0, 2);
                        hex[i] = (byte)int.Parse(strHex, System.Globalization.NumberStyles.HexNumber);
                    }
                    serialPort1.Write(hex, 0, strHexSplit.Length);
                }
                 
            }
        }
    }
}

 

File Hexa Serial monitor berbasis c#

 

Media pembelajaran polygon berbasis Delphi

Poligon adalah geometri dengan banyak sudut seperti segitiga, segi empat dan nonagon dan lainnya. poligon terdiri atas beberapa titik atau vertex yang terhubung menjadi sebuah bentuk geometri. Poligon memiliki penamaan khusus sesuai jumlah sudutnya.

Poligon merupakan geometri yang dapat dikembangkan secara luas sehingga digunakan di berbagai bidang.

Untuk memudahkan mengenal atau memperkenalkan polygon, salah satu media yang bisa digunakan adalah pc/laptop. Fitur dasar seperti create dan modify adalah sebagai langkah awal  untuk membangun sebuah media pembelajaran geometri. Selanjutnya  bisa dikembangkan menjadi lebih fungsional sesuai kebutuhan pengembangannya.

Screenshoot media pembelajaran polygin menggunakan delphi :

Kode delphi pengembangan media belajar geometri polygon :

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
unit Unit1;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, Buttons, Grids;
 
type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Panel2: TPanel;
    Image1: TImage;
    GroupBox1: TGroupBox;
    GroupBox3: TGroupBox;
    GroupBox2: TGroupBox;
    LabelPosisi: TLabel;
    ButtonClose: TButton;
    LabelVertex: TLabel;
    GroupBox4: TGroupBox;
    StringGrid1: TStringGrid;
    ButtonDelete: TButton;
    ButtonDraw: TButton;
    ButtonEdit: TButton;
    ButtonInsert: TButton;
    ButtonClear: TButton;
    ButtonSave: TButton;
    ButtonOpen: TButton;
    Label1: TLabel;
    procedure ButtonDrawClick(Sender: TObject);
    procedure ButtonEditClick(Sender: TObject);
    procedure Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure Image1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure ButtonCloseClick(Sender: TObject);
    procedure ButtonSaveClick(Sender: TObject);
    procedure ButtonLoadClick(Sender: TObject);
    procedure refreshCanvas();
    procedure StringGrid1SelectCell(Sender: TObject; ACol, ARow: Integer;
      var CanSelect: Boolean);
    procedure ButtonDeleteClick(Sender: TObject);
    procedure FormResize(Sender: TObject);
    procedure ButtonInsertClick(Sender: TObject);
    procedure ButtonClearClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
type Point = record
 X : integer;
 Y : integer;
end;
 
var
  Form1: TForm1;
  modeOperasi : integer;
  posisi : Point;
  tinggiCanvas : integer;
  startPolygon : boolean;
  polygon : array[0..20] of Point;
  polygonCount : integer;
  editIndex : integer;
 
const
  modeIdle = 0;
  modeDraw = 1;
  modeEdit = 3;
  modeInsert = 4;
 
implementation
 
{$R *.dfm}
 
procedure TForm1.refreshCanvas();
var
  i : integer;
begin
  StringGrid1.RowCount := polygonCount + 1;
 
  i := 0;
  while true do
  begin
    if polygon[i].X = -1 then
      break;
    StringGrid1.Cells[0,i+1] := inttostr(i+1);
    StringGrid1.Cells[1,i+1] := inttostr(polygon[i].X);
    StringGrid1.Cells[2,i+1] := inttostr(polygon[i].Y);
 
    if i = 0 then
    begin
      image1.Canvas.rectangle(0,0,image1.width-1, image1.height-1);
      image1.Canvas.MoveTo(polygon[0].X, tinggiCanvas - polygon[0].Y);
    end
    else
    begin
      if (modeOperasi = modeInsert) and (editIndex = i) then
      begin
        Image1.Canvas.Pen.Color := clRed;
      end
      else
      begin
        Image1.Canvas.Pen.Color := clBlack;
      end;
      image1.Canvas.LineTo(polygon[i].X, tinggiCanvas - polygon[i].Y);
    end;
 
    i := i + 1;
    if i = 20 then
      break;
 
  end;
 
   if modeOperasi = modeEdit then
   begin
    image1.Canvas.Rectangle(polygon[editIndex].X-5, tinggiCanvas - polygon[editIndex].Y - 5,
      polygon[editIndex].X+5, tinggiCanvas - polygon[editIndex].Y + 5);
   end;
 
end;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  StringGrid1.Cells[0,0] := 'No';
  StringGrid1.Cells[1,0] := 'X';
  StringGrid1.Cells[2,0] := 'Y';
end;
 
 
procedure TForm1.FormResize(Sender: TObject);
begin
  tinggiCanvas := Image1.Height;
 
end;
 
procedure TForm1.ButtonDrawClick(Sender: TObject);
begin
  buttonDraw.Font.Style := [fsBold];
  ButtonEdit.Font.Style := [];
  ButtonInsert.Font.Style := [];
 
  modeOperasi := modeDraw;
  startPolygon := true;
  polygonCount := 0;
  polygon[polygonCount].X := -1;
 
  refreshCanvas();
end;
 
procedure TForm1.ButtonCloseClick(Sender: TObject);
begin
 
  if (modeOperasi = modeDraw) and (polygonCount > 1) then
  begin
    polygon[polygonCount] := polygon[0];
    polygonCount := polygonCount + 1;
 
    polygon[polygonCount].X := -1;
 
    LabelVertex.Caption := 'Vertex ' + inttostr(polygonCount);
 
    refreshCanvas();
 
    buttonDraw.Font.Style := [];
    ButtonEdit.Font.Style := [];
    ButtonInsert.Font.Style := [];
    modeOperasi := modeIdle;
  end;
 
end;
 
procedure TForm1.ButtonEditClick(Sender: TObject);
begin
  buttonDraw.Font.Style := [];
  ButtonEdit.Font.Style := [fsBold];
  ButtonInsert.Font.Style := [];
  modeOperasi := modeEdit;
  editIndex := 1;
  refreshCanvas();
end;
 
procedure TForm1.ButtonInsertClick(Sender: TObject);
begin
  buttonDraw.Font.Style := [];
  ButtonEdit.Font.Style := [];
  ButtonInsert.Font.Style := [fsBold];
  modeOperasi := modeInsert;
  editIndex := 1;
  refreshCanvas();
end;
 
 
procedure TForm1.ButtonClearClick(Sender: TObject);
begin
  polygonCount := 0;
  polygon[polygonCount].X := -1;
 
  refreshCanvas();
end;
 
procedure TForm1.ButtonDeleteClick(Sender: TObject);
var
  i : integer;
begin
  if editIndex <> 0 then
  begin
    for i := editIndex to polygonCount do
    begin
      polygon[i].X := polygon[i+1].X;
      polygon[i].Y := polygon[i+1].Y;
    end;
    polygonCount := polygonCount - 1;
    refreshCanvas();
  end;
end;
 
 
procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
begin
  posisi.X := X;
  posisi.Y := tinggiCanvas - Y;
  LabelPosisi.Caption := 'Posisi ' + inttostr(posisi.X) + ', ' + inttostr(posisi.Y);
end;
 
procedure TForm1.Image1Click(Sender: TObject);
var
  i : integer;
begin
  if (modeOperasi = modeDraw) and (polygonCount < 20) then
  begin
    polygon[polygonCount].X := posisi.X;
    polygon[polygonCount].Y := posisi.Y;
    polygonCount := polygonCount + 1;
    polygon[polygonCount].X := -1;
    LabelVertex.Caption := 'Vertex ' + inttostr(polygonCount);
 
    refreshCanvas();
  end
  else if (modeOperasi = modeEdit) and (editIndex > 0)then
  begin
    if (editIndex = 1) or (editIndex = polygonCount-1) then
    begin
      polygon[1].X := posisi.X;
      polygon[1].Y := posisi.Y;
      polygon[polygonCount-1].X := posisi.X;
      polygon[polygonCount-1].Y := posisi.Y;
    end
    else if (editIndex > 0) then
    begin
      polygon[editIndex].X := posisi.X;
      polygon[editIndex].Y := posisi.Y;
 
    end;
 
    refreshCanvas();
  end
  else if (modeOperasi = modeInsert) and (editIndex > 0) and (polygonCount < 20) then
  begin
    for i := polygonCount downto editIndex do
    begin
      polygon[i+1].X := polygon[i].X;
      polygon[i+1].Y := polygon[i].Y;
    end;
    polygon[editIndex].X := posisi.X;
    polygon[editIndex].Y := posisi.Y;
    polygonCount := polygonCount + 1;
    refreshCanvas();
 end;
 
end;
 
 
procedure TForm1.ButtonSaveClick(Sender: TObject);
var
  Stream: TStream;
begin
  Stream:= TFileStream.Create('polygon.bin', fmCreate);
  Stream.WriteBuffer(polygonCount, SizeOf(integer));
  Stream.WriteBuffer(polygon, (polygonCount+1) * SizeOf(Point));
  Stream.Free;
end;
 
procedure TForm1.ButtonLoadClick(Sender: TObject);
var
  Stream: TStream;
begin
  Stream:= TFileStream.Create('polygon.bin', fmOpenRead);
  Stream.ReadBuffer(polygonCount, SizeOf(integer));
  Stream.ReadBuffer(polygon, (polygonCount+1) * SizeOf(Point));
  Stream.Free;
 
  refreshCanvas();
  LabelVertex.Caption := 'Vertex ' + inttostr(polygonCount);
 
end;
 
procedure TForm1.StringGrid1SelectCell(Sender: TObject; ACol,
  ARow: Integer; var CanSelect: Boolean);
begin
  editIndex := ARow - 1;
  refreshCanvas();
end;
 
end.

code lengkap media pengajaran geometri poligon:
library :

Penjadwalan pembacaan sensor berbasis RTC DS3231

Pembacaan sensor dengan arduino dapat dilakukan kapan saja dan dimana saja dalam sketch arduino sesuai kebutuhan. Penjadwalan diperlukan untuk mendapatkan nilai dari sensor dalam rentang tertentu atau pada waktu-waktu khusus misalnya baca sensor saat gerhana matahari. Jika menginginkan sensor dibaca hanya pada waktu-waktu tertentu saja berdasarkan RTC dapat menggunakan metode berikut:

  1. Metode pergantian waktu, yaitu aksi pembacaan sensor dilakukan ketika satuan waktu berubah, contohnya setiap detik, setiap menit dan seterusnya. contoh :
    1
    2
    3
    4
    5
    if (detikSebelumnya != now.second() )
    {
      detikSebelumnya = now.second();
      bacaSensor();
    }
  2. Metode modulus waktu, yaitu pembacaan sensor dilakukan pada setiap kelipatan satuan waktu, seperti pembacaan sensor setiap 2 detik, setiap 30 detik dan seterusnya. Contohnya :
    1
    2
    3
    4
    if (!(now.second() % periodaBacaSensor) )
    {
      bacaSensor();
    }
  3. Metode rentang waktu, yaitu pembacaan sensor dilakukan selama waktu pada rentang waktu tertentu. Contohnya :
    1
    2
    3
    4
    if ((now.hour() >= 20) || (now.hour() < 3))
    {
      bacaSensor();
    }
  4. Metode Tabel, yaitu pembacaan sensor sesuai waktu yang ditetapkan berdasarkan tanggal dan waktu tertentu, (pembacaan hanya dilakukan 1 kali). Contohnya:
    1
    2
    3
    4
    if (now.getEpoch() == databaseJadwal[i].getEpoch())
    {
      bacaSensor();
    }

Rangkaian yang digunakan pada pembacaan sensor sesuai jadwal tertentu berbasis rtc:

berikut kode/sketch penjadwalan pembacaan sensor menggunakan rtc pada 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
#define pinSensor     A0
 
#include <Wire.h>
#include "Sodaq_DS3231.h"
 
DateTime set = {2020, 2, 22, 7, 0, 0, 1};
DateTime now;
DateTime databaseJadwal[] = {
  {2020, 2, 22, 7, 0, 3, 1},
  {2020, 2, 23, 7, 0, 0, 1},
  {2020, 2, 24, 7, 0, 0, 1},
  {2020, 2, 25, 7, 0, 0, 1},
  {2020, 2, 26, 7, 0, 0, 1},
  {2020, 2, 27, 7, 0, 0, 1},
};
byte detikSebelumnya;
byte menitSebelumnya;
 
#define periodaBacaSensor   5//detik
 
void bacaSensor()
{
  analogRead(pinSensor);
}
 
void setup() {
  Serial.begin(9600);
  Serial.println("Penjadwalan pembacaan sensor berbasis RTC");
  Serial.println("https://www.project.semesin.com");
  Serial.println();
 
  Wire.begin();
  rtc.begin();
  now = rtc.now();
  //  if (now.year() == 2000)
  {
    rtc.setDateTime(set);
  }
}
 
void loop() {
  now = rtc.now();
 
  if (detikSebelumnya != now.second() )
  {
 
    char bufWaktu[32];
    sprintf(bufWaktu, "%02d:%02d:%02d %02d-%02d-%04d", now.hour(), now.minute(), now.second(), now.date(), now.month(), now.year());
    Serial.println(bufWaktu);
 
    //pembacaan setiap detik
    detikSebelumnya = now.second();
    Serial.println("setiap detik");
    bacaSensor();
 
 
    //pembacaan setiap 2 detik
    if (now.second() % 2)
    {
      Serial.println("setiap 2 detik");
      bacaSensor();
    }
 
    //pembacaan setiap detik ke-5
    if (now.second() == 5)
    {
      Serial.println("setiap detik ke-5");
      bacaSensor();
    }
 
    //pembacaan setiap n detik (n 1..60)
    if (!(now.second() % periodaBacaSensor) )
    {
      Serial.println("setiap n detik");
      bacaSensor();
    }
 
    //pembacaan setiap 937 detik (berlaku untuk x detik 1..~)
    if (!(now.getEpoch() % 937) )
    {
      Serial.println("setiap 937 detik");
      bacaSensor();
    }
 
    //pembacaan setiap menit
    if (menitSebelumnya != now.minute() )
    {
      Serial.println("setiap menit");
      menitSebelumnya = now.minute();
      bacaSensor();
    }
 
    //pembacaan setiap 3 jam = 00:00, 03:00, 06:00, 09:00, 12:00, 15:00, 18:00, 21:00
    if (!(now.hour() % 3) && !now.minute() && !now.second())
    {
      Serial.println("setiap 3 jam");
      bacaSensor();
    }
 
    //pembacaan dalam rentang waktu
    if ((now.hour() >= 7) && (now.hour() < 10))//jam 07:00 - jam 09:59
    {
      Serial.println("pembacaan dalam rentang waktu 1");
      bacaSensor();
    }
    else if ((now.hour() >= 11) && (now.hour() < 15))//jam 11:00 - jam 14:59
    {
      Serial.println("pembacaan dalam rentang waktu 2");
      bacaSensor();
    }
    else if ((now.hour() >= 20) || (now.hour() < 3))//jam 20:00 - jam 02:59
    {
      Serial.println("pembacaan dalam rentang waktu 3");
      bacaSensor();
    }
 
    //pembacaan berdasarkan tabel waktu
    for (byte i = 0; i < sizeof(databaseJadwal) / sizeof(DateTime); i++)
    {
      if (now.getEpoch() == databaseJadwal[i].getEpoch())
      {
        Serial.print("tabel waktu = ");
        Serial.println(i);
        bacaSensor();
      }
    }
  }
 
}

library :

DMD Jam, Timer, Countdown dengan arduino

Jam, timer/stopwatch, countdown seringkali di kombinasikan dalam sebuah perangkat, karena fitur2 ini memiliki kemiripan fungsi.

Fitur tampilan dapat dipilih melalui satu tombol, setiap tombol ditekan maka mode waktu akan berubah yaitu Watch – Timer – Countdown, fungsi masing-masing adalah :

Watch (Jam)

Ditandai dengan Karakter ‘W’ (watch) pada sudut kiri atas, berfungsi menampilan waktu rtc saat ini dalam format “hh:mm:dd” atau jam:menit:detik.

Timer (Hitung maju)

Ditandai dengan karakter ‘T’ (Timer) pada sudut kiri atas. Dalam mode ini pewaktu memulai hitungan dari 00:00:00 dan akan terus bertambah setiap detik. Apabila hitungan maju ini telah mencapai 86.400 detik atau 23:59:59 atau 1 hari penuh, maka hitungan akan dimulai lagi dari 0.

Countdown (Hitung mundur)

Ditandai dengan karakter ‘C’ (Count down) pada sudut kiri atas.berfungsi menampilkan waktu tersisa dari batas aawal yang bisa diatur dengan memodifikasi variabel ‘waktuHitungMundur’ seperti contoh :

1
#define waktuHitungMundur 5 * 60// 5 menit

Waktu hitung mungdur dapat diisi angka 1 – 86400 dalam satuan detik.

Apabila hitungan habis atau mencapai 0 (00:00:00) maka tampilan akan berubah ke mode watch dan menampilkan waktu rtc saat ini.

Komponen yang digunakan dalam perancangan jam, counter, countdown:

  1. Arduino uno
  2. 2x Panel P10 hub12
  3. RTC DS3231

berikut skema rakitan tampilan waktu, hitung maju dan hitung mundur:

Koding/sketch arduino tampilan jam, penghitung mundur dan pewaktu maju:

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
#define waktuHitungMundur     5 * 60// 5 menit
 
#define pinTombol             A0
 
 
#include "Sodaq_DS3231.h"
#include <DMD2.h>
#include <fonts/angka6x14.h>
#include <fonts/System_Min5x7.h>
 
enum Mode
{
  modeJam,
  modeHitungMaju,
  modeHitungMundur,
  jumlahMode,
};
 
DateTime now;
uint32_t hitungMundur;
uint32_t hitungMaju;
byte mode;
char buffer[10];
byte jam, menit, detik;
byte detikSebelumnya;
 
SPIDMD dmd(2, 1);
 
void setup() {
 
  pinMode(pinTombol, INPUT_PULLUP);
 
  Serial.begin(9600);
  Serial.println("Jam, Hitung maju, Hitung mundur (Watch, Timer, Count down)");
  Serial.println("https://www.project.semesin.com");
 
  rtc.begin();
 
  //Set rtc untuk keperluan testing
  DateTime dt(2020, 2, 20, 15, 30, 0, 1);
  rtc.setDateTime(dt);
 
  dmd.begin();
 
  setMode();
}
 
void loop() {
  now = rtc.now();
  if (detikSebelumnya != now.second())
  {
    detikSebelumnya = now.second();
 
    switch (mode)
    {
      case modeJam:
        sprintf(buffer, "%02d%s%02d%s%02d", now.hour(), now.second() % 2 ? ":" : " ", now.minute(), now.second() % 2 ? ":" : " ", now.second());
        dmd.drawString(8, 1, buffer);
        break;
 
      case modeHitungMaju:
        jam = hitungMaju / (3600L);
        menit = (hitungMaju % (3600L)) / 60;
        detik = hitungMaju % 60;
        sprintf(buffer, "%02d%s%02d%s%02d", jam, now.second() % 2 ? ":" : " ", menit, now.second() % 2 ? ":" : " ", detik);
        dmd.drawString(8, 1, buffer);
        hitungMaju++;
        if(hitungMaju == 86400L)
        {
          hitungMaju = 0;
        }
         
        break;
 
      case modeHitungMundur:
        jam = hitungMundur / (3600L);
        menit = (hitungMundur % (3600L)) / 60;
        detik = hitungMundur % 60;
        sprintf(buffer, "%02d%s%02d%s%02d", jam, now.second() % 2 ? ":" : " ", menit, now.second() % 2 ? ":" : " ", detik);
        dmd.drawString(8, 1, buffer);
 
        hitungMundur--;
        if (!hitungMundur)
        {
          mode = modeJam;
          setMode();
        }
        break;
    }
  }
  if (!digitalRead(pinTombol))
  {
    delay(100);
    if (!digitalRead(pinTombol))
    {
      mode++;
      mode %= jumlahMode;
      setMode();
 
      while (!digitalRead(pinTombol));
    }
  }
}
 
void setMode()
{
  dmd.selectFont(System_Min5x7);
  switch (mode)
  {
    case modeJam:
      dmd.drawString(0, 0, "W");
      break;
 
    case modeHitungMaju:
      dmd.drawString(0, 0, "T");
      hitungMaju = 0;
      break;
 
    case modeHitungMundur:
      dmd.drawString(0, 0, "C");
      hitungMundur = waktuHitungMundur;
      break;
  }
  dmd.selectFont(angka6x14);
  dmd.fontHeader.fixedWidth = 2;
}

library :

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:

simulasi Gerak lurus berubah beraturan (GLBB) – Gerak jatuh bebas menggunakan arduino

Gerak lurus berubah beraturan (GLBB) adalah gerak lurus yang percepatannya tetap, artinya kecepatannya berubah beraturan. terdapat beberapa jenis GLBB yaitu :

  1. Gerak vertikal ke atas
  2. Gerak jatuh bebas
  3. Gerak vertikal ke bawah

untuk keperluan simulasi gerak lurus berubah beraturan diperlukan peralatan sebagai berikut :

  1. Arduino uno
  2. 3x sensor obstacle
  3. sensor ultrasonic
  4. Tombol

Dengan tata letak seperti berikut:

Skema simulasi GLBB menggunakan arduino:

sketch/koding simulasi gerak lurus berubah beraturan 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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#define tinggiSensorBawah   10//cm
 
#define pinTombolMulai      A0
 
#define pinSensorA          8
#define pinSensorB          9
#define pinSensorC          10
 
#include <Ultrasonic.h>
 
Ultrasonic ultrasonic(3, 2);
 
uint16_t nomor;
 
void setup() {
  pinMode(pinTombolMulai, INPUT_PULLUP);
 
  pinMode(pinSensorA, INPUT_PULLUP);
  pinMode(pinSensorB, INPUT_PULLUP);
  pinMode(pinSensorC, INPUT_PULLUP);
 
  Serial.begin(9600);
  Serial.println("Gerak Lurus Berubah Beraturan");
  Serial.println("https://www.project.semesin.com");
 
  Serial.println();
  Serial.println("Gerak Lurus Berubah Beraturan (jatuh bebas)");
  Serial.println("No\tJarak (cm)\tWaktu (s)\tPercepatan (cm/s2)");
 
}
 
void loop() {
 
  if (!digitalRead(pinTombolMulai))
  {
    delay(50);
    if (!digitalRead(pinTombolMulai))
    {
      while (!digitalRead(pinTombolMulai));
 
      uint16_t tinggi = 1.0 * ultrasonic.read() - tinggiSensorBawah;
      float jarakSensor = 1.0 * tinggi / 2;
 
      unsigned long waktuA, waktuB, waktuC;
      bool mulaiDiTitikA, mulaiDiTitikC = false;
      while (1)
      {
        if (!digitalRead(pinSensorA))
        {
          waktuA = micros();
          mulaiDiTitikA = true;
          break;
        }
        if (!digitalRead(pinSensorC))
        {
          waktuC = micros();
          mulaiDiTitikC = true;
          break;
        }
      }
 
      while (digitalRead(pinSensorB));
      waktuB = micros();
 
      while (1)
      {
        if (!digitalRead(pinSensorA))
        {
          waktuA = micros();
          break;
        }
        if (!digitalRead(pinSensorC))
        {
          waktuC = micros();
          break;
        }
      }
 
      float waktu_ac = abs(1.0 * waktuC - waktuA) / 1000000;//detik
      float waktu_ab = abs(1.0 * waktuB - waktuA) / 1000000;//detik
      float waktu_bc = abs(1.0 * waktuC - waktuB) / 1000000;//detik
 
      float kecepatan_ab = 0.5 * jarakSensor / waktu_ab;//cm/s
      float kecepatan_cb = 0.5 * jarakSensor / waktu_ab;//cm/s
      float kecepatan_bc = 0.5 * jarakSensor / waktu_bc;//cm/s
 
      float percepatan;
      if (mulaiDiTitikA)
      {
        percepatan = (1.0 * kecepatan_bc - kecepatan_ab) / waktu_bc;//cm/s2
      }
      if (mulaiDiTitikC)
      {
        percepatan = (1.0 * kecepatan_ab - kecepatan_bc) / waktu_ab;//cm/s2
      }
 
      char buffer[200];
      char strWaktu_ac[10];
      char strPercepatan[10];
 
      dtostrf(waktu_ac, 8, 2, strWaktu_ac);
      dtostrf(percepatan, 8, 2, strPercepatan);
 
      sprintf(buffer, "%d\t%d\t\t%s\t%s", nomor, tinggi, strWaktu_ac, strPercepatan);
      Serial.println(buffer);
      nomor++;
 
    }
  }
}

Library:

webserver + ajax dengan Nodemcu (esp8266) (aplikasi monitoring suhu dan kelembaban)

Monitoring atau kegiatan pemantauan bisa dilakukan dari jarak jauh melalui sistem komunikasi internet maupun metode komunikasi lainnya. Salah satu unsur monitoring data adalah display atau tampilan dimana beberapa aspek yang perlu diperhatikan adalah :

  1. Informatif, data yang ditampilkan mampu memberikan perspektif kondisi yang ada, sebagai contoh tampilan grafik: selain menunjukkan data juga akan memberikan gambaran pergerakan dari data-data sebelumnya (naik/turun).
  2. Real time. yaitu datayang tampil merupakan data lapangan saat ini dan terus diperbaharui dalam frekuensi tertentu dimana semakin besar akan semakin realtime.
  3. Bandwidth, adalah besarnya lalu lintas data yang terpakai oleh aktifitas monitoring, jadi sistem yang baik perlu mempertimbangkan metode lalu lintas data sekecil mungkin tanpa mengurangi aspek lainnya.
  4. Kenyamanan, berkaitan dengan design dan pola dinamik tampilan saat perubahan data.

Ajax

Asynchronous Javascript and XML (Ajax) adalah metode lalu lintas data web secara asynchronous (dibelakang layar) antara interface web (browser) dengan server yang bertujuan memberikan fitur interaktif kepada pengguna.

penggunaan ajax memungkinkan update data fleksibel tanpa perlu melakukan aksi (menekan tombl update) atau refresh halaman web.

Tampilan monitoring suhu dan kelembaban menggunakan nodemcu:

Komponen yang digunakan dalam perancangan monitoring suhu dan kelembaban berbasis webserver nodemcu :

  1. Nodemcu
  2. DHT11

Skema ajax webserver dengan nodemcu:

Sketch/program webserver nodemcu dengan ajax relatime:

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
#define jumlahData        5
#define hotspotSSID       "XXXXXXXX"
#define hotspotPassword   "XXXXXXXX"
#define pinDHT            D4
 
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
 
#include <dht.h>
 
dht DHT;
 
ESP8266WebServer server(80);
 
struct Data
{
  uint32_t index;
  float temperatur;
  float kelembaban;
};
 
Data data[jumlahData];
byte ringIndex;
uint32_t indexDataDHT;
long millisBacaSensor;
 
void handleRoot() {
  char buffer[] =
    "<html><head>"
    "  <title>Temperatur dan Kelembaban</title>"
    "  <meta charset='UTF-8'>"
    "  <script src='https://code.highcharts.com/highcharts.js'></script>"
    "</head>"
    "<body>"
    "  <center>"
    "    <h1>Temperatur dan Kelembaban</h1>"
    "    <h2>Grafik Temperatur dan Kelembaban</h2>"
    "    <div id='grafik' style='height:400px;'></div>"
    "  </center>"
    "<script type='text/javascript'>"
    "  var timerId = setInterval('updateGrafik()', 1000);"
    "  var grafik = Highcharts.chart('grafik', {"
    "    title: {text: ''},"
    "    xAxis: {title: {text: 'index'},categories: [],rotation:90,},"
    "    yAxis: ["
    "      {labels: {format: '{value} °C',style: {color: Highcharts.getOptions().colors[1]}},title: {text: 'Temperatur'},},"
    "      {labels: {format: '{value} %',style: {color: Highcharts.getOptions().colors[1]}},title: {text: 'Kelembaban'},opposite: true,}, ],"
    "    credits: {enabled: false},"
    "    series: ["
    "      {name: 'Temperatur',yAxis: 0,data: []}, "
    "      {name: 'Kelembaban',yAxis: 1,data: []}, ]"
    "  });"
    "  function updateGrafik(){"
    "    var xhttp = new XMLHttpRequest();"
    "    xhttp.onreadystatechange = function() {"
    "      if (this.readyState == 4 && this.status == 200) {"
    "        eval(this.responseText.trim());}};"
    "    xhttp.open('GET', '/updateData', true);"
    "    xhttp.send(); }"
    "</script>"
    "</body></html>";
  server.send(200, "text/html", buffer);
}
 
void handleNotFound()
{
  server.send(404, "text/plain", "Alamat tidak ditemukan");
}
 
void updateData()
{
  char buffer[1000];
  byte index;
 
  strcpy(buffer, "grafik.xAxis[0].setCategories([");
 
  index = ringIndex;
  for (byte i = 0; i < jumlahData; i++)
  {
    sprintf(&buffer[strlen(buffer)], "%lu,", data[index].index);
    index++;
    index %= jumlahData;
  }
  strcpy(&buffer[strlen(buffer)], "]);");
 
  strcpy(&buffer[strlen(buffer)], "grafik.series[0].setData([");
  index = ringIndex;
  for (byte i = 0; i < jumlahData; i++)
  {
    dtostrf(data[index].temperatur, 8, 2, &buffer[strlen(buffer)]);
    strcpy(&buffer[strlen(buffer)], ",");
    index++;
    index %= jumlahData;
  }
  strcpy(&buffer[strlen(buffer)], "]);");
 
  strcpy(&buffer[strlen(buffer)], "grafik.series[1].setData([");
  index = ringIndex;
  for (byte i = 0; i < jumlahData; i++)
  {
    dtostrf(data[index].kelembaban, 8, 2, &buffer[strlen(buffer)]);
    strcpy(&buffer[strlen(buffer)], ",");
    index++;
    index %= jumlahData;
  }
  strcpy(&buffer[strlen(buffer)], "]);");
 
  server.send(200, "text/html", buffer);
 
}
 
 
void setup(void) {
  Serial.begin(9600);
  Serial.println("Web server dengan fitur ajax menggunakan nodemcu (aplikasi monitor suhu dan kelembaban)");
  Serial.println("https://www.project.semesin.com");
   
  WiFi.mode(WIFI_STA);
  WiFi.begin(hotspotSSID, hotspotPassword);
  Serial.println("");
 
  // Wait for connection
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
 
  Serial.println("");
  Serial.print("Connected to ");
  Serial.println(hotspotSSID);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
 
  server.on("/", handleRoot);
  server.on("/updateData", updateData);
  server.onNotFound(handleNotFound);
 
  server.begin();
  Serial.println("HTTP server started");
}
 
void loop(void) {
  server.handleClient();
 
  if (millisBacaSensor < millis())
  {
    millisBacaSensor = millis() + 1000;
 
    if (DHT.read11(pinDHT) == DHTLIB_OK)
    {
      data[ringIndex].index = indexDataDHT;
      data[ringIndex].temperatur = DHT.temperature;
      data[ringIndex].kelembaban = DHT.humidity;
 
      indexDataDHT++;
 
      ringIndex++;
      ringIndex %= jumlahData;
    }
  }
}

Library:

Timbangan tampilan seven segment menggunakan arduino

Penggunaan timbangan secara umum membutuhkan akurasi dan presisi. Dalam skala lebih luas sebaiknya unit timbangan juga informatif sehingga dapat diketahui hasilnya secara luas. Untuk keperluan ini, unit timbangan  harus memiliki sarana display yang memadai seperti menggunakan display dot mattrix, seven segment dan sebagainya.

Fitur timbangan

Fitur/fasilitas timbangan bisa bermacam sesuai kebutuhan. Dalam perancangan timbangan 7-segment ini memasukkan fitur-fitur penting diantaranya :

    1. Kalibrasi

Kalibrasi adalah kegiatan untuk memastikan timbangan memiliki akurasi dan presisi yang baik. dalam perancangan ini prosedur kalibrasinya sebagai berikut:

    • Posisi perangkat timbangan dalam keadaan mati
    • Letakkan beban tera 1Kg
    • Tekan dan tahan tombol [hold]
    • Hidupkan perangkat timbangan (akan muncul tulisan ‘load 1’ di tampilan seven segment)
    • lepas tombol [hold]
    • Tunggu hingga muncul tulisan ‘load 2’ di 7-segment
    • Letakkan beban tera 2.5 Kg
    • Tekan dan lepas tombol [hold]
    • Tunggu hingga muncul tulisan ‘siap’ didisplay 7-segment
    • Kalibrasi selesai
  1. tombol tare
  2. tombol hold
  3. Tampilan seven segment

Seven Segmen

Seven segment memiliki kelebihan dari display lainnya, diantaranya :

  1. Intensitas cahaya lebih terang (akan berkurang jika menggunakan sistem scanning)
  2. Mudah terbaca dari jarak jauh (lebih jelas)
  3. Jika menggunakan mikrokontroler, lebih sedikit menggunakan resources (memory dan waktu proses)
  4. Menggunakan komponen lebih sedikit (non module)
  5. Perbandingan cahaya vs daya terpakai lebih sedikit sehingga lebih hemat.

Dalam proyek timbangan informatif dengan display 7-segment berbasis arduino ini menggunakan komponen sebagai berikut:

Komponen yang digunakan dalam perancangan timbangan sevent segment menggunakan arduino:

  1. Arduino uno
  2. modul hx711 dan loadcell 5Kg
  3. IC uln2003
  4. 5x 7-Segment CC
  5. 2x Tombol

Skema timbangan tampilan seven segmen:

source code/program arduino timbangan seven segment:

 

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
#include "HX711.h"
#include <TimerOne.h>
#include <EEPROM.h>
 
#define CCorCA                1//0 = CC, 1 = CA (rangkaian dengan resistor)
#define tareSaatMulai         1
 
#define beratKalibrasi1Tera   1.0f  //Kg
#define beratKalibrasi2Tera   1.00f  //Kg
#define beratMaksimal         2.50 //Kg
#define jumlahSampling        5     //kali
#define frekuensiUpdateData   20    //kali per detik
 
//pin
HX711 scale(3, 2); // (DT, SCK)
 
#define pin1    A0
#define pin2    A1
#define pin3    A2
#define pin4    A3
#define pin5    A4
 
#define pinA    4
#define pinB    5
#define pinC    6
#define pinD    7
#define pinE    8
#define pinF    9
#define pinG    10
#define pinDot  11
 
#define pinTare 12
#define pinHold 13
 
#define dotBlank 6
#define dotAll   5
 
byte pin7Segment[] = {pinA, pinB, pinC, pinD, pinE, pinF, pinG};
byte pin7SegmentCommon[] = {pin1, pin2, pin3, pin4, pin5};
byte posisiTitik = dotBlank;
 
const char angka[] = {
  0b00111111,
  0b00000110,
  0b01011011,
  0b01001111,
  0b01100110,
  0b01101101,
  0b01111100,
  0b00000111,
  0b01111111,
  0b01100111,
  0b00000000,//blank
  0b01000000,//strip
  0b00111000,//L
  0b01011100,//o
  0b01011111,//a
  0b01011110,//d
  0b01101101,//S
  0b00000100,//i
  0b01110011,//p
   
};
#define Seg_blank 10
#define Seg_stip 11
#define Seg_L 12
#define Seg_o 13
#define Seg_a 14
#define Seg_d 15
#define Seg_S 16
#define Seg_i 17
#define Seg_p 18
 
//volatile uint32_t beratBCD = 0;
volatile uint8_t beratBCD[5];
volatile byte lastScanIndex = 0;
volatile byte index7Segment = 0;
 
long lastMillis;
long kirimDataMillis;
byte modeKalibrasi = 0;
long beratKalibrasi1;
long beratKalibrasi2;
float beratTerukur;
bool tahanNilai = false;
byte timbangBeratCounter = 0;
 
#define alamatKalibrasiM 0
#define alamatKalibrasiC 4
 
void setup() {
  Serial.begin(9600);
  Serial.println(F("Timbangan tampilan seven segment menggunakan arduino"));
  Serial.println(F("https://www.project.semesin.com"));
   
  pinMode(pin1, OUTPUT);
  pinMode(pin2, OUTPUT);
  pinMode(pin3, OUTPUT);
  pinMode(pin4, OUTPUT);
  pinMode(pin5, OUTPUT);
 
  pinMode(pinA, OUTPUT);
  pinMode(pinB, OUTPUT);
  pinMode(pinC, OUTPUT);
  pinMode(pinD, OUTPUT);
  pinMode(pinE, OUTPUT);
  pinMode(pinF, OUTPUT);
  pinMode(pinG, OUTPUT);
  pinMode(pinDot, OUTPUT);
 
  pinMode(pinTare, INPUT_PULLUP);
  pinMode(pinHold, INPUT_PULLUP);
 
  Timer1.initialize(2000);
  Timer1.attachInterrupt( timerIsr );
 
  float m,c;
 
  scale.power_up();
   
  //Mode kalibrasi
  if(!digitalRead(pinHold))
  {
    delay(50);
    if(!digitalRead(pinHold))
    {
      beratBCD[4] = Seg_L;
      beratBCD[3] = Seg_o;
      beratBCD[2] = Seg_a;
      beratBCD[1] = Seg_d;
      beratBCD[0] = 1;
 
      while(!digitalRead(pinHold))//lepas
      {
        while(!digitalRead(pinHold))
        {
          delay(50);
        }
      }
      delay(1000);
      beratKalibrasi1 = scale.read_average(10);
 
      beratBCD[0] = 2;
      while(digitalRead(pinHold))//tekan
      {
        while(digitalRead(pinHold))
        {
          delay(50);
        }
      }
      delay(1000);
      beratKalibrasi2 = scale.read_average(10);
       
      m = 1.0 * (beratKalibrasi2 - beratKalibrasi1) / ( beratKalibrasi2Tera - beratKalibrasi1Tera);
      c = beratKalibrasi2 - (1.0 * m * beratKalibrasi2Tera);
 
      EEPROM.put(alamatKalibrasiM, m);
      EEPROM.put(alamatKalibrasiC, c);   
 
      beratBCD[4] = Seg_S;
      beratBCD[3] = Seg_i;
      beratBCD[2] = Seg_a;
      beratBCD[1] = Seg_p;
      beratBCD[0] = Seg_blank;
 
      delay(500);
    }
  }
   
  EEPROM.get(alamatKalibrasiM, m);
  EEPROM.get(alamatKalibrasiC, c);
 
  scale.set_scale(m);
  scale.set_offset(c);
 
#if tareSaatMulai
  scale.tare();
#endif
   
  scale.power_down();
  lastMillis = millis();
  kirimDataMillis = millis();
}
 
void loop() {
 
  if(!tahanNilai)
  {
    if(millis() - lastMillis > 10)
    {
      scale.power_up();
      delay(10);
      beratTerukur += scale.get_units(1);
      if(timbangBeratCounter++ == jumlahSampling)
      {
        beratTerukur = beratTerukur * 100 / jumlahSampling;
        if(beratTerukur < 0)
        {
          beratBCD[0] = 0;
          beratBCD[1] = 0;
          beratBCD[2] = 0;
          beratBCD[3] = Seg_stip;
          beratBCD[4] = Seg_blank;
          posisiTitik = 2;
        }
        else if(beratTerukur <= (beratMaksimal*100))
        {
          uint32_t BCD = Convert_IntToBCD32(beratTerukur);
          if((BCD & 0x0F) <= 5)
          {
            beratBCD[0] = 0;
          }
          else
          {
            beratBCD[0] = 5;
          }
          beratBCD[1] = (BCD >> 4) & 0x0F;
          beratBCD[2] = (BCD >> 8) & 0x0F;
          beratBCD[3] = (BCD >> 12) & 0x0F;
          beratBCD[4] = (BCD >> 16) & 0x0F;
          posisiTitik = 2;
        }
        beratTerukur = 0;
        timbangBeratCounter = 0;
      }
      scale.power_down();
       
      lastMillis = millis();
    }
  }
 
  //Kirim data setiap 100ms
  if(millis() - kirimDataMillis > (1000/frekuensiUpdateData))
  {
    if(beratTerukur <= 0)
    {
      Serial.println("0.00");
    }
    else
    {
      Serial.println(floor(beratTerukur)/100, 2);
    }
 
    kirimDataMillis = millis();
  }
  if(!digitalRead(pinTare))
  {
    delay(50);
    if(!digitalRead(pinTare))
    {
      beratBCD[0] = Seg_blank;
      beratBCD[1] = Seg_blank;
      beratBCD[2] = Seg_blank;
      beratBCD[3] = Seg_blank;
      beratBCD[4] = Seg_blank;
      posisiTitik = dotAll;
      scale.power_up();
      delay(10);
      scale.tare();
      scale.power_down();
      while(!digitalRead(pinTare));
    }
  }
  if(!digitalRead(pinHold))
  {
    delay(50);
    if(!digitalRead(pinHold))
    {
      tahanNilai = !tahanNilai;
      while(!digitalRead(pinHold));
    }
  }
}
void timerIsr()
{
  digitalWrite(pin7SegmentCommon[lastScanIndex], CCorCA?LOW:HIGH);
  drive7Segment(beratBCD[index7Segment]);
  if(posisiTitik == dotAll)
  {
    digitalWrite(pinDot, CCorCA?LOW:HIGH);
  }
  else if(posisiTitik == dotBlank)
  {
    digitalWrite(pinDot, CCorCA?HIGH:LOW);
  }
  else
  {
    digitalWrite(pinDot, (index7Segment == posisiTitik)?CCorCA?LOW:HIGH:CCorCA?HIGH:LOW);
  }
  digitalWrite(pin7SegmentCommon[index7Segment], CCorCA?HIGH:LOW);
  lastScanIndex = index7Segment++;
  if(index7Segment > 4)index7Segment = 0;
}
void drive7Segment(byte nilai)
{
  byte nilai7Segment = CCorCA?~angka[nilai]:angka[nilai];
  for(byte i=0;i<sizeof(pin7Segment);i++)
  {
    digitalWrite(pin7Segment[i], nilai7Segment & 0x01);
    nilai7Segment >>= 1;
  }
}
uint32_t Convert_IntToBCD32(uint32_t DecimalValue)
{
    uint32_t returnValue = 0;
    //uint32_t LSB_L = DecimalValue;
  
    while (DecimalValue >= 10000000L)
    {
        DecimalValue -= 10000000L;
        returnValue += 0x10000000;
    }
    while (DecimalValue >= 1000000L)
    {
        DecimalValue -= 1000000L;
        returnValue += 0x01000000;
    }
    while (DecimalValue >= 100000L)
    {
        DecimalValue -= 100000L;
        returnValue += 0x00100000;
    }
    while (DecimalValue >= 10000)
    {
        DecimalValue -= 10000;
        returnValue += 0x00010000;
    }
    while (DecimalValue >= 1000L)
    {
        DecimalValue -= 1000L;
        returnValue += 0x00001000;
    }
    while (DecimalValue >= 100)
    {
        DecimalValue -= 100;
        returnValue += 0x00000100;
    }
    while (DecimalValue >= 10)
    {
        DecimalValue -= 10;
        returnValue += 0x00000010;
    }
    return returnValue + DecimalValue;
}

Library yang digunakan dalam perakitan timbangan arduino:

  1. HX711.zip
  2. TimerOne.zip

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

Mesin antrian dmd dilengkapi suara dengan arduino

Mesin antrian adalah sistem informasi antara meja layanan dan pengunjung untuk mengatur waktu pelayanan terhadap pengunjung sesuai urutan kedatangan. Sistem ini terdiri atas media, dan tombol panggil, bisa juga ditambahkan dengan tombol tiket (dengan cetak tiket). Media informasi seperti seven segment, running text (dmd), monitor, suara yang diletakkan di ruang tunggu yang terlihat/terdengar di kursi pengunjung yang sedang antri.

Mesin antrian dalam proyek ini memiliki fitur berikut :

  1. Tombol panggil 4 buah dengan fitur cascade yaitu masing-masing tombol dapat ditekan bersamaan tanpa harus menunggu proses panggilan meja operator lain.
  2. Tombol tiket 1 buah dan dilengkapi cetak tiket
  3. Tombol reset untuk mengembalikan ke keadaan awal
  4. Media dot matik P10 sebagai papan informasi.
  5. Suara panggil mp3 berupa nomor antrian dan nomor loket

Skema Mesin antrian arduino :

Komponen yang digunakan dalam membuat mesin antrian menggunakan dmd (dot matrix display) berbasis arduino :

  1. Arduino uno
  2. DMD P10
  3. Printer thermal
  4. DF Player mini mp3, speaker, resistor
  5. Tombol

Sketch / koding sistem antrian 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
#define pinTombolPanggil1   A0
#define pinTombolPanggil2   A1
#define pinTombolPanggil3   A2
#define pinTombolPanggil4   A3
 
#define pinTombolReset      A4
#define pinTombolTiket      A5
 
#define pinMP3Busy          2
 
#define belas               12 //belas.mp3
#define puluh               13 //puluh.mp3
#define seratus             14 //seratus.mp3
#define ratus               15 //ratus.mp3
#define seribu              16 //seribu.mp3
#define ribu                17 //ribu.mp3
#define koma                18 //Koma.mp3
 
#define antrianNomor        101
#define silahkanKeCS        102
 
#include &lt;SPI.h&gt;
#include &lt;DMD_Semesin.h&gt;
#include &lt;fonts/angka6x14ABCD.h&gt;
#include &lt;DFPlayer_Mini_Mp3.h&gt;
#include &quot;Adafruit_Thermal.h&quot;
 
 
byte nomorAntrianDaftar;
byte nomorAntrianPanggil;
byte nomorCSPanggil;
 
SPIDMD dmd(1, 1);
SoftwareSerial serialPrinter(4, 5);
Adafruit_Thermal printer(&amp;serialPrinter);
 
struct DataAntrian
{
  uint16_t counterTiket;
  uint16_t counterPanggil;
  uint8_t CS;
  bool dataTombolTekan[4];
};
 
DataAntrian dataAntrian;
byte pinTombolPanggil[] = {pinTombolPanggil1, pinTombolPanggil2, pinTombolPanggil3, pinTombolPanggil4};
char buffer[20];
 
bool statusTombolTiket;
byte statusTombolPanggil[4];
 
 
void setup() {
  pinMode(pinTombolPanggil1, INPUT_PULLUP);
  pinMode(pinTombolPanggil2, INPUT_PULLUP);
  pinMode(pinTombolPanggil3, INPUT_PULLUP);
  pinMode(pinTombolPanggil4, INPUT_PULLUP);
 
  pinMode(pinTombolReset, INPUT_PULLUP);
  pinMode(pinTombolTiket, INPUT_PULLUP);
 
  Serial.begin(9600);
 
  Serial.println(F(&quot;Mesin antrian arduino&quot;));
  Serial.println(F(&quot;https://www.project.semesin.com&quot;));
 
  mp3_set_serial (Serial);
  mp3_set_volume(30);
  Serial.println();
 
  serialPrinter.begin(9600);
  printer.begin();
  printer.sleep();
 
  dmd.clearScreen();
  dmd.setBrightness(255);
  dmd.selectFont(angka6x14ABCD);
  dmd.begin();
}
 
void loop() {
 
  bacaTombol();
 
  if (!digitalRead(pinTombolReset))
  {
    delay(100);
    if (!digitalRead(pinTombolReset))
    {
      dataAntrian.counterTiket = 0;
      dataAntrian.counterPanggil = 0;
      dataAntrian.CS = 0;
      dataAntrian.dataTombolTekan[0] = 0;
      dataAntrian.dataTombolTekan[1] = 0;
      dataAntrian.dataTombolTekan[2] = 0;
      dataAntrian.dataTombolTekan[3] = 0;
 
      dmd.clearScreen();
      Serial.println(&quot;Reset&quot;);
      while (!digitalRead(pinTombolReset));
    }
  }
 
  for (byte i = 0; i &lt; sizeof(pinTombolPanggil); i++)
  {
    if (dataAntrian.counterTiket &gt; dataAntrian.counterPanggil)
    {
      if (dataAntrian.dataTombolTekan[i])
      {
        dataAntrian.counterPanggil++;
        dataAntrian.CS = i + 1;
 
        sprintf(buffer, &quot;%02d&gt;%1d&quot;, dataAntrian.counterPanggil, dataAntrian.CS);
        dmd.drawString(2, 1, buffer);
 
        Serial.print(&quot;call=&quot;);
        Serial.println(dataAntrian.counterPanggil);
        Serial.print(&quot;cs=&quot;);
        Serial.println(dataAntrian.CS);
 
        mp3_play_and_wait(antrianNomor);
        suaraBilangan(dataAntrian.counterPanggil);
        mp3_play_and_wait(silahkanKeCS);
        suaraBilangan(dataAntrian.CS);
 
        Serial.println();
        dataAntrian.dataTombolTekan[i] = false;
      }
    }
  }
}
 
void suaraBilangan(uint32_t Bilangan)
{
  if (Bilangan &lt; 100)
  {
    suaraPuluhan(Bilangan);
  }
  else if (Bilangan &lt; 1000)
  {
    suaraRatusan(Bilangan);
  }
  else
  {
    suaraRibuan(Bilangan);
  }
}
void suaraPuluhan(uint8_t Bilangan)
{
  if (Bilangan &lt; 12)
  {
    mp3_play_and_wait(Bilangan);
  }
  else if (Bilangan &lt; 20)
  {
    mp3_play_and_wait(Bilangan - 10);
    mp3_play_and_wait(belas);
  }
  else
  {
    uint8_t puluhan = Bilangan / 10;
    mp3_play_and_wait(puluhan);
    mp3_play_and_wait(puluh);
 
    puluhan *= 10;
    if (Bilangan - puluhan != 0)
    {
      mp3_play_and_wait((Bilangan - puluhan));
    }
  }
}
void suaraRatusan(uint16_t Bilangan)
{
  uint8_t ratusan = (uint8_t)(Bilangan / 100);
  if (ratusan == 1)
  {
    mp3_play_and_wait(seratus);
  }
  else
  {
    mp3_play_and_wait(ratusan);
    mp3_play_and_wait(ratus);
  }
  if (Bilangan % 100)
  {
    suaraPuluhan(Bilangan - (ratusan * 100));
  }
}
void suaraRibuan(uint32_t Bilangan)
{
  uint16_t ribuan = (uint16_t)(Bilangan / 1000);
  if (ribuan == 1)
  {
    mp3_play_and_wait(seribu);
  }
  else if (ribuan &lt; 100)
  {
    suaraPuluhan(ribuan);
    mp3_play_and_wait(ribu);
  }
  else
  {
    suaraRatusan(ribuan);
    mp3_play_and_wait(ribu);
  }
  if (Bilangan % 1000)
  {
    suaraRatusan(Bilangan - (ribuan * 1000));
  }
}
 
void mp3_play_and_wait(uint16_t num) {
  mp3_play (num);
  delay(200);
  while (!digitalRead(pinMP3Busy))
  {
    bacaTombol();
  }
}
 
void bacaTombol()
{
  if (!digitalRead(pinTombolTiket))
  {
    if (!statusTombolTiket)
    {
      delay(100);
      if (!digitalRead(pinTombolTiket))
      {
        dataAntrian.counterTiket++;
        printer.wake();
        printer.setDefault();
 
        printer.justify('C');
        printer.println(&quot;Nomor Antrian&quot;);
        printer.doubleHeightOn();
        printer.println(dataAntrian.counterTiket);
        printer.doubleHeightOff();
        printer.println(&quot;Terima kasih&quot;);
        printer.feed(2);
        printer.sleep();
 
        Serial.print(&quot;ambil tiket : &quot;);
        Serial.println(dataAntrian.counterTiket);
 
        statusTombolTiket = true;
      }
    }
  }
  else
  {
    statusTombolTiket = false;
  }
 
  for (byte i = 0; i &lt; sizeof(pinTombolPanggil); i++)
  {
    if (!digitalRead(pinTombolPanggil[i]))
    {
      if (!statusTombolPanggil[i])
      {
        delay(100);
        if (!digitalRead(pinTombolPanggil[i]))
        {
          dataAntrian.dataTombolTekan[i] = true;
          statusTombolPanggil[i] = true;
 
          Serial.print(&quot;TombolPanggil:&quot;);
          Serial.println(i);
        }
      }
    }
    else
    {
      statusTombolPanggil[i] = false;
    }
  }
}

library :

suara mp3

  1. mp3 mesin antrian arduino.zip

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: