Jumat, 06 Maret 2015

Programmable Gain Amplifier (PGA) MCP6S21 menggunakan Arduino

PGA atau Programmable Gain Amplifier adalah OpAmp yang memiliki gain pada range tertentu dan dapat diprogram. Jika pada OpAmp biasa pensettingan gain dilakukan menggunakan konfigurasi resistor, maka pada PGA setting gain dilakukan dengan menggunakan software. Hal ini sangat berguna untuk pengukuran besaran analog atau pengaturan tegangan analog yang bersifat dinamis. Yang mana dibutuhkan besaran gain yang fleksibel sesuai kebutuhan.



Pada posting kali ini, PGA yang digunakan adalah MCP6S21 dari Microchip. MCP6S21 memiliki besaran gain +1, +2, +4, +5, +8, +10, +16 dan +32 dengan bandwith 2-12 MHz (typ). MCP6S21 hanya memiliki 1 (satu) channel input. MCP6S21 menggunakan komunikasi SPI untuk pengaturan gain maupun mode shutdown. Model PGA MCP6S21 tidak memiliki pin SO (MISO).





Berbeda dengan tipe MCP6S26 yang memiliki 6 channel input dan MCP6S28 dengan 8 channel input sehingga dapat sekaligus berfungsi sebagai multiplexer. MCP6S26 dan MCP6S28 memiliki pin SO (MISO) sehingga memungkinkan konfigurasi daisy chain (cascade atau bersambung dengan menggunakan SPI yang sama)


Berikut adalah source code untuk mengatur gain dan mode shutdown pada PGA MCP6S21. Code ini dibuat berdasarkan datasheet dan referensi lain. Source code berikut memungkinkan merubah gain maupun mode shutdown melalui serial terminal. Sehingga bisa dikembangkan untuk komunikasi dengan program desktop lain (seperti VB, Delphi, C atau yang lain).

/*
Author: Muhammad Nurul Puji
muhammadpuji.its@gmail.com
6 Mar 2015
*/

#include <SPI.h>
/*
CS- to pin 10 (SS Pin)
SI- to pin 11 (MOSI Pin)
CLK - to pin 13 (SCK Pin)
*/
const int CS_PGA = 10;  //#define CS_PGA 10

char buff_char;
String buff_string = "";
int gain;

void setup()
{
  //setting SPI-PGA MCP6S2x
  pinMode(CS_PGA,OUTPUT);
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);  //MSB first bit order
  SPI.setDataMode(SPI_MODE0);  //SPI Mode 0
  SPI.setClockDivider(SPI_CLOCK_DIV4);  //16MHZ/4=4MHZ
  
  //setting Serial
  Serial.begin(57600);
  delay(1);
  Serial.println("");
  Serial.println("Welcome Muhammad Nurul Puji");
  Serial.println("Silahkan masukkan nilai gain yang diinginkan");
  Serial.println("0--> +1; 1--> +2; 2--> +4; 3--> +5; 4--> +8; 5--> +10; 6--> +16; 7--> +32; Other--> Shutdown");
  Serial.println("");
  delay(1);
}

void loop()
{
  while(Serial.available()) {
    buff_char = Serial.read();
    buff_string.concat(buff_char);
    delay(1);  //delay ini sangat penting
  }  

  if(buff_string != ""){
    gain=buff_string.toInt();  
    if(gain<=7){
    PGA_set_gain(gain); 
    Serial.println("Gain is Changed");
    }
    else{
    PGA_shutdown();
    Serial.println("PGA is Shutdown");
    }
    buff_string="";
  }
}

//pengaturan set nilai gain pada PGA MCP6S21
void PGA_set_gain(int gain){
  int instruction = 0b01000000;  //untuk instruksi merubah gain
  digitalWrite(CS_PGA,LOW);
  SPI.transfer(instruction);   
  SPI.transfer(gain);    //set gain
  digitalWrite(CS_PGA,HIGH);
}

//untuk shutdown pada PGA MCP6s21
void PGA_shutdown(){
  int instruction = 0b00100000;  //untuk instruksi shutdown
  digitalWrite(CS_PGA,LOW);
  SPI.transfer(instruction);
  SPI.transfer(0);    //hanya untuk memenuhi aturan 16bit
  digitalWrite(CS_PGA,HIGH);
}



