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

Pengukuran Kecepatan ADC Internal ESP32

Pengukuran Kecepatan ADC Internal ESP32

int counter;  // how many iterations
int time_begin = 0;
int time_end = 0;
int duration;
const int PIN_OUTPUT = 19;
int sensorPin = 34;  // select the input pin for the potentiometer

void setup() {
  Serial.begin(115200);
  counter = 0;
  pinMode(PIN_OUTPUT, OUTPUT);
  Serial.println("start benchmark");
}
//---------------------------------------------------
void loop() {
  int data = 0;
  int value;  // angka yang ditulis
  value = 0;  // minimum value

  data = analogRead(sensorPin);
  //  Serial.println(data);
  //  delay(1000);
  digitalWrite(PIN_OUTPUT, HIGH);

  data = analogRead(sensorPin);
  //Serial.println(data);
  //delay(1000);
  digitalWrite(PIN_OUTPUT, LOW);

  counter = counter + 1;
  if (counter >= 10000) {
    float period;
    int time_now = millis();
    counter = 0;
    duration = time_now - time_begin;
    period = duration / 10000.0 / 2;
    Serial.print("period (ms): ");
    Serial.println(period);
    //  prepare next round
    time_begin = time_now;
  }
}

Pengukuran

Pengukuran perioda

start benchmark
period (ms): 0.09
period (ms): 0.09
period (ms): 0.09
period (ms): 0.09

Pengukuran pin output

Kesimpulan

Perioda ADC adalah 0.09 ms

Frekuensi ADC adalah 10,742 kHz

Referensi

Frekuensi DAC MCP4725 pada ESP32 C3

Pengukuran Frekuensi DAC MCP4725 pada ESP32

Foto perangkat

Kode Pengujian


#include <Wire.h>
#include <Adafruit_MCP4725.h>
#include <Wire.h>

#define I2C_SDA 15
#define I2C_SCL 13

Adafruit_MCP4725 dac;

void setup(void) {
  int address = 0;
  int hasil;
  uint32_t speed = 400000L;
  int status;
  status = Wire.begin(I2C_SDA, I2C_SCL, speed);
  Serial.begin(115200);
  Serial.print("Hello! Wire Init status:");
  Serial.println(status);
  Serial.println(speed);

  address = 0x62;
  dac.begin(address);
  Serial.println("Search I2C");
  SearchI2C();
  Serial.println("benchmark");
}
int start_sawtooth = 0;
int current_time;
int duration;
int time_begin;
int time_now;
uint32_t counter;
void loop(void) {
  dac.setVoltage(0, false);
  dac.setVoltage(4095, false);
  counter = counter + 1;
  if (counter >= 10000) {
    float period;
    int time_now = millis();
    counter = 0;
    duration = time_now - time_begin;
    period = duration / 10000.0 / 2;
    Serial.print("period (ms): ");
    Serial.println(period);
    //  prepare next round
    time_begin = time_now;
  }
}

void SearchI2C() {
  byte error, address;
  int nDevices;

  Serial.println("Scanning...");

  nDevices = 0;
  for (address = 1; address < 127; address++) {
    //    Serial.println(address, HEX);
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0) {
      Serial.print("I2C device found at address 0x");
      if (address < 16)
        Serial.print("0");
      Serial.print(address, HEX);
      Serial.println("  !");

      nDevices++;
    } else if (error == 4) {
      Serial.print("Unknown error at address 0x");
      if (address < 16)
        Serial.print("0");
      Serial.println(address, HEX);
    }
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");
}

Pengukuran

Hasil pengukuran perioda

benchmark
period (ms): 0.18
period (ms): 0.17
period (ms): 0.17

Hasil pengukuran sinyal output DAC

Frekuensi DAC adalah 2,867 kHz x 2 = 5,734 kHz

Kesimpulan

Perioda : 0.17 ms

Frekuensi: 5,734 kHz

Referensi

Pengukuran Frekuensi ADC ESP32 C3

Pengukuran frekuensi ADC internal pada modul ESP32-C3-Core (Luatos)

Berikut ini rangkaian untuk pengujian

Berikut ini kode yang dipakai untuk pengukuran

int counter;  // how many iterations
int time_begin = 0;
int time_end = 0;
int duration;
const int PIN_OUTPUT = 1;
int sensorPin = 0;  // select the input pin for the potentiometer

