IoT

🌑️ Sensor Interfacing dengan Microcontroller

Panduan lengkap menghubungkan sensor ke microcontroller β€” ADC, I2C, SPI, UART, kalibrasi sensor, dan contoh kode praktis untuk ESP32 dan Arduino

1. Pengenalan Sensor Interfacing

Sensor interfacing adalah proses menghubungkan sensor fisik ke microcontroller sehingga data dari dunia nyata (suhu, cahaya, kelembaban, tekanan, dll) dapat dibaca, diproses, dan dikirim ke sistem IoT. Memahami berbagai metode interfacing adalah keterampilan fundamental bagi setiap praktisi IoT.

Setiap sensor memiliki karakteristik berbeda: ada yang menghasilkan sinyal analog, ada yang digital; ada yang berkomunikasi via I2C, SPI, atau UART. Pemilihan metode interfacing yang tepat mempengaruhi akurasi, kecepatan, dan kompleksitas sistem Anda.

Mengapa Sensor Interfacing Penting?

Aspek Penjelasan
Akuisisi DataSensor adalah mata dan telinga sistem IoT β€” tanpa sensor, tidak ada data
AkurasiInterfacing yang benar memastikan pembacaan sensor akurat dan konsisten
EfisiensiPemilihan protokol yang tepat menghemat pin, power, dan bandwidth
SkalabilitasProtokol seperti I2C dan SPI memungkinkan banyak sensor di satu bus
ReliabilityKalibrasi dan filtering menghasilkan data yang dapat diandalkan
Diagram: Arsitektur Sensor Interfacing
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚            ARSITEKTUR SENSOR INTERFACING                β”‚
β”‚                                                         β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚  Sensor  β”‚     β”‚       MICROCONTROLLER           β”‚   β”‚
β”‚  β”‚  Analog  │────►│  ADC ──► Processing ──► Output  β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚                                 β”‚   β”‚
β”‚                    β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”        β”‚   β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚  β”‚ GPIO   β”‚  β”‚ Buffer β”‚        β”‚   β”‚
β”‚  β”‚  Sensor  │────►│  β”‚ Input  │──│ Filter │──► WiFiβ”‚   β”‚
β”‚  β”‚  Digital β”‚     β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚                                 β”‚   β”‚
β”‚                    β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”        β”‚   β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚  β”‚  I2C   β”‚  β”‚ Kalibr.β”‚        β”‚   β”‚
β”‚  β”‚  Sensor  │◄───►│  β”‚  Bus   │──│        │──► MQTTβ”‚   β”‚
β”‚  β”‚  I2C     β”‚     β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚                                 β”‚   β”‚
β”‚                    β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”                     β”‚   β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚  β”‚  SPI   β”‚                     β”‚   β”‚
β”‚  β”‚  Sensor  │◄───►│  β”‚  Bus   β”‚                     β”‚   β”‚
β”‚  β”‚  SPI     β”‚     β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜                     β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

2. Jenis-Jenis Sensor

Sensor dapat diklasifikasikan berdasarkan parameter yang diukur dan jenis sinyal outputnya.

Berdasarkan Parameter

Kategori Sensor Contoh IC/Module Output
SuhuNTC Thermistor, DS18B20, DHT22, BME280DHT22, BME280, LM35Analog / I2C / 1-Wire
KelembabanKapasitif, ResistifDHT22, BME280, SHT31Digital / I2C
TekananPiezoresistifBMP280, BME280, MPL3115A2I2C / SPI
CahayaLDR, PhotodiodeBH1750, TSL2561Analog / I2C
JarakUltrasonic, IR, ToFHC-SR04, VL53L0XDigital / I2C
GerakanPIR, Accelerometer, GyroMPU6050, ADXL345Digital / I2C / SPI
GasElectrochemical, MOSMQ-135, SGP30, SCD30Analog / I2C
pHElektrodaSEN0161Analog

Berdasarkan Jenis Output Sinyal

Jenis Output Karakteristik Contoh Sensor Interfacing
AnalogSinyal kontinu, perlu ADCLM35, LDR, MQ-135, pHADC pin
Digital On/OffHigh/Low sajaPIR, Reed switch, ButtonGPIO input
Digital ProtokolData terstruktur via busBME280, MPU6050I2C / SPI
PWM/PulseLebar pulsa bervariasiSome CO2 sensorsTimer capture
Serial/UARTData serial asynchronousGPS NEO-6M, PM2.5UART pins

3. ADC (Analog to Digital Converter)

ADC adalah konverter yang mengubah sinyal analog (kontinu) menjadi sinyal digital (diskrit) yang bisa diproses oleh microcontroller. Hampir semua sensor analog memerlukan ADC untuk dibaca oleh ESP32, Arduino, atau microcontroller lainnya.

Konsep Dasar ADC

Parameter ESP32 Arduino Uno STM32
Resolusi12-bit (4096 level)10-bit (1024 level)12-bit (4096 level)
Voltage Reference0 - 3.3V0 - 5V0 - 3.3V
Jumlah Channel18 channel6 channel (A0-A5)Bervariasi (10-16)
Sampling RateHingga 2 MSPS~10 KSPSHingga 5.33 MSPS
ADC PinGPIO 32-39A0 - A5PA0 - PA7

Cara Kerja ADC

