fungsi analogWrite() dengan variabel duty cycle dan frekuensi (aplikasi PWM)

Perintah analogWrite() dengan variabel duty cycle dan frekuensi pada pin 9 atau 10 ini berguna untuk membangkitkan sinyal PWM (PWM Generator) yang sangat variatif dari 0.24 Hz hingga 160kHz duty cycle 0.0 ~ 100.0%,sedangkan frekuensi 160kHz hingga 8MHz dengan duty cycle terbatas.

Modifikasi analogWrite ini menggunakan timer1 sebagai penanda waktunya, sehinggga hanya akan mempengaruhi pin 9 dan 10 saja, dan tidak bisa dikombinasikan dengan fungsi PWM arduino biasa.

Parameter PWM yang digunakan:

  1. pin, hanya pin 9 dan 10
  2. dutyCyclePersen, nilai 0..100 adalah lebar pulsa on dalam persen
  3. frekuensi, nilai 0.24 hingga 8000000 (8Mhz)

berikut sketch/program fungsi analogWrite serbaguna

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
#define PWM_1 9
#define PWM_2 10
 
void setup() {
  Serial.begin(9600);
  Serial.println("fungsi analogWrite() dengan variabel duty cycle dan frekuensi pada pin 9 atau 10");
  Serial.println("Pada penggunaan kombinasi pin 9 dan 10,");
  Serial.println("maka frekuensi yang di set terakhir yang akan digunakan");
  Serial.println("https://www.project.semesin.com");
}
 
void loop() {
  //analogWrite(pin, dutyCyclePersen, frekuensi)
  analogWrite(PWM_1, 50, 1000);
  while(1);
}
 
void analogWrite(byte pin, double dutyCyclePersen, double frekuensi)
{
  if(frekuensi > 244.0)
  {
    TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10);
    ICR1 = (16000000L/(frekuensi)) - 1;
  }
  else if(frekuensi > 30.0)
  {
    TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS11);
    ICR1 = (16000000L/(frekuensi * 8)) - 1;
  }
  else if(frekuensi > 3.0)
  {
    TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS11) | _BV(CS10);
    ICR1 = (16000000L/(frekuensi * 64)) - 1;
  }
  else if(frekuensi > 0.95)
  {
    TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS12);
    ICR1 = (16000000L/(frekuensi * 256)) - 1;
  }
  else if(frekuensi > 0.23)
  {
    TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS12) | _BV(CS10);
    ICR1 = (16000000L/(frekuensi * 1024)) - 1;
  }
  TCCR1A &= ~_BV(WGM10);
  TCCR1A |= _BV(WGM11);
  if(pin == 9)
  {
    pinMode(9, OUTPUT);
    TCCR1A |= _BV(COM1A1);
    OCR1A = (dutyCyclePersen/100) * (ICR1 + 1);
  }
  if(pin == 10)
  {
    pinMode(10, OUTPUT);
    TCCR1A |= _BV(COM1B1);
    OCR1B = (dutyCyclePersen/100) * (ICR1 + 1);
  }
}

Mengukur tegangan Vcc Arduino

Pengembangan perangkat arduino pintar salah satunya adalah mampu mendeteksi suplai tegangan utama-nya yati tegangan Vcc. Tujuannya adalah :

  1. mendeteksi secara dini kegagalan yang mungkin terjadi seperti kehilangan daya utama dan menyiapkan tenaga cadangan
  2. Menyimpan data-data penting kedalam EEPROM apabila ada indikasi tegangan akan drop

Cara mengukuran Vcc Arduino bisa dilakukan dengan dua cara :

Cara pertama

Menggunakan rangkaian pembagi tegangan sebagai input ke ADC yang menggunakan internal reference (1.1Volt)

resistor yang digunakan haruslah memiliki toleransi rendah / presisi tinggi (misal 1%).

skema pengukuran tegangan suplai arduino:

sketch / program menghitung tegangan catu daya 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
//pin
#define detektorBaterai A0
 
//Konstanta
#define resistorPlus 10000L
#define resistorGround 1000L
#define teganganReferesiAnalog 1.1
 
void setup() {
  Serial.begin(9600);
  Serial.println("Pengukuran tegangan Vcc Arduino");
  Serial.println("https://www.project.semesin.com");
 
  analogReference(INTERNAL1V1);
}
 
void loop() {
  uint16_t rawVcc = 0;
  for(int i=0;i<10;i++)
  {
    rawVcc += analogRead(detektorBaterai);
  }
  rawVcc /= 10;
   
  double teganganPembagi = teganganReferesiAnalog * rawVcc / 1023;//Volt
  double teganganVcc = teganganPembagi * ((resistorPlus + resistorGround) / resistorGround);//Volt
 
  Serial.print("Tegangan Vcc = ");
  Serial.println(teganganVcc);
 
  delay(1000);
}

Cara kedua

Pengukuran tegangan internal bandgap (1.1V) untuk dibandingkan dengan nilain ADC dari tegangan bandgap ideal.

nilai ADC ideal tegangan bandgap adalah:

dengan menggunakan rumusan perbandingan :

metode ini tanpa komponen external dengan sketch:

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
//Konstanta
#define ADCBandgapIdeal 225.06
#define TeganganVccIdeal 5.0
 
void setup() {
  Serial.begin(9600);
  Serial.println("Pengukuran tegangan Vcc Arduino");
  Serial.println("https://www.project.semesin.com");
}
 
void loop() {
  uint16_t rawVcc = 0;
  for(int i=0;i<10;i++)
  {
    ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);//ADC channel bandgap
    ADCSRA |= _BV( ADSC );
    while( ( (ADCSRA & (1<<ADSC)) != 0 ) );
    rawVcc += ADC;
  }
  rawVcc /= 10;
   
  double teganganVcc = ADCBandgapIdeal * TeganganVccIdeal / rawVcc;
 
  Serial.print("Tegangan Vcc = ");
  Serial.println(teganganVcc);
 
  delay(1000);
}

Arduino tenaga baterai dengan indikator baterai lemah

Board arduino (uno) membutuhkan tegangan nominal sebesar 5Volt yang dilengkapi dengan regulator 1117/7805 yang mampu meregulasi tegangan hingga 15Volt (max) menjadi 5Volt.

Penggunaan baterai sebagai catu daya arduino harus memiliki voltase diatas 6Volt (mengimbangi tegangan dropout) jiks menggunakan regulator 1117.

Dalam contoh ini saya menggunakan baterai kotak 9Volt. Untuk pembacaan tegangan baterai, sebagai penyetaraannya digunakan resistor pembagi tegangan dengan nilai 1KΩ dan 10KΩ (toleransi 1% dan kehilangan arus 0.8mA). Keluaran resistor pembagi tegangan menghasilkan tegangan 0.818 Volt jika tegangan baterai 9V.

Tegangan dari resistor pembagi tegangan ini menjadi input bagi ADC channel 0. untuk lebih memaksimalkan pembacaan ADC digunakan tegangan referensi analog internal 1.1Volt.

skema baterai arduino (arduino battery):

Sketch/program arduino dengan baterai:

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
//pin
#define detektorBaterai A0
#define indikatorBateraiLemah 13//internal LED
 
//Konstanta
#define resistorPlus 10000L
#define resistorGround 1000L
#define teganganReferesiAnalog 1.1
 
byte bateraiLemah;
bool statusIndikator;
long indikatorMillisMulai;
uint16_t delayIndikator = 1000;
 
void setup() {
  pinMode(indikatorBateraiLemah, OUTPUT);
  analogReference(INTERNAL);
  analogRead(detektorBaterai);
}
 
void loop() {
  uint16_t rawBaterai = 0;
  for(int i=0;i<10;i++)
  {
    rawBaterai += analogRead(detektorBaterai);
  }
  rawBaterai /= 10;
   
  double teganganPembagi = teganganReferesiAnalog * rawBaterai / 1023;//Volt
  double teganganBaterai = teganganPembagi * ((resistorPlus + resistorGround) / resistorGround);//Volt
 
  if((teganganBaterai < 8.0) && (bateraiLemah != 2))
  {
    bateraiLemah = 2;
    indikatorMillisMulai = millis();
  }
  else if((teganganBaterai < 8.5) && (teganganBaterai > 8.1) && (bateraiLemah != 1))
  {
    bateraiLemah = 1;
    indikatorMillisMulai = millis();
  }
  if((teganganBaterai > 8.6) && bateraiLemah)//Hysteresis
  {
    bateraiLemah = 0;
    digitalWrite(indikatorBateraiLemah, LOW);
  }
  if(bateraiLemah && (millis() - indikatorMillisMulai > delayIndikator))
  {
    digitalWrite(indikatorBateraiLemah, statusIndikator);
    if(statusIndikator)
    {
      delayIndikator = 100;
    }
    else
    {
      if(bateraiLemah == 1)
      {
        delayIndikator = 2000;
      }
      else if(bateraiLemah == 2)
      {
        delayIndikator = 200;
      }
    }
    statusIndikator = !statusIndikator;
    indikatorMillisMulai = millis();
  }
}

Memainkan suara 4-bit ADPCM langsung dari arduino

Rancangan bangun berbasis arduino kurang lengkap tanpa adanya suara. Fungsi suara tergantung kebutuhan, yang paling diutamakan adalah informasi audio. Perangkat audio arduino yang umum digunakan adalah mp3 shield, dan data suara mp3 disimpan dalam kartu memori/SDCard.

Untuk memainkan file suara dengan Arduino atau musik arduino memiliki permasalahan :

  1. Arduino memiliki memori flash yang kecil (Uno 32KB, Mega 256KB)
  2. Port yang hanya mampu mengeluarkan (source/sink) arus sebesar 40mA setiap pin.
  3. Kecepatan clock arduino yang hanya 16MHz, membatasi sampling rate dan ukuran sample.

Untuk menyimpan data suara lebih panjang kita bisa menggunakan data terkompresi, Salah satu sistem kompresi sederhana adalah 4-bit ADPCM (Adaptive differential pulse-code modulation), yaitu kompresi data suara kedalam 4-bit sehinggan file suara PCM yang umumnya 8-bit atau 16-bit bisa diperkecil menjadi 4-bit. Arduino adpcm juga bisa digunakan sebagai alternatif penggunaan modul suara WTV020SD yang juga bisa memainkan file dalam format 4-bit adpcm (.ad4)

Dalam contoh ini saya menggunakan sample rate 8KHz dan ukuran(size) sample 9 bit, alternatif yang disediakan 16KHz – 8 bit. Dengan properti 8KHz-9Bit, kompresi 4-bit ADPCM hanya menggunakan 4Kb setiap detiknya, sehingga uno mampu menyimpan 6 detik data suara (ruang memory lainnya digunakan oleh program), sedangkan mega mampu menampung 62 detik data suara.

untuk memaksimalkan arus port Arduino, saya menggunakan speaker 32Ohm.

Urusan memperhalus suara yang akan dihasilkan saya menggunakan metode bridge (tanpa kapasitor kopling) dengan menggunakan pin 9 dan 10 yang terhubung ke Timer1.

komponen:

  1. Arduino Uno
  2. Speaker 32ohm/head phone

skema:

Sketch / program :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#include "Selamat-datang-8000.h"
  
#define speakerA 9
#define speakerB 10
  
const int8_t IndexTable[16] = {
    -1, -1, -1, -1, 2, 4, 6, 8,
    -1, -1, -1, -1, 2, 4, 6, 8
};
int16_t StepSizeTable[89] = {
    7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
    19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
    50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
    130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
    337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
    876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
    2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
    5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
    15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
};
struct AD4Header
{
  byte ad4Code;
  char ad4Sign[4];
  uint16_t ad4SampleRate;
};
#define ad4DataOffset 6
  
long predsample;
int8_t index;
uint16_t panjangSuara;
uint16_t sampleCounter;
byte *dataSuara;
bool PWMUpdate;
bool swap;
AD4Header ad4Header;
bool suaraDimainkan;
  
void setup(void)
{
  pinMode(speakerA, OUTPUT);
  pinMode(speakerB, OUTPUT);
  
  Serial.begin(9600);
  Serial.println("Memainkan suara 4-bit ADPCM dengan arduino");
  Serial.println("https://www.project.semesin.com/");
}
  
void loop(void)
{
  if(!suaraDimainkan)
  {
    mainkanSuara(dataSuaraSelamatDatang8000, sizeof(dataSuaraSelamatDatang8000));
  }
  else
  {
    lanjutkanSuara();
  }
}
  
