Semua Tentang Belajar Teknologi Digital Dalam Kehidupan Sehari - Hari

  • IC Timer 555 yang Multifungsi

    IC timer 555 adalah sirkuit terpadu (chip) yang digunakan dalam berbagai pembangkit timer, pulsa dan aplikasi osilator. Komponen ini digunakan secara luas, berkat kemudahan dalam penggunaan, harga rendah dan stabilitas yang baik

  • Ayo Migrasi TV Digital

    Kami bantu anda untuk memahami lebih jelas mengenai migrasi tv digital, apa sebabnya dan bagaimana efek terhadap kehidupan. Jasa teknisi juga tersedia dan siap membantu instalasi - setting perangkat - pengaturan antena dan distribusi televisi digital ke kamar kos / hotel

  • Bermain DOT Matrix - LOVEHURT

    Project Sederhana dengan Dot Matrix dan Attiny2313. Bisa menjadi hadiah buat teman atau pacarmu yang ulang tahun dengan tulisan dan animasi yang dapat dibuat sendiri.

  • JAM DIGITAL 6 DIGIT TANPA MICRO FULL CMOS

    Jika anda pencinta IC TTL datau CMOS maka project jam digital ini akan menunjukkan bahwa tidak ada salahnya balik kembali ke dasar elektronika digital , sebab semuanya BISA dibuat dengan teknologi jadul

  • Node Red - Kontrol Industri 4.0

    Teknologi kontrol sudah melampaui ekspektasi semua orang dan dengan kemajuan dunia elektronika, kini semakin leluasa berkreasi melalui Node Red

Tampilkan postingan dengan label mikrokontroller. Tampilkan semua postingan
Tampilkan postingan dengan label mikrokontroller. Tampilkan semua postingan

Rabu, 20 September 2023

[Tutorial] Dasar Input - Output Pada Mikrokontroler




Pada umumnya terdapat 2 jenis input output yang terlihat paling "sederhana" dan paling sering dibahas pada sebuah sistem mikrokontroler AVR, arduino maupun ESP 8266. Dari list dibawah ini, nomer 1 dan 2 akan kita praktekkan pada tulisan blog kali ini, bersama dengan adik - adik mahasiswa di jurusan teknik listrik vokasi unesa Surabaya. 


Jenis Input Output :

  1. Digital Pin
  2. Analog Pin
  3. PWM
  4. Serial
  5. I2C
  6. SPI

- DIGITAL PIN

Digital pin ini merupakan hal yang paling dasar yang pertama kali harus dipraktekkan ketika memulai mikrokontroler sekelas arduino. Coba pembaca buka sketch dan akan menemukan example yang bernama "blink" yang merupakan coding untuk menyalakan dan mematikan LED internal pada bord arduino ( jenis apapun ) yang umumnya berada pada pin 13.


 void setup() {
  // inisialisasi digital pin LED_BUILTIN sebagai output.
  pinMode(LED_BUILTIN, OUTPUT);
}

//the loop function muter terus
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);  // HIGH = Nyala
  delay(1000);                      // Tunggu 1 detik
  digitalWrite(LED_BUILTIN, LOW);   // LOW = Mati
  delay(1000);                      // Tunggu 1 detik
}


Dan kemudian perhatikan gambar ekuivalen dari sebuah Bit Input Output pada mikrokontroler, melalui tombol sebagai Input dan Led sebagai output .



Saya ingin membuat penekanan tombol switch tactile bereaksi terhadap led, dan tidak ingin menjadi on off seperti saklar biasa. Jadi saat tombol (aktif low / pull up) maka akan merubah status dari led nyala atau mati. Perhatikan script berikut dan akan saya bahas per bagian.


const int buttonPin = 9;     // pin push button
const int ledPin =  13;      // pin LED

int buttonState = 0;         // variable status tombol
bool ledstate;

void setup() {
  //Pin LED sebagai output
  pinMode(ledPin, OUTPUT);
  // tombol sebagai intput
  pinMode(buttonPin, INPUT);
   
  //status awal led mati 
  ledstate = false;
  digitalWrite(ledPin, LOW);

  Serial.begin(9600); //agar bisa dilihat pada terminal
}

void loop() {

  // baca status tombol
  buttonState = digitalRead(buttonPin);

  // cek status tombol High atau Low
  if (buttonState == HIGH) {
    
    //nyalakan led dan ubah status led 
    if ( !ledstate){
      digitalWrite(ledPin, HIGH);
      ledstate =true;
      //kirim serial
      Serial.println("Kondisi led = Nyala");
     }
    //matikan led
     else {
      digitalWrite(ledPin, LOW);
      ledstate = false;
      Serial.println("Kondisi led = mati");
    }
  delay(200);
    
  } 
  
}


Dari script diatas, penjelasan perbagian  bisa dilihat pada bagian script berwarna merah, dan yang paling utama adalah proses perubahan status boolean dari led status yang akan tersimpan sesuai kondisi terakhir dari led.

    //nyalakan led dan ubah status led 
    if ( !ledstate){
      digitalWrite(ledPin, HIGH);
      ledstate =true;
      //kirim serial
      Serial.println("Kondisi led = Nyala");
     }

    //matikan led
    else {
      digitalWrite(ledPin, LOW);
      ledstate = false;
      Serial.println("Kondisi led = mati");
    }


Terdapat perintah Serial.println yang bertujuan untuk melihat kondisi led pada serial monitor yang merupakan fasilitas debuging paling utama pada sketch arduino.




Pada tulisan selanjutnya akan saya bahas input analog yang sangat bermanfaat.


Share:

Senin, 11 Juli 2022

Magang Industri "Kembali" Menghiasi Aisi555 Setelah Pandemi - Teknik Listrik D4 Unesa Surabaya

 



Semangat berbagi ilmu dari aisi555 baik melalui tulisan maupun praktek langsung dilapangan, sempat mengalami episode "down" setelah terpukul pandemi corona di tahun 2020 dan 2021. Padahal di tahun 2020 mendapat kepercayaan kembali untuk menerima magang anak - anak SMK 1 dan SMK 2 dari kota Kediri, serta yang menggembirakan adalah ditandatanganinya kerjasama magang industri dengan fakultas vokasi ITS, setelah pada 2019 berhasil menerima trial magang anak ITS - D4 kontrol selama 6 bulan. Dan ini semuanya buyar akibat pandemi yang mengurung semua kegiatan pendidikan di rumah saja. Ya saya sadar itu diluar kendali saya dan saya tetap berusaha berbagi ilmu melalui jalur online, baik di blog ini dan saya mulai membuat tutorial via video youtube dan facebook.



Kegiatan diatas merupakan puncak dari rencana besar aisi555 untuk berkecimpung di dunia pendidikan bertema elektronika dan IOT, dimana aisi555 menjadi tersadar bagaimana terbukanya pikiran bahwa dunia pendidikan memiliki pangsa pasar yang tidak akan habis. Namun seperti merupakan salah satu "takdir" penulis, ketika tawaran kerjasama banyak datang, namun 2 minggu setelah pameran diatas, dunia pendidikan dipaksa melakukan "lockdown" karena merebaknya kasus covid yg menyebar di sekolah. Dan setelah lama menunggu akhirnya aisi555 kembali mendapatkan kepercayaan mengisi kuliah tamu dalam bungkus "kampus merdeka" pada 2021. 


Aisi555 yang bernaung dibawah bendera PT. Indotech Infrastruktur Solusi kemudian menjalin kerjasama magang Industri untuk mahasiswa yang kini dibebaskan memilih jenis industri apa yang akan di ambil, yang kemudian kesempatan ini diambil oleh anak-anak jurusan D4 Teknik Listrik - Prodi Vokasi - Unesa Surabaya angkatan 2019. Magang industri ini telah diadakan pada februari - juni 2022 dengan tema yang diambil bergaris besar pada Baterai dan monitoringnya secara IOT. 



Pola magang kali ini diadakan secara Online dan Offline dimana ada meeting pengarahan teori setiap minggunya yang dilaksanakan melalui media meeting video online. Kemudian di tiap bulanannya diadakan pertemuan tatap muka untuk melakukan evaluasi dan menyusun project yang tepat sebagai tugas akhir dan laporan magang sesuai tema yang diberikan oleh pihak kampus. Berikut ini beberapa garis besar atau tema yang diberikan tiap bulannya :


  • Bulan 1 : Pengenalan organisasi perusahaan dan peraturan perusahaan
  • Bulan 2  : Teknologi baterai sell basah / aki, charging dan discharging serta perawatannya
  • Bulan 3  : Baterai Lithium ion dan Mikrokontroller
  • Bulan 4  : Komunikasi data sensor dan IOT  
  • Bulan 5  : Digital Marketing
  • Bulan 6  : Proyek akhir yang berhubungan dengan Baterai & IOT