void setup() {
  Serial.begin(115200);
  counter = 0;
  pinMode(PIN_OUTPUT, OUTPUT);
  Serial.println("start benchmark");
}
//---------------------------------------------------
void loop() {
  int data = 0;
  int value;  // angka yang ditulis
  value = 0;  // minimum value

  data = analogRead(sensorPin);
  //  Serial.println(data);
  //  delay(1000);
  digitalWrite(PIN_OUTPUT, HIGH);

  data = analogRead(sensorPin);
  //Serial.println(data);
  //delay(1000);
  digitalWrite(PIN_OUTPUT, LOW);

  counter = counter + 1;
  if (counter >= 10000) {
    float period;
    int time_now = millis();
    counter = 0;
    duration = time_now - time_begin;
    period = duration / 10000.0 / 2;
    Serial.print("period (ms): ");
    Serial.println(period);
    //  prepare next round
    time_begin = time_now;
  }
}

Berikut ini hasil pengukuran perioda di port serial

start benchmark
period (ms): 0.06
period (ms): 0.06
period (ms): 0.06

Berikut ini hasil pengukuran frekuensi sinyal di pin 1

Kesimpulan

frekuensi ADC adalah 17,288 kHz

perioda ADC adalah 0,06 ms

Frekuensi DAC MCP4725 pada ESP32 C3

Pada percobaan ini diukur frekuensi & perioda konversi DAC tipe MCP4725 pada modul ESP32 C3 Luatos.

Rangkaian yang diuji

 

Kode Program

#include <Wire.h>
#include <Adafruit_MCP4725.h>
#include <Wire.h>

#define I2C_SDA 2
#define I2C_SCL 3

Adafruit_MCP4725 dac;

void setup(void) {
  int address = 0;
  int hasil;
  uint32_t speed = 1000000L;
  int status;
  speed = 3000000L;
  status = Wire.begin(I2C_SDA, I2C_SCL, speed);
  Serial.begin(115200);
  Serial.print("Hello! Wire Init status:");
  Serial.println(status);
  Serial.println(speed);

  address = 0x60;
  dac.begin(address);
  Serial.println("Search I2C");
  SearchI2C();
  Serial.println("Generating a triangle wave");
}
int start_sawtooth = 0;
int current_time;
int duration;
int time_begin;
int time_now;
uint32_t counter;

void loop(void) {
  dac.setVoltage(0, false);
  dac.setVoltage(4095, false);
  counter = counter + 1;
  if (counter >= 10000) {
    float period;
    int time_now = millis();
    counter = 0;
    duration = time_now - time_begin;
    period = duration / 10000.0 / 2;
    Serial.print("period (ms): ");
    Serial.println(period);
    //  prepare next round
    time_begin = time_now;
  }
}

void SearchI2C() {
  byte error, address;
  int nDevices;

  Serial.println("Scanning...");

  nDevices = 0;
  for (address = 1; address < 127; address++) {
    //    Serial.println(address, HEX);
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0) {
      Serial.print("I2C device found at address 0x");
      if (address < 16)
        Serial.print("0");
      Serial.print(address, HEX);
      Serial.println("  !");

      nDevices++;
    } else if (error == 4) {
      Serial.print("Unknown error at address 0x");
      if (address < 16)
        Serial.print("0");
      Serial.println(address, HEX);
    }
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");
}

Kode ada di https://github.com/waskita/embedded/tree/master/esp32-c3-mcp4725

Pengukuran

Pengukuran dilakukan dengan frekuensi clock I2C dari 100 kHz sampai 3 Mhz. Semua menghasilkan angka yang sama.

Sinyal keluaran MCP4725 diukur dengan osiloskop.

Didapat frekuensi sinyal output adalah 3,080 kHz. Jadi frekuensi update DAC adalah 6,16 kHz

period (ms): 0.17
period (ms): 0.16
period (ms): 0.16
period (ms): 0.16

Pengukuran perioda menghasilkan angka 0,16 ms

Kesimpulan

Frekuensi update DAC adalah 6,16 kHz

Perioda 0,16 ms

Referensi

Pengukuran Frekuensi ADC pada Arduino Nano ATmega328

Pengukuran Frekuensi ADC internal pada Arduino Nano ATmega328

berikut ini kode yang dipakai untuk pengukuran

int counter;  // how many iterations
int time_begin = 0;
int time_end = 0;
int duration;

int sensorPin = A0;   // select the input pin for the potentiometer
int ledPin = 13;      // select the pin for the LED

void setup() {
  Serial.begin(115200);
  counter = 0;
  pinMode(2, OUTPUT);
  Serial.println("start benchmark");
}
//---------------------------------------------------
void loop() {
  int value;  // angka yang ditulis
  value = 0;  // minimum value
  analogRead(sensorPin);
  PORTD=0; // langsung akses port supaya lebih cepat
  analogRead(sensorPin);
  PORTD=255;
  counter = counter + 1;
  if (counter >= 10000) {
    float period;
    int time_now = millis();
    counter = 0;
    duration = time_now - time_begin;
    period = duration / 10000.0 /2;
    Serial.print("period (ms): ");
    Serial.println(period);
    //  prepare next round
    time_begin = time_now;
  }
}

