Apa Itu ADC (Analog to Digital Converter) dan Fungsi ADC

Apa itu ADC

ADC (Analog to Digital Converter) adalah perangkat yang mengubah sinyal analog menjadi sinyal digital. Besaran analog di sini maksudnya adalah besaran yang mempunyai nilai kontinyu pada waktu kontinyu, sedangkan digital di sini maksudnya adalah memiliki representasi diskrit pada waktu yang diskrit.

Perubahan waktu kontinyu menjadi waktu diskrit menggunakan proses pencuplikan (sampling). Perubahan amplitudo kontinyu menjadi amplitudo diskrit menggunakan proses kuantisasi.

Bentuk fisik ADC dapat berupa sebuah chip, bisa juga dibuat menggunakan komponen diskrit (transistor, gerbang logika, op-amp), ataupun sudah menyatu dengan mikrokontroler.

ADC tipe MCP3008 buatan Microchip

Jenis ADC

Jenis-jenis ADC adalah sebagai berikut:

  • Flash
  • Single slope converter
  • Dual slope converter
  • Successive Approximation Register
  • Delta Sigma

Berikut ini contoh skema suatu flash ADC (sumber)

Berikut ini contoh skema suatu SAR ADC (sumber)

Berikut ini contoh skema suatu Integrating ADC (sumber)

Parameter ADC

Parameter-parameter ADC adalah sebagai berikut

  • resolusi: menyatakan berapa jumlah nilai diskrit yang dapat dihasilkan untuk merepresentasikan nilai masukan analog. Umumnya dinyatakan dalam jumlah bit pada output ADC
  • kecepatan sampling: parameter ini menyatakan berapa banyak konversi analog ke digital yang dapat dilakukan setiap detik.

Resolusi

Konsep resolusi ADC dapat dilihat pada contoh ini. Berikut ini contoh pemetaan nilai analog (0 sampai 1.0) ke nilai biner terkait dari suatu ADC 8 bit (sumber)Pencuplikan

Sinyal analog bersifat kontinyu pada domain waktu. Untuk mengubah sinyal analog ini menjadi digital, perlu didefinisikan seberapa cepat nilai digital dicuplik dari sinyal analog. Kecepatan menghasilkan nilai digital ini adalah kecepatan sampling atau frekuensi sampling (sampling rate / sampling frequency).

Sinyal analog dapat dicuplik menjadi sinyal digital dan kemudian dapat dikembalikan lagi ke bentuk analog dengan syarat kecepatan samplingnya lebih tinggi dari dua kali frekuensi maksimum pada sinyal analog tersebut. Kriteria ini adalah disebut juga sebagai teorema pencuplikan Nyquist-Shannon.

Antar Muka ADC

ADC umumnya dipakai bersamaan dengan elemen komputasi seperti mikroprosesor/mikrokontroler ataupun FPGA (Field Programmable Array) . Antar muka antara ADC dengan elemen komputasi dapat dengan berbagai cara, seperti:

  • Terintegrasi dalam 1 chip, seperti ADC pada mikrokontroler ATmega328 di modul Arduino UNO / Arduino Nano / ESP32
  • Bus data mikroprosesor paralel
  • Komunikasi serial I2C (Inter Integrated Circuit)
  • Komunikasi serial SPI (Serial Peripheral Interface)
  • Komunikasi serial proprietary

Contoh ADC terintegrasi adalah mikrokontroler Arduino Nano yang di dalamnya ada ADC 10 bit.

Arduino Nano specimen 1
Arduino Nano

Contoh ADC yang menggunakan komunikasi bus data adalah ADC0804 (sumber). Berikut ini contoh skema rangkaian interkoneksi antara mikroprosesor dengan ADC0804

Bentuk fisik ADC0804
Bentuk fisik ADC0804

 

Skema rangkaian ADC0804
Skema rangkaian ADC0804

Pada saat ini jarang sekali orang menggunakan teknik ini, karena biasanya mikrokontroler tidak memiliki bus yang dapat diakses.

Contoh ADC dengan bus I2C adalah ADS1115 buatan Texas Instruments . ADC ini banyak dijual sebagai modul yang sudah disolder.

Modul ADS1115
Modul ADS1115

Contoh ADC dengan koneksi SPI  adalah MCP3008 buatan Microchip

MCP3008

Aplikasi ADC

ADC dipakai untuk berbagai aplikasi seperti

  • Perekaman suara
  • Pengolahan sinyal meliputi perekaman, penyimpanan dan pengiriman sinyal melalui media tertentu
  • Instrumentasi ilmiah untuk merekam sinyal dari berbagai sensor

Lebih jauh tentang ADC:

 

Pengukuran Kecepatan ESP32 dengan ADC MCP3008

Foto perangkat

// kode

Kode

library yang dipakai untuk MCP3008 adalah https://github.com/bakercp/MCP3XXX

Pengukuran Library Original

Pada pengukuran ini digunakan library https://github.com/bakercp/MCP3XXX tanpa perubahan

Kode ada di https://github.com/waskita/embedded/tree/master/esp32-mcp3008-baker-profile-v1

Kode program adalah sebagai berikut:

// library: https://github.com/bakercp/MCP3XXX
#include <MCP3XXX.h>
MCP3008 adc;

void setup() {
  Serial.begin(115200);
  Serial.println("start");
  // Use the default SPI hardware interface.
  adc.begin();
  // Or use custom pins to use a software SPI interface.
  // adc.begin(SS, MOSI, MISO, SCK);
  pinMode(22, OUTPUT); // digital output for monitoring
  pinMode(21, OUTPUT);
}
int counter = 0, last_time = 0, current_time = 0;
float durasi=0;
int jumlah_iterasi=100000;

void loop() {
  for (;;) {

    digitalWrite(22, HIGH);  // turn the LED on (HIGH is the voltage level)
    adc.analogRead(0);
    digitalWrite(22, LOW);  // turn the LED on (HIGH is the voltage level)

    counter = counter + 1;
    if (counter == jumlah_iterasi) {  // tiap 10000x berhenti
      counter = 0;
      current_time = millis();
      durasi = (float)(current_time - last_time) / (float) jumlah_iterasi;
      Serial.print("durasi (ms) ");
      Serial.println(durasi,4);
      last_time = current_time;
    }
  }
}

Hasil pengukuran perioda sebagai berikut

start
durasi (ms) 0.0375
durasi (ms) 0.0370
durasi (ms) 0.0370

Output osiloskop dari output digital sebagai berikut

Pengukuran Library Dimodifikasi

Pada percobaan ini dilakukan perubahan pada library untuk mempercepat proses pembacaan.

Kode ada di https://github.com/waskita/embedded/tree/master/esp32-mcp3008-baker-profile-v2

Kode program utama sebagai berikut:

// Profiling kecepatan konversi ADC MCP3008 di ESP32
// menggunakan modified header dari https://github.com/bakercp/MCP3XXX

#include "MCP3XXXZ.h" // custom header