Dan pada akhir dari periode magang kali ini telah dilaksanakan presentasi project akhir dari masing-masing peserta sebagai berikut :


Project 1 :  Charger Accu Auto Cut Off berbasis timer 555




Project 2 :  Desulfator Aki Basah berbasis timer 555




Project 3 :  BMS dan PowerBank Baterai Li-Ion 18650 




Project 4 :  Monitoring Kesehatan Accu Berbasis Arduino




Project 5 :   Monitoring Kesehatan Aki Secara IOT dengan Protokol MQTT





Berminat untuk magang bersama aisi555 ? Kontak kami ada di sebelah kanan layar ....Saya tunggu ....

Share:

Jumat, 17 September 2021

Lanjutan Praktek Dasar Input / Output - 7 Segmen Serta Penjelasan Blocking Delay

 



7-segmen Display , atau indikator tujuh-segmen, adalah suatu bentuk perangkat tampilan elektronik untuk menampilkan angka desimal. 7-segmen display yang banyak digunakan dalam jam digital, meter elektronik, dan perangkat elektronik lainnya untuk menampilkan informasi numerik. Pada umumnya 7 segmen merupakan kumpulan Led yang disusun sehingga terbentuk rangkaian yg dapat dipilih secara elektronik untuk menampilkan suatu digit desimal.



Dalam penjelasan praktek kali ini kita akan menggunakan 7 segmen komon anoda / positif dengan susunan rangkaian yang saya pakai masih menyambung dari praktek sebelumnya.




Untuk menampilkan angka digit 0 - 9 saat terjadi penekanan tombol, pola pikir yang digunakan sesuai dengan flowchart berikut ini :





Penjelasan:

  • Input tetap berupa tombol, posisi di PIN B#1.
  • 7 segmen dihubungkan pada output PORT D#0 sampai D#6.
  • Tiap segmen dihubungkan dengan kondisi nyala mati sedemikian rupa sehingga menampilkan digit angka 0,1,2,3,4,5,6,7,8,9 .
  • Tiap digit desimal segmen di masukkan kedalam Array Segmen[10] yang isinya susunan segmen penyusun digit dan kemudian ditampilkan sesuai variabel angka.
  • Ketika ada penekanan tombol maka variabel angka akan increment / nambah sampai kondisi angka >9 di reset kembali menjadi 0.


Scriptnya seperti berikut ini :

#define F_CPU 1000000UL      // frekuensi clock internal 1Mhz
#include <avr/io.h> // definisi library standar IO port
#include <util/delay.h> // definisi include untuk delay



//susunan segmen dari portD = GFEDCBA
//7 segmen common ANODA


uint8_t segmen[10]= {0b1000000, // 0
		     0b1111001, // 1
		     0b0100100, // 2
		     0b0110000, // 3
		     0b0011001, // 4
		     0b0010010, // 5
		     0b0000010, // 6
		     0b1111000, // 7
		     0b0000000, // 8
		     0b0010000}; // 9
int main(void)
{
   
   DDRD |= (1<<PD6) |(1<<PD5) |(1<<PD4) |(1<<PD3) |(1<<PD2) |(1<<PD1) | (1<<PD0) ; // 7 seg
   DDRB &= ~(1<<PB1);  //tombol
   
   uint8_t a =0;
   
    while (1) 
    {
		
		
		if(bit_is_set(PINB,PINB1)) { 
		      a++;	
		      if(a==10) a=0;
		      _delay_ms(300);
		    }
		
       PORTD = segmen[a]; //Tampilkan segmen
    }      }

Penjelasan :

  • Hal yang mungkin cukup spesial adalah array segmen[10] dengan 10 buah anggota, yang merupakan susunan segmen yang jumlahnya 7, sehingga sedemikian rupa untuk menampilkan digit 6, maka PORT D#0, D#2, D#3, D#4, D#5, D#6 diberikan logika 0 (ingat komonnya anoda /positif) sehingga segmen ini menyala. Sedangkan PORT D#1 diberikan logika HIGH (5 volt ) alias sama dengan commonnya dan menyebabkan LED segmennya mati.




  • Saat ada penekanan tombol pada PIN B#1 maka variabel angka akan berubah dan PORTD nilainya diubah sesuai angka binary yang diwakilkan oleh array segmen[angka], yang artinya jika angka bernilai 6, maka PORTD bernilai 0b0000010.  


Bagaimana jika saya ingin membuat perubahan digit berjarak 1 detik ? Kita akan bandingkan 2 tipe, yaitu dengan Blocking Delay serta dengan Timer Register.


BLOCKING DELAY

#define F_CPU 1000000UL      // frekuensi clock internal 1Mhz
#include <avr/io.h> // definisi library standar IO port
#include <util/delay.h> // definisi include untuk delay



//susunan segmen dari portD = GFEDCBA
//7 segmen common ANODA


uint8_t segmen[10]= {0b1000000, // 0
		     0b1111001, // 1
		     0b0100100, // 2
		     0b0110000, // 3
		     0b0011001, // 4
		     0b0010010, // 5
		     0b0000010, // 6
		     0b1111000, // 7
		     0b0000000, // 8
		     0b0010000}; // 9

int main(void)
{
   
   DDRD |= (1<<PD6) |(1<<PD5) |(1<<PD4) |(1<<PD3) |(1<<PD2) |(1<<PD1) | (1<<PD0) ;
   DDRB |= (1<<PB0); //led
   DDRB &= ~(1<<PB1);  //tombol
   
   uint8_t angka;
   
    while (1) 
    {
		
		
		for(angka=0 ; angka<10 ; angka++){
			
	                 PORTD=segmen[angka];
			_delay_ms(1000);
		}
		
		if(bit_is_set(PINB,PINB1)) PORTB |=(1<<PB0);
		else PORTB &= ~(1<<PB0);
		
		
    }
}

Penjelasan :

  • Loop for(angka=0 ; angka<10 ; angka++)  merupakan cara untuk melakukan pengulangan dan penambahan variabel angka secara satu persatu dari 0 sampai nilai maksimum 9. 
  • Delay 1000 mili second diberikan setiap loop for dan ini merupakan blocking delay atau menghentikan semua jalannya program mikrokontroller selama 1 detik.
  • Perintah dibawah loop For merupakan proses menunggu penekanan tombol dan perubahan LED pada Port B#0, dan karena terjadi blocking delay, maka penekanan tombol kadang tidak terbaca seperti animasi berikut.


 

  • Untuk mengatasi blocking delay maka dapat memanfaatkan fasilitas timer pada microcontroller.


Non Blocking Delay Menggunakan Timer



#define F_CPU 1000000UL      // frekuensi clock internal 1Mhz
#include <avr/io.h> // definisi library standar IO port
#include <util/delay.h> // definisi include untuk delay
#include <avr/interrupt.h> // library interupt timer



//susunan segmen dari portD = GFEDCBA
//7 segmen common ANODA


uint8_t segmen[10]= {0b1000000, // 0
		     0b1111001, // 1
		     0b0100100, // 2
		     0b0110000, // 3
		     0b0011001, // 4
		     0b0010010, // 5
		     0b0000010, // 6
		     0b1111000, // 7
		     0b0000000, // 8
		     0b0010000}; // 9

uint8_t angka=0;


ISR(TIMER1_COMPA_vect) // interupt jalan independen tiap selang 1 detik

{
 PORTD = segmen[angka];
 angka++;
 if(angka==10) angka=0;

}


int main(void)
{
   
   DDRD |= (1<<PD6) |(1<<PD5) |(1<<PD4) |(1<<PD3) |(1<<PD2) |(1<<PD1) | (1<<PD0) ;
   DDRB |= (1<<PB0);
   DDRB &= ~(1<<PB1);  
   
      TCCR1B |= (1 << WGM12); // Configure timer 1 for CTC mode
      TIMSK |= (1 << OCIE1A); // Enable CTC interrupt
      OCR1A  = 15625; //compare the CTC A for 1 second
      TCCR1B |= (1 << CS11)|(1 << CS10); // Start timer at Fcpu/64
   
    sei();  //mulai membaca interupt
    while (1) 
    {
		//penekanan tombol
		
		if(bit_is_set(PINB,PINB1)) PORTB |=(1<<PB0);
		else PORTB &= ~(1<<PB0);
	
		
    }
}


   