Diagram: Konversi ADC
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                CARA KERJA ADC                           β”‚
β”‚                                                         β”‚
β”‚  Sinyal Analog (kontinu):                               β”‚
β”‚                                                         β”‚
β”‚  Voltage                                                β”‚
β”‚  3.3V ─         β•±β•²        β•±β•²        β•±β•²                 β”‚
β”‚       β”‚        β•±  β•²      β•±  β•²      β•±  β•²                β”‚
β”‚  1.65V────────╱────╲────╱────╲────╱────╲───            β”‚
β”‚       β”‚      β•±      β•²  β•±      β•²  β•±      β•²              β”‚
β”‚  0V   ──────╱────────╲╱────────╲╱────────╲──► time     β”‚
β”‚                                                         β”‚
β”‚  Setelah ADC (diskritisasi):                            β”‚
β”‚                                                         β”‚
β”‚  Value                                                  β”‚
β”‚  4095 ─    β–ˆβ–ˆβ–ˆβ–ˆ      β–ˆβ–ˆβ–ˆβ–ˆ      β–ˆβ–ˆβ–ˆβ–ˆ                     β”‚
β”‚       β”‚   β–ˆβ–ˆ  β–ˆβ–ˆ    β–ˆβ–ˆ  β–ˆβ–ˆ    β–ˆβ–ˆ  β–ˆβ–ˆ                    β”‚
β”‚  2048 β”€β”€β”€β–ˆβ–ˆβ–ˆβ–ˆβ”€β”€β–ˆβ–ˆβ–ˆβ–ˆβ”€β”€β–ˆβ–ˆβ–ˆβ–ˆβ”€β”€β–ˆβ–ˆβ–ˆβ–ˆβ”€β”€β–ˆβ–ˆβ–ˆβ–ˆβ”€β”€                 β”‚
β”‚       β”‚ β–ˆβ–ˆ      β–ˆβ–ˆ β–ˆβ–ˆ      β–ˆβ–ˆ β–ˆβ–ˆ      β–ˆβ–ˆ               β”‚
β”‚  0    β”€β–ˆβ–ˆ        β–ˆβ–ˆβ–ˆβ–ˆ        β–ˆβ–ˆβ–ˆβ–ˆ        β–ˆ              β”‚
β”‚                                                         β”‚
β”‚  Rumus: Digital Value = (Vin / Vref) Γ— (2^resolusi - 1)β”‚
β”‚  ESP32: Value = (Vin / 3.3) Γ— 4095                     β”‚
β”‚  Arduino: Value = (Vin / 5.0) Γ— 1023                   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Membaca Sensor Analog dengan ESP32

Arduino β€” ADC ESP32
// Membaca sensor LM35 (suhu) dengan ESP32
// LM35: Output 10mV per Β°C

#define LM35_PIN 34     // ADC1 Channel 6
#define LDR_PIN 35      // ADC1 Channel 7
#define POT_PIN 36      // ADC1 Channel 0 (VP)

// ESP32 ADC non-linear, perlu kalibrasi
// Gunakan analogReadMilliVolts() untuk hasil lebih akurat

void setup() {
    Serial.begin(115200);
    analogReadResolution(12);    // 12-bit (0-4095)
    analogSetAttenuation(ADC_11db); // Range 0-3.3V
}

void loop() {
    // Baca sensor LM35
    int raw_lm35 = analogRead(LM35_PIN);
    float voltage_lm35 = analogReadMilliVolts(LM35_PIN) / 1000.0;
    float suhu = voltage_lm35 / 0.01;  // 10mV per Β°C

    // Baca LDR (Light Dependent Resistor)
    int raw_ldr = analogRead(LLDR_PIN);
    // Konversi ke persentase lux (approximate)
    int persen_cahaya = map(raw_ldr, 0, 4095, 0, 100);

    // Baca Potensiometer
    int raw_pot = analogRead(POT_PIN);
    float persen_pot = (raw_pot / 4095.0) * 100.0;

    // Tampilkan hasil
    Serial.printf("LM35  - Raw: %d, Voltage: %.3fV, Suhu: %.2fΒ°C\n",
                  raw_lm35, voltage_lm35, suhu);
    Serial.printf("LDR   - Raw: %d, Cahaya: %d%%\n",
                  raw_ldr, persen_cahaya);
    Serial.printf("Pot   - Raw: %d, Posisi: %.1f%%\n",
                  raw_pot, persen_pot);
    Serial.println("---");

    delay(1000);
}

Multiple Average untuk Akurasi

Arduino β€” Multi-Sample ADC
// Pembacaan ADC dengan averaging untuk mengurangi noise
// Berguna untuk sensor seperti pH meter dan turbidity

class ADCReader {
private:
    int _pin;
    int _samples;

public:
    ADCReader(int pin, int samples = 10) {
        _pin = pin;
        _samples = samples;
    }

    // Baca dengan averaging
    float readAverage() {
        long sum = 0;
        for (int i = 0; i < _samples; i++) {
            sum += analogRead(_pin);
            delayMicroseconds(100);  // Delay kecil antar sample
        }
        return (float)sum / _samples;
    }

    // Baca dengan median (lebih tahan terhadap spike)
    float readMedian() {
        int readings[_samples];
        for (int i = 0; i < _samples; i++) {
            readings[i] = analogRead(_pin);
            delayMicroseconds(100);
        }
        // Sort readings
        for (int i = 0; i < _samples - 1; i++) {
            for (int j = i + 1; j < _samples; j++) {
                if (readings[i] > readings[j]) {
                    int temp = readings[i];
                    readings[i] = readings[j];
                    readings[j] = temp;
                }
            }
        }
        return readings[_samples / 2];  // Median
    }

    // Baca voltage langsung (ESP32)
    float readVoltage() {
        float avg = readAverage();
        return (avg / 4095.0) * 3.3;
    }
};