MCP3008 adc;

void setup() {
  Serial.begin(115200);
  Serial.println("start");
  // Use the default SPI hardware interface.
  adc.begin();
  // Or use custom pins to use a software SPI interface.
  // adc.begin(SS, MOSI, MISO, SCK);
  pinMode(22, OUTPUT); // digital output for monitoring
  pinMode(21, OUTPUT);

  adc.spistart(); // 
}
int counter = 0, last_time = 0, current_time = 0;
float durasi=0;
int jumlah_iterasi=100000;

void loop() {
  for (;;) {

    digitalWrite(22, HIGH);  // turn the LED on (HIGH is the voltage level)
    adc.analogRead(0);
    digitalWrite(22, LOW);  // turn the LED on (HIGH is the voltage level)

    counter = counter + 1;
    if (counter == jumlah_iterasi) {  // tiap 10000x berhenti
      counter = 0;
      current_time = millis();
      durasi = (float)(current_time - last_time) / (float) jumlah_iterasi;
      Serial.print("durasi (ms) ");
      Serial.println(durasi,4);
      last_time = current_time;
    }
  }
}

Kode header sebagai berikut

//
// Copyright (c) 2018 Christopher Baker <https://christopherbaker.net>
//
// SPDX-License-Identifier:	MIT
//


#pragma once


#include <Arduino.h>
#include <SPI.h>


/// \brief A template class supporting MCP3XXX ADC SPI chips.
///
/// \tparam NumBits Number of ADC bits.
/// \tparam NumChannels Number of input channels.
/// \tparam MaxSPIClockSpeed Maximum SPI communication speed rate in Hz.
/// \tparam SPITransferLength The number of bytes transferred over SPI.
template<uint8_t NumBits,
         uint8_t NumChannels,
         uint32_t MaxSPIClockSpeed,
         uint8_t SPITransferLength = 3>
class MCP3XXX_
{
public:
	
    enum
    {
        /// \brief ADC error value.
        ADC_ERROR_INVALID_CHANNEL = -1,

        /// \brief ADC error value.
        ADC_UNSUPPORTED_CONFIGURATION = -2,

        /// \brief Number of ADC bits.
        NUM_BITS = NumBits,

        /// \brief A bit mask based on the number of bits.
        BIT_MASK = (1 << NUM_BITS) - 1,

        /// \brief Number of input channels.
        NUM_CHANNELS = NumChannels,

        /// \brief Maximum SPI communication speed rate in Hz.
        MAX_SPI_CLOCK_SPEED = MaxSPIClockSpeed,

        /// \brief The number of bytes transferred over SPI.
        SPI_TRANSFER_LEGNTH = SPITransferLength
    };


    /// \brief Construct a default MCP3XXX_ device.
    MCP3XXX_()
    {
    }

    /// \brief Destroy the MCP3XXX_ device.
    ~MCP3XXX_()
    {
    }
	
	void spistart(){
		SPI.beginTransaction(SPISettings(MAX_SPI_CLOCK_SPEED, MSBFIRST, SPI_MODE0));
	}
    /// \brief Set up the ADC using default hardware SPI pins.
    ///
    /// Hardware SPI pins vary based on the board being used. These default pins
    /// are represented by the constants SS, MOSI, MISO and SCK.
    ///
    /// \sa https://www.arduino.cc/en/Reference/SPI
    /// \param csPin Chip Select Pin. Default value is SS.
    void begin(uint8_t csPin = SS)
    {
      _useHardwareSPI = true;

      _csPin = csPin;
      _mosiPin = MOSI;
      _misoPin = MISO;
      _sckPin = SCK;

      // Set up pin modes.
      pinMode(_csPin, OUTPUT);

      // Begin software SPI.
      // Initializes the SPI bus by setting SCK, MOSI, and SS to outputs,
      // pulling SCK and MOSI low, and SS high.
      digitalWrite(_csPin, HIGH); // Redundant.
      SPI.begin();
    }

    /// \brief Set up the ADC using custom software SPI pins.
    ///
    /// This method forces the SPI to be accesed via software methods rather
    /// than hardware SPI. This is true, even if the default hardware SPI pins
    /// are used.
    ///
    /// \param csPin Chip Select Pin.
    /// \param mosiPin MOSI pin.
    /// \param misoPin MISO pin.
    /// \param sckPin Clock pin.
    void begin(uint8_t csPin, uint8_t mosiPin, uint8_t misoPin, uint8_t sckPin)
    {
      _useHardwareSPI = false;

      _csPin = csPin;
      _mosiPin = mosiPin;
      _misoPin = misoPin;
      _sckPin = sckPin;

      // Set up pin modes manually.
      pinMode(_csPin, OUTPUT);
      pinMode(_mosiPin, OUTPUT);
      pinMode(_misoPin, INPUT);
      pinMode(_sckPin, OUTPUT);

      // Begin software SPI. We initiate CS Pin HIGH to prepare it to go LOW
      // on our first read.
      digitalWrite(_csPin, HIGH);
    }

    /// \brief Read the analog value.
    ///
    /// Reads a single-ended analog value using the given channel.
    ///
    /// \param channel The channel (channel < NUM_CHANNELS) to read.
    /// \returns values [0, MAX_VALUE) on success or an error code on failure.
    uint32_t analogRead(uint8_t channel) const
    {
        if (channel < NUM_CHANNELS)
          return _read(channel, false);
        return ADC_ERROR_INVALID_CHANNEL;
    }

    /// \brief Read a differential analog value by specifying the IN+ channel.
    ///
    /// Consecutive channel pairs can be differentially read. For instance, if
    /// inPositiveChannel == 0, inNegativeChannel will be 1.
    /// If inPositiveChannel == 1, then inNegativeChannel will be 0. Thus if
    /// inPositiveChannel is odd, inNegativeChannel == (inPositiveChannel - 1).
    /// if inPositiveChannel is even, inNegativeChannel == (inPositiveChannel + 1).
    ///
    /// \param inPositiveChannel The channel that should be input positive.
    /// \returns Differential values. See the data sheet for information on how
    ///          to interpret these return values.
    uint32_t analogReadDifferential(uint8_t inPositiveChannel) const
    {
        if (inPositiveChannel < NUM_CHANNELS)
          return _read(inPositiveChannel, true);
        return ADC_ERROR_INVALID_CHANNEL;
    }

    /// \returns the number of ADC channels.
    size_t numChannels() const
    {
        return NUM_CHANNELS;
    }

    /// \returns the number of ADC bits.
    size_t numBits() const
    {
        return NUM_BITS;
    }

private:
    MCP3XXX_(const MCP3XXX_&);
    MCP3XXX_& operator = (const MCP3XXX_&);