Penjelasan :

  • Mikrokontroler memiliki fasilitas counter & timer internal, dan akan berjalan secara independen.
  • Tiap tick/clock akan diatur sedemikian rupa sehingga counter didalamnya dapat melakukan delay sesuai nilai yang ditentukan, semisal contoh diatas tiap 1 detik atau clock counter 15625 maka akan men-trigger fungsi interupt  ISR(TIMER1_COMPA_vect).
  • Hasilnya pada loop utama saat penekanan tombol tidak akan terpengaruh seperti pada animasi berikut ini.




Selamat Mencoba ...
Share:

Rabu, 18 Agustus 2021

ATtiny2313 vs DHT11 - Jangan pernah pakai library arduino, kembali ke dasar koding GCC !

 


Pembahasan kali ini sudah pernah saya tulis sebelumnya 8 tahun yg lalu, dimana DHT11 merupakan sensor sejuta umat yg sangat umum dipakai untuk belajar IOT. Sensor ini memiliki sistem komunikasi serial 1 bus wire, dimana semua datanya dikirim melalui 1 buah jalur data dengan pembeda 1 dan 0 nya berdasarkan lebar pulsa atau timer dari level logicnya. Jadi untuk pemahaman dasar pembacaan sensornya dapat dibaca di sini : https://www.aisi555.com/2013/05/dht-11-sensor-suhu-dan-kelembaban-murah.html

Jadi jika ingin mengirimkan pembacaan DHT11 menuju serial com di PC, maka scriptnya lumayan memusingkan untuk dilihat, terutama dibagian pembacaan pulsanya.


Namun jangan lupa baca dulu  pembahasan pengaturan fusebit nya disini : https://www.aisi555.com/2021/08/attiny2313-vs-arduino-library-bagaimana.html


#define F_CPU 8000000UL //frek clock internal
#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h> 
#include <string.h>
#include <stdlib.h>


//rumus penentuan baudrate

#define USART_BAUDRATE 9600  // baudrate 9600 bps
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)

//deklarasi menu & tulisan .
//gunakan memori flash(PROGMEM) biar cukup


const char suhunya[] PROGMEM = " suhu : ";
const char huminya[] PROGMEM = "C - kelembaban : ";



void init_usart(void)

{

	UCSRB |= (1 << TXEN);   // kirim aja
	UCSRC |= (1 << UCSZ0) | (1 << UCSZ1);
	UBRRL = BAUD_PRESCALE;
	UBRRH = (BAUD_PRESCALE >> 8);
}


//function untuk mengirim char

void USART_Tx(unsigned char data)

{	

	while (!(UCSRA & (1<<UDRE)));{} 
	UDR = data; // Send data to the computer


}



//function untuk kirim kalimat dari flash Progmem


void kirim_text(const char *data)

{

	while (pgm_read_byte(data) != 0x00)
	USART_Tx(pgm_read_byte(data++));

}

void kirim(char *data) //kirim teks dari ram

{

	while (*data != 0x00)
	USART_Tx(*data++);

}


uint8_t hitung(void)
{

	uint8_t a,counter,hasil;

	counter=0;
	hasil=0;

	for (a=8;a>0;a--) // 8 kali tiap perhitungan
	{


		while(counter <100) // deteksi saat LOW ( tidak ada perhitungan)
		{
			_delay_us(1);
			counter++;
			if (bit_is_set(PIND, 3)) break; //tunggu sampai high dan keluar loop
		}

		counter=0;

		while(counter <100)
		{
			_delay_us(1);
			counter++; // counter mendeteksi lebar pulsa
			if (bit_is_clear(PIND, 3)) break; //jika low maka keluar dari loop
		}

		// perhitungan 8 bit decimal dengan geser-geser bit
		//jika lebih 25us =1 , kurang < 25 us = 0
		
		if(counter > 25) hasil += (1 << (a-1)) ;

		counter=0;

	}

	return hasil;


}

void baca_sensor()
{

	char dum;  // variabel sementara

	int suhu;
	int suhuu;
	int humi;
	int counter=0;

	DDRD|=(1<<PD3); //PD3 sebagai output
	_delay_ms(250);

	PORTD &=~(1<<PD3); // nolkan PD3
	_delay_ms(18); //tunggu 18 ms

	PORTD |=(1<<PD3); // naikkan PD3
	_delay_us(40); //tunggu 40us


	DDRD &=~(1<<PD3); //PD3 sebagai input

	//tunggu response dari DHT11

	while(counter <100)
	{
		_delay_us(1);
		counter++;
		if (bit_is_set(PIND, 3)) break;
	}

	counter=0;

	while(counter <100)
	{
		_delay_us(1);
		counter++;
		if (bit_is_clear(PIND, 3)) break;
	}


	//baca data setelah response, lihat script di pembahasan selanjutnya untuk routine hitung()

	//8 bit pertama ( puluhan kelembaban )
	humi=hitung();
	//8 bit kedua( satuan kelembaban ), tidak usah di baca karena nilai selalu 0 untuk DHT11
	hitung();
	//8 bit ketiga ( puluhan suhu )
	suhu=hitung();
	//8 bit keempat ( satuan suhu ), tidak usah di baca karena nilai selalu 0 untuk DHT11
	suhuu=hitung();
	
	kirim_text(suhunya);
	itoa(suhu,&dum,10);
	kirim(&dum);
	USART_Tx('.');
	itoa(suhuu,&dum,10);
	kirim(&dum);
	USART_Tx(0xF8);
	kirim_text(huminya);
	itoa(humi,&dum,10);
	kirim(&dum);
	USART_Tx('%');
	USART_Tx('\n');
	USART_Tx('\r');
	
	
	
	
}




int main(void)

{
	
	
  init_usart();

  while(1) //muter tiada henti
	{

	baca_sensor();
	_delay_ms(5000);

	}

}









Wah ..segitu panjangnya, padahal jika dilihat kembali cara pembacaan DHT11 pada arduino, cukup mengikuti library buatan adafruit yg banyak contohnya beredar di internet dan cukup hanya beberapa baris coding saja. 

Namun ini dapat menjadi masalah besar saat ATtiny2313 yang digunakan, lalu bagaimana memampatkan nya di attiny menggunakan sketch arduino ? Bayangkan pembahasan sebelunya dimana attiny full hanya dengan script yg mengerjakan komunikasi serial, jadi jika menggunakan library DHT dari adafruit yg biasa dipakai pada arduino, dijamin flash memori akan melebihi 100% . Ada lagi yg penting yaitu butuh penanganan clock yang jauh berbeda. Dan hasilnay script saya diatas tidak berjalan  seperti yg diinginkan. Jadi pengaturan clock untuk mencari pewaktu 1 microseconds sangatlah critical.



Berikut ini script Attiny vs DHT11  pada  sketch arduino  :


#define USART_BAUDRATE 9600  // baudrate 9600 bps
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)

const char suhunya[] PROGMEM = " suhu : ";
const char huminya[] PROGMEM = " C - kelembaban : ";



int DHT11_Pin = 5; // DHT11 ke pin PD3

int Humidity = 0;
int Temp = 0;
int TempComma = 0;
bool DHTError = false; // Checksum Error

// a Delay routine. Call DelayTimer(time in uSec)

void DelayTimer(long int DelayValue){
long int DelayTime = micros();
do {

}while (micros()-DelayTime < DelayValue);
}
// Main DHT Void