void mainkanSuara(const byte *fileSuara, uint16_t ukuranFileSuara)
{
  dataSuara = (byte*)fileSuara;
    
  ad4Header.ad4Code = pgm_read_byte_near(dataSuara + 0);
  ad4Header.ad4Sign[0] = pgm_read_byte_near(dataSuara + 1);
  ad4Header.ad4Sign[1] = pgm_read_byte_near(dataSuara + 2);
  ad4Header.ad4Sign[2] = pgm_read_byte_near(dataSuara + 3);
  ad4Header.ad4Sign[3] = 0;
  ad4Header.ad4SampleRate = pgm_read_word_near(dataSuara + 4);
  
  Serial.println();
  Serial.println("Memainkan file suara");
  Serial.print("Sample Rate : ");
  Serial.print(ad4Header.ad4SampleRate);
  Serial.println("Hz");
  Serial.print("Ukuran : ");
  Serial.println(ukuranFileSuara);
  
  if(ad4Header.ad4SampleRate == 16000)
  {
    ICR1 = 512;
  }
  else if(ad4Header.ad4SampleRate == 8000)
  {
    ICR1 = 1024;
  }
  
  TCCR1A = _BV(COM1A1) | _BV(COM1B1);
  TCCR1B = _BV(WGM13) | _BV(CS10);
  
  panjangSuara = ukuranFileSuara;
  sampleCounter = ad4DataOffset;
  predsample = 0;
  index = 0;
  swap = false;
  suaraDimainkan = true;
}
  
void lanjutkanSuara()
{
  if(TIFR1 & _BV(TOV1))
  {
    TIFR1 |= _BV(TOV1);
    if (sampleCounter > panjangSuara)
    {
      stopPlayback();
    }
    else
    {
      byte data = pgm_read_byte_near(dataSuara + sampleCounter);
      if(!swap)
      {
        data >>= 4;
      }
      else
      {
        sampleCounter++; 
      }
      swap = !swap;
    
      int16_t sample;
      if(ad4Header.ad4SampleRate == 16000)
      {
        sample = (ADPCMDecoder(data & 0x0F)/128) + 256;
        OCR1B = 512 - sample;
      }
      else if(ad4Header.ad4SampleRate == 8000)
      {
        sample = (ADPCMDecoder(data & 0x0F)/64) + 512;
        OCR1B = 1024 - sample;
      }
      OCR1A = sample;   
    }           
  }
}
int16_t ADPCMDecoder(byte codeNibble)
{
  uint16_t sample;
  int16_t diffq;
  uint16_t step;
  
  step = StepSizeTable[index];
  
  diffq = step >> 3;
  if( codeNibble & 4 )
    diffq += step;
  if( codeNibble & 2 )
    diffq += step >> 1;
  if( codeNibble & 1 )
    diffq += step >> 2;
    
  if( codeNibble & 8 )
    predsample -= diffq;
  else
    predsample += diffq;
  
  index += IndexTable[codeNibble];
  
  if( index < 0 )
    index = 0;
  if( index > 88 )
    index = 88;
  
  if( predsample > 32767 )
    predsample = 32767;
  else if( predsample < -32768 )
    predsample = -32768;
  
  return predsample;
}
  
void stopPlayback()
{
  TIMSK1 &= ~_BV(OCIE1A);
  TCCR1B &= ~_BV(CS10);
  if(ad4Header.ad4SampleRate == 16000)
  {
    OCR1A = 256;
    OCR1B = 256;
  }
  else if(ad4Header.ad4SampleRate == 8000)
  {
    OCR1A = 512;
    OCR1B = 512;
  }
  digitalWrite(speakerA, LOW);
  digitalWrite(speakerB, LOW);
  
  suaraDimainkan = false;
}

contoh file suara (copy-kan ke folder sketch arduino)

Selamat datang 8000.h

untuk mengkonversi file .wav atau .mp3 ke file .ad4 bisa menggunakan software 4D-SOMO-Tool (tidak direkomendasikan menggunakan ad4Converter karena software ini tidak menyertakan header). kemudian file .ad4 tersebut dijadikan .h dengan software bin2c.

Kesalahan umum perancangan berbasis Arduino

Kendala perancangan arduino yang sering terjadi :

  1. Program berhenti ditengah jalan
  2. Contoh rangkaian dan sketch tidak jalan
  3. Tegangan referensi bersama
  4. Hasil pembacaan sensor analog tidak konsisten
  5. Jalannya program tersendat
  6. Pembacaan detik yang berulang pada RTC
  7. Modul serial tidak bisa berkomunikasi
  8. Data dari komunikasi melalui internet tidak lengkap
  9. Arduino kekurangan power
  10. Kesalaham umum sketch/program
  11. kondisi if..else tidak bekerja di dalam loop()
  12. Interupsi bertumpuk dan terabaikan
  13. Variabel tidak berubah didalam blok interupsi
  14. Arduino me-reset saat relay berubah keadaan
  15. Upload sketch gagal

Para perancang Arduino sering menghadapi masalah dalam mengembangkan sistem berbasis arduino, maka sebelum melakukan perakitan arduino pastikan hal sepele berikut :

  1. Pastikan kabel jumper tersambung antara ujung-ujungnya.
  2. Komponen tidak rusak/cacat secara fisik
  3. Power supply / baterai / adaptor tersambung dengan benar (sesuai polaritas dan tegangan)

Sebelum memulai merakit arduino Juga perlu diperhatikan jalur internal pin-pin di papan/board arduino yang terhubung secara fisik.

  1. Antara pin A0-A5 (A0 – A8 pada mega) dan pin 0  – 5 (0 – 8 pada mega) adalah berbeda.
  2. Pin TWI/I2C (SCL dan SDA) dan SPI (SCK, MOSI, MISO) terhubung seperti gambar berikut:

    Apabila salah satu pin telah digunakan, maka pasangannya tidak lagi bisa digunakan sebagai pin (kecuali keperluan sambungan tambahan).

berikut ini adalah beberapa permasalahan yang sering muncul dalam perancangan sistem otomatis berbasis arduino:

Program berhenti ditengah jalan

Perangkat berjalan normal tetapi terhenti setelah menyelesaikan tugasnya. dan tidak bisa menjalankan perintah lainnya. Hal ini terjadi karena didalam sketch terdapat baris berikut:

1
2
3
while(1);
atau
for(;;);

baris sketch ini akan menghentikan jalannya program (kecuali interrupt), biasanya disisipkan oleh perancang untuk melihat hasil dan membuat perangkat selesai melakukan tugasnya dan berhenti dititik itu.
dengan menghapus baris tersebut maka program akan kembali berjalan dan menjalankan baris perintah berikutnya.

Contoh rangkaian dan sketch tidak jalan

Rangkaian dan sketch dibuat serupa tanpa perubahan tetapi perangkat tidak berkerja.

Dalam merakit rangkaian, –utamakan– defenisi poisisi pin dari sketch yang akan di upload. contohnya kode berikut berarti pin sensor berada dan pin nomor 2:

1
2
#define sensor 2
int sensor = 2;

Tegangan referensi bersama

Groung/polaritas negatif yang tidak terhubung mengakibatkan intepretasi yang berbeda terhadap suatu nilai.

Membangun sebuah sistem digital atau sistem analog yang terhubung dengan beberapa perangkat lain harus memiliki tegangan referensi yang sama (biasanya ground/negatif) kecuali wireless.

Hasil pembacaan sensor analog tidak konsisten

Pembacaan sensor analog melalui pin A0-A5 (A0-A8 pada mega) menggunakan perintah analogRead(pin), hasil berubah-ubah padahal sensor mengukur sesuatu yang diam.

Pembacaan analog dengan Arduino menggunakan ADC. ADC pada Arduino sendiri memiliki spesifikasi yang harus dipenuhi seperti dalam datasheetnya, beberapa penyebab yang sering terjadi adalah:

  1. Tegangan sumber (power supply) ke Arduino dan sensor tidak stabil.
  2. Resistansi yang besar, bisa diakibatkan
  • Jarak sensor dan pin dengan kabel yang panjang.
  • kabel memiliki resistansi besar.
  • Koneksi konektor yang tidak bagus (tidak kontak sempurna) karena longgar atau karatan.
  • interferensi sinyal lain (sinyal yang bersebelahan, jala listrik, sinyal handphone dll)

Jalannya program tersendat

penyebab umum jalannya program arduino lambat dan tersendat:

  1. Delay sering digunakan, namun sebenarnya pengunaan perintah delay yang berlebihan sangat merugikan karena
    • Menyita kinerja CPU
    • Melewatkan adanya permintaan dari modul/komponen luar yang ingin segera ditanggapi.
  2. Interupsi yang berlangsung tanpa disadari seperti penggunaan library yang sebenarnya mengandung interupsi.
  3. Perulangan seperti for, do, while yang berlangsung terus menerus, sebaiknya lebih diefesien lagi dan keluar dengan perintah ‘break’ jika persyaratannya telah terpenuhi.

Pembacaan detik yang berulang pada RTC

RTC digunakan sebagai penedia data waktu real time, namun kesalahan yang sering terjadi adalah ketika menunggu adanya perubahan data dari RTC (detik), pembacaan dilakukan berulang-ulang ke RTC.

Jika dicermati RTC juga memiliki fitur interupsi yang memberii tahu CPU bahwa adanya perubahan data. Ketika CPU Arduino mendapat interupsi ini barulah dilakukan pembacaan data RTC.

Modul serial tidak bisa berkomunikasi

Beberapa baudrate yang direkomendasikan : 300, 1.200, 2.400, 4.800, 9.600, 19.200, 38.400, 57.600, 74.880, 115.200, 230.400, 250.000, 500.000, 1.000.000, 2.000.000. Pemilihan baudrate berdasarkan :

  1. Spesifikasi modul yang akan berkomunikasi dengan Arduino. beberapa modul memiliki fitur ‘auto Baudrate’
  2. Tingkat kesalahan data, hal ini berkaitan dengan frekuensi CPU arduino, batas yang dizinkan adalah 0.5%.
    yang dihitung menggunakan rumus :
    error(%) = ((baudrate sebenarnya/badudrate )- 1) * 100%
  3. Baud rate yang rendah akan menyebabkan waktu tunda (delay) yang lebih banyak, seringkali hal ini tidak disadari dan menyebabkan baris perintah lain terlambat untuk dieksekusi.
    untuk menghitung waktu yang dibutuhkan serial dalam mengirim data (1 start bit, 8 data, 1 parity, 1stop bit) digunakan formula:Waktu(detik) = (1/baudrate * 11) * jumlah datasebagai contoh untuk mengirim 100 karakter pada baud rate 9600 dalam mode asynchronous membutuhkan waktu ±1  detik

Data dari komunikasi melalui internet tidak lengkap

Akses Arduino bisa dilakukan menggunakan ethernet, Wifi, Modem. Kesalahan umumnya adalah data yang diterima tidak lengkap, terpotong, kacau. kemungkinan yang terjadi adalah :

  1. Koneksi terganggu, perbaiki pengkabelan dan periksa apakah koneksi ke internet berjalan dari perangkat lain.
  2. Upaya menampilkan hasil data yang diterima melalui komunikasi serial.
    • naikkan baudrate misal Serial.begin(115200) untuk mengurangi waktu bagi komunikasi serial
    • Simpan data yang diterima dalam variabel string, dan tampilkan melalui serial setelah komunikasi internet selesai.

Arduino kekurangan power

Arduino memiliki internal regulator tegangan 5V dan 3.3V, dengan kemampuan arus 0.8-1A. keluaran dari regulator ini digunakan oleh Arduino sendiri dan sisanya melalui pin power. Jika sumber tegangan ini juga digunakan oleh modul-modul diluar arduino, maka pastikan itu mencukupi (sesuai spesifikasi) untuk memperoleh kinerja maksimal.

Kesalaham umum sketch/program