// Penggunaan
ADCReader sensorPH(34, 20);     // 20 samples untuk pH
ADCReader sensorTurbid(35, 15); // 15 samples untuk turbidity

void loop() {
    float ph_raw = sensorPH.readMedian();
    float ph_voltage = sensorPH.readVoltage();
    float ph_value = 3.5 * ph_voltage + 0.0; // Rumus kalibrasi

    float turbid_raw = sensorTurbid.readAverage();

    Serial.printf("pH: %.2f (V: %.3f)\n", ph_value, ph_voltage);
    Serial.printf("Turbidity: %.0f\n", turbid_raw);

    delay(2000);
}
⚠️ Peringatan ESP32 ADC

ADC pada ESP32 memiliki non-linearity yang cukup signifikan, terutama di ujung bawah (0-100mV) dan atas (3.0-3.3V). Gunakan fungsi analogReadMilliVolts() atau kalibrasi manual untuk akurasi yang lebih baik. Untuk aplikasi presisi tinggi, gunakan ADC eksternal seperti ADS1115 (16-bit, I2C).

4. Komunikasi I2C

I2C (Inter-Integrated Circuit) adalah protokol komunikasi serial dua kabel yang dikembangkan oleh Philips (NXP) pada tahun 1982. I2C menggunakan hanya 2 kabel untuk menghubungkan banyak perangkat β€” sangat efisien untuk sistem dengan banyak sensor.

Karakteristik I2C

Parameter Nilai
Jumlah Kabel2 (SDA + SCL) + VCC + GND
KecepatanStandard: 100 KHz, Fast: 400 KHz, High: 3.4 MHz
TopologyMulti-master, multi-slave
Alamat Perangkat7-bit (128 alamat) atau 10-bit (1024 alamat)
JarakHingga ~1 meter (board-level)
Pull-up ResistorDiperlukan pada SDA dan SCL (biasanya 4.7KΞ©)

Cara Kerja I2C

Diagram: Bus I2C
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    BUS I2C                              β”‚
β”‚                                                         β”‚
β”‚        VCC (3.3V / 5V)                                  β”‚
β”‚         β”‚         β”‚                                     β”‚
β”‚        β”Œβ”΄β”       β”Œβ”΄β”                                    β”‚
β”‚        β”‚ β”‚4.7KΞ©  β”‚ β”‚4.7KΞ©                              β”‚
β”‚        β””β”¬β”˜       β””β”¬β”˜                                    β”‚
β”‚         β”‚         β”‚                                     β”‚
β”‚  SDA ───┼─────────┼─────────┼──────────                 β”‚
β”‚         β”‚         β”‚         β”‚                           β”‚
β”‚  SCL ───┼─────────┼─────────┼──────────                 β”‚
β”‚         β”‚         β”‚         β”‚                           β”‚
β”‚     β”Œβ”€β”€β”€β”΄β”€β”€β”€β” β”Œβ”€β”€β”€β”΄β”€β”€β”€β” β”Œβ”€β”€β”€β”΄β”€β”€β”€β”                      β”‚
β”‚     β”‚Master β”‚ β”‚Slave 1β”‚ β”‚Slave 2β”‚                      β”‚
β”‚     β”‚ESP32  β”‚ β”‚BME280 β”‚ β”‚OLED   β”‚                      β”‚
β”‚     β”‚       β”‚ β”‚0x76   β”‚ β”‚0x3C   β”‚                      β”‚
β”‚     β””β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”˜                      β”‚
β”‚                                                         β”‚
β”‚  Komunikasi: Master β†’ Start β†’ Address β†’ R/W β†’ ACK      β”‚
β”‚              β†’ Data β†’ ACK β†’ ... β†’ Stop                  β”‚
β”‚                                                         β”‚
β”‚  ⚠️ Setiap perangkat HARUS punya alamat unik di bus    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Scan Alamat I2C

Arduino β€” I2C Scanner
#include <Wire.h>

// I2C Scanner β€” cari semua device di bus I2C
// Berguna untuk menemukan alamat sensor baru

#define SDA_PIN 21    // ESP32 default SDA
#define SCL_PIN 22    // ESP32 default SCL

void setup() {
    Serial.begin(115200);
    Wire.begin(SDA_PIN, SCL_PIN);

    Serial.println("I2C Scanner - Scanning...");
    Serial.println("     0  1  2  3  4  5  6  7  8  9  A  B  C  D  E  F");

    int deviceCount = 0;

    for (byte addr = 1; addr < 127; addr++) {
        if (addr % 16 == 0) {
            Serial.printf("\n0x%02X:", addr);
        }

        Wire.beginTransmission(addr);
        byte error = Wire.endTransmission();

        if (error == 0) {
            Serial.printf(" %02X", addr);
            deviceCount++;
        } else {
            Serial.print(" --");
        }
    }

    Serial.printf("\n\nDitemukan %d perangkat I2C\n", deviceCount);

    // Tabel alamat umum
    Serial.println("\nAlamat Umum:");
    Serial.println("  0x27/0x3F - LCD I2C");
    Serial.println("  0x3C/0x3D - OLED SSD1306");
    Serial.println("  0x48      - ADS1115 (ADC)");
    Serial.println("  0x68      - MPU6050 (IMU)");
    Serial.println("  0x76/0x77 - BME280/BMP280");
    Serial.println("  0x23      - BH1750 (Light)");
    Serial.println("  0x5A      - SGP30 (Gas)");
}

void loop() {}

Membaca BME280 via I2C

Arduino β€” BME280 I2C
#include <Wire.h>
#include <Adafruit_BME280.h>