void DHT11(){

long int DataTime = 0;

byte Result[45];
byte DataArray = 0;
byte DataCounter = 0;
byte DHTData[4];

bool BlockDHT=false;

// Trigger Sensor (described in the Datasheet)

pinMode(DHT11_Pin,OUTPUT);
digitalWrite(DHT11_Pin,HIGH);
DelayTimer(250000); //Wait 250millisec
digitalWrite(DHT11_Pin,LOW);
DelayTimer(30000); //Wait 30millisec
digitalWrite(DHT11_Pin,HIGH);
DelayTimer(50); //Wait 50microsec
pinMode(DHT11_Pin,INPUT);
// read the Bits and put them into a Result array (It will count 42 bits. The first two one are useless due my code)

do {
if (digitalRead(DHT11_Pin) == 0 && BlockDHT == false) {BlockDHT = true;Result[DataArray]=(micros()-DataTime);DataArray++;DataTime=micros();} //If DHT pin is low, go to next Dataset
if (digitalRead(DHT11_Pin) == 1) {BlockDHT = false;} // As long as DHT pin is Hight add time in Microseconds to Result

}while((micros()-DataTime) < 150); // if DTH Sensor high for more than 150 usec, leave loop

// Asign 1 or 0 to Result variable. If more than 80uS Data as “1”
// Starting at Data set 02. First two Datasets are ignored!

for (int i=2; i< DataArray; i++) {
if (Result[i] <= 90) Result[i]=0; else Result[i]=1;

}


for (int j=0; j< 5; j++){ // redo it for the 5 Bytes (40 Databits /8 = 5)
for (int i=0; i< 8; i++) {bitWrite(DHTData[j], 7-i, Result[i+2+(j*8)]);} // Create 5 Databytes from the 40 Databits (Ignoring the 2 first Databits)

}
// check checksum }

if (DHTData[4] == (DHTData[0]+DHTData[1]+DHTData[2]+DHTData[3])){Humidity = DHTData[0];Temp = DHTData[2];TempComma = DHTData[3];DHTError=false;} else DHTError=true; //If Checksum is worng, Temp=99 (Dataset 0-3 in addition = Dataset 4 = Checksum OK)

}



  void init_usart(void)

{

  UCSRB |= (1 << TXEN);   // kirim aja
  UCSRC |= (1 << UCSZ0) | (1 << UCSZ1);
  UBRRL = BAUD_PRESCALE;
  UBRRH = (BAUD_PRESCALE >> 8);

}

 void USART_Tx(unsigned char data)

{

 

  while (!(UCSRA & (1<<UDRE)));{} // wait till transmit Data register is empty

  UDR = data; // Send data to the computer



}



//function untuk kirim kalimat



void kirim_text(const char *data)

{

  while (pgm_read_byte(data) != 0x00)

  USART_Tx(pgm_read_byte(data++));

}

void kirim(char *data)

{

  while (*data != 0x00)
  USART_Tx(*data++);

}



void setup() {
  // put your setup code here, to run once:
init_usart();

}

void loop() {
char dum;  
DHT11();
if (DHTError == false)
{ kirim_text(suhunya);
  itoa(Temp,&dum,10);
  kirim(&dum);
  USART_Tx(',');
  itoa(TempComma,&dum,10);
  kirim(&dum);
  kirim_text(huminya);
  itoa(Humidity,&dum,10);
  kirim(&dum);
  USART_Tx('%');
  USART_Tx('\n');
  USART_Tx('\r');
  } 
  else kirim("Error");


DelayTimer(1000000); //wait 1 sec
}



Wew...jadi kembali ke dasar koding GCC yuk...wong sama aja ribetnya...
Share:

Kamis, 22 April 2021

[ Node-RED ] Mengenal Function Node - Tools Ampuh Berbasis Java

 


Bagi penggiat IT yang mungkin kebingungan akan logika dari flow dan beragam node yang ada pada platform IOT Node-RED, mungkin pada saat belajar awal perlu berkenalan dengan node yang bernama  : "FUNCTION". Ya gak jauh berbeda dengan function atau sub-routine pada bahasa pemrograman apapun, function akan menyediakan editor script berbasis java yang akan memudahkan mengubah dan mengolah pesan Input Output pada flow yang anda buat.

Namun perlu diperhatikan komunikasi antar node bukan hanya kirim-terima String biasa, namun keseluruhan berpola JSON seperti contoh berikut:



atau kalau saya copy salah satu pesan raw dari salah satu output debug sebuah pesan yg diterima dari response perangkat modbus seperti berikut ini :


{"topic":"polling","payload":[30,0,71],"responseBuffer":{"data":[30,0,71],"buffer":[0,30,0,0,0,71]},"input":{"topic":"polling","from":"Modbus-DHT22","payload":{"unitid":"6","fc":4,"address":"0","quantity":"3","messageId":"6080af997665b3af28e2168f"},"queueLengthByUnitId":{"unitId":6,"queueLength":0},"queueUnitId":6,"unitId":6},"sendingNodeId":"1c4bea20.9b9666","_msgid":"b2c9254b.4553e8"}



Sepanjang itu pesan yg dikirimkan oleh node MODBUS READ ke node Debug yg saya buat. Jadi secara praktisnya saya hanya butuh data pada object bernama "payload" yang berisikan data array :[30,0,71]  . Jadi yg nantinya saya olah adalah data dari 3 isi array itu saja.

Kemudian saya ingin merubah data payload tadi menjadi NUMBER yang akan saya tampilkan pada web UI berupa GAUGE / Meter. Karena memang yang diminta oleh gauge adalah input data berupa  angka maka saya butuh sebuah Function untuk merubahnya.



Penjelasan dari function diatas adalah sebagai berikut :


  • Variabel temp mengambil data msg.payload yg dikirimkan oleh node modbus read
  • Data array 0 dan 1 dimasukkan ke dalam variabel
  • Karena data 0 berupa puluhan dan 1 berupa angka dibelakang koma, butuh melakukan penggabungan dengan jalan mengalikan data 0 / puluhan dengan 100, menambahkan dengan data 1 lalu membagi hasilnya dengan 100
  • Hasil suhu yg didapat berupa integer kemudian diubah ke float melalui parseFloat
  • Selanjutnya suhu yg sudah berupa desimal float dibungkus kembali menjadi Json  : {payload:suhu} dan dikembalikan ke flow dengan perintah return .


Dengan function yang tepat maka hasil yg diinginkan pun tercapai. Jadi kunci disini adalah kemampuan javascript / programming yang harus cukup dimiliki oleh pengguna Node-RED.




Yang menjadi perhatian dalam function adalah bagaimana menyimpan variabel yang nantinya akan diambil saat flow berikutnya, semisal saya ingin mengubah 7 segmen secara increment. Jika ketemu masalah seperti ini maka yang perlu dipahami adalah perintah java berupa context atau flow. Perhatikan node berikut :



Output Function 7 segmen yg ingin kita dapatkan adalah membaca node inject dan  tombol pada dashboard /web UI yang akan merubah angka 7 segmen naik turun. Singkat saja scriptnya, dimana payload dari inject atau tombol berupa msg.payload = 1 untuk tambah dan msg.payload = 2 untuk pengurangan. Sedangkan variabel 7 segmen yang harus disimpan dan dipanggil lagi pada flow berikutnya disimpan melalui flow.get dan flow.set . Selengkapnya seperti berikut :


var count=flow.get('count') || 0;

var temp = msg.payload


if(temp == 1) count+=1;

else if(temp == 2) count-=1;


if(count > 9) count =0;

if(count < 0) count =9;


flow.set('count',count);


var result = {payload:count};

return[result];



Garis besar dari script diatas seperti ini : 


  • Ambil nilai variabel 'count' yg disimpan pada flow (global) ke dalam variabel count lokal , jika belum ada kasikan nilai 0,   var count=flow.get('count') || 0; 
  • Ambil nilai payload yang diberikan oleh inject atau tombol ui, kemudian cek apakah 1 atau 2 dan lakukan penambahan atau pengurangan variabel count
  • Set kondisi maksimum dan minimum dari count
  • Simpan kembali nilai variabel count lokal ke variabel count global dengan perintah : flow.set('count',count);
  • Kembalikan data ke flow dan lanjut dikirim ke node Modbus Write

Dengan susunan script function yang tepat maka flows node-RED yang diingikan tercapai. Function node yang simple juga sudah disediakan, tinggal drag drop dan siap pakai, namun dengan beberapa keterbatasan. Jadi kalau mau berkreasi lebih manfaatkan script Function saja sesuai keinginan. 

Penjelasan function yang saya buat ini adalah kelanjutan dari praktek Modbus-RTU-Serial sebelumnya yg dapat dibaca disini.







Share:

Rabu, 21 April 2021

[ Node-RED ] Komunikasi Dengan Perangkat MODBUS-RTU Serial - Praktek Sensor Suhu + 7 Segmen


 

Modbus dan PLC  baik dalam komunikasi jadulnya yg berbasis serial RS 485/ RS 232 maupun kini sudah merambah ke komunikasi TCP/IP, menjadi pilihan yang menurut penulis sudah "Final" dikalangan dunia kontrol industrial. Pengalaman penulis ketika menawarkan otomasi berbasis mikrokontroller 8 bit yg saya rancang dengan fungsi yang hampir sama, tetap mendapatkan tantangan dan pertanyaan seputar kehandalannya. Jadi saya yang pecinta hardware dasar pun di sangsikan apalagi mereka yg ingin menawarkan kemudahan dari sisi dunia IT. Sehingga menurut rekan dosen otomasi di UK-Petra Surabaya, Node-Red menjadi jembatan yang ampuh untuk menyatukan perangkat jadul dengan sistem IOT-Industri 4.0