Dalam membuat sketch/koding/program/listing program dengan IDE Arduino kita harus mengikuti gaya bahasa C++, dan aturan gaya bahasa serta logika program yang sering terlewatkan adalah :

  1. Tanda titik koma (semicolon) pada setiap akhir perintah.
  2. Tanda kurung (parentheses) dan kurung kurawal (curly bracket) haruslah berpasangan.
  3. Penamaan variabel pada C++ bersifat case-sensitive, yang berarti perbedaan kapitalisasi huruf berarti beda variabel.
  4. Variabel global dan variabel local dengan nama yang sama sebaiknya dihindari.
  5. Tipe data antara signed dan unsigned harus menjadi perhatian khusus, karena akan menghasilkan logika matematika berbeda pada operasi tertentu.
  6. Variabel dengan bilangan berkoma (floating point) akan tersimpan sebagai bilangan digital basis 2 yang kadang berbeda (dibulatkan).

kondisi if..else tidak bekerja di dalam loop()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void setup() {
  pinMode(12, INPUT_PULLUP);//Tombol
  pinMode(13, OUTPUT);//LED
}
void loop() {
  if(digitalRead(12))
  {
    digitalWrite(13, HIGH);
  }
  else
  {
    digitalWrite(13, HIGH);
    delay(1000);
    digitalWrite(13, LOW);
  }
}

dari sketch diatas kita mengharapkan ketika tombol di pin 12 ditekan maka LED akan hidup terus, dan ketika dilepas LED akan hidup selama 1 detik kemudian mati.

Namun setelah dirunning ternyata LED terus hidup dan tidak pernah mati. kondisi ini disebut dengan “false loop”, karena sebenarnya kondisi dalam blok else selalu dijalakan karena berada didalam operasi loop().

Interupsi bertumpuk

Interupsi akan memotong jalannya program biasa untuk mengeksekusi baris yang ada dalam blok interupsi dan tidak dapat diinterupsi lagi. Apabila terjadi interupsi lain yang berbeda sebelum sebuah interupsi selesai/keluar (reti) maka interupsi lain itu harus menunggu.

Apabila sebuah interupsi berjalan dan terjadi kejadian interupsi yang sama lagi maka interupsi kedua ini akan dibatalkan (selama flag interupsi masih aktif).

Untuk interupsi yang sering terjadi dan dalam jeda yang singkat, maka baris program yang ada di badan interupsi haruslah sesingkat mungkin, baris program dihitung dalam satuan baris assembler misalnya satu baris “Serial.println();” akan menghasilkan lebih dari satu baris assembler.

Jika badan interupsi harus memiliki baris program yang besar, maka sebaiknya badan interupsi hanya menghasilkan flag, dan flag ini akan dibaca oleh baris program reguler untuk dieksekusi lebih lanjut.

Variabel tidak berubah didalam blok interupsi

Apabila interupsi digunakan untuk merubah keadaan/nilai sebuah variabel, maka variabel tersebut harus dideklarasikan dengan properti volatile.

Proses compile sketch menjadi bahasa mikrokontroller juga menjalankan fungsi optimalisasi, artinya baris program yang menurut compiler tidak efektif/sia-sia akan diabaikan, kecuali variabel dengan properti volatile (tetap diperhitungkan).

Arduino me-reset saat relay berubah keadaan

Relay merupakan komponen elektro mekanik yang memiliki koil (lilitan) untuk menggerakkan tuas kontak. Dalam operasional relay menghasilkan spike (kejut listrik) yang dihasilkan oleh:

  1. Koil, memiliki induktansi yang berpengaruh terhadap laju arus/detik, saat koil diberi tegangan maka koil akan dialiri arus sesaat yang besar sedangkan ketika di nonaktifkan relay akan menghasilkan arus sesaat yang besar dalam arah berlawanan (minus).
    Arus sesaat yang besar ini bisa mengakibatkan terjadinya kejut listrik diseluruh rangkaian nya.
  2. Kontak listrik, berlaku seperti saklar (switch) dimana semakin besar arus beban yang diputus/disambungkan maka akan semakin besar pula kemungkinan terjadinya bunga api, yang juga berpotensi besar menghasilkan kejut listrik.

Upaya pemecahan permasahan kontak relay ini bisa dilakukan dengan cara:

  1. Gunakan kabel berkualitas
  2. batasi arus ke koil dengan penambahan hambatan (resistor) yang sesuai
  3. Gunakan power supply yang bagus (dayanya cukup saat beban max) dan dilengkapi EMI filter (perlindungan dari gangguan luar)
  4. Pemisahan power supply arduino dan relay serta beban-beban besar
  5. Relay dilengkapi flyback dioda (seperti 1N4048)
  6. Lindungi kabel power dari EMI (twist, shielding)
  7. Lengkapi decoupling kapasitor sedekat mungkin ke pin power.
  8. Lindungi kabel komponen sensitif dari EMI (twist yang rapi) kabel clock diutamakan.
  9. tambahkan decoupling/filter kapasitor (1-100nf) di clock komponen sensitif
  10. saat relay bekerja, komponen sensitif dalam keadaan read mode
  11. Pisahkan jalur kabel daya dan kontrol, beda ducting.
  12. kabel antara Arduino dan komponen sensitif sedekat mungkin.
  13. firmware trick.

Upload sketch gagal

Sebelum mengupload sketch ke arduino pastikan memlih board dan processor serta port (dalam menu Tools) yang sesuai dengan board Arduino yang terpasang. Pastikan juga kabel usb dalam keadaan baik.

Masalah yang kerap terjadi saat proses upload adalah:

  1. Bentrok dengan Serial, arduino melakukan proses upload memanggunakan pin Serial (pin 0 dan 1) apabila pin tersebut juga digunakan untuk keperluan lain dapat dipastikan akan terjadi interferensi data.
  2. Gangguan juga bisa ditimbulkan oleh komponen/modul lain yang bekerja/berubah keadaan dan menyebabkan tegangan tidak stabil.
  3. Port Serial di PC/laptop digunakan oleh program lain seperti processing, putty atau serial monitor dari arduino IDE yang tidak se-gruop.

Membaca RTC DS1307 menggunakan interupsi SQW

RTC DS1307 memiliki pin keluaran/output SQW. Pin SQW berfungsi sebagai pembangkit sinyal digital yang frekuensinya bisa diatur pada 1, 4.096, 8.192, 32.768Hz.

Keluaran ini bisa dimanfaatkan oleh mikrokontroller untuk mendeteksi perubahan detik jika SQW diatur pada frekuensi 1Hz (saat pin SQW kondisi high).

penggunaan interupsi dalam mikrokontroller sangat bermanfaat karena:

  1. Menghentikan program yang sedang berjalan dan segera menjalankan baris program interupsi.
  2. Mengaktifkan mikrokontroller dari posisi sleep().
  3. Tidak memakai sumberdaya mikrokontroller, tidak seperti perintah delay() yang menyebabkan mikrokontroller melakukan proses perulangan di satu titik.

Kombinasi interupsi dan sleep() menjadikan kinerja mikrokontroler lebih efisien (hemat sumberdaya). Namun juga perlu diperhatikan bahwa penggunaan interupsi akan menghambat baris program lain, jadi pergunakan fungsi interupsi secepat mungkin.

fungsi interupsi SQW pada DS1307/interupsi SQW pada DS3231 adalah memliki register kontrol yang sama.

daftar interupsi pinChange:

  1. ISR (PCINT0_vect) pin change interrupt untuk D8 sampai D13
  2. ISR (PCINT1_vect) pin change interrupt untuk A0 sampai A5
  3. ISR (PCINT2_vect) pin change interrupt untuk D0 sampai D7

Skema RTC DS1307/DS3231 hemat energi dengan arduino:

berikut ini contoh sketch/program dari penggunaan RTC DS1307 menggunakan metode  interupsi:

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
#include <Wire.h>
#include <TimeLib.h>
#include <DS1307RTC.h>
#include <avr/sleep.h>
 
byte SQWPin = A3;
volatile bool interupsiDetik;
 
void setup() {
  Serial.begin(9600);
  Serial.println("Membaca DS1307 dengan metode interupsi SQW");
  Serial.println("https://www.project.semesin.com");
 
  //Mengaktifkan Pin SQW keluaran 1Hz pada DS1307
  Wire.beginTransmission(0x68);
  Wire.write((uint8_t)0x07);
  Wire.write(0x10);
  Wire.endTransmission();
 
  ////Mengaktifkan Pin SQW keluaran 1Hz pada DS3231
  //Wire.beginTransmission(0x68);
  //Wire.write((uint8_t)0x0E);
  //Wire.write(0x1C);
  //Wire.endTransmission();
 
  //Pendeteksi interupsi
  *digitalPinToPCMSK(SQWPin) |= bit (digitalPinToPCMSKbit(SQWPin));
  PCIFR  |= bit (digitalPinToPCICRbit(SQWPin));
  PCICR  |= bit (digitalPinToPCICRbit(SQWPin));
 
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);
  sleep_enable();
}
 