// I2C Pins untuk ESP32
#define SDA_PIN 21
#define SCL_PIN 22

Adafruit_BME280 bme;  // I2C (default address 0x76)

void setup() {
    Serial.begin(115200);
    Wire.begin(SDA_PIN, SCL_PIN);

    // Inisialisasi BME280
    if (!bme.begin(0x76)) {
        Serial.println("BME280 tidak ditemukan!");
        Serial.println("Cek wiring dan alamat I2C (0x76 atau 0x77)");
        while (1);
    }

    // Konfigurasi sensor
    bme.setSampling(
        Adafruit_BME280::MODE_NORMAL,        // Mode operasi
        Adafruit_BME280::SAMPLING_X2,        // Temperature oversampling
        Adafruit_BME280::SAMPLING_X16,       // Pressure oversampling
        Adafruit_BME280::SAMPLING_X1,        // Humidity oversampling
        Adafruit_BME280::FILTER_X16,         // IIR Filter
        Adafruit_BME280::STANDBY_MS_500      // Standby time
    );

    Serial.println("BME280 siap!");
}

void loop() {
    float suhu = bme.readTemperature();        // Β°C
    float tekanan = bme.readPressure() / 100.0; // hPa
    float kelembaban = bme.readHumidity();      // %
    float altitude = bme.readAltitude(1013.25); // meter (QNH)

    Serial.printf("Suhu      : %.2f Β°C\n", suhu);
    Serial.printf("Tekanan   : %.2f hPa\n", tekanan);
    Serial.printf("Kelembaban: %.2f %%\n", kelembaban);
    Serial.printf("Altitude  : %.2f m\n", altitude);
    Serial.println("========================");

    delay(2000);
}

5. Komunikasi SPI

SPI (Serial Peripheral Interface) adalah protokol komunikasi serial synchronous yang dikembangkan oleh Motorola. SPI lebih cepat dari I2C dan cocok untuk aplikasi yang membutuhkan throughput tinggi seperti display, ADC berkecepatan tinggi, dan SD card.

Karakteristik SPI

Parameter Nilai
Jumlah Kabel4 (MOSI, MISO, SCK, SS/CS) + VCC + GND
KecepatanHingga beberapa MHz (biasanya 1-10 MHz, max ~80 MHz)
TopologySingle master, multi-slave (dengan CS per slave)
DuplexFull duplex (bisa kirim dan terima bersamaan)
JarakHingga ~30 cm (board-level)
Pull-up ResistorTidak diperlukan

SPI Pin dan Fungsi

Diagram: Bus SPI
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    BUS SPI                              β”‚
β”‚                                                         β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚  MASTER β”‚         β”‚ SLAVE 1 β”‚         β”‚ SLAVE 2 β”‚   β”‚
β”‚  β”‚  ESP32  β”‚         β”‚ MCP3008 β”‚         β”‚ SD Card β”‚   β”‚
β”‚  β”‚         β”‚         β”‚ (ADC)   β”‚         β”‚ Module  β”‚   β”‚
β”‚  β”‚  MOSI ──┼────────►│ MOSI    β”‚         β”‚ MOSI    β”‚   β”‚
β”‚  β”‚  MISO ◄─┼─────────│ MISO    β”‚         β”‚ MISO    β”‚   β”‚
β”‚  β”‚  SCK  ──┼────────►│ SCK     β”‚         β”‚ SCK     β”‚   β”‚
β”‚  β”‚  CS1  ──┼────────►│ CS      β”‚         β”‚         β”‚   β”‚
β”‚  β”‚  CS2  ──┼─────────┼─────────┼────────►│ CS      β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                                                         β”‚
β”‚  MOSI = Master Out, Slave In  (data dari master)        β”‚
β”‚  MISO = Master In, Slave Out  (data dari slave)         β”‚
β”‚  SCK  = Serial Clock          (clock dari master)       β”‚
β”‚  CS   = Chip Select           (aktifkan slave tertentu) β”‚
β”‚                                                         β”‚
β”‚  βœ… Full Duplex: Kirim & terima bersamaan               β”‚
β”‚  βœ… Sangat cepat: cocok untuk high-speed data            β”‚
β”‚  ❌ Setiap slave butuh 1 pin CS di master               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

MCP3008 β€” ADC Eksternal via SPI

Arduino β€” MCP3008 SPI
#include <SPI.h>

// MCP3008: 10-bit ADC, 8 channel, SPI interface
// Cocok untuk ESP32 yang ADC-nya non-linear

#define CS_PIN 5     // Chip Select (GPIO 5)
#define SPI_FREQ 1000000  // 1 MHz SPI clock

void setup() {
    Serial.begin(115200);
    SPI.begin();        // Default: SCK=18, MISO=19, MOSI=23
    pinMode(CS_PIN, OUTPUT);
    digitalWrite(CS_PIN, HIGH);  // Deselect

    Serial.println("MCP3008 ADC via SPI siap!");
}

int readMCP3008(int channel) {
    // MCP3008 protocol:
    // Byte 1: Start bit (1) + Single-ended (1) + Channel (3 bit)
    // Byte 2: Don't care (8 clock)
    // Byte 3: Don't care (4 clock) + Data (4 bit MSB)
    // Byte 4: Data (8 bit LSB) ← tapi kita terima di byte 3 & 4

    byte command = 0b11000000 | (channel << 3);

    SPI.beginTransaction(SPISettings(SPI_FREQ, MSBFIRST, SPI_MODE0));
    digitalWrite(CS_PIN, LOW);     // Select MCP3008

    SPI.transfer(command);          // Kirim command
    byte highByte = SPI.transfer(0x00);  // Terima 5 bit
    byte lowByte = SPI.transfer(0x00);   // Terima 8 bit

    digitalWrite(CS_PIN, HIGH);    // Deselect
    SPI.endTransaction();

    // Gabungkan 10-bit result
    int result = ((highByte & 0x1F) << 8) | lowByte;
    return result;  // 0 - 1023
}