Seperti yang pernah saya bahas di tahun sebelumnya, saat saya belajar dan berhasil merancang Modbus-RTU bridging ke MQTT (silahkan mulai disini , dibaca dan dipahami terlebih dahulu), mutlak diperlukan pemahaman sistem pengiriman data, register I/O , error checking dan sebagainya. Untuk itu perlu diulang kembali praktek awal belajar modbus yaitu menjadikan arduino sebagai perangkat Modbus-slave, dengan penyesuaian rangkaian yg sudah saya buat di praktek node-red sebelumnya,  sebagai berikut :




Dengan Input berupa pembacaan suhu dan kelembaban, maka saya menempatkan data pada Input / Analog Register berupa :


  • 30001 : Angka didepan koma / Puluhan suhu
  • 30002 : Angka desimal / di belekang koma suhu
  • 30003 : Angka pengukukuran kelembaban


Sedangkan untuk Output berupa 7 segmen, register yg digunakan adalah Holding Register dengan alamat 40001. Register ini juga dapat diubah mengunakan Function 0x06. Jadi script untuk merubah rangkaian arduino diatas menjadi berbasis MODBUS-RTU sebagai berikut :



//Silahkan unduh Library modbus slave: 
//https://code.google.com/archive/p/arduino-modbus-slave/downloads

#include <modbus.h>
#include <modbusDevice.h>
#include <modbusRegBank.h>
#include <modbusSlave.h>
#include "DHT.h"

//7seg

#define SEGA 5
#define SEGB 6
#define SEGC 7
#define SEGD 8
#define SEGE 9
#define SEGF 10
#define SEGG 11

#define dhtPin 4
#define DHTTYPE DHT22
DHT dht(dhtPin, DHTTYPE);

unsigned long previousMillis = 0;
const long interval = 5000; 


modbusDevice regBank;
modbusSlave slave;

void setup()
{   //7 seg
    pinMode(SEGA, OUTPUT);
    pinMode(SEGB, OUTPUT);
    pinMode(SEGC, OUTPUT);
    pinMode(SEGD, OUTPUT);
    pinMode(SEGE, OUTPUT);
    pinMode(SEGF, OUTPUT);
    pinMode(SEGG, OUTPUT);

 //Ubah modbus device ID.  
  regBank.setId(6);
  dht.begin();
/*
register modbus mengikuti format berikut
00001-09999 Output Digital, Perangkat master dapat membaca dan menulis ke register ini
10001-19999 Input Digital, Perangkat master hanya dapat membaca nilai dari register ini
30001-39999 Input Analog, Perangkat master hanya dapat membaca nilai dari register ini
40001-49999 Output Analog/ Holding register, 
            Perangkat master dapat membaca dan menulis ke register ini

Nilai analog adalah kata unsigned 16 bit yang disimpan dengan kisaran 0-32767
Nilai digital disimpan sebagai byte, nilai nol OFF dan nilai nonzer ON

Cara terbaik adalah mengkonfigurasi register tipe serupa ke dalam blok yang bersebelahan. ini
memungkinkan pencarian register yang lebih efisien dan dan mengurangi jumlah pesan
dibutuhkan oleh master untuk mengambil data
*/

 
//Pesan alamat Register Analog input di register bank 30001-10010 
  regBank.add(30001);  //DHT11 - suhu puluhan
  regBank.add(30002);  //DHT11 - suhu desimal
  regBank.add(30003);  //DHT11 - kelembaban
  
//Pesan alamat Holding Register 40001
  regBank.add(40001);  // 7 SEGMEN
//Isi nilai awal dari 7 segmen
  regBank.set(40001,8);
    

  slave._device = &regBank;  

// Serial 9600 baud  
  slave.setBaud(9600);   

}

void segmen(int angka)
{
 
   switch(angka) {
                  case 0 : { digitalWrite(SEGA, HIGH);
                             digitalWrite(SEGB, HIGH);
                             digitalWrite(SEGC, HIGH);
                             digitalWrite(SEGD, HIGH);                             
                             digitalWrite(SEGE, HIGH);
                             digitalWrite(SEGF, HIGH);
                             digitalWrite(SEGG, LOW);
                             break;
                  }
                  case 1 : { digitalWrite(SEGA, LOW);
                             digitalWrite(SEGB, HIGH);
                             digitalWrite(SEGC, HIGH);
                             digitalWrite(SEGD, LOW);                             
                             digitalWrite(SEGE, LOW);
                             digitalWrite(SEGF, LOW);
                             digitalWrite(SEGG, LOW);
                             break;
                  }
                  case 2 : { digitalWrite(SEGA, HIGH);
                             digitalWrite(SEGB, HIGH);
                             digitalWrite(SEGC, LOW);
                             digitalWrite(SEGD, HIGH);                             
                             digitalWrite(SEGE, HIGH);
                             digitalWrite(SEGF, LOW);
                             digitalWrite(SEGG, HIGH);
                             break;
                  }
                  case 3 : { digitalWrite(SEGA, HIGH);
                             digitalWrite(SEGB, HIGH);
                             digitalWrite(SEGC, HIGH);
                             digitalWrite(SEGD, HIGH);                             
                             digitalWrite(SEGE, LOW);
                             digitalWrite(SEGF, LOW);
                             digitalWrite(SEGG, HIGH);
                             break;
                  }
                  case 4 : { digitalWrite(SEGA, LOW);
                             digitalWrite(SEGB, HIGH);
                             digitalWrite(SEGC, HIGH);
                             digitalWrite(SEGD, LOW);                             
                             digitalWrite(SEGE, LOW);
                             digitalWrite(SEGF, HIGH);
                             digitalWrite(SEGG, HIGH);
                             break;
                  }

                  case 5 : { digitalWrite(SEGA, HIGH);
                             digitalWrite(SEGB, LOW);
                             digitalWrite(SEGC, HIGH);
                             digitalWrite(SEGD, HIGH);                             
                             digitalWrite(SEGE, LOW);
                             digitalWrite(SEGF, HIGH);
                             digitalWrite(SEGG, HIGH);
                             break;
                  }                                                          
                  case 6 : { digitalWrite(SEGA, HIGH);
                             digitalWrite(SEGB, LOW);
                             digitalWrite(SEGC, HIGH);
                             digitalWrite(SEGD, HIGH);                             
                             digitalWrite(SEGE, HIGH);
                             digitalWrite(SEGF, HIGH);
                             digitalWrite(SEGG, HIGH);
                             break;
                  }
                  case 7 : { digitalWrite(SEGA, HIGH);
                             digitalWrite(SEGB, HIGH);
                             digitalWrite(SEGC, HIGH);
                             digitalWrite(SEGD, LOW);                             
                             digitalWrite(SEGE, LOW);
                             digitalWrite(SEGF, LOW);
                             digitalWrite(SEGG, LOW);
                             break;
                  }
                  case 8 : { digitalWrite(SEGA, HIGH);
                             digitalWrite(SEGB, HIGH);
                             digitalWrite(SEGC, HIGH);
                             digitalWrite(SEGD, HIGH);                             
                             digitalWrite(SEGE, HIGH);
                             digitalWrite(SEGF, HIGH);
                             digitalWrite(SEGG, HIGH);
                             break;
                  }
                  case 9 : { digitalWrite(SEGA, HIGH);
                             digitalWrite(SEGB, HIGH);
                             digitalWrite(SEGC, HIGH);
                             digitalWrite(SEGD, HIGH);                             
                             digitalWrite(SEGE, LOW);
                             digitalWrite(SEGF, HIGH);
                             digitalWrite(SEGG, HIGH);
                             break;
                  }
   }
}

// mengubah koma 
int ExtractDecimalPart(float Value, int numberOfDecimals)
{
  float temp = Value - (long)(Value); 
  long p = 1;
  for (int i=0; i< numberOfDecimals; i++) p*=10;
  long DecimalPart = p * temp;
  return DecimalPart;
}