ISR (PCINT1_vect)
{
  if(digitalRead(SQWPin))
  {
    interupsiDetik = true;
  }
  
void loop() {
  tmElements_t tm;
  if (interupsiDetik)
  {
    interupsiDetik = false;
 
    RTC.read(tm);
    Serial.print("Time = ");
    print2digits(tm.Hour);
    Serial.write(':');
    print2digits(tm.Minute);
    Serial.write(':');
    print2digits(tm.Second);
    Serial.print(", Date (D/M/Y) = ");
    Serial.print(tm.Day);
    Serial.write('/');
    Serial.print(tm.Month);
    Serial.write('/');
    Serial.print(tmYearToCalendar(tm.Year));
    Serial.println();
  }
 
  sleep_mode();
}
 
void print2digits(int number) {
  if (number >= 0 && number < 10) {
    Serial.write('0');
  }
  Serial.print(number);
}

Pengaturan alarm dengan arduino dan RTC DS1307 melalui 4 tombol

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

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

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

breadboard:

komponen yang digunakan:

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

sketch/program:

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

 

I2C scanner

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

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

alamat tulis I2C yang umum:

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

Library:

Linear-feedback shift register (LFSR) dengan arduino

LFSR (linear-feedback shift register) adalah metode matematis untuk menghasilkan sebuah bilangan yang linear dengan bilangan sebelumnya.

Fungsi matematis ini digunakan sebagai:

  1. menghasilkan bilangan acak (random generator)
  2. Menghasilkan bilangan tersusun yang berulang sehingga bisa dimanfaatkan sebagai pembangkit suara gangguan (noise) seperti di tv/radio dengan siaran acak ketika tidak siaran.

sketch/program arduino LFSR:

metode Fibonacci

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
uint16_t LFSRBuffer;
 
void setup() {
  Serial.begin(9600);
  Serial.println("LFSR metode Fibonacci");
  Serial.println("https://www.project.semesin.com");
   
  uint16_t nilaiAwal = analogRead(0);
  LFSRFibonacci(nilaiAwal);
  //LFSRFibonacci(100);
}
 
void loop() {
  uint16_t bilanganLFSR = LFSRFibonacci();
  Serial.println(bilanganLFSR);
 
  delay(1000);
}
 
void LFSRFibonacci(uint16_t nilaiAwal)
{
  LFSRBuffer = nilaiAwal;
}
 
uint16_t LFSRFibonacci()
{
    uint16_t bit;
     
    bit  = ((LFSRBuffer >> 0) ^ (LFSRBuffer >> 2) ^ (LFSRBuffer >> 3) ^ (LFSRBuffer >> 5)) & 1;
    LFSRBuffer =  (LFSRBuffer >> 1) | (bit << 15);
    return LFSRBuffer;
}

metode Galois

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
uint16_t LFSRBuffer;
 
void setup() {
  Serial.begin(9600);
  Serial.println("LFSR metode Galois");
  Serial.println("https://www.project.semesin.com");
   
  uint16_t nilaiAwal = analogRead(0);
  LFSRGalois(nilaiAwal);
  //LFSRGalois(100);
}
 
void loop() {
  uint16_t bilanganLFSR = LFSRGalois();
  Serial.println(bilanganLFSR);
 
  delay(1000);
}
 
void LFSRGalois(uint16_t nilaiAwal)
{
  LFSRBuffer = nilaiAwal;
}
 
uint16_t LFSRGalois()
{
    unsigned lsb = LFSRBuffer & 1;
    LFSRBuffer >>= 1;
    if (lsb)
    {
        LFSRBuffer ^= 0xB400;
    }
    return LFSRBuffer;
}

Trik menyimpan bilangan random dengan arduino

Dengan arduino kita bisa menghasilkan bilangan acak (random generator) dengan menggunakan sketch/program:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
long randNumber;
 
void setup(){
  Serial.begin(9600);
  Serial.println("Menyimpan bilangan acak/random");
  Serial.println("https://www.project.semesin.com");
 
  randomSeed(analogRead(0));
}
 
void loop() {
  // print bilangan acak dari 0 hingga 299
  randNumber = random(300);
  Serial.println(randNumber);
 
  delay(1000);
}

Nilai acak/random yang dihasilkan oleh mesin digital seperi arduino tidaklah sepenuhnya acak, karena secara pandang digital diperlukan metode matematis (contohnya LFSR – linear-feedback shift register) dengan menerapkan suatu persamaan dimana bilangan berikutnya dihitung dari bilangan yang ada sekarang.

Dengan demikian nilai random yang dihasilkan merupakan perulangan terus menerus dan berulang. Agar deretan acak ini menghasilkan deretan berbeda setiap waktu, maka diberikan nilai awal (seed). salah satu contoh pepuler adalah perintah analogRead(pin):

1
2
nilaiAwal = analogRead(0);
randomSeed(nilaiAwal);

Untuk kembali ke bilangan sebelumnya kita bisa menyimpan deret bilangan ke dalam array, namun tidak efisien untuk jumlah bilangan yang besar. Untuk itu kita bisa menggunakan trik yaitu dengan melakukan perulangan dengan memberi nilai awal (seed) yang sama.

contohnya seperti sketch berikut:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
long randNumber;
uint16_t nilaiAwal;
 
void setup(){
  Serial.begin(9600);
 
  nilaiAwal = analogRead(0);
  randomSeed(nilaiAwal);
}
 
void loop() {
  randNumber = ambilDeretAcak(nilaiAwal, 100, 300);
  Serial.println(randNumber);
   
  delay(1000);
}
 
uint16_t ambilDeretAcak(uint16_t nilaiawal, uint16_t urutan, uint16_t nilaiAcakMaksimal)
{
  uint16_t nilaiAcak;
 
  randomSeed(nilaiawal);
  for(uint16_t i=0;i<urutan;i++)
  {
    nilaiAcak = random(nilaiAcakMaksimal);
  }
  return nilaiAcak;
}

fungsi ambilDeretAcak akan menghasilkan bilangan yang berada di urutan tertentu dalam deret acak dengan nilai awal tertentu.

Konversi penanggalan Masehi ke Hijriah menggunakan Arduino

Penanggalan masehi mengacu pada peredaran matahari, satu tahun masehi terhitung sebesar 365,25 hari, sedangkan Kalender hijriah mengacu pada peredaran bulan, waktu 12 kali peredaran bulan terhitung sebesar 354,367068 hari.
Untuk konversi masehi ke hijriah mengikuti kaidah berikut ini :

  1. Basis perhitungan Masehi ditetapkan pada 18 April 1999.
  2. Basis perhitungan Hijriah ditetapkan pada 1 Muharram 1420.
  3. Jumlah hari dalam satu bulan Hijriah adalah: 30, 29, 30, 29, 30, 29, 30, 29, 30, 29, 30, 29(30).
  4. Berlaku dari jam 00.00 hingga waktu Maghrib karena penanggalan Hijriah berganti hari pada waktu Maghrib

penerapan dalam Arduino bisa menggunakan program/sketch berikut ini:

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
double tahunBulan = 354.367068;
double tahunMatahari = 365.25;
 
String namaBulanHijriah[] = {"Muharram","Safar","Rabiul awal","Rabiul akhir","Jumadil awal","Jumadil akhir","Rajab","Sya'ban","Ramadhan","Syawal","Dzulkaidah","Dzulhijjah"};
String namaBulanMasehi[] = {"Januari","Februari","Maret","April","Mei","Juni","Juli","Agustus","September","Oktober","November","Desember"};
uint16_t jumlahHariPerBulanHijriah[] = {0,30,59,89,118,148,177,207,236,266,295,325,354};
uint16_t jumlahHariPerBulanMasehi[]={0,31,59,90,120,151,181,212,243,273,304,334};
 
void setup() {
  Serial.begin(9600);
  Serial.println("Konversi Penanggalan Masehi ke Hijriah");
  Serial.println("https://www.project.semesin.com");
}
 
void loop() {
  uint32_t jumlahHari;
  double jumlahHariMatahari;
   
  byte tanggalMasehi = 16;
  byte bulanMasehi = 3;
  uint16_t tahunMasehi = 2018;
 
  byte tanggalHijriah;
  byte bulanHijriah;
  uint16_t tahunHijriah;
 
  jumlahHari = jumlahHariDariTanggal(tanggalMasehi, bulanMasehi, tahunMasehi - 2000);
  masehiKeHijriah(jumlahHari, &tanggalHijriah, &bulanHijriah, &tahunHijriah);
 
  Serial.print(tanggalMasehi);
  Serial.print(" ");
  Serial.print(namaBulanMasehi[bulanMasehi-1]);
  Serial.print(" ");
  Serial.print(tahunMasehi);
 
  Serial.print(" == ");
 
  Serial.print(tanggalHijriah);
  Serial.print(" ");
  Serial.print(namaBulanHijriah[bulanHijriah-1]);
  Serial.print(" ");
  Serial.println(tahunHijriah);
 
  while(1);
}
 
//tanggal mulai dari 1
//bulan mulai dari 1
//tahun dua digit
//minggu = 1, sabtu = 7
//base 18 April 1999
uint32_t jumlahHariDariTanggal(byte tanggal, byte bulan, uint16_t tahun)
{
  uint32_t jumlahHari = (uint32_t)tahun * 365;
  for (uint16_t i = 0; i < tahun; i++)
  {
    if (!(i%4))
    {
      jumlahHari++;
    }
  }
  jumlahHari += jumlahHariPerBulanMasehi[bulan-1];
  if ( (bulan >= 2) && !(tahun % 4))
  {
    jumlahHari++;
  }
  jumlahHari+= tanggal;
  return jumlahHari + 259;// base 18 April 1999
}
 
void masehiKeHijriah(uint32_t HariMasehi, byte *tanggal, byte *bulan, uint16_t *tahun)
{
  uint16_t sisaHari;
  *tahun = floor(HariMasehi/tahunBulan);
  sisaHari = HariMasehi - (tahunBulan * *tahun);
 
  for(byte i=0;i<sizeof(jumlahHariPerBulanHijriah);i++)
  {
    if(sisaHari <= jumlahHariPerBulanHijriah[i])
    {
      sisaHari -= jumlahHariPerBulanHijriah[i-1];
      *bulan = i;
      break;
    }
  }
  *tanggal = sisaHari;
  *tahun += 1420;
}

hasil keluaran di serial monitor:

Catatan : metode ini memiliki kekurangan yaitu menghitung penanggalan Hijriah dengan jumlah bulan yang tetap (hanya bagus untuk mengenal prinsip konversi) untuk konversi yang lebih presisi bisa menggunakan metode Julian Date :
Konversi masehi ke Pasaran Jawa dan Hijriah dengan metode Julian Date

Komunikasi dua arah Arduino dengan Web Browser menggunakan MySQL, XAMPP/web hosting dan ESP8266

Untuk komunikasi jarak jauh atau komunikasi tanpa kabel menggunakan Arduino bisa menggunakan ESP8266 (wifi shield) yang akan menghubungkan arduino ke internet/jaringan lokal. Disamping itu harus pula dibangun server yang berfungsi sebagai penyedia layanan sehingga sistem komunikasi bisa berjalan timbal balik. Dalam server juga dibutuhkan media untuk merekam komunikasi tersebut, salah satu yang populer adalah database MySQL. Ini adalah salah satu cara menghubungkan arduino dengan database yang paling efisien.

Menghubungkan MySQL – Arduino dibutuhkan bahasa php sebagai penerjemah query (bahasa database), baik permintaan (GET request) dari arduino – MySQL dan web browser – MySQL. Jika skema ini sudah terbangun maka kita bisa mengkomunikasikan arduino – web browser (lokal / internet).

Menyimpan data dari arduino ke mysql esp8266 bisa dilaksanakan dengan cara ini, data dari arduino ditransmisikan melalui jaringan wifi dan diterima oleh web server. Data tersebut kemudian di proses oleh php dan juka diizinkan maka data tersebut akan disimpan dalam database.

Mengirim perintah dari browser ke arduino dengan esp8266 juga dapat dilakukan dengan cara sebaliknya.

Webserver yang digunakan dalam perancangan ini adalah XAMPP di PC lokal dan jasa server hosting.

Langkah perancangannya sebagai berikut:

  1. Merangkai Arduino + ESP8266
  2. Membuat sketch Arduino untuk mengirim dan menerima data dari database
  3. Konfigurasi koneksi ESP8266 ke access point wifi (AP)
  4. Install XAMPP server dan mengaktifkannya
  5. Untuk web server hosting, membuat database, user account dan priveleged-nya
  6. Membuat program php, dariArduino.php, keArduino.php, dariBrowser.php serta program php pendukung.

Arduino + ESP8266

Rangkaian yang digunakan:

Diagram:

Untuk menghubungkan arduino dengan jaringan, salah satu yang bisa digunakan adalah modul wifi shiel ESP8266. kali ini saya menggunakan library “WiFiEsp.h”.

Catatan, untuk terhubung ke web hosting, pastikan wifi terhubung ke internet (bridge connection)

sebelum menggunakannya konfigurasi dahulu modul tersebut, editlah bagian berikut:

1
2
3
4
char ssid[] = "ArduinoMySQL";        // Isi dengan nama profil Wifi
char pass[] = "12345678";            // password wifi
//char server[] = "192.168.123.1";     // alamat access point yang
char server[] = "semesin.com";     // alamat server hosting

sketch atau program berikut memiliki fitur:

  1. Menerima masukan string/text dari serial monitor dan mengirimkannya ke webserver untuk disimpan ke database MySQL.
  2. Menerima data perintah dari webserver dalam jangka waktu tertentu contoh kali ini setiap 5 detik.

sketch atau program lengkapnya sebagai berikut:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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
#include "WiFiEsp.h"
 
char ssid[] = "ArduinoMySQL";        // Isi dengan nama profil Wifi
char pass[] = "12345678";            // password wifi
//char server[] = "192.168.123.1";     // alamat access point yang telah terinstall XAMPP local host
char server[] = "semesin.com";     // alamat web hosting
 
char namaVariabel[] = "Variabel";
String text = "";
String Respon = "";
bool responDariServer = false;
 
bool statusKomunikasiWifi = false;
long waktuMulai;
long waktuMintaData = 5000; //minta data setiap 5000ms
 
WiFiEspClient client;
int status = WL_IDLE_STATUS;
 
void setup()
{
  Serial.begin(9600);
  Serial.println("Koneksi arduino dengan mySql menggunakan ESp8266 dan XAMPP");
  Serial.println("Ketik pesan yang akan dikirim (pastikan setting serial ke \"both NL & CR\")");
  Serial.println("https://www.project.semesin.com");
  Serial.println();
 
  Serial1.begin(115200);
  WiFi.init(&Serial1);
 
  // check for the presence of the shield
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // don't continue
    while (true);
  }
 
  // attempt to connect to WiFi network
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to WPA SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network
    status = WiFi.begin(ssid, pass);
  }
 
  // you're connected now, so print out the data
  Serial.println("You're connected to the network");
   
  printWifiStatus();
  waktuMulai = millis();
}
 