    /// \brief Read the value from the given channel using the given mode.
    /// \param channel The channel to read.
    /// \param differential If true, use differential read mode.
    uint32_t _read(uint8_t channel, bool differential) const
    {
      // Data transfers are done using "8-bit segments" approach in data sheet.
      // The sent data alignment resuls in correctly aligned return bytes after
      // the SPI transfer.
      uint8_t data[SPI_TRANSFER_LEGNTH];

      // Check for MCP3004
      if (NUM_CHANNELS == 2)
      {
        if (NUM_BITS == 10)
        {
          // Start bit.
          data[0] = 0b01000000;
          // Differential bit.
          data[0] |= (differential ? 0b00000000 : 0b00100000);
          // Channel bit.
          data[0] |= (channel == 0 ? 0b00000000 : 0b00010000);
          // MSBF bit is set to 1. See section 5.1 of the data sheet.
          data[0] |= 0b00001000;
          // It doesn't matter what data[1] is set to.
        }
        else
        {
          return ADC_UNSUPPORTED_CONFIGURATION;
        }
      }
      else
      {
        if (NUM_BITS == 10)
        {
          // The start bit. We position it here to align our output data.
          data[0] = 0b00000001;
          // Set the differential / single bit and the channel bits.
          data[1] = (differential ? 0b00000000 : 0b10000000) | (channel << 4);
          // It doesn't matter what data[2] is set to.
        }
        else
        {
          return ADC_UNSUPPORTED_CONFIGURATION;
        }
      }

      if (_useHardwareSPI)
      {
        // Here we replace the sent data with the received data.
//        SPI.beginTransaction(SPISettings(MAX_SPI_CLOCK_SPEED, MSBFIRST, SPI_MODE0));
//		digitalWrite(21, HIGH);  // turn the LED on (HIGH is the voltage level)
        digitalWrite(_csPin, LOW);
        for (size_t i = 0; i < SPI_TRANSFER_LEGNTH; ++i)
        {
          data[i] = SPI.transfer(data[i]);
        }
        digitalWrite(_csPin, HIGH);
//		digitalWrite(21, LOW);  // turn the LED on (HIGH is the voltage level)
//        SPI.endTransaction();
      }
      else
      {
        // Slower, but can use any pin.
        // We could save a few operations by skipping some digitalWrites(),
        // using bitwise operators and doing direct port-manipulation.
        // But this is used because it is "easier" to read.
        digitalWrite(_csPin, LOW);
        for (size_t i = 0; i < SPI_TRANSFER_LEGNTH; ++i)
        {
          for (size_t j = 8; j-- > 0;)
          {
            // Set MOSI data.
            digitalWrite(_mosiPin, bitRead(data[i], j));
            // Set Clock HIGH.
            digitalWrite(_sckPin, HIGH);
            // Read MISO data.
            bitWrite(data[i], j, digitalRead(_misoPin));
            // Set Clock LOW.
            digitalWrite(_sckPin, LOW);
          }
        }
        digitalWrite(_csPin, HIGH);
      }

      // Here we take the second two bytes returned as our value.
      // This value is already correctly aligned since we are using the 8-bit
      // segments approach. The BIT_MASK is calculated based on the number out
      // bits specified in the template parameters.
      return ((data[SPI_TRANSFER_LEGNTH - 2] << 8) | data[SPI_TRANSFER_LEGNTH - 1]) & BIT_MASK;
    }


    /// \brief Use hardware SPI to communicate.
    bool _useHardwareSPI = true;

    /// \brief Chip Select pin.
    uint8_t _csPin = SS;

    /// \brief MOSI pin.
    uint8_t _mosiPin = MOSI;

    /// \brief MISO pin.
    uint8_t _misoPin = MISO;

    /// \brief SCLK pin.
    uint8_t _sckPin = SCK;

};

/// \brief A typedef for the MCP3002.
/// Max clock frequency for 2.7V: 1200000 Hz
/// Max clock frequency for 5.0V: 3200000 Hz
/// \sa http://ww1.microchip.com/downloads/en/DeviceDoc/21294E.pdf
typedef MCP3XXX_<10, 2, 1200000, 2> MCP3002;

/// \brief A typedef for the MCP3004.
/// Max clock frequency for 2.7V: 1350000 Hz
/// Max clock frequency for 5.0V: 3600000 Hz
/// \sa http://ww1.microchip.com/downloads/en/DeviceDoc/21295C.pdf
typedef MCP3XXX_<10, 4, 1350000> MCP3004;

/// \brief A typedef for the MCP3008.
/// Max clock frequency for 2.7V: 1350000 Hz
/// Max clock frequency for 5.0V: 3600000 Hz
/// \sa http://ww1.microchip.com/downloads/en/DeviceDoc/21295C.pdf
//typedef MCP3XXX_<10, 8, 1350000> MCP3008;
typedef MCP3XXX_<10, 8, 3000000> MCP3008;

// /// \brief A typedef for the MCP3202.
// /// Max clock frequency for 2.7V:  900000 Hz
// /// Max clock frequency for 5.0V: 1800000 Hz
// /// \sa http://ww1.microchip.com/downloads/en/DeviceDoc/21034D.pdf
// typedef MCP3XXX_<12, 2, 900000> MCP3202;
//
// /// \brief A typedef for the MCP3204.
// /// Max clock frequency for 2.7V: 1000000 Hz
// /// Max clock frequency for 5.0V: 2000000 Hz
// /// \sa http://ww1.microchip.com/downloads/en/DeviceDoc/21298c.pdf
// typedef MCP3XXX_<12, 4, 1000000> MCP3204;
//
// /// \brief A typedef for the MCP3208.
// /// Max clock frequency for 2.7V: 1000000 Hz
// /// Max clock frequency for 5.0V: 2000000 Hz
// /// \sa http://ww1.microchip.com/downloads/en/DeviceDoc/21298c.pdf
// typedef MCP3XXX_<12, 8, 1000000> MCP3208;
//
// /// \brief A typedef for the MCP3208.
// /// Max clock frequency for 2.7V: 1050000 Hz
// /// Max clock frequency for 5.0V: 2100000 Hz
// /// \sa http://ww1.microchip.com/downloads/en/DeviceDoc/21697e.pdf
// typedef MCP3XXX_<13, 8, 1050000> MCP3304;

Hasil pengukuran perioda sebagai berikut

start
durasi (ms) 0.0137
durasi (ms) 0.0132
durasi (ms) 0.0132
durasi (ms) 0.0132

Output osiloskop

Pengukuran kecepatan konversi ADC MCP3008 pada ESP32 Devkit C clone
Output osiloskop

Frekuensi sinyal output sama dengan frekuensi konversi ADC , yaitu 75,739 kHz

Kesimpulan

  • Library original menghasilkan frekuensi ADC 26,685 kHz, sedangkan library yang dimodifikasi menghasilkan frekuensi ADC 75,739 kHz
  • Library original menghasilkan perioda ADC 0,0370 ms, sedangkan library yang dimodifikasi menghasilkan perioda 0,0132 ms

Referensi

Perancangan dan Implementasi Low Pass Filter Digital Dengan ESP32

Perancangan Filter