void loop() {
    // Baca semua 8 channel
    for (int ch = 0; ch < 8; ch++) {
        int raw = readMCP3008(ch);
        float voltage = (raw / 1023.0) * 3.3;  // Vref = 3.3V
        Serial.printf("CH%d: %d (%.3fV)  ", ch, raw, voltage);
    }
    Serial.println();
    delay(1000);
}

6. Komunikasi UART/Serial

UART (Universal Asynchronous Receiver-Transmitter) adalah protokol komunikasi serial asynchronous yang paling banyak digunakan. UART tidak memerlukan clock line β€” komunikasi disinkronisasi berdasarkan baud rate yang disepakati kedua belah pihak.

Karakteristik UART

Parameter Nilai
Jumlah Kabel2 minimum (TX + RX) + GND
Baud Rate Umum9600, 19200, 38400, 57600, 115200
TopologyPoint-to-point (2 device)
DuplexFull duplex (TX dan RX terpisah)
SynchronizationAsynchronous (tidak perlu clock)
Data FrameStart bit + Data (5-9 bit) + Parity + Stop bit

UART Data Frame

Diagram: UART Data Frame
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              UART DATA FRAME                            β”‚
β”‚                                                         β”‚
β”‚  Idle ──┐  β”Œβ”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”  β”Œβ”€β”€ Idle β”‚
β”‚  HIGH   β”‚  β”‚  β”‚  β”‚   DATA BITS      β”‚  β”‚  β”‚  β”‚        β”‚
β”‚         β”‚  β”‚S β”‚  β”‚ D0 D1 D2 D3 D4  β”‚  β”‚P β”‚  β”‚S       β”‚
β”‚         β””β”€β”€β”˜  └──│ D5 D6 D7        β”‚β”€β”€β”˜  β””β”€β”€β”˜ ──      β”‚
β”‚                  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                   β”‚
β”‚                                                         β”‚
β”‚  S     = Start bit (selalu LOW, 1 bit)                  β”‚
β”‚  D0-D7 = Data bits (8 bits, LSB first)                 β”‚
β”‚  P     = Parity bit (opsional: even/odd)                β”‚
β”‚  S     = Stop bit (selalu HIGH, 1 atau 2 bit)          β”‚
β”‚                                                         β”‚
β”‚  Contoh mengirim karakter 'A' (0x41 = 01000001):       β”‚
β”‚                                                         β”‚
β”‚  Idleβ”‚Startβ”‚ 1 β”‚ 0 β”‚ 0 β”‚ 0 β”‚ 0 β”‚ 0 β”‚ 1 β”‚ 0 β”‚Stopβ”‚Idleβ”‚
β”‚  HIGHβ”‚ LOW β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚   β”‚HIGHβ”‚HIGH β”‚
β”‚                                                         β”‚
β”‚  ⚠️ TX device β†’ RX device (sambung silang!)            β”‚
β”‚     TX1 ────► RX2                                       β”‚
β”‚     RX1 ◄──── TX2                                       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

GPS Module dengan UART

Arduino β€” GPS UART
#include <TinyGPS++.h>
#include <HardwareSerial.h>

// GPS Module NEO-6M via UART
// Baud rate default GPS: 9600

#define GPS_RX_PIN 16    // ESP32 RX ← GPS TX
#define GPS_TX_PIN 17    // ESP32 TX β†’ GPS RX (opsional)

TinyGPSPlus gps;
HardwareSerial SerialGPS(2);  // UART2 pada ESP32

void setup() {
    Serial.begin(115200);
    SerialGPS.begin(9600, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN);

    Serial.println("GPS Module via UART siap!");
    Serial.println("Menunggu sinyal GPS...");
}

void loop() {
    // Baca data GPS dari UART
    while (SerialGPS.available() > 0) {
        char c = SerialGPS.read();
        gps.encode(c);
    }

    // Tampilkan data jika ada update
    if (gps.location.isUpdated()) {
        double lat = gps.location.lat();
        double lng = gps.location.lng();
        double alt = gps.altitude.meters();
        int sats = gps.satellites.value();

        Serial.printf("Lat: %.6f, Lng: %.6f\n", lat, lng);
        Serial.printf("Altitude: %.1f m, Satellites: %d\n", alt, sats);

        // Cek kualitas fix
        if (gps.hdop.isValid()) {
            Serial.printf("HDOP: %.1f ", gps.hdop.hdop());
            if (gps.hdop.hdop() < 2) Serial.println("(Excellent)");
            else if (gps.hdop.hdop() < 5) Serial.println("(Good)");
            else Serial.println("(Poor)");
        }
    }

    // Tampilkan raw NMEA (debug)
    // while (SerialGPS.available()) {
    //     Serial.write(SerialGPS.read());
    // }
}

7. Perbandingan Protokol Komunikasi

Memilih protokol komunikasi yang tepat sangat penting untuk kesuksesan proyek IoT Anda. Berikut perbandingan lengkap antara ADC, I2C, SPI, dan UART.

Tabel Perbandingan Lengkap