void loop()
{
  //tunggu imputan nilai dari untuk dikirim ke server
  while(Serial.available())
  {
    char c = Serial.read();
    if((c != '\r') && (c != '\n'))
    {
      text += c;
    }
    if(c == '\n')
    {
      statusKomunikasiWifi = kirimKeDatabase("dataDariSerial",text);
      text = "";
      waktuMulai = millis();
    }
  }
 
  if(waktuMintaData < millis() - waktuMulai)
  {
    statusKomunikasiWifi = ambilDatabase("perintah");
    waktuMulai = millis();
  }
   
  // periksa respon dari server
  if(statusKomunikasiWifi)
  {
    // if there are incoming bytes available
    // from the server, read them and print them
    while (client.available())
    {
      char c = client.read();
      Respon += c;
    }
   
    // if the server's disconnected, stop the client
    if (!client.connected()) {
      Serial.println("Disconnecting from server...");
      client.stop();
      statusKomunikasiWifi = false;
      responDariServer = true;
    }
  }
 
  // penanganan data yang diretima dari server
  if(responDariServer)
  {
    responDariServer = false;
    //Serial.println(Respon);
    int posisiData = Respon.indexOf("\r\n\r\n");
    String Data = Respon.substring(posisiData+4);
    Data.trim();
 
    String variabel;
    String nilai;
 
    Serial.println("Data dari server");
    posisiData = Data.indexOf('=');
    if(posisiData > 0)
    {
      variabel = Data.substring(0,posisiData);
      nilai = Data.substring(posisiData+1);
   
      //===========Penanganan respon disini
      Serial.print(variabel);
      Serial.print(" = ");
      Serial.println(nilai);
    }
    Respon = "";
  }
}
bool ambilDatabase(String variabel)
{
  Serial.println();
  Serial.println("Starting connection to server...");
  // if you get a connection, report back via serial
  if (client.connect(server, 80)) {
    Serial.println("Connected to server");
    // Make a HTTP request
    client.print("GET /arduino_mysql/keArduino.php?variabel=");
    client.print(variabel);
    client.println(" HTTP/1.1");
    client.print("Host: ");
    client.println(server);
    client.println("Connection: close");
    client.println();
 
    long _startMillis = millis();
    while (!client.available() and (millis() - _startMillis < 2000));
 
    return true;
  }
  return false;
}
 
bool kirimKeDatabase(String namaVariabel, String nilai)
{
  Serial.println();
  Serial.println("Starting connection to server...");
  // if you get a connection, report back via serial
  if (client.connect(server, 80)) {
    Serial.println("Connected to server");
    // Make a HTTP request
 
    // parameter 1
    client.print("GET /arduino_mysql/dariArduino.php?");
    client.print("variabel=");
    client.print(namaVariabel);
     
    // parameter 2 dan selanjutnya
    client.print("&");
    client.print("nilai=");
    client.print(nilai);
     
    client.println(" HTTP/1.1");
    client.print("Host: ");
    client.println(server);
    client.println("Connection: close");
    client.println();
 
    return true;
  }
  return 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");
 
  IPAddress gateway = WiFi.gatewayIP();
  Serial.print("gateway:");
  Serial.print(gateway);
  Serial.println(" ");
}

tampilan serial monitor dari arduino:

 

XAMPP webserver + database MySQL

untuk membuat webserver di komputer lokal instal XAMPP (saya menggunakan v3.2.2) atau bundel webserver lain yang termasuk didalamnya MySQL.

untuk memulainya jalankan/aktifkan webserver dan MySQL

 

Web Hosting + Database MySQL

catatan: huruf besar/kecil berpengaruh (case-sensitif)

Server hosting umumnya memiliki fitur kemanan, untuk itu kita harus masuk ke cpanel kemudian membuat sebuah database dengan memilih menu ‘MySQL® Database Wizard‘ dan mengisi nama database, misalnya ‘arduino_mysql’.

selanjutnya ‘next step’ buatlah akun dengan memasukkan nama dan paswword (nama dan password ini akan dimasukkan ke ‘fungction.php’).

selanjutnya prilih privileges yang akan digunakan.

sebagai webserver dan database server yang akan berhubungan timbal balik dengan arduino, maka kita buat halaman web berbasis bahasa PHP dan memiliki fitur:

  1. Menerima data dari Arduino menggunakan metode ‘GET’ dengan parameter ‘variabel’, ‘nilai’, dan ‘status’.
  2. Menyimpan data dari entri data di webserver, dan akan mengirimkannya ke Arduino saat diminta.
  3. Menyedian halaman tampilan database ke halaman web.

fitur-fitur ini saya buatkan dalam beberapa program PHP, untuk menggunakannya extract file Arduino MySQL dan copy ke folder “/arduino_mysql” (untuk XAMPP root folder “C:\xampp\htdocs\arduino_mysql”, untuk web hosting “public_html/arduino_mysql”) dengan program berikut:

file php yang digunakan diuraikan disini:

function.php

sebelum menggunakan file ini edit dahulu bagian sesuai kebutuhan:

1
2
3
4
$servername = "localhost";
$username = "******_Arduino";
$password = "Arduino";
$database = "******_arduino_mysql";

kode lengkap function.php

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
  <?php
 
 function databaseConnect()
  {
    /* XAMPP
    $servername = "localhost";
    $username = "root";
    $password = "";
    $database = "arduino_mysql";
    */
     
    $servername = "localhost";
    $username = "******_Arduino";
    $password = "Arduino";
    $database = "******_arduino_mysql";
     
    // Create connection
    $conn = new mysqli($servername, $username, $password);
 
    // Check connection
    if ($conn->connect_error) {
      die("Connection failed: " . $conn->connect_error);
    }
    echoDebug("Connected successfully<br>");
     
    // Create database
    $sql = "CREATE DATABASE IF NOT EXISTS ".$database;
    if ($conn->query($sql) === TRUE) {
      echoDebug("Database created successfully<br>");
    } else {
      echoDebug("Error creating database: " . $conn->error);
    }
     
    // Connect to database
    $conn = new mysqli($servername, $username, $password, $database);
    // Check connection
    if ($conn->connect_error) {
      die("Database connection failed: " . $conn->connect_error);
    }
    echoDebug("Database connected successfully<br>");
     
    // sql to create table
    $sql = "CREATE TABLE IF NOT EXISTS arduino_data (
    id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    variabel VARCHAR(30) NOT NULL,
    nilai VARCHAR(30) NOT NULL
    )";
     
    if ($conn->query($sql) === TRUE) {
      echoDebug("Table arduino_data created successfully</br>");
    } else {
      echoDebug("Error creating table: " . $conn->error);
    }
    // sql to create table
    $sql = "CREATE TABLE IF NOT EXISTS browser_data (
    id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    variabel VARCHAR(30) NOT NULL,
    nilai VARCHAR(30) NOT NULL
    )";
     
    if ($conn->query($sql) === TRUE) {
      echoDebug("Table arduino_data created successfully</br>");
    } else {
      echoDebug("Error creating table: " . $conn->error);
    }
    return $conn;
  }
  function echoDebug($message)
  {
    // hapus komen '//' jika ingin men-debug pesan
    //echo $message;
  }
?>

index.php

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
<?php
  include("function.php");
   
  $conn = databaseConnect();
 
  if(isset($_GET['message']))
  {
    echo $_GET['message'];
    echo "<br>";
    echo "<br>";
  }
  $sql = "SELECT * FROM arduino_data";
  $result = $conn->query($sql);
 
  echo "<html>";
  echo "<head>";
  echo "<meta http-equiv='refresh' content='10'>";
  echo "</head>";
  echo "<body>";
  echo "Arduino Data";
  echo "<table border='1'>";
  echo "<tr>";
  echo "<td width='50'>id</td><td width='100'>Variabel</td><td width='200'>Nilai</td>";
  echo "</tr>";
  if ($result->num_rows > 0) {
    // output data of each row
    while($row = $result->fetch_assoc()) {
      echo "<tr>";
      echo "<td>".$row["id"]."</td><td>".$row["variabel"]."</td><td>".$row["nilai"]. "</td>";
      echo "</tr>";
    }
  } else {
    echo "<td colspan='3'>";
    echo("tidak ada hasil");
    echo "</td>";
  }
  echo "</table>";
   
  echo "<form action='dariBrowser.php' method=GET>";
  echo "<input type='hidden' name='aksi' value='hapus'><br>";
  echo "<input type='submit' value='Hapus semua data'>";
  echo "</form>";
 
  echo "<br>Kirim data ke Arduino<br>";
  echo "<form action='dariBrowser.php' method=GET>";
  echo "Nama variabel:<br><input type='text' name='variabel'><br>";
  echo "Nilai:<br><input type='text' name='nilai'><br>";
  echo "<input type='submit' value='Kirim'>";
  echo "</form>";
  echo "</body>";
  echo "</html>";
 
  $conn->close();
?>

keArduino.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
  include("function.php");
   
  $conn = databaseConnect();
   
  // Kirim respon bila ada
  if(isset($_GET["variabel"]))
  {
    $variabel = $_GET["variabel"];
    $sql = "SELECT * FROM browser_data WHERE variabel='".$variabel."'";
 
    if($result = $conn->query($sql))
    {
      $row = $result->fetch_assoc();
      echo $row["variabel"]."=".$row["nilai"];
    }
  }
   
  $conn->close();
?>

dariArduino.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
  include("function.php");
   
  $conn = databaseConnect();
   
  if(isset($_GET["variabel"]) && isset($_GET["nilai"]))
  {
    // Simpan data yang diterima ke database
    $variabel = $_GET["variabel"];
    $nilai = $_GET["nilai"];
 
    $sql = "INSERT INTO arduino_data (variabel, nilai) VALUES ('".$variabel."', '".$nilai."')";
 
    if ($conn->query($sql) === TRUE) {
      echoDebug("New record created successfully</br>");
    } else {
      echoDebug("Error: " . $sql . "<br>" . $conn->error);
    }
  }
  $conn->close();
?>

dariBrowser.php

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
<?php
  include("function.php");
   
  $conn = databaseConnect();
   
  if(isset($_GET["variabel"]) && isset($_GET["nilai"]))
  {
    // Simpan data yang diterima ke database
    $variabel = $_GET["variabel"];
    $nilai = $_GET["nilai"];
     
    $sql = "SELECT * FROM browser_data WHERE variabel='".$variabel."'";
    $result = $conn->query($sql);
 
    if ($result->num_rows > 0)
    {
      $sql = "UPDATE browser_data SET nilai='".$nilai."' WHERE variabel='".$variabel."'";
      if ($conn->query($sql) === TRUE) {
        echoDebug("Record updated successfully</br>");
      } else {
        echoDebug("Error updating record: " . $sql . "<br>" . $conn->error);
      }
    }
    else
    {
      $sql = "INSERT INTO browser_data (variabel, nilai) VALUES ('".$variabel."', '".$nilai."')";
      if ($conn->query($sql) === TRUE) {
        echoDebug("New record created successfully</br>");
      } else {
        echoDebug("Error: " . $sql . "<br>" . $conn->error);
      }
    }
      echo "<script type='text/javascript'> document.location = 'index.php?message=Entri data berhasil'; </script>";
    exit();
  }
  else if(isset($_GET['aksi']))
  {
    if($_GET['aksi'] == "hapus")
    {
      // sql to delete a record
      $sql = "TRUNCATE arduino_data";
 
      if ($conn->query($sql) === TRUE) {
        echoDebug("Record deleted successfully");
      } else {
        echoDebug("Error deleting record: " . $conn->error);
      }
      echo "<script type='text/javascript'> document.location = 'index.php?message=database telah dikosongkan'; </script>";
      exit();
    }
  }
  $conn->close();
?>

Cara penggunaan

  • Nyalakan wifi (pastikan terhubung ke internet)
  • Masukkan perintah dari serial monitor, data akan tercatat dalam tabel ‘arduino_data’, dalam contoh ini nama variabelnya adalah ‘dataDariSerial’ dengan nilai sesuai dengan entry dari Serial monitor (pastikan setting serial ke “both NL & CR”)
  • Buka halaman “localhost/arduino_mysql/” atau “**nama server**/arduino_mysql/” di browser untuk melihat data yang dikirim dari arduino.
  • Masukan perintah dari formulir di halaman web, dan klik kirim untuk mengirim data ke Arduino, (dalam contoh ini arduino membaca variabel ‘perintah’ jadi masukkan nama variabel sebagai ‘perintah’ serta isikan juga kotak ‘nilai’nya)
  • Arduino akan membaca perintah setiap 5 detik dan akan dilaporkan di Serial monitor.

tampilan halaman web:

library : WiFiEsp.zip

Koneksi Arduino dan Android melalui bluetooth dan MIT App Inventor

Bluetooth dan Arduino bisa digunakan untuk berkomunikasi dengan Android menggunakan MIT App Inventor, berikut langkahnya:

Arduino + bluetooth

Mempersiapkan rangkaian yang terdiri dari Arduino mega dan modul bluetooth HC-05.

Masukkan program atau sketch berikut

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
String text = "";
void setup() {
  Serial.begin(9600);
  Serial1.begin(9600);
 
  Serial.println("Koneksi arduino dengan app inventor melalui bluetooth");
  Serial.println("Ketik pesan yang akan dikirim (pastikan setting serial ke \"both NL &amp; CR\"");
  Serial.println("https://www.project.semesin.com");
}
 