Hasil Pengukuran

Pengukuran output pada pin D2 dengan osiloskop menghasilkan sinyal berikut

Dari data port serial, didapatkan angka perioda 0,11 ms

start benchmark
period (ms): 0.11
period (ms): 0.11
period (ms): 0.11
period (ms): 0.11
period (ms): 0.11

Dengan osiloskop didapatkan sinyal kotak dengan frekuensi 4,45532 kHz . Artinya frekuensi ADC adalah dua kalinya, yaitu 8,91064 kHz

Angka 8900 Hz ini sesuai dengan pengukuran di artikel lain: https://chisight.wordpress.com/2016/03/25/speeding-up-the-adc-on-an-arduino-atmega-328p/

Kesimpulan

Frekuensi ADC adalah 8,91064 kHz

Frekuensi ini jauh di bawah kecepatan teoritis. Kemungkinan kelambatan karena library yang dipakai.

Referensi

  • Open Music Labs : ATmega ADC
  • https://www.ee-diary.com/2022/08/programming-atmega328p-adc-in-c.html#
  • https://chisight.wordpress.com/2016/03/25/speeding-up-the-adc-on-an-arduino-atmega-328p/
  • Kode di https://github.com/waskita/embedded/tree/master/nano-adc

Frekuensi DAC MCP4725 pada Arduino Nano ATmega328

Pada percobaan ini diukur frekuensi & perioda konversi DAC (Digital to Analog Converter) tipe MCP4725  pada modul Arduino Nano dengan prosesor ATmega328.

Rangkaian sistem adalah sebagai berikut

 

Kode yang dipakai untuk pengujian adalah sebagai berikut:

// idea from https://learn.sparkfun.com/tutorials/mcp4725-digital-to-analog-converter-hookup-guide/all
#define MCP4725_ADDR 0x60
#include <Wire.h>  //Include the Wire library to talk I2C

int counter;  // how many iterations
int time_begin = 0;
int time_end = 0;
int duration;
void setup() {
  Wire.begin();
  Serial.begin(115200);
  counter = 0;
  Serial.println("start benchmark");
}
//---------------------------------------------------
void loop() {
  int value;  // angka yang ditulis
  value = 0;  // minimum value
  Wire.beginTransmission(MCP4725_ADDR);
  Wire.write(64);                 // cmd to update the DAC
  Wire.write(value >> 4);         // the 8 most significant bits...
  Wire.write((value & 15) << 4);  // the 4 least significant bits...
  Wire.endTransmission();

  value = 4095;  // maximum value
  Wire.beginTransmission(MCP4725_ADDR);
  Wire.write(64);                 // cmd to update the DAC
  Wire.write(value >> 4);         // the 8 most significant bits...
  Wire.write((value & 15) << 4);  // the 4 least significant bits...
  Wire.endTransmission();

  counter = counter + 1;
  if (counter >= 10000) {
    float  period;
    int time_now = millis();
      counter = 0;
    duration = time_now - time_begin;
    period = duration / 10000.0 / 2.0 ;
    Serial.print("period (ms): ");
    Serial.println(period);
    //  prepare next round
    time_begin = time_now;
  }
}

I2C 100 kHz

ATmega328 menggunakan 2 frekuensi I2C: 100 kHz dan 400 kHz. Percoban pertama menggunakan kecepatan default adalah 100 kHz.

Sinyal yang dihasilkan pada output MCP4725 adalah sebagai berikut:

Tampilan pada serial monitor adalah sebagai berikut:

start benchmark
period (ms): 0.43
period (ms): 0.43
period (ms): 0.43
period (ms): 0.43
period (ms): 0.43
period (ms): 0.43

Pengukuran dengan osiloskop menunjukkan sinyal persegi dengan frekuensi 1,166 kHz

Jumlah transisi adalah 2x frekuensi ini, jadi frekuensi konversi adalah 1,166 x 2 = 2,332 kHz

I2C 400 kHz

Pada pengukuran ini, kecepatan I2C dinaikkan menjadi 400 kHz. Caranya menggunakan fungsi Wire.setClock()

Perioda menjadi 0,15 ms

start benchmark
period (ms): 0.15
period (ms): 0.15
period (ms): 0.15
period (ms): 0.15
period (ms): 0.15

Output DAC diukur dengan osiloskop, dengan hasil sebagai berikut

Frekuensi output adalah 3,41733 kHz, sehingga frekuensi DAC adalah 2x 3,417 = 6,834 kHz

Kesimpulan

Dengan clock I2C 100 kHz, didapatkan

  • Perioda konversi ADC adalah 0,43 ms
  • frekuensi konversi ADC adalah 2,332 kHz