Perancangan filter menggunakan tools dari https://fiiir.com/

Parameter yang digunakan:

  • Sampling rate: 20000 Hz
  • Cut off frequency 800 Hz
  • Transition bandwidth 1800 Hz
  • Window type : Blackman

Berikut ini karakteristik filter yang dapat dilihat di laman yang sama

Kode dalam bahasa Python untuk menghitung parameter filter dan konvolusinya juga dihasilkan dari laman yang sama, sebagai berikut:

from __future__ import print_function
from __future__ import division

import numpy as np

# Example code, computes the coefficients of a low-pass windowed-sinc filter.

# Configuration.
fS = 20000 # Sampling rate.
fL = 800 # Cutoff frequency.
N = 53 # Filter length, must be odd.

# Compute sinc filter.
h = np.sinc(2 * fL / fS * (np.arange(N) - (N - 1) / 2))

# Apply window.
h *= np.blackman(N)

# Normalize to get unity gain.
h /= np.sum(h)

print(h)

# Applying the filter to a signal s can be as simple as writing
# s = np.convolve(s, h)

Parameter filter yang dihasilkan adalah sebagai berikut  (sebagai Python array)

[-4.29317419e-20 -4.18549678e-21 -1.79819385e-05 -8.38178513e-05
 -2.28616892e-04 -4.79528638e-04 -8.51847897e-04 -1.33864303e-03
 -1.89910369e-03 -2.44776137e-03 -2.84740649e-03 -2.90866942e-03
 -2.39870072e-03 -1.06016948e-03  1.35995551e-03  5.07437980e-03
  1.02166209e-02  1.68050560e-02  2.47160945e-02  3.36720917e-02
  4.32479500e-02  5.28978134e-02  6.20002342e-02  6.99171799e-02
  7.60597872e-02  7.99523091e-02  8.12855501e-02  7.99523091e-02
  7.60597872e-02  6.99171799e-02  6.20002342e-02  5.28978134e-02
  4.32479500e-02  3.36720917e-02  2.47160945e-02  1.68050560e-02
  1.02166209e-02  5.07437980e-03  1.35995551e-03 -1.06016948e-03
 -2.39870072e-03 -2.90866942e-03 -2.84740649e-03 -2.44776137e-03
 -1.89910369e-03 -1.33864303e-03 -8.51847897e-04 -4.79528638e-04
 -2.28616892e-04 -8.38178513e-05 -1.79819385e-05 -4.18549678e-21
 -4.29317419e-20]

Simulasi dengan Python di Desktop

Berikut ini kode untuk simulasi filter tersebut di Jupyter Notebook dengan bahasa Python.

from __future__ import print_function
from __future__ import division

import numpy as np
import math
import matplotlib.pyplot as plt

# Example code, computes the coefficients of a low-pass windowed-sinc filter.

# Configuration.
fS = 20000 # Sampling rate.
fL = 800 # Cutoff frequency.
N = 53 # Filter length, must be odd.

# Compute sinc filter.
h = np.sinc(2 * fL / fS * (np.arange(N) - (N - 1) / 2))

# Apply window.
h *= np.blackman(N)

# Normalize to get unity gain.
h /= np.sum(h)

print(h)

# Applying the filter to a signal s can be as simple as writing
# s = np.convolve(s, h)

x = np.linspace(0,1, 20001)

# filter digital
signal_frequency=8000 # diubah-ubah sesuai keperluan
y=np.sin(x*2*math.pi * signal_frequency)
# Applying the filter to a signal s can be as simple as writing
y_out = np.convolve(y, h)
plt.figure(figsize=(16,6))
plt.plot(x, y_out[0:20001],label="output")
plt.plot(x, y[0:20001],label="input")
plt.title("signal:{} Hz".format(signal_frequency))
plt.legend()
plt.axis('tight')
plt.xlim([0, 0.01])
plt.savefig("simulasi-signal-{}.jpg".format(signal_frequency))

Hasil simulasi untuk frekuensi 8 Hz

Hasil simulasi untuk frekuensi 80 HzHasil simulasi untuk frekuensi 800 Hz

Hasil simulasi untuk frekuensi 8000 Hz

Simulasi dengan C di Desktop

Pada percobaan ini filter disimulasikan di Desktop PC untuk mengecek ketepatan perhitungan dibandingkan dengan versi Python.

Kode untuk simulasi C sebagai berikut:

#include <stdio.h>
#include <stdlib.h>
#include "math.h"

int main()
{

#define ORDE_FILTER 53
int i,j,k;
FILE * fp;
char filename[100];
printf("Hello world!\n");
// simulasi 1 detik saja

float signal_frequency=8; // frekuensi input signal
float filter_coefficients[]= {-4.29317419e-20, -4.18549678e-21, -1.79819385e-05, -8.38178513e-05,
-2.28616892e-04, -4.79528638e-04, -8.51847897e-04, -1.33864303e-03,
-1.89910369e-03, -2.44776137e-03, -2.84740649e-03, -2.90866942e-03,
-2.39870072e-03, -1.06016948e-03, 1.35995551e-03, 5.07437980e-03,
1.02166209e-02, 1.68050560e-02, 2.47160945e-02, 3.36720917e-02,
4.32479500e-02, 5.28978134e-02, 6.20002342e-02, 6.99171799e-02,
7.60597872e-02, 7.99523091e-02, 8.12855501e-02, 7.99523091e-02,
7.60597872e-02, 6.99171799e-02, 6.20002342e-02, 5.28978134e-02,
4.32479500e-02, 3.36720917e-02, 2.47160945e-02, 1.68050560e-02,
1.02166209e-02, 5.07437980e-03, 1.35995551e-03, -1.06016948e-03,
-2.39870072e-03, -2.90866942e-03, -2.84740649e-03, -2.44776137e-03,
-1.89910369e-03, -1.33864303e-03, -8.51847897e-04, -4.79528638e-04,
-2.28616892e-04, -8.38178513e-05, -1.79819385e-05, -4.18549678e-21,
-4.29317419e-20
};
int orde_filter=ORDE_FILTER;
float y_history[ORDE_FILTER];
signal_frequency=8000;
sprintf(filename,"simulasi-%d.csv",(int)signal_frequency);
fp = fopen (filename, "w");
fprintf(fp,"time,y,y_out\n");

// zeros y_history
for (i=0; i<orde_filter; i++)
{
y_history[i]=0;
}
for (i=0; i<20000; i++)
{
printf(".");
float t,y;
t=(float)i/(float)20000; // time axis
y=sin(2 * M_PI *signal_frequency* t);
// fprintf(fp,"%f,%f\n",t,y);

// hitung history signal
for (j=orde_filter-1; j>=1; j--)
{
int src=j-1;
int dst=j;
y_history[dst]=y_history[src];
// printf("%d %d\n",src,dst);
}
y_history[0]=y;

// hitung konvolusi
float y_out=0;
for (k=0; k<orde_filter; k++)
{
// fprintf(fp,"%5.3f ",y_history[k]);
y_out=y_out+y_history[k]*filter_coefficients[k];
}
// fprintf(fp,"\n");
fprintf(fp,"%f,%f,%f\n",t,y,y_out);
}
fclose(fp);
return 0;
}