void loop()
{
//Tulis 7 segmen sesuai nilai pada register
  segmen(regBank.get(40001));  


//Baca suhu 5 detikan
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis >= interval) {
   
    previousMillis = currentMillis;   
 
    int h = dht.readHumidity();
    float t= dht.readTemperature();
    int t1 = t;
    int t2 = ExtractDecimalPart(t,2);

//tulis ke register 30001 -30003
    if (isnan(h) || isnan(t)) {
    regBank.set(30001,1000);
    regBank.set(30002,1000);
    regBank.set(30003,1000); 
    }

    
    regBank.set(30001,t1);
    regBank.set(30002,t2);
    regBank.set(30003,h);
   } 

  //jalan terus berulang sebagai slave  
  slave.run();  

}


Jadi jika selesai programming, dapat dilakukan test dengan software simulator modbus RADZIO : 




7 segmen kemudian bisa juga diubah dengan klik 2x pada kolom register  yang sesuai .




Selanjutnya di sisi Node-RED kita akan melakukan instalasi node yg bernama node-red-contrib-modbus. Instalasinya bisa juga dilakukan melalui editor Node-RED dengan memilih pilihan "manage pallete" di menu kanan atas.



Dengan demikian kita bisa menggunakan NODE modbus paling dasar yaitu MODBUS READ untuk membaca sensor suhu kelembaban DHT22 yg saya pakai. Settingnya cukup menyesuaikan dengan praktek sebelumnya yaitu penyesuaian com port, ID slave, dan debug sebagai output.



Hasilnya mencengangkan !



Sehari-semalam saya bingung dibuatnya, kenapa response dari Modbus Slave menampilkan array [0,0,0] ? Sampai kemudian saya ingat ada tools untuk melakukan debug / spy serial port bernama " SerialMon".



Dari hasil penelusuran, saya bandingkan serial yg dikirim terima oleh Radzio dengan Node-RED dan hasilnya saya salah di penomeran register.



Kejadian lagi deh kesalahan saat awal belajar modbus dulu ...jadi alamat register bukan dimulai dari 30001 melainkan cukup ditulis 0 (karena aturan offset jadi 1), ingat deh dulu seperti ini nih seharusnya :


06 04 00 00 00 03 B1 BC

06     =  Alamat device id slave
04     =  Perintah baca input analog/ function 04
00 00  = 2 byte alamat address memori (mulai 0 , logic 1)
00 03  = 2 byte panjang data yg diharapkan (3 buah data)
B1 BC  = Checksum / CRC 16 modbus


Dan yang benar seperti ini nih...langsung muncul angka suhu dan kelembabanya ...


 

Selanjutnya praktek sangat lancar dan cukup mengikuti praktek Node-RED web UI sebelumnya dan berhasil membuat hasil seperti video berikut ini :




Untuk Script Node-Red dalam JSON, saya tempel aja disini, kemudian bisa di import dan copy paste pada editor Node-RED kamu :



[{"id":"a8d0e1d9.32142","type":"tab","label":"Flow 5","disabled":false,"info":""},{"id":"d299086b.f08a88","type":"modbus-read","z":"a8d0e1d9.32142","name":"","topic":"","showStatusActivities":false,"logIOActivities":false,"showErrors":false,"unitid":"6","dataType":"InputRegister","adr":"0","quantity":"3","rate":"5","rateUnit":"s","delayOnStart":false,"startDelayTime":"","server":"824b1538.161228","useIOFile":false,"ioFile":"","useIOForPayload":false,"emptyMsgOnFail":false,"x":279.32994079589844,"y":205.96183681488037,"wires":[["7967f3c9.3415bc","5cfa62af.b1f89c","e0c9cab0.13e948"],[]]},{"id":"7967f3c9.3415bc","type":"debug","z":"a8d0e1d9.32142","name":"read_modbus","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":526.3299407958984,"y":55.16672134399414,"wires":[]},{"id":"341bb8e1.0d3b38","type":"modbus-write","z":"a8d0e1d9.32142","name":"","showStatusActivities":false,"showErrors":false,"unitid":"6","dataType":"HoldingRegister","adr":"0","quantity":"1","server":"824b1538.161228","emptyMsgOnFail":false,"keepMsgProperties":false,"x":685.3369064331055,"y":450.8092050552368,"wires":[[],[]]},{"id":"b0f6eeca.9fc8f","type":"debug","z":"a8d0e1d9.32142","name":"out_modbus","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":681.3334045410156,"y":365.1701936721802,"wires":[]},{"id":"36302ceb.d3b7b4","type":"inject","z":"a8d0e1d9.32142","name":"decrement","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":"","topic":"","payload":"2","payloadType":"num","x":272.8958435058594,"y":403.8888854980469,"wires":[["44bf1fc9.8d7fd"]]},{"id":"96e67c14.b9386","type":"inject","z":"a8d0e1d9.32142","name":"increment","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":"","topic":"","payload":"1","payloadType":"num","x":272.8958435058594,"y":363.8888854980469,"wires":[["44bf1fc9.8d7fd"]]},{"id":"44bf1fc9.8d7fd","type":"function","z":"a8d0e1d9.32142","name":"7 segmen","func":"var count=flow.get('count') || 0;\n\nvar temp = msg.payload\n\nif(temp == 1) count+=1;\nelse if(temp == 2) count-=1;\n\nif(count > 9) count =0;\nif(count < 0) count =9;\n\nflow.set('count',count);\n\nvar result = {payload:count};\nreturn[result];","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":473.89587783813477,"y":379.8889045715332,"wires":[["b0f6eeca.9fc8f","341bb8e1.0d3b38","8ca591c3.507c8"]]},{"id":"39680ef0.a0ec02","type":"ui_gauge","z":"a8d0e1d9.32142","name":"SUHU DHT 11","group":"fc14d827.fe2ea8","order":1,"width":0,"height":0,"gtype":"gage","title":"Suhu Celcius","label":"Celcius","format":"{{value}}","min":0,"max":"50","colors":["#00b500","#e6e600","#ca3838"],"seg1":"","seg2":"","x":746.8958358764648,"y":147.88887405395508,"wires":[]},{"id":"fc85d4ce.fbaa78","type":"ui_chart","z":"a8d0e1d9.32142","name":"","group":"fc14d827.fe2ea8","order":2,"width":0,"height":0,"label":"Kelembaban %Rh","chartType":"line","legend":"false","xformat":"HH:mm:ss","interpolate":"linear","nodata":"","dot":false,"ymin":"40","ymax":"100","removeOlder":1,"removeOlderPoints":"","removeOlderUnit":"60","cutout":0,"useOneColor":false,"useUTC":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"outputs":1,"useDifferentColor":false,"x":756.8958511352539,"y":260.88890075683594,"wires":[[]]},{"id":"5cfa62af.b1f89c","type":"function","z":"a8d0e1d9.32142","name":"ubah suhu","func":"var temp = msg.payload;\nvar puluhan = temp[0]\nvar desimal = temp[1]\n\nvar ongko = (parseInt(puluhan) * 100) + desimal;\nvar suhu = parseFloat(ongko /100);\nvar result = {payload:suhu};\nreturn[result];\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":532.3402481079102,"y":154.70834350585938,"wires":[["39680ef0.a0ec02"]]},{"id":"e0c9cab0.13e948","type":"function","z":"a8d0e1d9.32142","name":"ubah humi","func":"var temp = msg.payload\nvar humi = parseInt( temp[2] )\n\nvar result = {payload:humi};\nreturn[result];\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":527.8958129882812,"y":237.88888549804688,"wires":[["fc85d4ce.fbaa78","f739dfd5.58126"]]},{"id":"f739dfd5.58126","type":"debug","z":"a8d0e1d9.32142","name":"ubah suhu","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":755.3402862548828,"y":202.18057250976562,"wires":[]},{"id":"8ca591c3.507c8","type":"ui_text","z":"a8d0e1d9.32142","group":"fc14d827.fe2ea8","order":4,"width":0,"height":0,"name":"","label":"7 Segmen","format":"{{msg.payload}}","layout":"row-spread","x":681.3299102783203,"y":407.0590515136719,"wires":[]},{"id":"5b185e1a.af2f7","type":"ui_button","z":"a8d0e1d9.32142","name":"Tambah","group":"fc14d827.fe2ea8","order":8,"width":"3","height":"2","passthru":false,"label":"Tambah ","tooltip":"","color":"","bgcolor":"","icon":"","payload":"1","payloadType":"num","topic":"payload","topicType":"msg","x":269.32643127441406,"y":313.2986240386963,"wires":[["44bf1fc9.8d7fd"]]},{"id":"a4c4a5d.a88cc58","type":"ui_button","z":"a8d0e1d9.32142","name":"Kurang","group":"fc14d827.fe2ea8","order":8,"width":"3","height":"2","passthru":false,"label":"Kurang","tooltip":"","color":"","bgcolor":"","icon":"","payload":"2","payloadType":"num","topic":"payload","topicType":"msg","x":273.8958435058594,"y":454.8888854980469,"wires":[["44bf1fc9.8d7fd"]]},{"id":"824b1538.161228","type":"modbus-client","name":"","clienttype":"simpleser","bufferCommands":true,"stateLogEnabled":false,"queueLogEnabled":false,"tcpHost":"127.0.0.1","tcpPort":"502","tcpType":"DEFAULT","serialPort":"COM7","serialType":"RTU-BUFFERD","serialBaudrate":"9600","serialDatabits":"8","serialStopbits":"1","serialParity":"none","serialConnectionDelay":"100","unit_id":"1","commandDelay":"1","clientTimeout":"1000","reconnectOnTimeout":true,"reconnectTimeout":"2000","parallelUnitIdsAllowed":true},{"id":"fc14d827.fe2ea8","type":"ui_group","name":"modbus RTU ui testing","tab":"53c1826d.1539dc","order":2,"disp":true,"width":"6","collapse":false},{"id":"53c1826d.1539dc","type":"ui_tab","name":"HumiTemp Node Red","icon":"dashboard","order":1,"disabled":false,"hidden":false}]