void loop() {
  while(Serial.available())
  {
    char c = Serial.read();
    text += c;
    if(c == '\n')
    {
      Serial1.print(text);
      text = "";
    }
  }
  while(Serial1.available())
  {
    Serial.print(char(Serial1.read()));
  }
}

Sketch ini akan menerima text dari “Serial Monitor” dan meneruskannya ke sambungan bluetooth

Begitu juga apabila ada data yang masuk melalui hubungan bluetooth akan ditampilkan ke Serial monitor.

 

Android + App Inventor

Instal apk ini di android BluetoothConnection.apk

Atau bisa mengedit Design MIT App Inventor berikut BluetoothConnection.aia

Design:

Block :

Blok inisialisasi merupakan block yang pertama kali dipanggil ketika aplikasi dijalankan, Jika bluetooth tidak aktif maka blok ini akan memberikan peringatan dan jika bluetooth aktif maka daftar perangkat bluetooth yang terhubung dimasukkan dalam daftar (list)

Blok buttonConnect.Click memiliki dua fungsi yaitu menghubungkan bluetooth dengan perangkat arduino dan memutuskan koneksi bluetooth. Jika bluetooth belum terhubung maka fungsi ini akan memanggil fungsi ListPicker1 yang menampilkan daftar perangkat bluetooth yang terhubung ke android.

Blok ListPicker1.AfterPicking merupakan sebuah even yang berjalan ketika daftar perangkat bluetooth sudah dipilih. Kemudian android diperintahkan untuk membuat sambungan bluetooth dengan perangkat arduino.

Blok buttonSend.Click bekerja saat pengguna menekan tombol kirim dan akan mengirimkan data yang ditulis di textBox.

Blok Clock1.Timer bekerja setiap interval untuk memantau adanya pengiriman data dari perangkat arduino, kemudian akan ditampilkan di layar aplikasi.

Blok Screen1.ErrorOccured merupakan sistem penanganan apabila aplikasi bermasalah dan akan memutuhkan hubungan bluetoothnya.

Block lengkapnya:

Artikel terkait : https://www.project.semesin.com/2018/06/02/komunikasi-data-bluetooth-dengan-app-inventor/

Sistem kontrol PID dengan Arduino

Sistem kontrol adalah suatu sistem untuk mengendalikan keadaan sehingga diperoleh hasil bersesuaian dengan nilai yang diinginkan se-efektif mungkin.

diagram diatas merupakan sistem kontrol terbuka (open loop), dalam sistem ini tidak ada pemberitahuan (klarifikasi).

Dalam suatu sistem pasti terdapat gangguan dan variabel didalam dan dari luar sistem yang mengakibatkan ketidaksesuaian antara hasil yang diperoleh dan nilai yang diinginkan.

diagram diatas merupakan sistem kontrol tertutup (close loop), dengan adanya umpan balik maka sistem bisa melakukan koreksi.

Untuk menjadikan sistem se-efektif mungkin, perlu dilakukan pemodelan terhadap sistem yang dibangun yakni:

    1. Pemodelan masukan (input)
    2. Pemodelan sistem kontrol
      • hidup mati (on/off)
      • proporsional (P)
      • integral (I)
      • proporsional + integral (PI)
      • proporsional + derivative (PD)
      • proporsional + integral + derivative (PID)
    3. Pemodelan gangguan baik baik dari dalam maupun dari luar, dari dalam lebih kepada keandalan pelaksana/actuator (contohnya motor, pemanas, dll) dan gangguan dari luar adalah kondisi-kondisi yang dapat mempengaruhi kinerja pelaksana (contohnya penambahan beban pada motor, sumber panas lain pada pemanas)
    4. pemodelan pelaksana/actuator adalah karakteristik respon dari pelaksana terhadap perintah/sinyal yang diberikan (contohnya perubahan kecepatan motor terhadap setiap level sinyal yang diberikan)
    5. pemodelan objek/plant menyangkut sifat dan variasi perubahan yang akan terjadi pada objek.
    6. pemodelan sensor juga mencakup karakteristik pembacaan sensor terhadap perubahan dari perangkat pelaksana yang diukur.

Adanya model dari sistem yang dibangun akhirnya dapat diperoleh hasil akhir berikut ini:

Keluaran (objek) = Sistem kontrol x masukan

penyederhanaan ini bisa dilakukan dengan metode laplace. persamaan diatas adalah bagaimana hubungan antara masukan dan keluaran sehingga tergambar perilaku dinamik dari sistem kontrol.

apabila variabel-variabel sistem kontrol tidak memberikan respon yang efektif seperti yang diinginkan, maka dilakukan penyesuaian (tuning)

Sistem kontrol PID (Proportional–Integral–Derivative)

PID merupakan mekanisme pengambil keputusan dalam merespon adanya nilai kesalahan. Mekanisme ini memiliki 3 variabel (Kp, Ki, Kd) yang bisa disesuaikan guna memperoleh respon yang efektif.
Sistem kontrol itu berbasis dengan waktu, untuk memperoleh nilai kesalahan berbasis waktu digunakan :

1
2
3
4
kesalahan = input - sensor;
integralKesalahan += kesalahan;
derivatifKesalahan = kesalahan - kesalahanLalu;
kesalahanLalu = kesalahan;
  1. Proporsional adalah faktor kali dari nilai kesalahan saat ini (berbanding lurus), nilai ini berpengaruh langsung terhadap sensitifitas dan responsifitas suatu sistem. Jika nilai Kp dibuat lebih tinggi maka sistem menjadi lebih responsif terhadap nilai kesalahan, tetapi apabila nilai kesalahan terlalu tinggi maka sistem akan terlalu sensitif.
    1
    Respon = Kp * kesalahan;
  2. Integral adalah faktor kali dari nilai kesalahan sebelumnya, nilai Ki merupakan penjumlahan dari nilai-nilai kesalahan yang berfungsi untuk mempercepat sistem menuju nilai yang diinginkan. Jika nilai Ki terlalu tinggi maka dikhawatirkan sistem akan menjadi tidak stabil (overshoot)
    1
    Respon += Ki * integralKesalahan;
  3. Derivatif adalah faktor kali dari kemungkinan nilai kesalahan yang akan datang, nilai Kd berfungsi untuk memprediksi nilai kesalahan beikutnya disebut juga faktor redam karena nilai Kd akan memperlambat tercapainya nilai yang diinginkan namun membuat sistem lebih stabil
    1
    Respon += Kd * derivatifKesalahan;

sketch/program lengkapnya seperti berikut

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
float kesalahan;
float integralKesalahan;
float derivatifKesalahan;
float kesalahanLalu = 0;
float Kp, Ki, Kd;
float input;
 
//Pin
byte sensorPin = A0;
byte Pemanas = 2;
 
//konstanta
#define Ksensor 0.2 //faktor koreksi sensor panas
 
void setup() {
  pinMode(Pemanas, OUTPUT);
  Serial.begin(9600);
  Serial.println("Sistem kendali PID dengan Arduino");
  Serial.println("https://www.project.semesin.com");
   
  input = 100;
  Kp = 1;
  Ki = 0.5;
  Kd = -0.2;
}
 
void loop() {
  float sensor = 1.0 * analogRead(sensorPin) * Ksensor;
   
  float respon = hitungPID(input, sensor);
  analogWrite(Pemanas, respon);
  Serial.print(input);
  Serial.print(",");
  Serial.println(sensor);
}
 
float hitungPID(float input, float sensor)
{
  kesalahan = input - sensor;
  integralKesalahan += kesalahan;
  derivatifKesalahan = kesalahan - kesalahanLalu;
  kesalahanLalu = kesalahan;
   
  return (Kp * kesalahan) + (Ki * integralKesalahan) + (Kd * derivatifKesalahan);
}

suara bilangan hingga 999.999 dengan arduino

Modul suara arduino yang ada sudah memenuhi kebutuhan perancangan multimedia saat ini, seperti modul suara WTV020SD, mini TF MP3 player, MP3 shield dan lain-lain. Suara arduino bisa digunakan sebagai alarm peringatan, pengisi suara, suara latar, pemberitahuan dan keperluan lainnya.

Dalam perancangam suara dengan arduino kali ini diperuntukkan sebagai pembilang angka dan bisa diterapkan dalam berbagai proyek arduino. Angka/bilangan berasal dari pembacaan sensor dan dikirim ke modul suara.

Pada modul suara sudah disimpan dalam memorinya (microSD) berbagai macam kemungkinan suara angka dengan urutan tertentu. Arduino berfungsi sebagai pengatur suara angka yang akan diputar.

Suara pembilang arduino dimulai dengan kata pembuka contohnya “nomor antrian”, kemudian diikuti suara deret angka dan terakhir satuannya misalnya “di loket 1”.

Suara bilangan sampai 999.999 dengan komponen :

  1. arduino mega 2560
  2. MP3 DFPlayer
  3. Ampli modul LM386 (bila ada)

Bisa dikombinasikan sebagai pemberi suara :

  1. Mesin timbangan yang menginformasikan berat terukur
  2. Pemberi tahu bila jarak terlalu dekat pada sistem keamanan parkir
  3. Pengingat suhu dan kelembaban dengan sensor humidity
  4. Informasi kecepatan kendaraan kecepatan
  5. Suara antrian pada mesin antrian di perkantoran
  6. Pembilang total belanja
  7. dll

Video:

skema suara informasi arduino:

sketch/program:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#include <miniMP3.h>
 
#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 berat 110 //berat.mp3
#define gram 111 //gram.mp3
#define kiloGram 112 //kilogram.mp3
#define jarak 120 //jarak.mp3
#define sentiMeter 121 //sentimeter.mp3
#define meter 122 //meter.mp3
#define suhu 130 //suhu.mp3
#define derajat 131 //derajat_celsius.mp3
#define ph 140 //P_H.mp3
#define kelembaban 150 //Kelembaban.mp3
#define persen 151 //Persen.mp3
#define kecepatan 160 //kecepatan.mp3
#define meterPerDetik 161 //meter_per_detik.mp3
#define kilometerPerJam 162 //kilometer_per_jam.mp3
#define nomorantrian 170 //nomor antrian.mp3
#define totalBelanja 180 //total belanja.mp3
#define rupiah 181 //rupiah.mp3
 
void setup() {
  mp3_set_serial (Serial1, 17);
  mp3_set_volume(30);
 
  uint32_t beratTimbangan = 0;
   
  mp3_play(berat);
  suaraBilangan(beratTimbangan);
  mp3_play(gram);
}
 
void loop() {
 
}
 
void suaraBilangan(uint32_t Bilangan)
{
  if (Bilangan < 12)
  {
    mp3_play(Bilangan);
  }
  else if (Bilangan < 20)
  {
    suaraBelasan(Bilangan);
  }
  else if (Bilangan < 100)
  {
    suaraPuluhan(Bilangan);
  }
  else if (Bilangan < 1000)
  {
    suaraRatusan(Bilangan);
  }
  else
  {
    suaraRibuan(Bilangan);
  }
}
void suaraBelasan(uint8_t Bilangan)
{
  mp3_play(Bilangan - 10);
  mp3_play(belas);
}
void suaraPuluhan(uint8_t Bilangan)
{
  uint8_t puluhan = Bilangan / 10;
  mp3_play(puluhan);
  mp3_play(puluh);
 
  uint8_t satuan = Bilangan % 10;
  if (satuan)
  {
    suaraBilangan(satuan);
  }
}
void suaraRatusan(uint16_t Bilangan)
{
  uint8_t ratusan = (uint8_t)(Bilangan / 100);
  if (ratusan == 1)
  {
    mp3_play(seratus);
  }
  else
  {
    mp3_play(ratusan);
    mp3_play(ratus);
  }
  byte puluhan = Bilangan % 100;
  if(puluhan)
  {
    suaraBilangan(puluhan);
  }
}
void suaraRibuan(uint32_t Bilangan)
{
  uint16_t ribuan = Bilangan / 1000;
  if (ribuan == 1)
  {
    mp3_play(seribu);
  }
  else
  {
    suaraBilangan(ribuan);
    mp3_play(ribu);
  }
  uint16_t ratusan = Bilangan % 1000;
  if (ratusan)
  {
    suaraBilangan(ratusan);
  }
}

file pendukung:
Suara : Suara bilangan mp3
Library : miniMP3