// https://www.tutorialspoint.com/c_standard_library/c_function_fprintf.htm

Output kode C tersebut berupa file *.csv

Visualisasi data di file *.csv dilakukan menggunakan Jupyter Notebook dengan kode sebagai berikut:

import pandas as pd
import math
import matplotlib.pyplot as plt

name="simulasi-8"
name="simulasi-80"
name="simulasi-800"
name="simulasi-8000"
df = pd.read_csv('../filter-simulasi-c/{}.csv'.format(name))

plt.figure(figsize=(16,6))
plt.plot(df["time"], df["y"],marker='o',label="input")
plt.plot(df["time"], df["y_out"],marker='o',label="output")
plt.legend()
plt.axis('tight')
plt.xlim([0, 0.001])
plt.savefig("visualisasi-{}.jpg".format(name))

Tampilan Visualisasi untuk sinyal 8 Hz

nampak sinyal 8 Hz tidak teredam

Tampilan Visualisasi untuk sinyal 80 Hz

sinyal 80 Hz nampak teredam sedikit sekali dan ada lag

Tampilan Visualisasi untuk sinyal 800 Hz

nampak sinyal 800 Hz teredam sekitar 50%

Tampilan Visualisasi untuk sinyal 8000 Hz

nampak sinyal 8000 Hz teredam hampir semuanya

Simulasi dengan C di ESP32

pada percobaan ini kode dijalankan di ESP32 namun input adalah simulasi bukan dari generator sinyal. Output direkam ke port serial, bukan ke osiloskop.

Kode ESP32 adalah sebagai berikut

#define ORDE_FILTER 53

void setup() {

  Serial.begin(115200);

  //

  int i, j, k;

  char filename[100];

  // simulasi 1 detik saja

  float signal_frequency = 8;  // frekuensi input signal

  float filter_coefficients[] = { -4.29317419e-20, -4.18549678e-21, -1.79819385e-05, -8.38178513e-05,

                                  -2.28616892e-04, -4.79528638e-04, -8.51847897e-04, -1.33864303e-03,

                                  -1.89910369e-03, -2.44776137e-03, -2.84740649e-03, -2.90866942e-03,

                                  -2.39870072e-03, -1.06016948e-03, 1.35995551e-03, 5.07437980e-03,

                                  1.02166209e-02, 1.68050560e-02, 2.47160945e-02, 3.36720917e-02,

                                  4.32479500e-02, 5.28978134e-02, 6.20002342e-02, 6.99171799e-02,

                                  7.60597872e-02, 7.99523091e-02, 8.12855501e-02, 7.99523091e-02,

                                  7.60597872e-02, 6.99171799e-02, 6.20002342e-02, 5.28978134e-02,

                                  4.32479500e-02, 3.36720917e-02, 2.47160945e-02, 1.68050560e-02,

                                  1.02166209e-02, 5.07437980e-03, 1.35995551e-03, -1.06016948e-03,

                                  -2.39870072e-03, -2.90866942e-03, -2.84740649e-03, -2.44776137e-03,

                                  -1.89910369e-03, -1.33864303e-03, -8.51847897e-04, -4.79528638e-04,

                                  -2.28616892e-04, -8.38178513e-05, -1.79819385e-05, -4.18549678e-21,

                                  -4.29317419e-20 };

  int orde_filter = ORDE_FILTER;

  float y_history[ORDE_FILTER];

  signal_frequency = 800;

//  signal_frequency = 80;

//  signal_frequency = 8;

  sprintf(filename, "simulasi-%d.csv", (int)signal_frequency);

  printf("time,y,y_out\n");

  // zeros y_history

  for (i = 0; i < orde_filter; i++) {

    y_history[i] = 0;

  }

  for (i = 0; i < 20000; i++) {

    float t, y;

    t = (float)i / (float)20000;  //  time axis

    y = sin(2 * M_PI * signal_frequency * t);

    //        fprintf(fp,"%f,%f\n",t,y);

    // hitung history signal

    for (j = orde_filter - 1; j >= 1; j--) {

      int src = j - 1;

      int dst = j;

      y_history[dst] = y_history[src];

      //            printf("%d %d\n",src,dst);

    }
  y_history[0] = y;
    // hitung konvolusi
    float y_out = 0;
    for (k = 0; k < orde_filter; k++) {
      y_out = y_out + y_history[k] * filter_coefficients[k];
    }

    //        fprintf(fp,"\n");

    printf("%f,%f,%f\n", t, y, y_out);

  }

}

void loop() {

  // put your main code here, to run repeatedly:

}

Output dari ESP32 direkam dengan software RealTerm ke sebuah file *.txt

File *.txt tersebut dirapikan dan disimpan sebagai *.csv

File *.csv ini kemudian divisualisasikan dengan Jupyter Notebook

Kode visualisasi sebagai berikut

# graph simulasi C filter
import pandas as pd
import math
import matplotlib.pyplot as plt

name="esp32-8.csv"
name="esp32-80.csv"
#name="esp32-800.csv"
#name="esp32-8000.csv"
df = pd.read_csv('{}'.format(name))

plt.figure(figsize=(16,6))
plt.plot(df["time"], df["y"],label="input")
plt.plot(df["time"], df["y_out"],label="output")
plt.legend()
plt.axis('tight')
plt.xlim([0, 0.1])
plt.title(name)
plt.savefig("visualisasi-{}.jpg".format(name))

Sinyal 8 Hz:

Sinyal 80 Hz

Sinyal 800 Hz

Sinyal 8000 Hz

Kesimpulan: output dari software LPF di ESP32 sama dengan output dari software C di Desktop

Profiling di ESP32

Pada percobaan ini waktu yang diperlukan untuk menghitung filter diukur di ESP32.

Pewaktuan menggunakan fungsi millis(). Fungsi millis() tidak 100% akurat. Untuk lebih tepat perlu interupsi timer, atau dengan osiloskop.

Kode profiling:

#define ORDE_FILTER 53
float buffer[100];
void setup() {
  int buffer_index = 0;
  int durasi;
  Serial.begin(115200);
  //
  long int i;
  int j, k;
  char filename[100];
  // simulasi 1 detik saja

  float signal_frequency = 8;  // frekuensi input signal
  float filter_coefficients[] = { -4.29317419e-20, -4.18549678e-21, -1.79819385e-05, -8.38178513e-05,
                                  -2.28616892e-04, -4.79528638e-04, -8.51847897e-04, -1.33864303e-03,
                                  -1.89910369e-03, -2.44776137e-03, -2.84740649e-03, -2.90866942e-03,
                                  -2.39870072e-03, -1.06016948e-03, 1.35995551e-03, 5.07437980e-03,
                                  1.02166209e-02, 1.68050560e-02, 2.47160945e-02, 3.36720917e-02,
                                  4.32479500e-02, 5.28978134e-02, 6.20002342e-02, 6.99171799e-02,
                                  7.60597872e-02, 7.99523091e-02, 8.12855501e-02, 7.99523091e-02,
                                  7.60597872e-02, 6.99171799e-02, 6.20002342e-02, 5.28978134e-02,
                                  4.32479500e-02, 3.36720917e-02, 2.47160945e-02, 1.68050560e-02,
                                  1.02166209e-02, 5.07437980e-03, 1.35995551e-03, -1.06016948e-03,
                                  -2.39870072e-03, -2.90866942e-03, -2.84740649e-03, -2.44776137e-03,
                                  -1.89910369e-03, -1.33864303e-03, -8.51847897e-04, -4.79528638e-04,
                                  -2.28616892e-04, -8.38178513e-05, -1.79819385e-05, -4.18549678e-21,
                                  -4.29317419e-20 };
  int orde_filter = ORDE_FILTER;
  float y_history[ORDE_FILTER];
  signal_frequency = 800;
  //  signal_frequency = 80;
  //  signal_frequency = 8;
  printf(“time,y,y_out\n”);

  // zeros y_history
  for (i = 0; i < orde_filter; i++) {
    y_history[i] = 0;
  }
  int time_start = millis();

  for (i = 0; i < 1000000L; i++) {
    float t, y;
    t = (float)i / (float)20000;  //  time axis
    y = sin(2 * M_PI * signal_frequency * t);
    //        fprintf(fp,”%f,%f\n”,t,y);

    // hitung history signal
    for (j = orde_filter – 1; j >= 1; j–) {
      int src = j – 1;
      int dst = j;
      y_history[dst] = y_history[src];
      //            printf(“%d %d\n”,src,dst);
    }
    y_history[0] = y;

    // hitung konvolusi
    float y_out = 0;
    for (k = 0; k < orde_filter; k++) {
      y_out = y_out + y_history[k] * filter_coefficients[k];
    }
    //        fprintf(fp,”\n”);
    //    Serial.print(“.”);
    buffer[buffer_index] = y_out;
    buffer_index++;
    if (buffer_index>100){
      buffer_index=0;
    }
  }
  int time_end = millis();
  durasi = time_end – time_start;
  Serial.println(“durasi”);
  Serial.println(durasi);
}

void loop() {
  // put your main code here, to run repeatedly:
}

Hasil profiling: kode memerlukan 16479 ms untuk menjalankan 1000000 kali perhitungan. jadi setiap perhitungan memerlukan 16.479 us

Konversi DAC di ESP32 memerlukan sekitar 20 us (pesimis), jadi jika kode sekuensial maka didapatkan perioda 36.479 us, atau frekuensi = 27413 Hz.

Frekuensi filter yang dirancang adalah 20000 Hz, jadi masih di bawah batas 27413 Hz.

Pengujian Dengan Sinyal Sesungguhnya

Pada percobaan ini kode dijalankan di ESP32 dengan input dari generator sinyal dan output diamati di osiloskop

Berikut ini implementasi rangkaian:

Implementasi filter digital dengan ESP32, MCP3008 dan level converter
Implementasi filter digital dengan ESP32, MCP3008 dan level converter

Implementasi software dapat dilihat di https://github.com/waskita/embedded/tree/master/esp32_mcp3008_baker_adc_dac_filter-timer

Sinual input didapat dari  generator sinyal GW Instek AFG-2012

Pengukuran output menggunakan osiloskop GW Instek-1152A-U

Berikut ini pengukuran pada frekuensi cut off = 100 Hz jauh di bawah frekuensi cut off.

Berikut ini pengukuran pada frekuensi cut off = 800 Hz. Amplitudo sinyal output sekitar 50% sinyal input.

Berikut ini pengukuran pada frekuensi 1600 Hz, jauh di atas cut off. Amplitudo sinyal output kecil sekali hampir tidak ada.

Berikut ini pengukuran pada frekuensi input 19200 Hz. Terjadi aliasing karena pada sistem ini tidak ada filter anti aliasing.

Referensi

ADC untuk Arduino: MCP3008, ADS1115, HX711

Arduino UNO dan NANO sudah memiliki ADC di dalamnya. Jika ingin menambah ADC lagi, berikut ini ada beberapa alternatif yang banyak dijual di pasaran:

MCP3008

ADC 8Channel 10Bit SPI DIP 16Pin

MCP3008

 

ADS1115

– Produsen: Texas Instruments
– jumlah kanal: 4
– protokol: I2C
– resolusi: 16 bit
– tegangan supply: 2 ~ 5,5 volt
– tautan: https://www.ti.com/product/ADS1115

Modul ADS1115
Modul ADS1115

 

HX711

– Produsen: Avia Semiconductor
– umumnya dipakai untuk timbangan elektronik
– jumlah kanal: 2 , differential
– protokol: proprietary
– resolusi: 24 bit
– tegangan supply: 2,6 ~ 5,5 volt
– Tautan: https://cdn.sparkfun.com/datasheets/Sensors/ForceFlex/hx711_english.pdf

 

HX711 Precision Analog to Digital Converter
HX711 Precision Analog to Digital Converter

AD7705

MAX174

MAX174 power supply grounding
MAX174 power supply grounding

ADS1256

ADC0804

PCF8591

PCF8591 blok diagram
PCF8591 blok diagram

ADS1232

Antar Muka Input Analog Multi Kanal

Berikut ini beberapa cara menyambungkan beberapa input analog ke suatu mikrokontroler.

Pencuplikan Sekuensial Konversi Sekuensial

Cara pertama adalah dengan menggunakan 1 buah ADC yang dipakai untuk membaca semua kanal secara bergantian. Agar dapat membaca beberapa kanal, maka di depan ADC dipasang sebuah multiplekser analog, yang dapat memilih input analog mana yang akan dibaca. Pada metode ini , pencuplikan / sampling pada setiap kanal input terjadi tidak serentak, namun secara berurutan.

 

Input analog sekuensial
Input analog sekuensial

Pencuplikan terjadi di waktu yang tidak sama, sehingga dapat menjadi noise/ jitter, terutama kalau waktu konversi ADC agak panjang.

Pencuplikan Serentak Konversi Sekuensial

Cara kedua adalah dengan menggunakan beberapa komponen sample/hold, agar memungkinkan terjadinya pencuplikan semua kanal pada waktu yang bersamaan. Konversi dari analog ke digital dilakuan satu per satu dengan sebuah ADC. Cara ini memiliki kelebihan yaitu semua data diambil pada waktu yang bersamaan, sehingga lebih mudah untuk pengolahan sinyal digitalnya.

 

Input analog serentak versi 1
Input analog serentak versi 1

Pencuplikan Serentak Konversi Serentak

Cara ketiga adalah melakukan pencuplikan secara bersamaan, dan melakukan konversi analog ke digital secara bersamaan juga. Cara ini lebih cepat dibandingkan cara kedua.