Prosedur PGA_set_gain() dan PGA_shutdown() dapat dikembangkan untuk PGA MCP6S26 maupun MCP6S26 baik mode single maupun mode daisy chain serta untuk pemilihan channel. Hal ini harus disesuaikan dengan datasheet.

Thanks to Mas Rohmadi (http://rohmadi.my.id) atas pinjaman Oscilloscopnya :)
--
Referensi:
http://ww1.microchip.com/downloads/en/DeviceDoc/21117B.pdf (Datasheet)
http://forum.arduino.cc/index.php?topic=19775.0

Kamis, 26 Februari 2015

Arduino Komunikasi serial dan pemisahan terhadap separator perintah

Berikut adalah penggunaan Arduino dengan komunikasi serial. Yang mana perintah dikirim dari pc melalui komunikasi serial. Perintah yang dikirim oleh pc memiliki format "data_1""separator""data_2". Disini separator yang digunakan adalah tanda "+". Misalnya pc mengirimkan perintah "12+3" maka Arduino harus memisahkan perintah tersebut menjadi data_1 dan data_2. Pada percobaan kali ini data_1 dan data_2 kemudian dijumlahkan.

Berikut adalah sourcecode yang digunakan: 


/*
Author: Muhammad Nurul Puji
muhammadpuji.its@gmail.com
16 Feb 2015
*/

char buff_char;
String buff_string = "";
float data_1, data_2, total;
String buff_data_1, buff_data_2;

void setup()
{
  Serial.begin(57600);
  delay(100);
  Serial.println("Welcome Muhammad Nurul Puji");
  Serial.println("");
  delay(1000);
}

void loop()
{
 

while(Serial.available()) {  //blok untuk menerima perintah serial    
    buff_char = Serial.read();
    buff_string.concat(buff_char);
    delay(1);  //delay ini sangat penting
  } 
 
 
  if(buff_string != ""){
    buff_data_1=(splitValue(buff_string, '+', 0));  //memisahkan string data dengan string separator "+"
    buff_data_2=(splitValue(buff_string, '+', 1));
   
    //char buff[buff_data_1.length()];               //mengubah string ke float
    //buff_data_1.toCharArray(buff,buff_data_1.length()+1);
    //data_1=atof(buff);

    data_1=buff_data_1.toInt();   //cara singkat mengubah string ke number
   
    //buff[buff_data_2.length()];                    //mengubah string ke float
    //buff_data_2.toCharArray(buff,buff_data_2.length()+1);
    //data_2=atof(buff); 

    data_2=buff_data_2.toInt();   //cara singkat mengubah string ke number   
    

    total = data_1 + data_2;
   
    Serial.print("Perintah awal adalah ");
    Serial.print(buff_string);  //bukan println karena perintah dikirim setelah ditekan enter
    Serial.print("Data 1 = ");
    Serial.println(data_1);
    Serial.print("Data 2 = ");
    Serial.println(data_2);
    Serial.print("Total data adalah ");
    Serial.println(total);
    Serial.println("");
   
    buff_string="";
  }
}

//Function untuk memisahkan data dengan separator

String splitValue(String data, char separator, int index){
  int found = 0;
  int strIndex[]={0, -1};
  int maxIndex = data.length()-1;
  for(int i=0; i<=maxIndex && found<=index; i++){
    if(data.charAt(i) == separator || i==maxIndex){
      found++;
      strIndex[0] = strIndex[1]+1;
      strIndex[1] = (i == maxIndex) ? i+1 : i;
    }
  }
  return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
}



Referensi: dari postingan - postingan sebelumnya...........
--
Semoga bermanfaat

Selasa, 24 Februari 2015

Source code untuk mengenali pola data string dan memisahkannya dalam masing-masing variabel

Berikut adalah beberapa code untuk mengenali pattern ato pola string kemudian data string tersebut dapat dipisah sesuai "separator" yg digunakan. Source code berikut sangat powerfull dan terpilih dari beberapa sumber.

Pemisahan pattern string sangat penting dalam pemberian perintah (command), misal dalam aplikasi mikrokontroler yg diperintah oleh PC (atau mikrokontroller lain) untuk kontrol pengambilan data. Sehingga dalam sekali kirim perintah bisa dimasukkan beberapa parameter yg diinginkan. Kemudian mikrokontroller bisa memisahkan parameter-parameter tsb dgn sourcecode berikut ini.

Excellent code....

Stackexchange.com







Stackoverflow.com



Github.com



--
Sumber referensi (dicopy tgl 15 Februari 2015)
http://arduino.stackexchange.com/questions/1013/how-do-i-split-an-incoming-string
http://stackoverflow.com/questions/9072320/split-string-into-string-array
https://github.com/ka1/sousVide/blob/master/arduino/TempYun/functions.ino#

Rabu, 17 September 2014

Signal Generator (DDS AD9850) dan Frekuensi Meter dan Kontrol Frekuensi dari Serial Monitor

Ini adalah posting lanjutan dari Signal Signal Generator DDS A9850 dan Frekuensi Meter . Dengan Saya tambahkan bagian untuk dapat merubah frekuensi secara serial melalui serial monitor pada Arduino sehingga frekuensi dapat diatur lebih fleksibel tanpa bolak balik upload program. 

Berikut definisi variable yang perlu ditambahkan pada source code sebelumnya:

float buff_data;
String buff_string = "";
char buff_char;
 

Berikut modifikasi souce code (pengganti) yang berada pada bagian void loop(). Sedangkan yang lain masih tetap sama dengan source code sebelumnya.

void loop()
{
       
        //lcd.clear();
       
        //cek perintah serial
        while(Serial.available()) {
        buff_char = Serial.read();
        buff_string.concat(buff_char);    //menggabungkan variabel buff_char ke variable buff_string
        }
       
        //merubah tipe data string ke float (tipe data float = double)
        char buf[buff_string.length()];
        buff_string.toCharArray(buf,buff_string.length()+1);
        float buff_data=atof(buf);  //buff_data akan nol pada loop berikutnya jika tidak ada perintah

                                    //(karena buff_string dikosongkan "" diakhir loop)
       
        //cek jika ada permintaan perubahan frekuensi 
        if (buff_data>0) sendFrequency(buff_data);
      
        Serial.print(freq_cek);
        Serial.print(" ");
        Serial.println(freq_satuan);
        lcd.setCursor(0,0);   
        lcd.print("Freq DDS AD9850");
        lcd.setCursor(0,1);   
        lcd.print("Freq= ");
        lcd.print(freq_cek);
        lcd.print(" ");
        lcd.print(freq_satuan);
        //delay(500);
       
        buff_string="";
}



Berikut adalah screenshot hasil modifikasi dengan source code di atas:

Contoh Hasil pada Serial Monitor


Beberapa referensi utama:
http://www.instructables.com/id/Arduino-Timer-Interrupts/?ALLSTEPS
http://www.ad7c.com/projects/ad9850-dds-vfo/

http://letsmakerobots.com/content/how-convert-strings-double
http://stackoverflow.com/questions/5697047/convert-serial-read-into-a-useable-string-using-arduino 

Merubah tipe data String ke Float (atau Double)

Berikut adalah source code untuk merubah tipe data String ke tipe data float (atau double). Ini sangat berguna saat komunikasi serial yang biasanya perintah dikirimkan melalui tipe data string

float buff_data;
String buff_string = "123.22";

//merubah tipe data string ke float (tipe data float = double)
        char buf[buff_string.length()];
        buff_string.toCharArray(buf,buff_string.length()+1);
        float buff_data=atof(buf);


double buff_data;
String buff_string = "123.22";

//merubah tipe data string ke float (tipe data float = double)
        char buf[buff_string.length()];
        buff_string.toCharArray(buf,buff_string.length()+1);
        double buff_data=atof(buf);


Referensi:
http://letsmakerobots.com/content/how-convert-strings-double

Membaca tipe String pada komunikasi serial (Arduino - PC)

Berikut adalah source code untuk membaca string pada komunikasi serial. Hasil yang terbaca adalah semua string yang dikirim secara serial setelah ditekan enter.

String buff_string = "";
char buff_char;

while(Serial.available()) {
  buff_char = Serial.read();
  buff_string.concat(buff_char);    //menggabungkan variabel buff_char ke variable buff_string

}

Referensi:
http://stackoverflow.com/questions/5697047/convert-serial-read-into-a-useable-string-using-arduino

Signal Generator (DDS AD9850) dan Frekuensi Meter

Posting kali ini bertujuan untuk membangkitkan signal DDS menggunakan IC AD 9850. IC ini sudah tersedia dalam bentuk modul. Keluaran IC ini berupa gelombang sinus dan kotak. Karena IC ini bersifat programmable maka frekuensi akan disetting menggunakan Arduino Uno.

Kemudian dibuat pula program untuk mengecek frekuensi yang dikeluarkan oleh IC tersebut setelah diprogram sebelumnya. Aplikasi penghitung frekuensi ini juga dapat digunakan untuk menghitung frekuensi yang lain dengan cara menghubungkan sumber frekuensi ke pin T1 (timer1 sebagai counter.

Untuk menghitung frekuensi yang dikeluarkan oleh DDS AD9850 maka output signal kotak dihubungkan ke pin T1 dari Arduino Uno.

Hasil penghitungan frekuensi kemudian ditampilkan dalam LCD 16x2 dan dikirim ke PC secara serial.

Konfigurasi Pin Arduino Uno

Konfigurasi Pin Modul DDS AD9850
Konfigurasi LCD:
LiquidCrystal lcd(12,13,3,4,6,7); //Konfigurasi schematic LCD Keypad

Konfigurasi DDS AD9850:
///////////////AD9850
#define W_CLK 8   // Pin 8 - connect to AD9850 module word load clock pin (CLK)
#define FQ_UD 9   // Pin 9 - connect to freq update pin (FQ)
#define DATA 10   // Pin 10 - connect to serial data load pin (DATA)
#define RESET 11  // Pin 11 - connect to reset pin (RST)
///////////////AD9850
Konfigurasi Counter1:
Pin output gelombang kotak dari DDS AD9850 dihubungkan ke pin T1 pada Arduino Uno.

Berikut Source Code Lengkapnya:
/*
Author: Muhammad Nurul Puji
muhammadpuji.its@gmail.com
This program have been tested on Arduino Uno R3, DDS AD9850 and LCD Keypad
2013
*/

#include <LiquidCrystal.h>

LiquidCrystal lcd(12,13,3,4,6,7); //Konfigurasi schematic LCD Keypad

///////////////AD9850
#define W_CLK 8   // Pin 8 - connect to AD9850 module word load clock pin (CLK)
#define FQ_UD 9   // Pin 9 - connect to freq update pin (FQ)
#define DATA 10   // Pin 10 - connect to serial data load pin (DATA)
#define RESET 11  // Pin 11 - connect to reset pin (RST)
#define pulseHigh(pin) {digitalWrite(pin, HIGH); digitalWrite(pin, LOW); }
String freq; // string to hold the frequency
///////////////AD9850

/////////Freq Cek
float freq_cek;
int kilo,mega, timer0;
String freq_satuan;
/////////Freq Cek

void setup()
{
       
        ///////////setting counter atau timer
        timer0;
        kilo=0;
        mega=0;
        freq_cek=0;
        freq_satuan="Hz";
       
        cli();//stop interrupts
     
        //set timer0 interrupt
        TCCR0A = 0;// set entire TCCR0A register to 0
        TCCR0B = 0;// same for TCCR0B
        TCNT0  = 0;//initialize counter value to 0
        // set compare match register for 2khz increments
        OCR0A = 249;// 250 (dimulai dari 0) - karena prescaler 64 (250KHz) maka diperlukan 1000 kali interrupt untuk 1 detik
        // turn on CTC mode
        TCCR0A |= (1 << WGM01);
        // Set CS01 and CS00 bits for 64 prescaler (250KHz)
        TCCR0B |= (1 << CS01) | (1 << CS00);  
        // enable timer compare interrupt
        TIMSK0 |= (1 << OCIE0A);
     
        //set timer1 interrupt sebagai counter sinyal frekuensi yang masuk
        TCCR1A = 0;// set entire TCCR1A register to 0
        TCCR1B = 0;// same for TCCR1B
        TCNT1  = 0;//initialize counter value to 0
        // set compare match register for 1hz increments
        OCR1A = 999;//seribu kali - mulai dari 0
        // turn on CTC mode
        TCCR1B |= (1 << WGM12);
        // Set CS10 and CS11 bits for external clock T1 falling edge
        TCCR1B |= (1 << CS12) | (1 << CS11); 
        // enable timer compare interrupt
        TIMSK1 |= (1 << OCIE1A);
     
        sei();//allow interrupts       
        //////////////setting counter atau timer
     
   
        ///////////////AD9850
        pinMode(FQ_UD, OUTPUT);
        pinMode(W_CLK, OUTPUT);
        pinMode(DATA, OUTPUT);
        pinMode(RESET, OUTPUT);
        pulseHigh(RESET);
        pulseHigh(W_CLK);
        pulseHigh(FQ_UD);  // this pulse enables serial mode on the AD9850 - Datasheet page 12.
        sendFrequency(1000000); //tes frekuensi 1MHz
        ///////////////AD9850 
 
      Serial.begin(9600);
    lcd.begin(16,2);
}

void loop()
{
       
        //lcd.clear();
        Serial.print(freq_cek);
        Serial.print(" ");
        Serial.println(freq_satuan);
        lcd.setCursor(0,0);   
        lcd.print("Freq DDS AD9850");
        lcd.setCursor(0,1);   
        lcd.print("Freq= ");
        lcd.print(freq_cek);
        lcd.print(" ");
        lcd.print(freq_satuan);
        //delay(500);
}


//////////////untuk handle interrupt counter dan timer
ISR(TIMER0_COMPA_vect){//timer0 interrupt
 
timer0++; 
if (timer0==1000) {    //setiap 1 detik dicek jumlah pulsanya
  if (mega>0){
    freq_cek=((float)mega+((float)kilo/1000) + ((float)TCNT1/1000000))*1;    //dikali 1 supaya 1 detik
    freq_satuan = "MHz  ";
  }else if (kilo>0){
    freq_cek=((float)kilo + ((float)TCNT1/1000))*1;    //dikali 1 supaya 1 detik
    freq_satuan = "KHz  ";
  }else {
    freq_cek = ((float)TCNT1) * 1;
    freq_satuan = "Hz   ";
  } 
  timer0=0;
  kilo=0;
  mega=0;
  TCNT1=0;
  TCNT0=0;
}
}

ISR(TIMER1_COMPA_vect){//counter1 interrupt
 
kilo++;
if (kilo==1000){
  mega++;
  kilo=0;
}
}
//////////////untuk handle interrupt counter dan timer


/////////////////////AD9850
// frequency calc from datasheet page 8 = <sys clock> * <frequency tuning word>/2^32
void sendFrequency(double frequency) { 
  int32_t freq = frequency * 4294967295/125000000;  // note 125 MHz clock on 9850.  

  for (int b=0; b<4; b++, freq>>=8) {
    tfr_byte(freq & 0xFF);
  }
  tfr_byte(0x000);   // Final control byte, all 0 for 9850 chip
  pulseHigh(FQ_UD);  // Done!  Should see output
}
// transfers a byte, a bit at a time, LSB first to the 9850 via serial DATA line
void tfr_byte(byte data)
{
  for (int i=0; i<8; i++, data>>=1) {
    digitalWrite(DATA, data & 0x01);
    pulseHigh(W_CLK);   //after each bit sent, CLK is pulsed high
  }
}
/////////////////////AD9850

Hasil:
DDS AD9850 dapat membangkitkan gelombang sinus dan kotak. Berikut pengambilan data menggunakan ADC pada frekuensi rendah (0,5 Hz; 1 Hz; 2Hz)
 - Mungkin akan dijabarkan diposting terpisah :)

Hasil keluaran DDS AD9850 gelombang sinus dan kotak

Hasil keluaran DDS AD9850 sine 1 dan sine 2

Hasil pengukuran frekuensi oleh Arduino Uno menggunakan Counter dan Timer1:

Pengukuran Nilai Frekuensi keluaran DDS AD9850 (di tes pada 1 MHz)
Pengukuran Nilai Frekuensi keluaran DDS AD9850 (di tes pada 1 Hz)
Pengukuran Nilai Frekuensi keluaran DDS AD9850 (dites pada 2,25 MHz)


Beberapa referensi utama:
http://www.instructables.com/id/Arduino-Timer-Interrupts/?ALLSTEPS
http://www.ad7c.com/projects/ad9850-dds-vfo/

Cara mengetahui ip address raspberry atau perangkat lain yg terhubung pada wifi yg sama

1. Install nmap [jika belum ada]: sudo apt install nmap 2. Cek ip address komputer (yg akses ke wifi yang sama): ip addr misal hasilnya 192....