SELAMAT MENCOBA ....

Share:

Selasa, 20 April 2021

[ Node-RED ] Komunikasi ke sensor menggunakan MQTT


Blog ini sudah banyak membahas MQTT terutama sejak 2 tahun lalu saat saya mulai melirik barang yang bernama IOT. Bagi kalian yang baru beralih dari microcontroller 8 bit ke dunia IOT atau kebalikannya  seorang IT programmer yang ingin berkecimpung di dunia 8 bit, mungkin ini suatu keputusan yg akan membingungkan. Jangan salah langkah deh pokoknya, lalu mulai dari mana sih ? Jadi saran saya adalah :


  • Jika anda pecinta elektronika, skema belajar yg tepat adalah Serial Com=>MQTT => Python => Node-RED
  • Jika anda seorang praktisi IT maka kebalikannya  Node-RED => MQTT => Arduino => Serial com

Jadi seperti saya ini yg pecinta dunia 8 bit, maka sudah tepat sekali menghindari Node-RED di awal belajar, karena akan mengalami kesulitan mengikuti logika Flow diagramnya. Sehingga saat saya sudah menguasai betul- betul MQTT sampai ke level advance ( bisa dibaca disini ), saat menghadapi Node-RED yang tinggal Drag-Drop maka akan sangat dimudahkan.



Untuk melanjutkan project MQTT pada Node-RED sebaiknya baca terlebih dahulu praktek MQTT sebelumnya pada pembahasan saya 2 tahun yang lalu : https://www.aisi555.com/2019/10/iot-lebih-lanjut-dengan-mqtt.html .

Dengan rangkaian yg masih sama dengan praktek sebelumnya, kita akan mebutuhkan modul esp8266 sebagai jembatan ke TCP/IP  menggunakan wi-fi. Sehingga akan lebih mudah jika menggunakan WeMos D1 dan sejenis. Jika tidak maka tinggal disesuaikan saja sesuai perangkat yg ada. Script yg dulu kita bahas 2 tahun yg lalu kita modifikasikan seperti ini, menggunakan DHT 22 dan 7 segmen komon katoda.



#include <DHT.h>
#include <ESP8266WiFi.h> //library esp 8266
#include <PubSubClient.h> //library MQTT pubsub client


const char *ssid =  "wifiku";   // nama AP wifi dirumah
const char *pass =  "passwordku";   
//server atau broker MQTT gratis
const char *mqtt_server = "broker.hivemq.com";
const int mqtt_port = 1883;
const char *mqtt_user = "";
const char *mqtt_pass = "";
const char *mqtt_client_name = "ahocool123"; 
//topik yang akan dituju
#define SUHUTOPIC "/test/suhu" 
#define HUMITOPIC "/test/kelembaban"
#define SEGTOPIC "/test/seg"

//Constants
#define DHTPIN 13     // what pin we're connected to
#define DHTTYPE DHT22   // DHT 22  (AM2302)
DHT dht(DHTPIN, DHTTYPE); //// Initialize DHT sensor for normal 16mhz Arduino

//7seg

#define SEGA 16
#define SEGB 5
#define SEGC 4
#define SEGD 14
#define SEGE 12
#define SEGF 0
#define SEGG 2

//timer dht22
unsigned long previousMillis = 0;
const long interval = 5000;  

//Variables
float hum;  //Stores humidity value
float temp; //Stores temperature value

int incomingByte = 0; // for incoming serial data

//inisialisasi klien wifi vs Mqtt
WiFiClient wclient;
PubSubClient client(wclient);

void setup()
{

    pinMode(SEGA, OUTPUT);
    pinMode(SEGB, OUTPUT);
    pinMode(SEGC, OUTPUT);
    pinMode(SEGD, OUTPUT);
    pinMode(SEGE, OUTPUT);
    pinMode(SEGF, OUTPUT);
    pinMode(SEGG, OUTPUT);

    client.setServer(mqtt_server, mqtt_port);
    client.setCallback(mqtt_callback);
    
    Serial.begin(9600);
    setupwifi();
    dht.begin();

}

void setupwifi()  
{
   if (WiFi.status() != WL_CONNECTED) {
    Serial.print("Connecting to Wifi:  ");
    Serial.print(ssid);
    Serial.println("...");
    WiFi.begin(ssid, pass);

    if (WiFi.waitForConnectResult() != WL_CONNECTED)
      return;
    Serial.println("WiFi connected");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
  }
}

void reconnectmqtt()  //ngecek broker KQTT 
{
   
    
      Serial.println("Connecting to MQTT server..");
     
      if (client.connect(mqtt_client_name,mqtt_user, mqtt_pass)) {
        Serial.println("Connected to MQTT server");
      } else {
        Serial.println("Could not connect to MQTT server");   
      }
   

    if (client.connected()){
      Serial.println("subscribe to topic: ");
      Serial.println(SEGTOPIC);
      client.subscribe(SEGTOPIC); //subscribe ke topic 7 segmen
    }  
  
}