Aspek Analog/ADC I2C SPI UART
Jumlah Kabel1 (+ GND)2 (+ VCC + GND)4 (+ VCC + GND)2 (+ GND)
KecepatanTergantung ADC100K-3.4M Hz1-80 MHz9600-115200+ baud
DuplexN/AHalf duplexFull duplexFull duplex
Multi-device1 pin/device128+ devicePerlu CS/devicePoint-to-point
Jarak~1 meter~1 meter~30 cm~15 meter
Pin Usage1 per sensor2 shared4+N CS2 per connection
Kompleksitas🟒 Rendah🟑 Sedang🟑 Sedang🟒 Rendah
Cocok untukSensor analogBanyak sensorHigh speedModule serial

Kapan Menggunakan Apa?

πŸ’‘ Panduan Pemilihan
  • Analog/ADC β€” Sensor sederhana (suhu LM35, cahaya LDR, pH meter) yang outputnya tegangan analog
  • I2C β€” Banyak sensor digital di satu bus (BME280, MPU6050, OLED). Pin-efficient!
  • SPI β€” Butuh kecepatan tinggi (SD card, display TFT, ADC presisi, radio LoRa)
  • UART β€” Module yang sudah punya serial interface (GPS, Bluetooth, PM2.5 sensor)

8. Kalibrasi Sensor

Kalibrasi adalah proses menyesuaikan pembacaan sensor dengan nilai referensi yang diketahui untuk memastikan akurasi. Tanpa kalibrasi, data sensor bisa menyimpang jauh dari nilai sebenarnya.

Metode Kalibrasi

Metode Cara Kerja Cocok Untuk
OffsetTambah/kurangi nilai konstanDrift yang konsisten
Lineary = mx + b (slope dan intercept)Hubungan linear
Polynomialy = axΒ² + bx + cHubungan non-linear
Lookup TableTabel mapping input β†’ outputKurva kompleks
Multi-pointKalibrasi di beberapa titik referensiAkurasi tinggi

Kalibrasi pH Meter

Arduino β€” pH Sensor Calibration
// Kalibrasi pH meter dengan 2 titik referensi
// Larutan buffer pH 4.0 dan pH 7.0

class PHSensor {
private:
    int _pin;
    float _acidVoltage;    // Voltage di pH 4.0
    float _neutralVoltage; // Voltage di pH 7.0
    float _slope;
    float _intercept;

public:
    PHSensor(int pin) {
        _pin = pin;
        _acidVoltage = 1.650;    // Default, harus dikalibrasi
        _neutralVoltage = 1.250;  // Default, harus dikalibrasi
        _calculateCoefficients();
    }

    // Kalibrasi dengan 2 titik
    void calibrateTwoPoint(float ph1, float voltage1,
                           float ph2, float voltage2) {
        // ph1 = 7.0 (neutral), voltage1 = voltage saat pH 7.0
        // ph2 = 4.0 (acid), voltage2 = voltage saat pH 4.0
        _neutralVoltage = voltage1;
        _acidVoltage = voltage2;
        _calculateCoefficients();
        Serial.printf("Kalibrasi: slope=%.4f, intercept=%.4f\n",
                      _slope, _intercept);
    }

    void _calculateCoefficients() {
        // Linear: pH = slope * voltage + intercept
        _slope = (7.0 - 4.0) / (_neutralVoltage - _acidVoltage);
        _intercept = 7.0 - _slope * _neutralVoltage;
    }

    float readVoltage() {
        long sum = 0;
        for (int i = 0; i < 40; i++) {
            sum += analogRead(_pin);
            delay(10);
        }
        float avg = sum / 40.0;
        return (avg / 4095.0) * 3.3;
    }

    float readPH() {
        float voltage = readVoltage();
        float ph = _slope * voltage + _intercept;
        return constrain(ph, 0.0, 14.0);
    }
};

// Setup kalibrasi
PHSensor phSensor(34);

void setup() {
    Serial.begin(115200);
    delay(3000);

    // Mode kalibrasi
    Serial.println("=== KALIBRASI pH METER ===");
    Serial.println("Celupkan ke larutan pH 7.0, lalu ketik 'ok'");
    while (!Serial.available()) {}
    float voltage7 = phSensor.readVoltage();
    Serial.printf("Voltage pH 7.0: %.4f V\n", voltage7);

    Serial.println("Celupkan ke larutan pH 4.0, lalu ketik 'ok'");
    while (!Serial.available()) {}
    float voltage4 = phSensor.readVoltage();
    Serial.printf("Voltage pH 4.0: %.4f V\n", voltage4);

    phSensor.calibrateTwoPoint(7.0, voltage7, 4.0, voltage4);
    Serial.println("Kalibrasi selesai!");
}

void loop() {
    float ph = phSensor.readPH();
    Serial.printf("pH: %.2f\n", ph);
    delay(2000);
}

Kalibrasi Sensor Suhu (NTC Thermistor)

Arduino β€” NTC Thermistor
// NTC Thermistor dengan Steinhart-Hart equation
// Lebih akurat dari linearisasi sederhana

#include <math.h>

#define THERMISTOR_PIN 34
#define R_FIXED 10000.0     // Resistor tetap 10KΞ©
#define R_NTC_25 10000.0    // Resistansi NTC pada 25Β°C
#define B_COEFFICIENT 3950  // Beta coefficient dari datasheet