running text anti flicker (improved DMD) dengan arduino

DMD (dot matrix display) yang dikontrol dengan arduino dengan segala keterbatasannya memiliki permasalahan saat panel DMD disusun dalam lebih dari 4 panel. Flicker terjadi karena proses pengiriman data serial dari arduino harus mengantri sekian lama sehingga pergantian aktifasi baris per baris tertangkap oleh mata seperti berayun (berkedip) dan tentu membuat mata tidak nyaman.

Untuk itu saya melakukan improvisasi terhadap library arduino –DMD2– dengan prinsip kerja satu clock untuk lebih dari satu baris. contohnya untuk ukuran panel 4 kolom 2 baris kelompok DMD dibagi menjadi 2 bagian (baris 1 dan baris 2) dengan entri data yang sama setiap clock-nya.

Kelebihan alat DMD2 arduino:

  1. Sensor DHT11 untuk memantau keadaan suhu dan kelembaban sekitar
  2. Database waktu sholat 5 waktu (statis) dan dilengkapi buzzer yang menandakan waktu sholat telah masuk.

 

Komponen yang dibutuhkan :

  1. 8 Panel P10
  2. Arduino Mega 2560
  3. RTC DS1307
  4. DHT11
  5. Buzzer

DS1307 dapat diganti dengan DS3231 untuk keperluan presisi RTC.

berikut skema-nya :

berserta sketch atau program nya:

 

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
#include <DMD2.h>
#include <fonts/SystemFont5x7.h>
#include <fonts/Arial14.h>
#include <TimeLib.h>
#include <DS1307RTC.h>
#include "DHT.h"
 
byte DataPins[2] = {33, 35}; //pin jalur out
SoftDMD dmd(4, 2, 23, 25, 27, 31, 29, 2, DataPins); //kolom, baris, OE, A, B, SCK, CLK, jumlah jalur out, pin jalur out
//SoftDMD dmd(4,2,23,25,27,31,29,33); //standard
 
DMD_TextBox box(dmd, 0, 0, 78, 32);
 
DHT dht(A0, DHT11);
String namaSholat[] = {"  Subuh", "  Zuhur", "   Asar", " Maghrib", "   Isya"};
byte waktuSholat[][2] = {{5, 12},
                        {12, 32},
                        {15, 45},
                        {18, 35},
                        {19, 44}
};
 
#define waktunyaSholat 1
#define pesanSMS 2
 
int n = 123;
byte lastSecond = 60;
byte lastDay = 32;
byte lastH = 60;
byte lastT = 32;
String Sholat;
String pesanDisplay;
byte pesan;
int buzzer = 8;
bool buzz;
byte buzzCounter;
 
void setup() {
  Serial.begin(9600);
  Serial.println("Running text dengan Arduino bebas kedip");
  Serial.println("https://www.project.semesin.com");
  dht.begin();
  dmd.setBrightness(255);
  dmd.begin();
 
  pesan = pesanSMS;
  pesanDisplay = "  Selamat\n  datang";
  dmd.selectFont(Arial14);
  box.print(pesanDisplay);
}
 
void loop()
{
  tmElements_t tm;
  byte h = (byte)dht.readHumidity();
  byte t = (byte)dht.readTemperature();
  RTC.read(tm);
 
  if (pesan == waktunyaSholat)
  {
    buzzCounter++;
    if (!(buzzCounter % 32))
    {
      buzz = !buzz;
      digitalWrite(buzzer, buzz);
      pinMode(buzzer, OUTPUT);
    }
  }
 
  if (tm.Second != lastSecond)
  {
    String waktu = "";
    if (tm.Hour < 10)
      waktu += "0";
    waktu += tm.Hour;
    waktu += ":";
    if (tm.Minute < 10)
      waktu += "0";
    waktu += tm.Minute;
    waktu += ":";
    if (tm.Second < 10)
      waktu += "0";
    waktu += tm.Second;
    lastSecond = tm.Second;
 
    dmd.selectFont(SystemFont5x7);
    dmd.drawString(80, 0, waktu);
 
    if ((pesan == waktunyaSholat) && (tm.Second >= 58))
    {
      box.clear();
      dmd.selectFont(Arial14);
      box.print(pesanDisplay);
      pesan = pesanSMS;
      digitalWrite(buzzer, LOW);
    }
    else if (tm.Second <= 1)
    {
      for (byte i = 0; i < 5; i++)
      {
        if ((waktuSholat[i][0] == tm.Hour) && (waktuSholat[i][1] == tm.Minute))
        {
          Sholat = namaSholat[i];
          box.clear();
          dmd.selectFont(Arial14);
          box.println("  Sholat");
          box.print(Sholat);
          pesan = waktunyaSholat;
        }
      }
    }
  }
  if (tm.Day != lastDay)
  {
    String tanggal = "";
    if (tm.Day < 10)
      tanggal += "0";
    tanggal += tm.Day;
    tanggal += "/";
    if (tm.Month < 10)
      tanggal += "0";
    tanggal += tm.Month;
    tanggal += "/";
    if (tmYearToCalendar(tm.Year) < 10)
      tanggal += "0";
    tanggal += tmYearToCalendar(tm.Year);
    lastDay = tm.Day;
 
    dmd.selectFont(SystemFont5x7);
    dmd.drawString(80, 8, tanggal);
  }
  if ((h != lastH) || (t != lastT))
  {
    String suhu = "";
    if (t < 10)
      suhu += "0";
    suhu += t;
    suhu += "'C ";
    if (h < 10)
      suhu += "0";
    suhu += h;
    suhu += "%";
 
    lastT = t;
    lastH = h;
 
    dmd.selectFont(SystemFont5x7);
    dmd.drawString(80, 16, suhu);
  }
}

dokumentasi Galeri DMD arduino anti flicker

Library yang sudah dimodifikasi: DMD-GL

Jika menginginkan jadwal sholat yang dinamis (waktu matahari) bisa menggunakan library “PrayerTimes.h”.

Timbangan digital presisi dan lcd pabrikan dengan arduino

dalam projek msin timbangan otomatis ini saya memanfatkan timbangan digital merk Quattro yang sudah tidak berfungsi normal. Fokus proyek ini adalah untuk memanfatkan Sensor berat/loadcell yang presisi dan linear serta LCD pabrikannya sehingga timbangan bisa dimanfatkan kembali.

komponen yang digunakan:

  1. Arduino Uno
  2. Loadcell
  3. HX711
  4. LCD pabrikan (driver HT1621)

Diagram:

Loadcell

Loadcell atau sensor berat pada perangkat quttro yang digunakan memiliki ukuran lebih besar dari loadcell yang ada dipasaran namun memiliki kesamaan cara kerja dan pengkabelan, kabel terdiri dari empat warna yaitu merah – E+, hitam – E-,  putih – A/B+ dan hijau – A/B-.

HX711

komponen (modul) ini berfungsi sebagai ADC – analog to digital converter 24 bit yang akan mengkonversi nilai resistansi dari jembatan Wheatstone menjadi nilai yang berbanding lurus dengan berat benda yang ditimbang

LCD pabrikan

LCD yang digunakan merupakan bawaan perangkat timbangan quattro yang khusus dipakai untuk jenis timbangan ini saja. karakter Terdiri dari 6 digit seven segmen, 3 digit character segmen (seperti seven segmen digabung dengan garis diagonal), 10 bar/garis penanda berat, dan tampilan penunjuk lainnya.

LCD ini dikontrol oleh driver HT1621 dengan 4 jalur input, saya hanya menggunakan 3 saja yaitu CS, WR dan Data. sedangkan  untuk tampilannya saya hanya menggunakan 6 seven segmen dan 2 character segment untk text “Gr”.

 

Skema:

program/sketch:

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
#include "HX711.h"
 
HX711 scale(8,9);
 
#define jumlahSegmen 15
  
//Command
#define  ComMode    0x52
#define  RCosc    0x30
#define  LCD_on  0x06
#define  LCD_off    0x04 
#define  Sys_en  0x02
#define  CTRl_cmd   0x80 
#define  Data_cmd   0xa0 
 
//pin
int CS = A3;
int WR = A1;
int Data = A0;
int backLight = 7;
int buttonESC = 5;
int buttonPCS = 4;
int buttonUNIT = 3;
int buttonTARE = 6;
int buttonZERO = 2;
 
byte angka[] = {0xBE, 0x06, 0x7C, 0x5E, 0xC6, 0xDA, 0xF2, 0x0E, 0xFE, 0xCE};
byte byteArrayBerat[8];
byte strBerat[6];
  
void SendBit_1621(byte sdata,byte cnt)
{
  for(byte i=0;i<cnt;i++)
  {
    digitalWrite(WR, LOW);
     
    if(sdata&0x80)
      digitalWrite(Data, HIGH);
    else
      digitalWrite(Data, LOW);
       
    digitalWrite(WR, HIGH);
    sdata<<=1;
  }
}
  
void SendCmd_1621(byte command)
{
  digitalWrite(CS, LOW);
  SendBit_1621(0x80,4); 
  SendBit_1621(command,8);
  digitalWrite(CS, HIGH);                   
}
  
void Write_1621(byte addr,byte sdata)
{
  addr<<=3;
 digitalWrite(CS, LOW);
 SendBit_1621(0xa0,3);  
 SendBit_1621(addr,6);  
 SendBit_1621(sdata,8);  
 digitalWrite(CS, HIGH);
}
 
void doubleToDecArray(double value, byte *byteArray)
{
  double divider = 1000.0;
  for(byte i=0;i<8;i++)
  {
    byte divValue = value / divider;
    byteArray[i] = divValue;
    value = value - (divValue * divider);
    divider /= 10;
  }
}
 
void setup() {
  pinMode(CS, OUTPUT);
  pinMode(WR, OUTPUT);
  pinMode(Data, OUTPUT);
  pinMode(backLight, OUTPUT);
  pinMode(buttonESC, INPUT_PULLUP);
  pinMode(buttonPCS, INPUT_PULLUP);
  pinMode(buttonUNIT, INPUT_PULLUP);
  pinMode(buttonTARE, INPUT_PULLUP);
  pinMode(buttonZERO, INPUT_PULLUP);
 
  digitalWrite(backLight,LOW);
  digitalWrite(CS, HIGH);
  digitalWrite(Data, HIGH);
  digitalWrite(WR, HIGH);
 
  Serial.begin(9600);
  Serial.println("Timbangan Arduino");
  Serial.println("https://www.project.semesin.com");
   
  delay(50);
  SendCmd_1621(Sys_en);
  SendCmd_1621(RCosc); 
  SendCmd_1621(ComMode); 
  SendCmd_1621(LCD_on);
 
  for(byte i=0;i<jumlahSegmen;i++)
  {
    Write_1621(i,0xff);
  }
  delay(1000);
  for(byte i=0;i<jumlahSegmen;i++)
  {
    Write_1621(i,0x00);
  }
  Write_1621(6,0x85);// huruf 'G'
  Write_1621(7,0xA6);
  Write_1621(10,0x02);//Huruf 'r'
  Write_1621(11,0x40);
 
  scale.set_scale(2280.f);
  scale.tare();
  }
  
void loop() {
 
  double Berat = scale.get_units(10);
  Serial.println(Berat);
   
  bool getNum = false;
  byte numPointer = 0;
  byte numCounter = 0;
   
  if(Berat < 0)
  {
    Berat = 0;
  }
  else
  {
    doubleToDecArray(Berat, byteArrayBerat);
    for(byte i=0;i<8;i++)
    {
      if(byteArrayBerat[i] != 0)
      {
        getNum = true;
      }
      if(getNum)
      {
        numCounter++;
        strBerat[numPointer] = angka[byteArrayBerat[i]];
        if(i==3)
        {
          strBerat[numPointer] |= 0x01;//Koma
        }
        if(numPointer++ == 6)
        {
            numCounter--;
            break;
        }
      }
      else if(i==3)
      {
        getNum = true;
        strBerat[numPointer++] = angka[0] | 0x01;
      }
    }
    byte j=0;
    for(int8_t i=0;i<6-numCounter;i++)
    {
      Write_1621(i,0x00);
    }
    for(byte i=6-numCounter;i<6;i++)
    {
      Write_1621(i,strBerat[j++]);
    }
  }
 
  if(!digitalRead(buttonTARE))
  {
    delay(200);
    if(!digitalRead(buttonTARE))
    {
      scale.tare();
      while(!digitalRead(buttonTARE));
    }
  }
  delay(50);
}