Input analog serentak versi 2
Input analog serentak versi 2

Komponen yang dapat dipakai

  • Sample & Hold dapat menggunakan “LF398 Monolithic Sample and Hold Circuit” ataupun rangkaian diskrit dengan op-amp dan kapasitor.
  • ADC dapat menggunakan ADC yang sudah built in di mikrokontroler, ataupun ADC eksternal seperti ADC MCP3008
  • Multiplexer analog dapat menggunakan built-in multiplekser di dalam ATMega328, atau menggunakan ADC yang sudah ada multiplexer (MCP3008), atau menggunakan switch analog seperti CD4066

Referensi

Komponen Pendukung Sistem Mikroprosesor

 

Saat ini mikroprosesor sudah tersedia dalam bentuk mikrokontroler seperti ATmega328 yang sudah mengintegrasikan CPU, memori dan periferal input output di dalamnya. Akibatnya untuk membuat suatu sistem mikroprosesor tidak lagi diperlukan banyak komponen pendukung lain. Mikrokontroler ini masih memerlukan kristal, power supply dan beberapa komponen lain.

Selain itu juga banyak yang sudah tersedia dalam bentuk modul, seperti Arduino UNO, Arduino Nano, Blue Pill dan sebagainya. Pada modul seperti ini, kita dapat menjalankan sistem mikroprosesor tersebut cukup hanya dengan menambahkan catu daya USB saja.

Namun demikian, kadang-kadang fasilitas yang disediakan oleh mikrokontroler ataupun modul tersebut masih kurang, sehingga masih diperlukan tambahan komponen pendukung. Berikut ini beberapa komponen pendukung yang sering dipakai.

Mikroprosesor / CPU

Komponen utama suatu sistem mikroprosesor adalah sebuah  CPU (Central Processing Unit). CPU ini belum dilengkapi dengan memori, sehingga untuk dapat dijalankan sebagai sistem minimum, CPU ini masih perlu ditambah memori RAM dan EEPROM. Berikut ini keluarga CPU yang (dulu) populer di Indonesia:

  • Keluarga Z80 buatan Zilog
  • Keluarga 6800 buatan Motorola
Zilog Z0840004PSC
Zilog Z0840004PSC

Pada saat ini penggunaan CPU sudah jarang, biasanya kita menggunakan mikrokontroler yang lebih praktis.