float readNTCTemperature() {
    // Baca ADC
    int raw = analogRead(THERMISTOR_PIN);

    // Hitung resistansi NTC
    // Voltage divider: Vout = Vcc * R_fixed / (R_ntc + R_fixed)
    float voltage = (raw / 4095.0) * 3.3;
    float r_ntc = R_FIXED * (3.3 / voltage - 1.0);

    // Steinhart-Hart (simplified with B coefficient)
    // 1/T = 1/T0 + (1/B) * ln(R/R0)
    float tempK = 1.0 / (
        (1.0 / 298.15) +                    // 1/T0 (T0=25Β°C=298.15K)
        (1.0 / B_COEFFICIENT) * log(r_ntc / R_NTC_25)
    );

    float tempC = tempK - 273.15;

    // Atau gunakan persamaan Steinhart-Hart penuh (3 titik kalibrasi):
    // 1/T = A + B*ln(R) + C*(ln(R))^3
    // Perlu mengukur resistansi pada 3 suhu berbeda

    return tempC;
}

void setup() {
    Serial.begin(115200);
}

void loop() {
    float suhu = readNTCTemperature();
    Serial.printf("Suhu: %.2f Β°C\n", suhu);
    delay(1000);
}

9. Noise Filtering dan Signal Processing

Sinyal dari sensor sering terganggu oleh noise (gangguan listrik) dari berbagai sumber seperti motor, switching power supply, dan interferensi RF. Filtering sangat penting untuk mendapatkan data yang bersih dan akurat.

Jenis Filter

Filter Kompleksitas Kelebihan Kekurangan
Moving Average🟒 MudahMudah implementasi, halusLambat merespon perubahan cepat
Exponential Moving Average🟒 MudahResponsif, hemat memoryPerlu tuning alpha
Median Filter🟑 SedangTahan spike/outlierKurang halus
Kalman FilterπŸ”΄ KompleksOptimal untuk noisy dataSulit implementasi dan tuning
IIR/Butterworth🟑 SedangFleksibel (low/high/band pass)Perlu koefisien filter

Implementasi Filter

Arduino β€” Signal Filters
// Implementasi berbagai filter untuk sensor

// 1. Moving Average Filter
class MovingAverage {
private:
    float* _buffer;
    int _size;
    int _index;
    float _sum;
    bool _filled;

public:
    MovingAverage(int size) {
        _size = size;
        _buffer = new float[size]();
        _index = 0;
        _sum = 0;
        _filled = false;
    }

    float update(float value) {
        _sum -= _buffer[_index];
        _buffer[_index] = value;
        _sum += value;
        _index = (_index + 1) % _size;
        if (_index == 0) _filled = true;
        return _sum / (_filled ? _size : _index);
    }
};

// 2. Exponential Moving Average (EMA)
class EMAFilter {
private:
    float _alpha;
    float _ema;
    bool _initialized;

public:
    EMAFilter(float alpha) {
        _alpha = constrain(alpha, 0.0, 1.0);
        _ema = 0;
        _initialized = false;
    }

    float update(float value) {
        if (!_initialized) {
            _ema = value;
            _initialized = true;
        } else {
            _ema = _alpha * value + (1.0 - _alpha) * _ema;
        }
        return _ema;
    }
};

// 3. Median Filter
class MedianFilter {
private:
    float* _buffer;
    int _size;
    int _index;
    bool _filled;

public:
    MedianFilter(int size) {
        _size = size;
        _buffer = new float[size]();
        _index = 0;
        _filled = false;
    }

    float update(float value) {
        _buffer[_index] = value;
        _index = (_index + 1) % _size;
        if (_index == 0) _filled = true;
        int count = _filled ? _size : _index;

        // Copy and sort
        float sorted[count];
        for (int i = 0; i < count; i++) sorted[i] = _buffer[i];
        for (int i = 0; i < count - 1; i++) {
            for (int j = i + 1; j < count; j++) {
                if (sorted[i] > sorted[j]) {
                    float t = sorted[i]; sorted[i] = sorted[j]; sorted[j] = t;
                }
            }
        }
        return sorted[count / 2];
    }
};

// Penggunaan
MovingAverage filterMA(10);     // 10-sample moving average
EMAFilter filterEMA(0.1);       // alpha=0.1 (halus)
MedianFilter filterMed(7);      // 7-sample median

void loop() {
    float raw = analogRead(34);

    float filtered_ma = filterMA.update(raw);
    float filtered_ema = filterEMA.update(raw);
    float filtered_med = filterMed.update(raw);

    Serial.printf("Raw: %.0f | MA: %.1f | EMA: %.1f | Med: %.1f\n",
                  raw, filtered_ma, filtered_ema, filtered_med);
    delay(100);
}

10. Proyek Multi-Sensor

Mari gabungkan semua pengetahuan dalam satu proyek: Stasiun Monitoring Lingkungan dengan beberapa sensor yang menggunakan berbagai protokol berbeda.

Arduino β€” Multi-Sensor Station
#include <WiFi.h>
#include <Wire.h>
#include <Adafruit_BME280.h>
#include <BH1750.h>
#include <DHT.h>

// ========== KONFIGURASI PIN ==========
// I2C Bus (shared)
#define SDA_PIN 21
#define SCL_PIN 22

// Analog Sensors
#define MQ135_PIN 34    // Gas sensor (ADC)
#define LM35_PIN 35     // Suhu reference (ADC)

// Digital Sensors
#define DHT_PIN 4       // DHT22 (One-wire digital)

// ========== SENSOR OBJECTS ==========
// I2C sensors
Adafruit_BME280 bme;       // BME280 (0x76) - Suhu, Tekanan, Lembab
BH1750 lightMeter(0x23);   // BH1750 - Cahaya (lux)

// Digital sensor
DHT dht(DHT_PIN, DHT22);  // DHT22 - Backup suhu & lembab