Fitur-fitur modul HX711:

  1. Memiliki 2 block differential ADC sehingga bisa dengan gain yang berbeda disesuaikan dengan tingkat presisi yang diinginkan , yang tersedia 32, 64 dan 128.
  2. Memiliki regulator tegangan sendiri untuk loadcell dan ADC.
  3. Interface serial yang disederhanakan.
  4. Frekuensi keluaran dapat diatur 10SPS dan 80sps
  5. Penyaring/filter riak 50Hz dan 60Hz.

Dengan spesifikasi:

  1. Tegangan operasional dc 2.6 ~ 5.5v.
  2. ADC 24 bit yang presisi.
  3. frekuensi Internal clock 11.0592 MHz.
  4. Konsumsi arus, 1500uA (normal), 0,5uA (power down).

dokumentasi Galeri timbangan digital presisi

Library : HX711.zip

Menentukan nama hari dari tanggal [Arduino]

Untuk memperoleh nama hari dari tanggal yang diberikan dapat mengikuti dengan langkah berikut:

  1. Menetapkan basis hari, misalnya 1 januari 2000 jatuh pada hari sabtu = 7
  2. Menghitung jumlah hari dari basis hari hingga tanggal yang ditentukan dengan memperhitungkan:
    • tahun x 365
    • jumlah tahun kabisat
    • jumlah hari dalam setiap bulan
    • tanggal
  3. dan terakhir mencari nilai sisa setelah dibagi dengan 7

berikut program atau sketch fungsi yang dapat digunakan:

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
String namaHari[] = {"Minggu","Senin","Selasa","Rabu","Kamis","Jum'at","Sabtu"};
uint16_t jumlahHariPerBulan[]={0,31,59,90,120,151,181,212,243,273,304,334};
 
void setup() {
  Serial.begin(9600);
  Serial.println("fungsi mendapatkan Nama hari dari tanggal yang diberikan");
  Serial.println("https://www.project.semesin.com");
}
 
void loop() {
  byte hari;
  byte tanggal = 4;
  byte bulan = 3;
  byte tahun = 18;
   
  hari = hariDariTanggal(tanggal, bulan, tahun);
 
  Serial.print(tanggal); 
  Serial.print("/"); 
  Serial.print(bulan); 
  Serial.print("/"); 
  Serial.print(tahun); 
  Serial.print(" => "); 
  Serial.print(hari); 
  Serial.print(" : "); 
  Serial.println(namaHari[hari - 1]); 
 
  while(1);
}
 
//tanggal mulai dari 1
//bulan mulai dari 1
//tahun dua digit
//minggu = 1, sabtu = 7
//basis 1 Januari 2000
byte hariDariTanggal(byte tanggal, byte bulan, uint16_t tahun)
{
  uint32_t jumlahHari = tahun * 365;
  uint16_t tahunKabisat = tahun/4;
  for (byte i = 0; i < tahun; i++)
  {
    if (!(i%4))
    {
      jumlahHari++;
    }
  }
  jumlahHari += jumlahHariPerBulan[bulan-1];
  if ( (bulan >= 2) && !(tahun % 4))
  {
    jumlahHari++;
  }
  jumlahHari+= tanggal;
  return ((jumlahHari + 5) % 7) + 1;
}

Pengaturan frekuensi PWM pada arduino (fungsi analogWrite(pin, value) tetap seperti biasa)

Perintah analogWrite(pin, onTime) pada arduino berfungsi membangkitkan sinyal PWM pada pin dimaksud. biasanya frekuensi yang dibangkitkan adalah :

  1. 976.5625Hz untuk arduino Uno pin 5 dan 6 (clock 16MHz)
  2. 488.28125Hz untuk arduino Uno pin 3, 9,10 dan 11 (clock 16MHz)

adakalanya kita membutuhkan frekuensi berbeda dari standar ini. Dengan mengatur register TCCRnB kita bisa mengatur frekuensi PWM arduino sehingga diperoleh frekuensi maksimum 62500Hz pada pin 5 dan 6 Arduino Uno, dan minimum 30.517578125Hz pada pin 3,9,10 dan 11 Arduino Uno. Formula/rumus yang dapat dipergunakan adalah :

A. Timer 0 Arduino Uno

frekuensi = io_clock/(N * TOP)

B. Timer 1 dan 2 Arduino Uno

frekuensi = io_clock/(2 * N * TOP)

dengan io_clock = 16Mhz dan TOP = 256

dengan merubah nilai N kita bisa mendapatkan harga frekuensi yang berbeda:

Penggunaan perintah analogWrite(pin, value) tetap seperi biasa (nilai value berkisar antara 0 ~ 255).

catatan : merubah register Timer 0 akan berdampak langsung terhadap fungsi delay(), millis() dan micros()

A.  Arduino UNO

Nomor urut pembagi Pembagi frekuensi (Hz)
Timer 0, pin 5 dan 6
1 1 62500
2 8 7812.5
3* 64 976.5625
4 256 244.140625
5 1024 61.03515625
Timer 1, pin 9 dan 10
1 1 31250
2 8 3906.25
3* 64 488.28125
4 256 122.0703125
5 1024 30.517578125
Timer 2, pin 3 dan 11
1 1 31250
2 8 3906.25
3 32 976.5625
4* 64 488.28124
5 128 244.140625
6 256 122.0703125
7 1024 30.517578125

tanda * adalah nilai default

B. Arduino Mega

—Menyusul

cara penggunaannya:

  1. Ketahui Timer yang digunakan (contoh pin 5 terintegrasi pada Timer 0).
  2. Catat nilai nomor urut pembagi sesuai dengan frekuensi yang diinginkan
  3. masukkan kedalam baris sketch

TCCR0B = TCCR0B & B11111000 | Nomor-urut-pembagi; (TCCR0B = Timer 0, TCCR1B = Timer 1, TCCR2B = Timer 2)

contoh: TCCR0B = TCCR0B  & B11111000 | 1;

contoh dalam sketch/program:

1
2
3
4
5
6
7
8
9
10
11
12
int pinPWM = 5;
 
void setup() {
  pinMode(pinPWM,OUTPUT);
}
 
void loop() {
  analogWrite(pinPWM,128);
  TCCR0B = (TCCR0B & 0b11111000) | 1;
 
  while(1);
}

atau menggunakan fungsi yang fleksibel berikut:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
void setPwmFrequency(int pin, int divisor) {
  byte mode;
  if(pin == 5 || pin == 6 || pin == 9 || pin == 10) {
    switch(divisor) {
      case 1: mode = 0x01; break;
      case 8: mode = 0x02; break;
      case 64: mode = 0x03; break;
      case 256: mode = 0x04; break;
      case 1024: mode = 0x05; break;
      default: return;
    }
    if(pin == 5 || pin == 6) {
      TCCR0B = TCCR0B & 0b11111000 | mode;
    } else {
      TCCR1B = TCCR1B & 0b11111000 | mode;
    }
  } else if(pin == 3 || pin == 11) {
    switch(divisor) {
      case 1: mode = 0x01; break;
      case 8: mode = 0x02; break;
      case 32: mode = 0x03; break;
      case 64: mode = 0x04; break;
      case 128: mode = 0x05; break;
      case 256: mode = 0x06; break;
      case 1024: mode = 0x07; break;
      default: return;
    }
    TCCR2B = TCCR2B & 0b11111000 | mode;
  }
}

Mendeteksi koneksi serial yang terputus pada Arduino

Koneksi serial pada berfungsi sebagai sarana komunikasi (–utama) pada arduino. Untuk mengetahui apakah port serial tersebut terhubung atau tidak dapat dideteksi dengan membaca register ‘frame error’, yaitu register yang bernilai 1 apabila frame serial yang diterima tidak sesuai dengan format yang ditentukan.

Ketika koneksi serial diputus, maka kondisi pin RX akan bernilai 0. Kondisi pin RX 0 juga berarti dimulainya pengiriman sebuah frame (start bit), namun dikarenakan koneksi terputus maka bit yang diterima berikutnya akan bernilai 0 juga. seperti kita ketahui sebuah frame komunikasi serial terdiri dari start bit, data, parity dan stop bit. dan tentu saja block serial akan melaporkan kesalahan ini sebagai ‘frame error’ yang bisa dimanfaatkan untuk mendeteksi menyambung atau terputusnya koneksi komunikasi serial.

Tester : Arduino mega 2560 (memanfaatkan Serial1)

Skema detektor serial:

catatan: metode register  ‘frame error’ ini tidak berfungsi pada Serial biasa (Serial0) karena Serial0 terhubung ke downloader (USB to Serial)

Program/sketch:

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
bool serial1TidakTersambung = false;
 
void setup() {
    Serial.begin(9600);
    Serial1.begin(9600);
    Serial.println("Mendeteksi koneksi serial");
    Serial.println("Jika Koneksi serial dilepas, maka arduino akan mengirimkan pesan");
    Serial.println("'Serial1 tidak terhubung' hingga Serial port menerima data valid");
  Serial.println("https://www.project.semesin.com");
}
     
void loop() {
    char c;
    if(Serial1.available())
    {
        if(UCSR1A & (1<<FE1))
        {
            serial1TidakTersambung = true;
        }
        else
        {
            serial1TidakTersambung = false;
            c = Serial1.read();
            Serial.print(c);
        }
    }
     
    if(serial1TidakTersambung)
    {
        Serial.println("Serial1 tidak terhubung");
        delay(1000);
    }
}

Sistem blink alarm dengan arduino

Dalam proses perulangan dengan delay, seringkali kita harus menunggu proses tersebut hingga selesai. terdapat beberapa metode untuk menghentikan/memotong perulangan tersebut diantaranya:

  1. Metode interrupt
  2. Metode millis (tanpa for-loop secara langsung).

Berukut ini saya sertakan sketch dengan metode millis, cara kerjanya sbb:

  1. tekan ‘m’ untuk mulai LED blinking (100 kali)
  2. tekan ‘b’ untuk menghentikan proses perulangan LED blinking

nb: melalui serial monitor (setting baudrate 9600, no ending line)

Komponen pengujian yang digunakan:

  1. Arduino UNO (internal LED)

sketch dengan millis():

Metode serial available:

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
char input = 0;
int counter = 0;
long MillisValue = 0;
int timeDelay = 500;//dalam milisecond
bool pinState = false;
 
void setup() {
  Serial.begin(9600);
  pinMode(LED_BUILTIN,OUTPUT);
  Serial.println("Tekan 'm' untuk mulai, dan 'b' untuk berhenti");
  Serial.println("https://www.project.semesin.com");
}
 
void loop() {
  if(Serial.available())
  {
    input = Serial.read();
    Serial.println(input);
  }
  if(input=='m')//mulai
  {
    counter = 200; // dikali 2 (on-off-on = 3)
    MillisValue = millis();
    input = 0;
    Serial.println("Mulai");
  }
  else if(input=='b')//berhenti
  {
    counter = 0;
    input = 0;
    digitalWrite(LED_BUILTIN, LOW);
    Serial.println("Berhenti");
  }
  if(counter && ((MillisValue + timeDelay) < millis()))
  {
    counter--;
    pinState = !pinState;
    digitalWrite(LED_BUILTIN, pinState);
    MillisValue = millis();
  }
}

 

metode serialEvent:

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
char input = 0;
int counter = 0;
long MillisValue = 0;
int timeDelay = 500;//dalam milisecond
bool pinState = false;
 
void setup() {
  Serial.begin(115200);
  pinMode(LED_BUILTIN,OUTPUT);
  Serial.println("Tekan 'm' untuk mulai, dan 'b' untuk berhenti");
  Serial.println("https://www.project.semesin.com");
}
 
void loop() {
  if(input=='m')//mulai
  {
    counter = 200; // dikali 2 (on-off-on = 3)
    MillisValue = millis();
    input = 0;
    Serial.println("Mulai");
  }
  else if(input=='b')//berhenti
  {
    counter = 0;
    input = 0;
    digitalWrite(LED_BUILTIN, LOW);
    Serial.println("Berhenti");
  }
  if(counter && ((MillisValue + timeDelay) < millis()))
  {
    counter--;
    pinState = !pinState;
    digitalWrite(LED_BUILTIN, pinState);
    MillisValue = millis();
  }
}
void serialEvent() {
  input = Serial.read();
}