Dengan clock I2C 400 kHz, didapatkan

  • Perioda konversi ADC adalah 0,15 ms
  • frekuensi konversi ADC adalah 6,384 kHz

Referensi

ADC dan DAC Populer

Berikut ini ADC yang populer dipakai

  • ADC internal di ATMega328
  • ADC internal di ESP32
  • VS1003
  • ADS1115
  • PCF8591
  • AD7705
  • HX711
  • ADC0804
  • ADS1256
  • ADS1232
  • MCP3008
  • MCP3201

Parameter yang perlu dibandingkan:

  • resolusi (bit)
  • tegangan input maksimum
  • sumber tegangan referensi (internal atau external)
  • tegangan minimum yang dapat diukur
  • jenis ADC (SAR, flash, dsb)
  • kebutuhan daya
  • frekuensi maksimum sampling
  • protokol komunikasi ke mikrokontroler

DAC yang populer dipakai:

  • DAC internal ESP32
  • VS1003
  • PCF8591
  • DAC0800
  • MCP4725

Parameter yang perlu dibandingkan:

  • resolusi (bit)
  • tegangan output maksimum
  • sumber tegangan referensi (internal atau external)
  • tegangan minimum yang dapat diukur
  • jenis ADC (SAR, flash, dsb)
  • kebutuhan daya
  • frekuensi maksimum sampling
  • protokol komunikasi ke mikrokontroler

Literatur

Maxim ADC App Notes, berisi:

  • AN1041: Understanding Integrating ADC
  • AN810: Understanding Flash ADCs
  • AN2102: Migrating from Integrating ADC Architectures to Sigma Delta

 

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

Sensor Debu ZH03A

Sensor debu ZH03A dibuat oleh perusahaan Zhengzhou Winsen Electronics Technology Co., Ltd

Sensor debu ini dapat mengukur kadar debu pada ukuran PM1.0, PM2.5 dan PM10

Berikut ini foto sensor tersebut.

 

Foto tampak depan

Foto tampak samping

Tampak samping

Foto tampak atas

 

Referensi

Cara Membuat Tegangan -10 volt Sampai +10 volt

Permasalahan

Saya mau kontrol variabel dari tegangan negatif (-10) hingga (+10) DC menggunakan mikrokontroler (0 ~ 3,3 VDC). Rangkaian apa yang saya butuhkan?

Jawaban:

Untuk membangkitkan tegangan analog anda bisa pakai DAC (Digital to Analog Converter). Ada mikrokontroler yang sudah ada DACnya, misal ESP32. Kalau belum ada, bisa pakai DAC tambahan seperti MCP4725 . Jadi di sini kita sudah dapat tegangan analog 0 ~ 3,3 volt. Kemudian tegangan ini dikurangi dengan 1,65 volt dengan rangkaian penjumlah op-amp dan sumber tegangan -1,65 volt. Di sini kita dapat tegangan analog -1,65 V ~ 1,65V. Tegangan ini kemudian dikalikan dengan op-amp non inverting supaya menghasilkan rentang -10V ~ +10V.

3500 VA Berapa Watt

3500 VA artinya 3500 volt-ampere, yang mengindikasikan ukuran daya aparent (volt-ampere) dari perangkat atau sistem. Volt-ampere (VA) adalah hasil kali dari tegangan (volt) dan arus (ampere) yang mengalir dalam suatu rangkaian listrik.

Namun, penting untuk memahami bahwa daya tampak (VA) tidak sama dengan daya aktif (watt) yang sebenarnya digunakan oleh perangkat atau sistem. Faktor daya (power factor) digunakan untuk menggambarkan perbandingan antara daya aktif (watt) dan daya aparent (VA). Faktor daya dapat berkisar antara 0 hingga 1.

Jika kita asumsikan faktor daya adalah 1 (cos φ = 1), maka 3500 VA juga setara dengan 3500 watt (W), artinya perangkat atau sistem menggunakan atau menghasilkan daya sebesar 3500 watt. Namun, jika faktor daya lebih rendah dari 1, daya yang sebenarnya akan lebih rendah dari 3500 watt.

Jadi, 3500 VA berarti ukuran daya aparent (volt-ampere) dari perangkat atau sistem, tetapi untuk mengetahui daya aktif (watt) yang sebenarnya, Anda perlu mengetahui berapa sebenarnya faktor daya yang berlaku pada sistem anda.

Rumah dengan kapasitas daya 3500 VA biasanya menggunakan MCB (mini circuit breaker) dengan batas arus 16 ampere. Jadi sebenarnya dayanya adalah 2200 x 16 = 3520 VA, namun untuk mudahnya dibulatkan ke 3500 VA.

MCB merek Schneider dengan batas arus 16 ampere dengan latar belakang hitam tampak depan
MCB merek Schneider dengan batas arus 16 ampere