Berikut ini contoh rangkaian mikroprosesor berbasis CPU tipe 6802, dari keluarga 6800 buatan Motorola. (https://www.sbprojects.net/projects/nano6802/index.php)

Sistem minimum 6802
Sistem minimum 6802

Pada rangkaian tersebut, komponen utamanya adalah sebagai berikut:

  • 6802 sebagai CPU
  • 2732A sebagai EPROM
  • 6821 sebagai antar muka digital

Pada rangkaian tersebut tidak ada SRAM, karena di dalam 6802 sudah ada RAM sebanyak 128 byte.

Sumber Clock

Mikroprosesor yang kita pakai sekarang umumnya termasuk ke dalam sistem digital sinkron sekuensial, sehingga suatu mikroprosesor memerlukan clock. Sumber clock yang umum digunakan adalah osilator internal menggunakan resistor dan kapasitor, serta bisa juga menggunakan kristal. Rangkaian osilator dengan resistor dan kapasitor sangat sederhana, namun kurang teliti. Kristal menghasilkan clock yang lebih teliti. Jika diperlukan ketelitian waktu yang lebih tinggi, dapat dilihat di artikel “Sumber Clock pada Rangkaian Elektronik

Kristal 12 MHz dan resonator 18.083 MHz

RAM

RAM (Random Access Memori) fungsinya sebagai memori yang dapat dibaca dan ditulis oleh mikroprosesor.

Salah satu jenis static RAM yang populer dipakai adalah tipe 6264. RAM ini berkapasitas 8 kilobyte (8192 byte).

Static Random Access Memori 6264
Static Random Access Memori 6264

Mikrokontroler versi terbaru umumnya sudah dilengkapi RAM di dalamnya, sehingga kita tidak perlu menambahkan RAM lagi.

Selain static RAM (SRAM), ada juga dynamic RAM (DRAM). DRAM lebih murah dibandingkan SRAM, namun rangkaiannya lebih kompleks. DRAM populer digunakan pada mikroprosesor yang memerlukan RAM besar.

Lebih jauh tentang RAM dan memori sejenisnya dapat dilihat di artikel “Memori pada Sistem Mikroprosesor

EPROM

EPROM atau Erasable Programmable Read Only Memory, adalah memori yang dapat diprogram dengan menggunakan perangkat programmer, dan dapat dihapus dengan menggunakan cahaya ultraviolet.

EPROM yang populer digunakan adalah tipe 27C64. EPROM ini berkapasitas 8 kilobyte (8192 byte)

EPROM 27C64
EPROM 27C64

Input Output Digital Mikroprosesor

Untuk antar muka digital dari bus di dalam sistem mikroprosesor ke luar, diperlukan komponen antar muka digital. Komponen yang populer dipakai adalah IC PPI (Programmable Peripheral Interface) tipe 8255 buatan Intel dan 6821 dari Motorola.

Berikut ini PPI 8255 yang sering dipakai bersama mikroprosesor keluaran Intel, seperti 8088 dan 8086

Intel PPI 8255
Intel PPI 8255

Berikut ini IC Peripheral Interface Adapter (PIA) model MC6820 dan MC6821. Keduanya sering dipakai bersama mikroprosesor keluaran Motorola, seperti 6802 dan 6805.

Motorola MC6820 dan MC6821
Motorola MC6820 dan MC6821

Fungsi input output digital dari bus mikroprosesor juga dapat dilakukan dengan komponen IC digital berikut ini

  • 74HC373 latch 8 bit
  • 74HC573 latch 8 bit

Referensi:

Bus Mikroprosesor

Pada mikroprosesor model lama seperti Z80 dan Motorola 6800, masih diperlukan komponen register pada bus mikroprosesor. Pada mikrokontroler model baru seperti ATmega328 dan ESP32, bus mikroprosesor sudah built-in, jadi tidak perlu diutak atik lagi oleh pendesain sistem.

Komponen yang dipakai pada bus antara lain sebagai berikut:

  • 74HC138 Multiplexer, sebagai address decoder
  • 74HC245 buffer 2 arah 8 bit, sebagai input output digital , ataupun bus driver
  • 74HC573 latch 8 bit, sebagai bus multiplexer

Input Digital

Mikrokontroler zaman sekarang sudah memiliki input output digital built-in, sehingga tidak memerlukan tambahan PPI atau PIA. Namun kadang perlu komponen tambahan untuk menambah jumlah port, ataupun untuk konversi tegangan.

Berikut ini beberapa komponen yang umum dipakai pada sistem mikroprosesor untuk menambah kemampuan input digital:

  • 74HC164 serial input parallel output shift register tanpa output latch, dipakai untuk menambah jumlah port output
  • 74HC165 parallel input serial output shift register, dipakai untuk menambah jumlah port input
  • PCF8574 untuk menambah jumlah port input output , antar muka ke mikrokontroler menggunakan protokol I2C
  • Level Converter jika tegangan input dari sensor/transduser tidak sama dengan tegangan input mikrokontroler. Detail dibahas di artikel “Teknik Input Digital“. Salah satu cara yang praktis dengan menggunakan bidirectional logic level converter.

Output Digital

Berikut ini beberapa komponen yang umum dipakai pada sistem mikroprosesor untuk menambah output digital:

  • 74HC595 serial input parallel output shift register dengan output latch, dipakai untuk menambah jumlah port output
  • PCF8574 untuk menambah jumlah port input output , antar muka ke mikrokontroler menggunakan protokol I2C

Output digital dari mikrokontroler juga kadang-kadang perlu diperkuat arusnya, ataupun diubah tegangannya. Berikut ini beberapa komponen yang sering dipakai:

  • ULN2803 Darlington driver, untuk memperkuat arus dari port mikroprosesor, dapat menangani arus sampai 500 mA
  • Digital Level Converter jika tegangan output mikrokontroler tidak sama dengan tegangan perangkat yang dikendalikan.  Salah satu cara yang praktis dengan menggunakan modul bidirectional logic level converter.
  • Transistor NPN, PNP, MOSFET kanal N, kanal P sebagai penguat arus. Dibahas detail di artikel “Teknik Output Digital
3.3V 5V Bi Directional Level Converter
3.3V 5V Bi Directional Level Converter

Referensi

  • https://www.ti.com/product/PCF8574

Penguat Output  Dengan H-Bridge

H-Bridge adalah rangkaian output khusus untuk menggerakkan motor DC dengan 2 arah. Pada umumnya komponen utamanya adalah 4 buah transistor BJT/MOSFET yang dapat dikonfigurasikan sehingga polaritas output dapat dibalik.

Contoh komponen H-Bridge:

Motor driver TB6612FNG
Motor driver TB6612FNG

Input Analog

Untuk input analog diperlukan ADC (Analog to Digital Converter). Pada mikrokontroler seperti ATmega328 sudah dilengkapi ADC. Jika ADC ini tidak cukup , atau mikrokontroler tidak ada ADC, maka kita perlu menambah ADC eksternal.

Contoh ADC yang mudah dipakai untuk mikrokontroler:

  • MCP3008: 8 kanal 10 bit, antar muka SPI
  • ADS1115: 4 kanal 16 bit, antar muka I2C
  • HX711: 2 kanal 24 bit, antar muka serial digital. Umumnya dipakai untuk timbangan digital.
  • AD7705
  • MAX174
  • ADS1256
  • ADC0804
  • PCF8591
  • ADS1232

ADC dibahas secara lebih detail di artikel “ADC untuk Arduino

MCP3008

Output Analog

Untuk output analog diperlukan DAC (Digital to Analog to Converter). Mikrokontroler seperti ESP32 sudah dilengkapi DAC 8 bit, namun umumnya mikrokontroler tidak dilengkapi DAC.

Contoh DAC yang sering dipakai:

MCP4725
MCP4725

Komunikasi Digital

Komunikasi digital ke periferal sering menggunakan protokol I2C ataupun SPI. Namun jika level tegangan dengan periferal berbeda, maka perlu tambahan komponen bidirectional logic converter.

Mikrokontroler umumnya memiliki port komunikasi serial asinkron dengan level tegangan 3,3 volt ataupun 5 volt, sesuai dengan tegangan kerja mikrokontroler tersebut. Supaya dapat dihubungkan dengan perangkat lain yang menggunakan level tegangan RS232, perlu ada konverter TTL ke RS232, seperti MAX232

Jika komunikasi menggunakan RS-485, maka perlu mengubah level tegangan TTL menjadi RS-485 dengan komponen seperti MAX485.

Jika ingin menghubungkan port komunikasi asinkron dengan port USB di komputer, maka perlu menggunakan modul USB to Serial. Modul USB to serial yang populer adalah yang berbasis chipset FTDI dan chipset CH340

Modul USB to Serial TTL CH340
Modul USB to Serial TTL CH340

Regulator DC

Jika tegangan dari power supply/baterai tidak sama dengan tegangan kerja mikrokontroler, maka perlu ditambahkan regulator yang sesuai.

Regulator yang umum dipakai adalah dari tipe linear dan tipe switching.

Contoh regulator linear yang umum:

  • LM7805
  • LM317
Regulator LM7805
Regulator LM7805

Contol regulator step down DC to DC converter adalah LM2596. IC ini sudah tersedia dalam bentuk modul, sehingga tidak perlu dirakit lagi dari komponen diskrit.

DC to DC Converter step down LM2596
DC to DC Converter step down LM2596

Jika diinginkan konversi energi yang lebih efisien, lebih baik menggunakan DC to DC converter. Saat ini sudah banyak dijual berbagai macam modul DC to DC converter.

Contoh komponen DC to DC konverter dibahas di artikel “Cara menurunkan tegangan aki 12 volt ke 6 volt

Power Supply

Power supply / adaptor diperlukan untuk mengubah tegangan jala-jala listrik 220 volt menjadi tegangan rendah yang dapat dipakai untuk mikroprosesor. Umumnya mikroproser memerlukan tegangan 5 volt DC, namun kadang ada juga perangkat seperti motor DC yang memerlukan tegangan 12 volt DC.

Jika memerlukan beberapa tegangan, dapat dipakai beberapa power supply, atau 1 power supply ditambah dengan regulator untuk mengubah tegangan output ke tegangan lain yang diinginkan. Misal jika diperlukan tegangan 12 volt dan 5 volt, bisa saja dipakai 1 power supply dengan output 12 volt DC dan ditambah regulator DC to DC converter step down 12 volt ke 5 volt DC.

Power Supply 12 volt 5 ampere
Power Supply 12 volt 5 ampere

Power supply yang hemat energi adalah dari tipe switching power supply, misal power supply 12 volt berikut ini.

Perbandingan power supply omron 12 volt
Beberapa macam power supply 12 volt

Baterai

Jika perangkat dirancang untuk mobile atau tidak ada akses ke jala-jala listrik, maka perlu sumber daya internal berupa baterai. Alternatif lain menggunakan sel surya plus baterai.

Baterai 18650 4200 mWh
Baterai 18650 4200 mWh

Tegangan baterai jarang yang sesuai dengan tegangan kerja mikroprosesor. Tegangan baterai juga berubah (menurun) tergantung kapasitas baterai yang terpakai. Untuk menjaga tegangan supply yang konstan, biasanya output dari baterai ini perlu disambungkan ke regulator  atau DC to DC converter.

Komponen lain yang diperlukan namun belum dibahas di artikel ini:

Referensi