// Analog filter
float filterAnalog(int pin, int samples = 20) {
    long sum = 0;
    for (int i = 0; i < samples; i++) {
        sum += analogRead(pin);
        delayMicroseconds(200);
    }
    return (float)sum / samples;
}

void setup() {
    Serial.begin(115200);

    // Init I2C bus
    Wire.begin(SDA_PIN, SCL_PIN);

    // Init BME280
    if (!bme.begin(0x76)) {
        Serial.println("⚠️ BME280 tidak ditemukan!");
    } else {
        Serial.println("βœ… BME280 OK");
    }

    // Init BH1750
    if (lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE)) {
        Serial.println("βœ… BH1750 OK");
    } else {
        Serial.println("⚠️ BH1750 tidak ditemukan!");
    }

    // Init DHT22
    dht.begin();
    Serial.println("βœ… DHT22 OK");

    // ADC config
    analogReadResolution(12);
    analogSetAttenuation(ADC_11db);

    Serial.println("\n=== Stasiun Monitoring Lingkungan ===\n");
}

void loop() {
    // ===== BACA I2C SENSORS =====
    float bme_suhu = bme.readTemperature();
    float bme_lembab = bme.readHumidity();
    float bme_tekanan = bme.readPressure() / 100.0;
    float lux = lightMeter.readLightLevel();

    // ===== BACA DIGITAL SENSOR =====
    float dht_suhu = dht.readTemperature();
    float dht_lembab = dht.readHumidity();

    // ===== BACA ANALOG SENSORS =====
    float mq135_raw = filterAnalog(MQ135_PIN);
    float mq135_voltage = (mq135_raw / 4095.0) * 3.3;
    float lm35_raw = filterAnalog(LM35_PIN);
    float lm35_voltage = (lm35_raw / 4095.0) * 3.3;
    float lm35_suhu = lm35_voltage / 0.01;

    // ===== KALIBRASI & VALIDASI =====
    // Cross-check suhu dari 3 sensor
    float suhu_avg = bme_suhu;
    int suhu_count = 1;

    if (!isnan(dht_suhu)) {
        suhu_avg += dht_suhu;
        suhu_count++;
    }
    suhu_avg += lm35_suhu;
    suhu_count++;
    suhu_avg /= suhu_count;

    // ===== TAMPILKAN HASIL =====
    Serial.println("╔══════════════════════════════════════╗");
    Serial.println("β•‘     STASIUN MONITORING LINGKUNGAN    β•‘");
    Serial.println("╠══════════════════════════════════════╣");
    Serial.printf("β•‘ Suhu     : %.2f Β°C (rata-rata 3 sensor)\n", suhu_avg);
    Serial.printf("β•‘  β”œ BME280: %.2f Β°C\n", bme_suhu);
    Serial.printf("β•‘  β”œ DHT22 : %.2f Β°C\n", dht_suhu);
    Serial.printf("β•‘  β”” LM35  : %.2f Β°C\n", lm35_suhu);
    Serial.printf("β•‘ Kelembaban: %.1f %% (BME280)\n", bme_lembab);
    Serial.printf("β•‘ Tekanan   : %.1f hPa\n", bme_tekanan);
    Serial.printf("β•‘ Cahaya    : %.1f lux\n", lux);
    Serial.printf("β•‘ Udara (MQ135): %.3f V\n", mq135_voltage);
    Serial.println("β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•\n");

    delay(5000);
}

11. Best Practices

Aspek Best Practice Hindari
WiringGunakan kabel pendek, twisted pair untuk I2CKabel panjang tanpa shielding
PowerDecoupling capacitor 100nF dekat sensorPower langsung dari pin MCU
ADCMulti-sample averaging, kalibrasiSingle read tanpa filtering
I2CPull-up 4.7KΞ©, scan bus saat startupAsumsi alamat, skip error handling
SPISPI.beginTransaction() setiap transaksiSPI tanpa CS management
Error HandlingCek return value, timeout, retryAssume sensor selalu bekerja
KalibrasiKalibrasi berkala, simpan offset di EEPROMPakai default tanpa kalibrasi

12. Quiz: Uji Pemahamanmu!

Setelah membaca tutorial di atas, jawablah 5 pertanyaan berikut untuk menguji pemahamanmu tentang sensor interfacing:

Pertanyaan 1: Berapa banyak kabel minimum yang diperlukan untuk komunikasi I2C (selain power)?

a) 1 kabel (SDA saja)
b) 2 kabel (SDA dan SCL)
c) 3 kabel (SDA, SCL, dan CS)
d) 4 kabel (MOSI, MISO, SCK, CS)

Pertanyaan 2: Protokol mana yang mendukung full duplex (kirim dan terima bersamaan)?

a) I2C
b) SPI
c) UART
d) B dan C

Pertanyaan 3: Mengapa ESP32 ADC memerlukan kalibrasi khusus?

a) Karena resolusi hanya 8-bit
b) Karena ADC ESP32 bersifat non-linear
c) Karena hanya bisa membaca 3.3V
d) Karena tidak punya ADC internal

Pertanyaan 4: Filter apa yang paling tahan terhadap spike/noise outlier?

a) Moving Average
b) Exponential Moving Average
c) Median Filter
d) Semua sama

Pertanyaan 5: Apa fungsi pull-up resistor pada bus I2C?

a) Meningkatkan kecepatan komunikasi
b) Membuat SDA dan SCL default HIGH saat idle
c) Menghubungkan ground ke data line
d) Melindungi sensor dari overvoltage
πŸ” Zoom
100%
🎨 Tema