void segmen(int angka)
{
 
   switch(angka) {
                  case 0 : { digitalWrite(SEGA, HIGH);
                             digitalWrite(SEGB, HIGH);
                             digitalWrite(SEGC, HIGH);
                             digitalWrite(SEGD, HIGH);                             
                             digitalWrite(SEGE, HIGH);
                             digitalWrite(SEGF, HIGH);
                             digitalWrite(SEGG, LOW);
                             break;
                  }
                  case 1 : { digitalWrite(SEGA, LOW);
                             digitalWrite(SEGB, HIGH);
                             digitalWrite(SEGC, HIGH);
                             digitalWrite(SEGD, LOW);                             
                             digitalWrite(SEGE, LOW);
                             digitalWrite(SEGF, LOW);
                             digitalWrite(SEGG, LOW);
                             break;
                  }
                  case 2 : { digitalWrite(SEGA, HIGH);
                             digitalWrite(SEGB, HIGH);
                             digitalWrite(SEGC, LOW);
                             digitalWrite(SEGD, HIGH);                             
                             digitalWrite(SEGE, HIGH);
                             digitalWrite(SEGF, LOW);
                             digitalWrite(SEGG, HIGH);
                             break;
                  }
                  case 3 : { digitalWrite(SEGA, HIGH);
                             digitalWrite(SEGB, HIGH);
                             digitalWrite(SEGC, HIGH);
                             digitalWrite(SEGD, HIGH);                             
                             digitalWrite(SEGE, LOW);
                             digitalWrite(SEGF, LOW);
                             digitalWrite(SEGG, HIGH);
                             break;
                  }
                  case 4 : { digitalWrite(SEGA, LOW);
                             digitalWrite(SEGB, HIGH);
                             digitalWrite(SEGC, HIGH);
                             digitalWrite(SEGD, LOW);                             
                             digitalWrite(SEGE, LOW);
                             digitalWrite(SEGF, HIGH);
                             digitalWrite(SEGG, HIGH);
                             break;
                  }

                  case 5 : { digitalWrite(SEGA, HIGH);
                             digitalWrite(SEGB, LOW);
                             digitalWrite(SEGC, HIGH);
                             digitalWrite(SEGD, HIGH);                             
                             digitalWrite(SEGE, LOW);
                             digitalWrite(SEGF, HIGH);
                             digitalWrite(SEGG, HIGH);
                             break;
                  }                                                          
                  case 6 : { digitalWrite(SEGA, HIGH);
                             digitalWrite(SEGB, LOW);
                             digitalWrite(SEGC, HIGH);
                             digitalWrite(SEGD, HIGH);                             
                             digitalWrite(SEGE, HIGH);
                             digitalWrite(SEGF, HIGH);
                             digitalWrite(SEGG, HIGH);
                             break;
                  }
                  case 7 : { digitalWrite(SEGA, HIGH);
                             digitalWrite(SEGB, HIGH);
                             digitalWrite(SEGC, HIGH);
                             digitalWrite(SEGD, LOW);                             
                             digitalWrite(SEGE, LOW);
                             digitalWrite(SEGF, LOW);
                             digitalWrite(SEGG, LOW);
                             break;
                  }
                  case 8 : { digitalWrite(SEGA, HIGH);
                             digitalWrite(SEGB, HIGH);
                             digitalWrite(SEGC, HIGH);
                             digitalWrite(SEGD, HIGH);                             
                             digitalWrite(SEGE, HIGH);
                             digitalWrite(SEGF, HIGH);
                             digitalWrite(SEGG, HIGH);
                             break;
                  }
                  case 9 : { digitalWrite(SEGA, HIGH);
                             digitalWrite(SEGB, HIGH);
                             digitalWrite(SEGC, HIGH);
                             digitalWrite(SEGD, HIGH);                             
                             digitalWrite(SEGE, LOW);
                             digitalWrite(SEGF, HIGH);
                             digitalWrite(SEGG, HIGH);
                             break;
                  }
   }
}
void loop()
{
   if (!client.connected())  //ngecek koneksi ke broker
   {
    reconnectmqtt();
   }
   else client.loop(); //cek terus kalau ada data masuk
  
    
    
    
    unsigned long currentMillis = millis();
 
   if(currentMillis - previousMillis >= interval) {
    // save the last time you read the sensor 
    previousMillis = currentMillis;   
    
    //Read data and store it to variables hum and temp
    hum = dht.readHumidity();
    temp= dht.readTemperature();
    //Print temp and humidity values to serial monitor
    Serial.print("Humidity: ");
    Serial.print(hum);
    Serial.print(" %, Temp: ");
    Serial.print(temp);
    Serial.println(" Celsius");
   
    String pubStringt = String(temp);
    String pubStringh = String(hum);
    

    Serial.println("publish to topic: " );
    Serial.print(SUHUTOPIC);
    Serial.print(" : ");
    Serial.println(pubStringt);
    char message_bufft[pubStringt.length() + 1];
    pubStringt.toCharArray(message_bufft, pubStringt.length() + 1);
    client.publish(SUHUTOPIC,message_bufft );

    Serial.println("publish to topic: " );
    Serial.print(HUMITOPIC);
    Serial.print(" : ");
    Serial.println(pubStringh);
    char message_buffh[pubStringh.length() + 1];
    pubStringh.toCharArray(message_buffh, pubStringh.length() + 1);
    client.publish(HUMITOPIC,message_buffh );
   
   
   }


}
   // call back untuk SUBSCRIBE topik 7 segmen
void mqtt_callback(char* topic, byte* payload, unsigned int length) {
 
  Serial.print("Message arrived in topic: ");
  Serial.println(topic);
 
  Serial.print("Message:");
  //ada SUB masuk
  String message;
  for (int i = 0; i < length; i++) {
    message = message + (char)payload[i];  //Conver *byte to String
  }
   Serial.print(message);
  //ubah tampilan 7 segmen
  if(message == "SEG1") {segmen(1); }
  if(message == "SEG2") {segmen(2); }
  if(message == "SEG3") {segmen(3); }
  if(message == "SEG4") {segmen(4); }
  if(message == "SEG5") {segmen(5); }
  if(message == "SEG6") {segmen(6); }
  if(message == "SEG7") {segmen(7); }
  if(message == "SEG8") {segmen(8); }
  if(message == "SEG9") {segmen(9); }
  if(message == "SEG0") {segmen(0);}
}


   


Saya memilih broker MQTT di internet yg opensource dan gratis yaitu htp://broker.hivemq.com dengan port 1883. Jika tidak ada internet di rumah anda dapat menginstall Mosquitto pada PC berbasis linux atau raspberry pi. Penjelasannya dapat dibaca disini : https://www.aisi555.com/2020/05/iot-geopy-sebagai-pengolah-data-gis.html . Jadi jika hardware sudah terhubung dan kita ingin mengetest koneksi PUBLISH dan SUBSCRIBE nya , dapat menggunakan software MQTT FX di pc windows anda.


Setting parameter Broker :



PUBLISH message ke TOPIC di Broker


SUBSCRIBE Topic ke broker dan melihat outputnya berupa suhu dan kelembaban.


Setelah hardware arduino / wemos terhubung dengan sukses ke Broker dan bisa dilakukan kontrol terhadapnya, maka di sisi Node-RED kita perlu menambahan Node MQTT dengan perintah pada command prompt seperti berikut :

npm install node-red-contrib-mqtt-broker

Dan kita bisa langsung melakukan drag-drop node MQTT in seperti gambar dibawah ini :




Karena HiveMq sangat sederhana dan tanpa security, maka dengan setup seperti diatas kita bisa melakukan subscribe pada topic yang diinginkan , seperti  contoh yg kita pakai di topik : /test/suhu :


 
Dan kita bisa menghubungkan MQTT input ke debug sehingga dapat melihat pesan yang masuk.



Tambahkan juga untuk topik :  /test/kelembaban 



Untuk proses PUBLISH yang bertujuan ingin merubah 7 segmen maka Node-RED melakukan PUB ke topik  /test/seg , kita gunakan 10 injector saja untuk memudahkan mengirim string " SEG0 - SEG9 " ke MQTT broker.



Dan hasilnya bisa dilihat pada monitor serial di Arduino lanjut bisa dilihat pula pada display 7 segmen.





Nahh..mudah bukan ? Untuk menghadirkan tampilan yang lebih interaktif pada WEB UI seperti pada pembahasan sebelumnya ( disini ) , maka kita cukup mengganti input port serial menjadi MQTT, kemudian 7 segmennya saya tambahkan drop down menu seperti gambar dibawah :






Tampilannya pun cukup menarik sebagai interface otomasi perangkat IOT di rumah anda.




Wew ...kerennn....Lanjut ke Node-RED vs MODBUS ya pada pembahasan selanjutnya.
Share:

Kontak Penulis



12179018.png (60×60)
+628155737755

Mail : ahocool@gmail.com

Site View

Categories

555 (8) 7 segmen (3) adc (4) amplifier (2) analog (19) android (12) antares (8) arduino (25) artikel (11) attiny (3) attiny2313 (19) audio (5) baterai (5) blog (1) bluetooth (1) chatgpt (2) cmos (2) crypto (2) dasar (46) digital (11) dimmer (5) display (3) esp8266 (25) euro2020 (13) gcc (1) iklan (1) infrared (2) Input Output (3) iot (58) jam (7) jualan (12) kereta api (1) keyboard (1) keypad (3) kios pulsa (2) kit (6) komponen (17) komputer (3) komunikasi (1) kontrol (8) lain-lain (8) lcd (2) led (14) led matrix (6) line tracer (1) lm35 (1) lora (5) MATV (1) memory (1) metal detector (4) microcontroller (70) micropython (6) mikrokontroler (1) mikrokontroller (14) mikrotik (5) modbus (9) mqtt (3) ninmedia (5) ntp (1) paket belajar (19) palang pintu otomatis (1) parabola (88) pcb (2) power (1) praktek (2) project (33) proyek (1) python (7) radio (15) raspberry pi (4) remote (1) revisi (1) rfid (1) robot (1) rpm (2) rs232 (1) script break down (3) sdcard (3) sensor (2) sharing (3) signage (1) sinyal (1) sms (6) software (18) solar (1) solusi (1) tachometer (2) technology (1) teknologi (2) telegram (2) telepon (9) televisi (167) television (28) transistor (2) troubleshoot (3) tulisan (92) tutorial (108) tv digital (6) tvri (2) vu meter (2) vumeter (2) wav player (3) wayang (1) wifi (3)

Arsip Blog

Diskusi


kaskus
Forum Hobby Elektronika