ESP32 Dengan BMP280

Berikut ini antar muka minimalis antara ESP32 dengan sensor lingkungan BMP280

Pin yang dipakai:

  • VCC di ESP32 dihubungkan ke VCC di BMP280
  • GND di ESP32 dihubungkan ke GND di BMP280
  • SCL di ESP32 dihubungkan ke SCL di BMP280
  • SDA di ESP32 dihubungkan ke SDA di BMP280

Software juga dibuat minimalis

// https://bitbucket.org/christandlg/bmx280mi/src/master/examples/BMx280_I2C/BMx280_I2C.ino
// BMx280_I2C.ino
//
// shows how to use the BMP280 / BMx280 library with the sensor connected using I2C.
//
// Copyright (c) 2018 Gregor Christandl
//
// connect the AS3935 to the Arduino like this:
//
// Arduino - BMP280 / BME280
// 3.3V ---- VCC
// GND ----- GND
// SDA ----- SDA
// SCL ----- SCL
// some BMP280/BME280 modules break out the CSB and SDO pins as well:
// 5V ------ CSB (enables the I2C interface)
// GND ----- SDO (I2C Address 0x76)
// 5V ------ SDO (I2C Address 0x77)
// other pins can be left unconnected.

#include <Arduino.h>
#include <Wire.h>

#define I2C_SDA 15
#define I2C_SCL 13

#include <BMx280I2C.h>

#define I2C_ADDRESS 0x76

//create a BMx280I2C object using the I2C interface with I2C Address 0x76
BMx280I2C bmx280(I2C_ADDRESS);

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  delay(1000);

  //wait for serial connection to open (only necessary on some boards)
  while (!Serial);

  //  Wire.begin();
  Wire.begin(I2C_SDA, I2C_SCL);

  I2C_Scan() ; // just for verifying
  
  //begin() checks the Interface, reads the sensor ID (to differentiate between BMP280 and BME280)
  //and reads compensation parameters.
  if (!bmx280.begin())
  {
    Serial.println("begin() failed. check your BMx280 Interface and I2C Address.");
    while (1);
  }

  if (bmx280.isBME280())
    Serial.println("sensor is a BME280");
  else
    Serial.println("sensor is a BMP280");

  //reset sensor to default parameters.
  bmx280.resetToDefaults();

  //by default sensing is disabled and must be enabled by setting a non-zero
  //oversampling setting.
  //set an oversampling setting for pressure and temperature measurements.
  bmx280.writeOversamplingPressure(BMx280MI::OSRS_P_x16);
  bmx280.writeOversamplingTemperature(BMx280MI::OSRS_T_x16);

  //if sensor is a BME280, set an oversampling setting for humidity measurements.
  if (bmx280.isBME280())
    bmx280.writeOversamplingHumidity(BMx280MI::OSRS_H_x16);
}

void loop() {
  float temperature = 0;
  float pressure = 0;
  float humidity = 60; // default humidity
  float co2 = 0;
  float tvoc = 0;

  delay(1000);

  //start a measurement
  if (!bmx280.measure())
  {
    Serial.println("could not start measurement, is a measurement already running?");
    return;
  }

  //wait for the measurement to finish
  do
  {
    delay(100);
  } while (!bmx280.hasValue());

  //  Serial.print("Pressure: "); Serial.println(bmx280.getPressure());
  //  Serial.print("Pressure (64 bit): "); Serial.println(bmx280.getPressure64());
  //  Serial.print("Temperature: "); Serial.println(bmx280.getTemperature());

  pressure = bmx280.getPressure();
  temperature = bmx280.getTemperature();

  //important: measurement data is read from the sensor in function hasValue() only.
  //make sure to call get*() functions only after hasValue() has returned true.
  if (bmx280.isBME280())
  {
    //    Serial.print("Humidity: ");
    //    Serial.println(bmx280.getHumidity());
    humidity = bmx280.getHumidity();
  }

  Serial.print("Temp\t");
  Serial.print(temperature);
  Serial.print("\t");
  Serial.print("Humidity\t");
  Serial.print(humidity);
  Serial.print("\t");
  Serial.print("Pressure\t");
  Serial.print(pressure);
  Serial.print("\t");
  Serial.println("");
}

void I2C_Scan() {
  byte error, address;

  int nDevices;
  Serial.println("I2C Scanning...");
  nDevices = 0;
  for (address = 1; address < 127; 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.println(address, HEX);
      nDevices++;
    }
    else if (error == 4) {
      Serial.print("Unknow 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");
  }
}

Perekam Modbus RTU Dengan ESP32

Pada pengembangan sistem dengan komunikasi Modbus RTU dengan RS485, kadang-kadang kita perlu memonitor pertukaran data di kabel RS-485 untuk memantau apakah komunikasi data berjalan dengan benar. Pada artikel ini diuraikan secara ringkas pembuatan perangkat untuk memantau dan merekam trafik data di komunikasi RS-485 tersebut.

 

Berikut ini skema rangkaiannya secara sederhana

Rangkaian ESP32 dengan RS485
Rangkaian ESP32 dengan RS485

Penjelasan cara kerja rangkaian

Komponen utama sistem adalah sebagai berikut

  • MAX485 berfungsi untuk mengubah level tegangan RS-485 menjadi TTL 5 volt.
  • Level converter berfungsi mengubah tegangan TTL 5 volt dari MAX485 menjadi TTL dengan tegangan 3 volt.
  • Mikrokontroler ESP32 berfungsi merekam data serial dan mengirimnya menggunakan kabel USB ke komputer.
  • Komputer untuk merekam data serial dari ESP32
  • Power supply 5 volt untuk MAX485
Pin pada MAX485
Pin pada MAX485

Berikut ini foto rangkaian dengan breadboard

Alat untuk merekam sinyal Modbus RTU di RS485 dengan mikrokontroler ESP32

Rangkaian ESP32 , MAX485 dan level converter di breadboard
Rangkaian ESP32 , MAX485 dan level converter di breadboard

 

#esp32-freertos-rs485-analyzer
/**
   analisis data RS485
*/
#define LED_BUILTIN 22

#define RXD1 17
#define TXD1 5
#define RXD2 18
#define TXD2 23


void setup() {
  Serial.begin(115200);
  Serial1.begin(9600, SERIAL_8N1, RXD1, TXD1);
  Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);

  Serial.println("Serial Txd 0 is on pin: " + String(TX));
  Serial.println("Serial Rxd 0 is on pin: " + String(RX));

  Serial.println("Serial Txd 1 is on pin: " + String(TXD1));
  Serial.println("Serial Rxd 1 is on pin: " + String(RXD1));

  Serial.println("Serial Txd 2 is on pin: " + String(TXD2));
  Serial.println("Serial Rxd 2 is on pin: " + String(RXD2));

  pinMode(LED_BUILTIN, OUTPUT);


  if (1)
    xTaskCreate(
      TaskBlinker, /* Task function. */
      "TaskBlinker", /* String with name of task. */
      1000, /* Stack size in bytes. */
      NULL, /* Parameter passed as input of the task */
      1, /* Priority of the task. */
      NULL); /* Task handle. */
  xTaskCreate(
    TaskSerial1, /* Task function. */
    "TaskSerial1", /* String with name of task. */
    2000, /* Stack size in bytes. */
    NULL, /* Parameter passed as input of the task */
    1, /* Priority of the task. */
    NULL); /* Task handle. */
}


// the loop function runs over and over again forever

void loop() {
  delay(10000);
}


void TaskBlinker(void *parameter) {
  int counter = 0;
  TickType_t xLastWakeTime;
  const TickType_t xPeriod = 500      ;
  xLastWakeTime = xTaskGetTickCount();
  //  dht.begin(); // aktifkan sensor DHT22
  while (1) {
    digitalWrite(LED_BUILTIN, HIGH);
    vTaskDelayUntil(&xLastWakeTime, xPeriod);
    digitalWrite(LED_BUILTIN, LOW);
    vTaskDelayUntil(&xLastWakeTime, xPeriod);
//    Serial.print("Counter:");
//    Serial.println(counter);
    counter++;
  }
}

#define BUFFER_MAX 200

void TaskSerial1(void *parameter) {
  int interframe_timer_max = 0;
  int interframe_timer = 0; // untuk mengukur waktu antar frame
  char buffer_data[BUFFER_MAX];
  int buffer_idx = 0;
  TickType_t xLastWakeTime;
  const TickType_t xPeriod = 1      ;
  xLastWakeTime = xTaskGetTickCount();
  while (1) {
    int incomingByte;
    if (Serial1.available() > 0) {
      interframe_timer = 0;
    } else {
      interframe_timer++;
    }
    while (Serial1.available() > 0) {
      // read the incoming byte:
      incomingByte = Serial1.read();
      buffer_data[buffer_idx] = incomingByte ;
      buffer_idx++;
      if (buffer_idx > BUFFER_MAX) {
        buffer_idx = BUFFER_MAX;  // buffer overflow protection
      }
    }
    //Serial.print(incomingByte, HEX);
    //Serial.print(" ");
    if (interframe_timer > interframe_timer_max) {
      interframe_timer_max = interframe_timer;
      Serial.print("interframe_max ");
      Serial.println(interframe_timer_max);
    }
    if (interframe_timer > 6 && buffer_idx > 0) {
      // cetak semua data di buffer
      for (int i = 0; i < buffer_idx; i++) {
        Serial.print(buffer_data[i], HEX);
        Serial.print(" ");
      }
      Serial.println();
      buffer_idx = 0; // empty buffer
    }
    vTaskDelayUntil(&xLastWakeTime, xPeriod);
  }
}

Referensi

Lampu Kedip di ESP32 Dengan Sistem Operasi FreeRTOS

Berikut ini contoh program sederhana untuk membuat LED onboard berkedip di pada ESP32 Lolin32 Lite. Sistem operasi yang digunakan adalah FreeRTOS. IDE menggunakan Arduino. Delay menggunakan delay dari FreeRTOS, dengan fungsi vTaskDelayUntil().

ESP32 Lolin32 Lite (atas) dan ESP32 DevkitC (bawah)
ESP32 Lolin32 Lite (atas) dan ESP32 DevkitC (bawah)

Lampu berkedip dengan frekuensi 1 Hz. Suatu angka (counter) dikirim melalui port serial setiap detik. Kecepatan port serial adalah 115200 bps

#define LED_BUILTIN 22 # Wemos Lolin32 onboard LED di pin 22

void setup() {
  Serial.begin(115200);
  Serial.println("Start");  
  pinMode(LED_BUILTIN, OUTPUT);

  if (1)
    xTaskCreate(
      TaskBlinker, /* Task function. */
      "TaskBlinker", /* String with name of task. */
      1000, /* Stack size in bytes. */
      NULL, /* Parameter passed as input of the task */
      1, /* Priority of the task. */
      NULL); /* Task handle. */
}

// the loop function runs over and over again forever

void loop() {
  delay(10000);
}

void TaskBlinker(void *parameter) {  
  int counter = 0;
  TickType_t xLastWakeTime;
  const TickType_t xPeriod = 500      ;   
  xLastWakeTime = xTaskGetTickCount();
  while (1) {
    digitalWrite(LED_BUILTIN, HIGH);
    vTaskDelayUntil(&xLastWakeTime, xPeriod);
    digitalWrite(LED_BUILTIN, LOW);
    vTaskDelayUntil(&xLastWakeTime, xPeriod);
    Serial.print("Counter:");
    Serial.println(counter);
    counter++;
  }
}

Lampu Geser 2 Arah Asinkron Dengan Mikroprosesor

Spesifikasi

  • Input 2 buah tombol SPST
  • Nama input: tombol kiri, tombol kanan
  • Output 4 buah lampu LED
  • Lampu dipasang berjejer, dari kiri ke kanan. Nama lamput: OUT1,OUT2,OUT3,OUT4

Perilaku yang diharapkan

  • pada satu saat hanya 1 lampu yang menyala
  • kondisi awal lampu paling kiri menyala
  • jika tombol kanan ditekan, lampu yang menyala bergeser ke kanan
  • jika tombol kiri ditekan, lampu yang menyala bergeser ke kiri
  • jika lampu yang menyala sudah sampai di paling kanan, penekanan ke kanan akan membuat lampu paling kiri menyala
  • jika lampu yang menyala sudah sampai di paling kiri , penekanan ke kiri akan membuat lampu paling kanan menyala

Perancangan

Pada artikel ini, solusi yang dibuat memiliki sifat berikut

  • even triggered, input penekanan tombol menyebabkan terjadinya interupsi yang akan memanggil Finite State Machine (FSM)
  • FSM bersifat asinkron. Transisi/ reaksi FSM ditrigger oleh penekanan tombol

Perilaku sistem yang diharapkan dapat dimodelkan dengan menggunakan Timing Diagram (diagram waktu).. Untuk sederhananya dimulai dulu dengan kasus lampu hanya digeser ke 1 arah saja.

Diagram waktu lampu geser kanan 1 arah
Diagram waktu lampu geser kanan 1 arah

Model Flowchart (Diagram Alir)

Model State Chart

State chart lampu geser asinkron
State chart lampu geser asinkron

Video demo

 

Hasil

  • Lampu sudah dapat bergeser kiri kanan sesuai penekanan tombol
  • Masih terjadi bouncing, yaitu penekanan tombol satu kali menghasilkan pergeseran lampu lebih dari satu. Solusinya  mesti ditambahkan fitur debouncing.

Lampiran

Implementasi perangkat lunak

 /*
  lampu geser dengan input event-triggerred dari interupsi eksternal
  FSM dengan model asinkron 
*/

#define OUT1 12
#define OUT2 11
#define OUT3 10
#define OUT4 9

#define STATE1 101
#define STATE2 102
#define STATE3 103
#define STATE4 104

#define EVENT_A 201
#define EVENT_B 202

int state = STATE1;

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(OUT1, OUTPUT);
  pinMode(OUT2, OUTPUT);
  pinMode(OUT3, OUTPUT);
  pinMode(OUT4, OUTPUT);

  pinMode(2, INPUT_PULLUP);
  pinMode(3, INPUT_PULLUP);

  attachInterrupt(digitalPinToInterrupt(2), Pin2_isr, FALLING );
  attachInterrupt(digitalPinToInterrupt(3), Pin3_isr, FALLING );

  // initial state
  state = STATE1;
  digitalWrite(OUT1, HIGH);
}

void Pin2_isr() {
  fsm(EVENT_B);
}

void Pin3_isr() {
  fsm(EVENT_A);
}

int fsm(int event) {
  switch (state) {
    case STATE1: {
        if (event == EVENT_A) {
          state = STATE2;
          digitalWrite(OUT1, LOW);
          digitalWrite(OUT2, HIGH);
          digitalWrite(OUT3, LOW);
          digitalWrite(OUT4, LOW);
        } else if (event == EVENT_B)
        {
          state = STATE4;
          digitalWrite(OUT1, LOW);
          digitalWrite(OUT2, LOW);
          digitalWrite(OUT3, LOW);
          digitalWrite(OUT4, HIGH);
        }
        break;
      }
    case STATE2: {
        if (event == EVENT_A) {
          state = STATE3;
          digitalWrite(OUT1, LOW);
          digitalWrite(OUT2, LOW );
          digitalWrite(OUT3, HIGH);
          digitalWrite(OUT4, LOW);
        } else if (event == EVENT_B)
        {
          state = STATE1;
          digitalWrite(OUT1, HIGH);
          digitalWrite(OUT2, LOW);
          digitalWrite(OUT3, LOW);
          digitalWrite(OUT4, LOW);
        }
        break;
      }
    case STATE3: {
        if (event == EVENT_A) {
          state = STATE4;
          digitalWrite(OUT1, LOW);
          digitalWrite(OUT2, LOW );
          digitalWrite(OUT3, LOW);
          digitalWrite(OUT4, HIGH);
        } else if (event == EVENT_B)
        {
          state = STATE2;
          digitalWrite(OUT1, LOW);
          digitalWrite(OUT2, HIGH);
          digitalWrite(OUT3, LOW);
          digitalWrite(OUT4, LOW);
        }
        break;
      }
    case STATE4: {
        if (event == EVENT_A) {
          state = STATE1;
          digitalWrite(OUT1, HIGH);
          digitalWrite(OUT2, LOW);
          digitalWrite(OUT3, LOW);
          digitalWrite(OUT4, LOW);
        } else if (event == EVENT_B)
        {
          state = STATE3;
          digitalWrite(OUT1, LOW);
          digitalWrite(OUT2, LOW);
          digitalWrite(OUT3, HIGH);
          digitalWrite(OUT4, LOW);
        }
        break;
      }
    default: {
        break;
      }
  }
}

void loop() {
}

Contoh-contoh lain pemodelan dengan FSM dapat dilihat di artikel “Contoh Implementasi FSM dengan mikrokontroler

Model Matematis Untuk Pengembangan Sistem Mikroprosesor

Ada banyak cara untuk membuat aplikasi pada sistem mikroprosesor.

Untuk persoalan-persoalan sederhana, dapat langsung dibuat flowchart (diagram alir) berdasarkan algoritma tertentu.

Untuk kasus-kasus spesifik, kita bisa pakai model matematis yang powerful.

Dasar-dasar matematika untuk membangun suatu perangkat lunak mikroprosesor di antaranya:

  • Matematika kontinyu, misalnya kalkulus dan matematika lain yang berbasis persamaan differensial
  • Matematika diskrit, misal graph theory, set theory, dan sebagainya
  • Matematika berbasis konsep fuzzy, untuk membangun sistem fuzzy
  • Probabilitas dan Statistika, untuk sistem-sistem yang berhadapan dengan hal-hal non deterministik.

Teknologi di bidang elektro  yang dapat dipakai:

  • Sinyal & Sistem
  • Filter analog
  • Filter digital
  • Sistem kendali , biasanya berbasis PID (Proportional, Integral Derivative)
  • Finite State Machine / State Chart
  • Artificial Intelligence, baik yang non-learning (kecerdasan diprogram) maupun machine learning (pembelajaran mesin)
  • Sistem-sistem digital yang dapat dibuat:
  • Filter digital berbasis mikroprosesor
  • Kendali digital berbasis mikroprosesor
  • Finite State Machine berbasis mikroprosesor
  • Artificial Intelligence berbasis mikroprosesor. Jika komputasinya berat, mungkin diperlukan mikroprosesor khusus seperti Jetson Nano.

Contoh model matematis untuk kasus khusus:

  • Filter digital dapat dipakai untuk membuat filter digital berbasis mikroprosesor
  • Kendali digital dapat dipakai untuk membuat pengendali digital berbasis mikroprosesor. Umumnya kendali yang dipakai adalah berbasis PID (Proportional Integral Derivative)

Jetson Nano 2GB

Saya baru saja mendapatkan modul Jetson Nano 2GB. Rencananya board ini akan dipakai untuk percobaan dengan machine learning / artificial intelligence.

Berikut ini perbandingan ukuran fisik antara Arduino Nano, ESP32 Lolin Lite, Raspberry Pi dan Jetson Nano.

Fitur utama dari Jetson Nano ini adalah memiliki CUDA core, seperti yang dipakai di GPU (Graphical Processing Unit) untuk komputer desktop/laptop, hanya saja di Jetson Nano jumlah dan kemampuannya lebih kecil.

Referensi

Sensor CO2 MH-Z19B

Sensor Winsen MH-Z19B berfungsi mengukur kadar CO2 di udara. Prinsip pengukuran menggunakan NDIR (Non Dispersive Infrared). Fitur utama: selektivitas tinggi, tidak tergantung oksigen, masa pakai panjang. Di dalamnya sudah ada kompensasi temperatur. Outputnya tersedia 3 macam, berupa sinyal digital serial asinkron, sinyal digital PWM (pulse width modulation) dan tegangan analog.

Kadar CO2 di udara dapat dipakai untuk indikator kualitas ventilasi di suatu ruangan. Ventilasi yang baik ini penting untuk mengurangi penularan COVID-19.

Spesifikasi

Product Model MH-Z19B
Target Gas
CO2
Working voltage 4.5~ 5.5 V DC
Average current < 60mA(@5V)
Peak current 150mA (@5V)
Interface level 3.3 V(Compatible with 5V)
Measuring range refer to Table 2
Output signal
UART(TTL interface level 3.3V)
PWM
DAC(default 0.4-2V)
Preheat time 3 min
Response Time T90< 120 s
Working temperature
0 ~ 50 ℃
Working humidity 0~ 90% RH (No condensation)
Dimension 33 mm×20 mm×9 mm (L×W×H)
Weight 5g
Lifespan > 5 years
 

Penampakan

Berikut ini contoh sensor MH-Z19B yang dihubungkan ke prosesor ESP32 DevkitC. Pertimbangan menggunakan DevkitC adalah karena tegangan sinyal sensor adalah 3 volt namun juga memerlukan tegangan Vcc sebesar 5 volt. Board ESP32 Lolin32 Lite tidak memiliki output 5 volt, jadi agak sulit digunakan pada aplikasi ini.

Contoh Kode

Berikut ini contoh pembacaan sensor melalui port serial.

Konfigurasi port serial di ESP32 menggunakan pin 22 sebagai RXD dan pin 23 sebagai TXD. Jalur port serial dihubungkan melalui resistor 100 ohm untuk perlindungan kalau terjadi kesalahan polaritas pin TX dan RX.

// https://circuits4you.com/2018/12/31/esp32-hardware-serial2-example/

#define RXD2 22
#define TXD2 23

// These constants won't change. They're used to give names to the pins used:

int sensorValue = 0;        // value read from the pot
int outputValue = 0;        // value output to the PWM (analog out)

#define LED_BUILTIN 2

void setup() {
  // initialize serial communications at 9600 bps:
  Serial.begin(9600);
  Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);
  Serial.println("Start Devkit");
  Serial.println("Start Devkit");

  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(21, OUTPUT);
}

void loop() {
  char cmd;

  Serial2.print((char)0xff); // 0 : start byte
  Serial2.print((char)0x01);
  Serial2.print((char)0x86);
  Serial2.print((char)0x00);
  Serial2.print((char)0x00);
  Serial2.print((char)0x00);
  Serial2.print((char)0x00);
  Serial2.print((char)0x00);
  Serial2.print((char)0x79); // 8: checksum

  int counter = 0;
  int co2_high, co2_low;
  int available;
  available = Serial2.available();
  while (available > 0) {

    // read the incoming byte:
    int incomingByte = Serial2.read();

    // say what you got:
    Serial.print(">>:");
    Serial.println(incomingByte, DEC);

    if (counter == 2) {
      co2_high = incomingByte;
    }
    if (counter == 3) {
      co2_low = incomingByte;
    }
    available = Serial2.available();

    counter++;
  }
  Serial.print("CO2: ");
  Serial.println(co2_high * 256 + co2_low);

  //  Serial.print("available: ");
  //  Serial.println(available);

  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  digitalWrite(21, HIGH);
  delay(500);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  digitalWrite(21, LOW);    // turn the LED off by making the voltage LOW
  delay(500);
}

Referensi

 

Mengukur kadar Karbondioksida Dengan Sensor CJMCU-8118

Kode

 

// https://github.com/adafruit/Adafruit_CCS811/blob/master/examples/CCS811_test/CCS811_test.ino
// https://github.com/closedcube/ClosedCube_HDC1080_Arduino
// https://github.com/closedcube/ClosedCube_HDC1080_Arduino/blob/master/examples/hdc1080measurement/hdc1080measurement.ino

#define I2C_SDA 15
#define I2C_SCL 13
#define LED_ONBOARD 22

#include "Adafruit_CCS811.h"
#include <Arduino.h>
#include <Wire.h>
#include "ClosedCube_HDC1080.h"

Adafruit_CCS811 ccs;
ClosedCube_HDC1080 hdc1080;

void setup() {
  pinMode(LED_ONBOARD, OUTPUT);
  // put your setup code here, to run once:
  Serial.begin(9600);
  delay(1000);

  //wait for serial connection to open (only necessary on some boards)
  while (!Serial);

  Wire.begin(I2C_SDA, I2C_SCL);

  I2C_Scan() ; // just for verifying

  // check CCS811
  Serial.println("CCS811 test");
  if (!ccs.begin()) {
    Serial.println("Failed to start sensor! Please check your wiring.");
    while (1);
  } else {
    Serial.println("CCS811 ready");
  }


  hdc1080.begin(0x40);
  Serial.println("HDC1080");
  Serial.print("Manufacturer ID=0x");
  Serial.println(hdc1080.readManufacturerId(), HEX); // 0x5449 ID of Texas Instruments
  Serial.print("Device ID=0x");
  Serial.println(hdc1080.readDeviceId(), HEX); // 0x1050 ID of the device

  hdc1080.setResolution(HDC1080_RESOLUTION_11BIT, HDC1080_RESOLUTION_11BIT);

}

void loop() {
  float temperature = 25;
  float pressure = 0;
  float humidity = 60; // default humidity
  float co2 = 0;
  float tvoc = 0;



  temperature = hdc1080.readTemperature();
  humidity = hdc1080.readHumidity();

  ccs.setEnvironmentalData( humidity, temperature );

  if (ccs.available()) {
    if (!ccs.readData()) {
      //      Serial.print("CO2: ");
      //Serial.print(ccs.geteCO2());
      //Serial.print("ppm, TVOC: ");
      //Serial.println(ccs.getTVOC());
      co2 = ccs.geteCO2();
      tvoc =   ccs.getTVOC();
    }
  }

  Serial.print("Temp\t");
  Serial.print(temperature);
  Serial.print("\t");

  Serial.print("Humidity\t");
  Serial.print(humidity);
  Serial.print("\t");

  Serial.print("CO2\t");
  Serial.print(co2);
  Serial.print("\t");
  Serial.print("TVOC\t");
  Serial.print(tvoc);
  Serial.println("");
  delay(500);
  digitalWrite(LED_ONBOARD, HIGH);
  delay(500);
  digitalWrite(LED_ONBOARD, LOW);
}

void I2C_Scan() {
  byte error, address;

  int nDevices;
  Serial.println("I2C Scanning...");
  nDevices = 0;
  for (address = 1; address < 127; 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.println(address, HEX);
      nDevices++;
    }
    else if (error == 4) {
      Serial.print("Unknow 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");
  }
}

Referensi

 

Mengukur Kadar Karbondioksida Dengan Sensor CCS811 dan Mikrokontroler ESP32

Pada percobaan ini dilakukan pengukuran kadar gas CO2  (karbon dioksida) di udara dengan sensor CCS811.

Mikrokontroler yang digunakan adalah modul ESP32 Lolin32 Lite

Modul CJMCU-811 tidak dilengkapi sensor temperatur & kelembaban, sehingga perlu tambahan sensor BME280.

Kompensasi temperatur dan kelembaban untuk sensor CCS811 menggunakan sensor BME280

Berikut ini foto perangkat keras yang digunakan

Berikut ini rangkaian sistem mikroprosesornya

Berikut ini source code program yang dipakai (dengan Arduino)

// https://bitbucket.org/christandlg/bmx280mi/src/master/examples/BMx280_I2C/BMx280_I2C.ino
// BMx280_I2C.ino
//
// shows how to use the BMP280 / BMx280 library with the sensor connected using I2C.
//
// Copyright (c) 2018 Gregor Christandl
//
// connect the AS3935 to the Arduino like this:
//
// Arduino - BMP280 / BME280
// 3.3V ---- VCC
// GND ----- GND
// SDA ----- SDA
// SCL ----- SCL
// some BMP280/BME280 modules break out the CSB and SDO pins as well:
// 5V ------ CSB (enables the I2C interface)
// GND ----- SDO (I2C Address 0x76)
// 5V ------ SDO (I2C Address 0x77)
// other pins can be left unconnected.


// https://github.com/adafruit/Adafruit_CCS811
// https://github.com/adafruit/Adafruit_CCS811/blob/master/examples/CCS811_test/CCS811_test.ino


#include "Adafruit_CCS811.h"
Adafruit_CCS811 ccs;

#include <Arduino.h>
#include <Wire.h>

#define I2C_SDA 15
#define I2C_SCL 13


#include <BMx280I2C.h>

#define I2C_ADDRESS 0x76

//create a BMx280I2C object using the I2C interface with I2C Address 0x76
BMx280I2C bmx280(I2C_ADDRESS);

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  delay(1000);

  //wait for serial connection to open (only necessary on some boards)
  while (!Serial);

  //  Wire.begin();
  Wire.begin(I2C_SDA, I2C_SCL);

  I2C_Scan() ; // just for verifying

  // check CCS811
  Serial.println("CCS811 test");
  if (!ccs.begin()) {
    Serial.println("Failed to start sensor! Please check your wiring.");
    while (1);
  } else {
    Serial.println("CCS811 ready");
  }

  //begin() checks the Interface, reads the sensor ID (to differentiate between BMP280 and BME280)
  //and reads compensation parameters.
  if (!bmx280.begin())
  {
    Serial.println("begin() failed. check your BMx280 Interface and I2C Address.");
    while (1);
  }

  if (bmx280.isBME280())
    Serial.println("sensor is a BME280");
  else
    Serial.println("sensor is a BMP280");

  //reset sensor to default parameters.
  bmx280.resetToDefaults();

  //by default sensing is disabled and must be enabled by setting a non-zero
  //oversampling setting.
  //set an oversampling setting for pressure and temperature measurements.
  bmx280.writeOversamplingPressure(BMx280MI::OSRS_P_x16);
  bmx280.writeOversamplingTemperature(BMx280MI::OSRS_T_x16);

  //if sensor is a BME280, set an oversampling setting for humidity measurements.
  if (bmx280.isBME280())
    bmx280.writeOversamplingHumidity(BMx280MI::OSRS_H_x16);
}

void loop() {
  float temperature = 0;
  float pressure = 0;
  float humidity = 60; // default humidity
  float co2 = 0;
  float tvoc = 0;

  delay(1000);

  //start a measurement
  if (!bmx280.measure())
  {
    Serial.println("could not start measurement, is a measurement already running?");
    return;
  }

  //wait for the measurement to finish
  do
  {
    delay(100);
  } while (!bmx280.hasValue());

  //  Serial.print("Pressure: "); Serial.println(bmx280.getPressure());
  //  Serial.print("Pressure (64 bit): "); Serial.println(bmx280.getPressure64());
  //  Serial.print("Temperature: "); Serial.println(bmx280.getTemperature());

  pressure = bmx280.getPressure();
  temperature = bmx280.getTemperature();

  //important: measurement data is read from the sensor in function hasValue() only.
  //make sure to call get*() functions only after hasValue() has returned true.
  if (bmx280.isBME280())
  {
    //    Serial.print("Humidity: ");
    //    Serial.println(bmx280.getHumidity());
    humidity = bmx280.getHumidity();
  }

  ccs.setEnvironmentalData( humidity, temperature );

  if (ccs.available()) {
    if (!ccs.readData()) {
      //      Serial.print("CO2: ");
      //Serial.print(ccs.geteCO2());
      //Serial.print("ppm, TVOC: ");
      //Serial.println(ccs.getTVOC());



      co2 = ccs.geteCO2();
      tvoc =   ccs.getTVOC();
    }
  }

  Serial.print("Temp\t");
  Serial.print(temperature);
  Serial.print("\t");

  Serial.print("Humidity\t");
  Serial.print(humidity);
  Serial.print("\t");

  Serial.print("Pressure\t");
  Serial.print(pressure);
  Serial.print("\t");

  Serial.print("CO2\t");
  Serial.print(co2);
  Serial.print("\t");
  Serial.print("TVOC\t");
  Serial.print(tvoc);
  Serial.println("");
}

void I2C_Scan() {
  byte error, address;

  int nDevices;
  Serial.println("I2C Scanning...");
  nDevices = 0;
  for (address = 1; address < 127; 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.println(address, HEX);
      nDevices++;
    }
    else if (error == 4) {
      Serial.print("Unknow 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");
  }
}

Berikut ini software versi lain

// pengukuran CO2, tanpa wifi

// https://bitbucket.org/christandlg/bmx280mi/src/master/examples/BMx280_I2C/BMx280_I2C.ino
// BMx280_I2C.ino
//
// shows how to use the BMP280 / BMx280 library with the sensor connected using I2C.
//
// Copyright (c) 2018 Gregor Christandl
//
// connect the AS3935 to the Arduino like this:
//
// Arduino - BMP280 / BME280
// 3.3V ---- VCC
// GND ----- GND
// SDA ----- SDA
// SCL ----- SCL
// some BMP280/BME280 modules break out the CSB and SDO pins as well:
// 5V ------ CSB (enables the I2C interface)
// GND ----- SDO (I2C Address 0x76)
// 5V ------ SDO (I2C Address 0x77)
// other pins can be left unconnected.


// https://github.com/adafruit/Adafruit_CCS811
// https://github.com/adafruit/Adafruit_CCS811/blob/master/examples/CCS811_test/CCS811_test.ino


#include "Adafruit_CCS811.h"
Adafruit_CCS811 ccs;

#include <Arduino.h>
#include <Wire.h>
#include <BMx280I2C.h>
#include "ClosedCube_HDC1080.h"

#define I2C_SDA 15
#define I2C_SCL 13
#define I2C_ADDRESS 0x76
#define LED_ONBOARD 22

const char *ssid     = "First";
const char *password = "satu2345";

//create a BMx280I2C object using the I2C interface with I2C Address 0x76
BMx280I2C bmx280(I2C_ADDRESS);
ClosedCube_HDC1080 hdc1080;

char mac_str[20];
byte mac_byte[6];

void setup() {
  pinMode(LED_ONBOARD, OUTPUT);
  // put your setup code here, to run once:
  Serial.begin(9600);
  delay(1000);

  //wait for serial connection to open (only necessary on some boards)
  while (!Serial);

  //  Wire.begin();
  Wire.begin(I2C_SDA, I2C_SCL);

  I2C_Scan() ; // just for verifying

  // check CCS811
  Serial.println("CCS811 test");
  if (!ccs.begin()) {
    Serial.println("Failed to start sensor! Please check your wiring.");
    while (1);
  } else {
    Serial.println("CCS811 ready");
  }
  SetupBME280();
  SetupHDC1080();
}

void SetupBME280() {
  //begin() checks the Interface, reads the sensor ID (to differentiate between BMP280 and BME280)
  //and reads compensation parameters.
  if (!bmx280.begin())
  {
    Serial.println("begin() failed. check your BMx280 Interface and I2C Address.");
    while (1);
  }

  if (bmx280.isBME280())
    Serial.println("sensor is a BME280");
  else
    Serial.println("sensor is a BMP280");

  //reset sensor to default parameters.
  bmx280.resetToDefaults();

  //by default sensing is disabled and must be enabled by setting a non-zero
  //oversampling setting.
  //set an oversampling setting for pressure and temperature measurements.
  bmx280.writeOversamplingPressure(BMx280MI::OSRS_P_x16);
  bmx280.writeOversamplingTemperature(BMx280MI::OSRS_T_x16);

  //if sensor is a BME280, set an oversampling setting for humidity measurements.
  if (bmx280.isBME280())
    bmx280.writeOversamplingHumidity(BMx280MI::OSRS_H_x16);
}

void SetupHDC1080() {

  hdc1080.begin(0x40);
  Serial.println("HDC1080");
  Serial.print("Manufacturer ID=0x");
  Serial.println(hdc1080.readManufacturerId(), HEX); // 0x5449 ID of Texas Instruments
  Serial.print("Device ID=0x");
  Serial.println(hdc1080.readDeviceId(), HEX); // 0x1050 ID of the device
  hdc1080.setResolution(HDC1080_RESOLUTION_11BIT, HDC1080_RESOLUTION_11BIT);
}

void loop() {
  float temperature = 0;
  float pressure = 0;
  float humidity = 60; // default humidity
  float co2 = 0;
  float tvoc = 0;

  if (1) {
    //start a measurement
    if (!bmx280.measure())
    {
      Serial.println("could not start measurement, is a measurement already running?");
    }
    do
    {
      delay(100);
    } while (!bmx280.hasValue());

    pressure = bmx280.getPressure();
    temperature = bmx280.getTemperature();
    //important: measurement data is read from the sensor in function hasValue() only.
    //make sure to call get*() functions only after hasValue() has returned true.
    if (bmx280.isBME280())
    {
      humidity = bmx280.getHumidity();
    }
  }
  ccs.setEnvironmentalData( humidity, temperature ); // kompensasi humidity & temperature

  if (ccs.available()) {
    if (!ccs.readData()) {
      //      Serial.print("CO2: ");
      //Serial.print(ccs.geteCO2());
      //Serial.print("ppm, TVOC: ");
      //Serial.println(ccs.getTVOC());
      co2 = ccs.geteCO2();
      tvoc =   ccs.getTVOC();
    }
  }

  Serial.print("Temp\t");
  Serial.print(temperature);
  Serial.print("\t");

  Serial.print("Humidity\t");
  Serial.print(humidity);
  Serial.print("\t");

  Serial.print("Pressure\t");
  Serial.print(pressure);
  Serial.print("\t");

  Serial.print("CO2\t");
  Serial.print(co2);
  Serial.print("\t");
  Serial.print("TVOC\t");
  Serial.print(tvoc);
  Serial.println("");

  delay(500);
  digitalWrite(LED_ONBOARD, HIGH);
  delay(500);
  digitalWrite(LED_ONBOARD, LOW);
}

void I2C_Scan() {
  byte error, address;

  int nDevices;
  Serial.println("I2C Scanning...");
  nDevices = 0;
  for (address = 1; address < 127; 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.println(address, HEX);
      nDevices++;
    }
    else if (error == 4) {
      Serial.print("Unknow 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");
  }
}

Berikut ini contoh tampilan outputnya

13:08:18.861 -> I2C Scanning...
13:08:18.861 -> I2C device found at address 0x5A
13:08:18.896 -> I2C device found at address 0x76
13:08:18.931 -> done
13:08:18.931 -> 
13:08:18.931 -> CCS811 test
13:08:19.101 -> CCS811 ready
13:08:19.101 -> sensor is a BME280
13:08:19.135 -> HDC1080
13:08:19.135 -> Manufacturer ID=0xFFFF
13:08:19.135 -> Device ID=0xFFFF
13:08:19.239 -> Temp	30.83	Humidity	50.10	Pressure	87156.00	CO2	0.00	TVOC	0.00
13:08:20.368 -> Temp	30.83	Humidity	50.29	Pressure	91715.00	CO2	0.00	TVOC	0.00
13:08:21.464 -> Temp	30.84	Humidity	50.37	Pressure	91714.00	CO2	0.00	TVOC	0.00

 

Referensi

 

Rangkaian Pengkondisi Sinyal Untuk ADC

Sinyal dari sensor dapat memiliki rentang tegangan besar, rentangan tegangan kecil ataupun tegangan negatif dan positif. ADC pada mikroprosesor umumnya hanya dapat menerima input tegangan positif dengan rentang tegangan terbatas. Untuk itu sinyal dari sensor perlu diperkuat/diperlemah, dan digeser supaya tepat dengan rentang tegangan ADC.

Skema Rangkaian

Berikut ini contoh rangkaian untuk melakukan pengkondisian sinyal tersebut.

Rangkaian Pengkondisi Sinyal ADC dengan 3 buah op-amp
Rangkaian Pengkondisi Sinyal ADC

Dasar Teori

Rangkaian ini terdiri dari 3 bagian:

  • inverting amplifier
  • buffer amplifier
  • summing amplifier

Inverting amplifier

Komponen IC1 berfungsi sebagai inverting amplifier. Menguatkan input dan membalik polaritasnya.

Berikut ini bentuk dasar rangkaian inverting Inverting amplifier

 

Buffer amplifier

Detail dan rumus-rumus terkait dapat dipelajar di Inverting Amplifier

Buffer amplifier

Komponen IC2 berfungsi sebagai buffer

Summing amplifier

Detail dan rumus-rumus buffer amplifier dapat dipelajari di Buffer Amplifier

Komponen IC3 berfungsi sebagai summing amplifier / adder  / penjumlah.

Detail dan rumus-rumus summing amplifier dapat dipelajari di Summing Amplifier

Cara Kerja

Cara kerja rangkaian adalah sebagai berikut

Rangkaian ini terdiri dari 3 buah op-amp. Op-amp yang digunakan adalah LM358. Power supply plus minus 12 volt, dari DC to DC converter.

IC1 berfungsi sebagai penguat/peredam inverting.  Penguatan/peredaman dapat diatur dengan menggunakan potensiometer VR1. Total penguatan/redaman dapat dihitung berdasarkan nilai R1 dan VR1.

Tegangan untuk menggeser naik-turun tegangan dihasilkan oleh VR2. Pada contoh ini sumber tegangan menggunakan power supply -12 volt. Jika diinginkan ketelitian lebih tinggi, sumber tegangan dapat menggukan dioda zener atau sumber tegangan referensi yang lebih baik. Pada contoh ini tegangan penggeser adalah negatif, karena hanya diperlukan penaikan tegangan  Jika diinginkan juga penurunan tegangan, maka tegangan referensi yang diperlukan adalah plus minus 12 volt.

IC2 berfungsi sebagai buffer dari VR2. Jika tidak ada IC2, resistansi dari VR2 dapat mempengaruhi penguatan summing amplifier, karena resistansi dari VR2 akan diseri dengan R3.

Sinyal hasil penguatan/peredaman dan sinyal penggeseran dijumlahkan dengan menggunakan IC3. IC3 dikonfigurasikan sebagai op-amp penjumlah inverting.

Pada contoh ini semua resistor yang digunakan sama, 1k ohm untuk memudahkan pembuatan dan perhitungan.

Untuk lebih amannya , pada bagian output perlu dipasang dioda clamp, supaya tegangan output tidak melebihi batas maksimum dan minimum ADC pada mikrokontroler.

Foto Alat

Pada percobaan ini, digunakan sinyal dengan frekuensi 50 Hz dan tegangan amplitudo 1 volt.

Sumber sinyal dengan generator sinyal GW Instek AFG-2012.

Pengukuran sinyal dengan Osiloskop GW Instek GDS-1152-U

Sumber sinyal dari generator sinyal GW Instek AFG 2012
Generator sinyal
 

Implementasi rangkaian dengan breadboard, sebagai berikut:

Percobaan rangkaian pengkondisi sinyal dengan breadboard
Rangkaian dengan breadboard
Suasana percobaan
Suasana percobaan

Foto Sinyal

Berikut ini contoh sinyal yang dihasilkan.

Pertama-tama sinyal dengan penggeseran tanpa penguatan.

Contoh geser naik saja
Contoh geser naik saja

Sinyal input pada kanal 1, dengan warna kuning. Sinyal output pada kanal 2, dengan warna biru.

Berikut ini sinyal yang diredam, dan digeser naik ke positif.

Contoh redaman dan geser naik
Contoh redaman dan geser naik

Berikut ini sinyal dengan penguatan dan penggeseran naik.

Contoh penguatan dan geser naik
Contoh penguatan dan geser naik

 

Arduino Nano memerlukan tegangan ADC antara 0~5 volt atau 0~1,1 volt, tergantung setting tegangan referensi ADC tersebut. Arduino Nano KW biasanya tegangan VCC nya adalah kurang dari 5 volt, sekitar 4,6 volt. Untuk itu perlu tegangan input ADC antara 0 ~ 4 volt. Berikut ini contoh sinyal (biru) yang sudah cocok untuk rentang tersebut.

Contoh penguatan dan geser naik
Contoh penguatan dan geser naik untuk Arduino

Output dari op-amp dibatasi oleh tegangan supply. Percobaan berikut menunjukkan apa yang terjadi jika output mengalami saturasi. 

Output saturasi
Output saturasi

Output (warna biru) mengalami saturasi di 7.12 volt. Tegangan supply positif yang dipakai adalah 9 volt. Datasheet LM358 menunjukkan bahwa LM358 memiliki ‘voltage output swing to rail’ sebesar 1.35 volt sampai 1,61 volt tergantung arus output. Hasil pengukuran menunjukkan jarak antara output ke VCC adalah 1,88 volt, masih di sekitar angka yang ditunjukkan di datasheet LM358.

Referensi

 

STM32F103C8T Blue Pill Dengan Display LCD 20×4 (I2C)

Berikut ini percobaan menghubungkan STM32F103C8T dengan display LCD 20×4. Antar muka menggunakan komunikasi serial I2C. LCD 20×4 menggunakan protokol serial, sehingga perlu modul I2C. STM32 menggunakan tegangan 3,3 volt, sedangkan LCD 20×4 menggunakan tegangan 5 volt, sehingga perlu level converter antara I2C di ESP32 dan I2C di modul PCF8752. Pada LCD 20×4 dipasang modul serial to paralel PCF8574 untuk menghubungkan protokol I2C ke paralel input/output pada LCD.

STM32 dengan display LCD 20x4
STM32 dengan display LCD 20×4

Berikut ini blok diagram sistem

Pin I2C dapat dilihat pada daftar pin pada STM32F103 berikut ini.

 

 

STM32F103 Pinout Diagram

Komunikasi I2C

Pin I2C yang dipakai adalah PB6 (SCL1) dan PB7 (SDA1).

Tegangan I2C dari STM32 adalah 3,3 volt, sedangkan PCF8574 perlu 5 volt. Untuk itu perlu komponen bi directional logic level converter di antara keduanya.

Power Supply

Pada board Blue Pill sudah terdapat output 5 volt, jadi tegangan  5 volt untuk LCD dapat diambil dari situ.

Software

 

 

#include <LiquidCrystal_I2C.h>
// https://circuitdigest.com/microcontroller-projects/stm32-stm32f103c8-i2c-communication-tutorial
// Include the libraries:
// LiquidCrystal_I2C.h: https://github.com/johnrickman/LiquidCrystal_I2C

#include <Wire.h> // Library for I2C communication
#include <LiquidCrystal_I2C.h> // Library for LCD

LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 20, 4);

void setup() {
  Wire.begin();
  // Initiate the LCD:
  lcd.init();
  lcd.backlight();
  Serial.begin(115200);
  Serial.println("\nLCD Test");
  pinMode(LED_BUILTIN, OUTPUT);
}
int counter = 0;
void loop() {
  lcd.setCursor(0, 0);
  lcd.print("Elektrologi");
  lcd.setCursor(0, 1);
  lcd.print("IPTEK.WEB.ID");
  lcd.setCursor(0, 2);
  lcd.print("STM32F103C8T BluePill");
  lcd.setCursor(0, 3);
  lcd.print("31 Januari 2021");

  lcd.setCursor(12, 0);
  lcd.print(counter);

  Serial.print("Send data: ");
  Serial.println(counter);

  delay(500);
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(500);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);
  counter++;
}

Referensi

  • https://circuitdigest.com/microcontroller-projects/stm32-stm32f103c8-i2c-communication-tutorial

Pemrograman STM32 Blue Pill Dengan Arduino dan ST-LINK-V2

Berikut ini uraian untuk melakukan proses upload program menggunakan ST Link V2 dari Arduino IDE. Cara lain adalah menggunakan ST Link Utility.

Hardware

Siapkan hardware berupa board STM32F103C8T dan programmer ST-LINK-V2

Instalasi Arduino IDE

Proses instalasi software untuk board STM32duino dapat dilihat di sini: https://github.com/stm32duino/wiki/wiki/Getting-Started

Konfigurasi Arduino IDE

Pilih Board -> STM32 Boards (STM32duino.com) (in sketchbook) -> Generic STM32F103C series

Pilih variant 64k Flash .

Pilih Upload Method: Tools -> Upload method -> STLink

Pilih port COM yang sesuai. Jika dilihat di Device Manager, akan nampak sebagai “Maple Serial”.

Setelah itu coba jalankan software Blink (File -> Examples -> Basics -> Blink). Jika semuanya lancar, maka LED akan berkedip dengan frekuensi 0,5 Hz.

Referensi

Alternatif Board STM32

Berikut ini survey singkat tentang board STM32 yang dapat dipakai untuk belajar.

STM32 Blue Pill. ST Link V2 (clone), STM32F4 Discovery, STM32 Discovery
STM32 Blue Pill. ST Link V2 (clone), STM32F4 Discovery, STM32 Discovery

 

Alternatif #1 STM32 Blue Pill

STM32 Blue Pill dan STL LINK V2
STM32 Blue Pill dan STL LINK V2

Prosesornya adalah STM32F103C8T6 , board ini dikenal luas sebagai ‘Blue Pill’. Untuk memasukkan program dan debugging dapat menggunakan modul ST-Link-V2.

Harga:

  • Blue Pill: sekitar Rp 32 ribu
  • ST LINK V2: sekitar Rp 33 ribu

Artikel terkait:

Alternatif #2 STM32F Discovery

STM32F407G Discovery
STM32F407G Discovery

Resource: https://www.st.com/en/evaluation-tools/stm32f4discovery.html

Harga sekitar Rp 400 ribuan, kata kunci “STM32F Discovery Boards”

Alternatif #3 STM32VL  Discovery

STM32 Value Line Discovery
STM32 Value Line Discovery

Prosesor: STM32F100

Resource: https://www.st.com/en/evaluation-tools/stm32vldiscovery.html

Harga: barang susah dicari.

STM32F401

STM32F401
STM32F401
STM32F401CCU6
STM32F401CCU6

Belum pernah dicoba, harga Rp 60 ribuan.

Perlu ST-Link-V2 untuk upload software

STM32F411CEU6

STM32F411CEU6
STM32F411CEU6

Prosesor STM32F411CEU6, belum pernah dicoba.

Harga Rp 200 ribuan.

Perlu ST-Link-V2 untuk upload software

Saran

Solusi murah meriah adalah STM32 Blue Pill dengan ST-LINK-V2. Board ini banyak dipakai dan ada banyak versinya, banyak juga resourcenya.

Jika ingin performance yang lebih baik, bisa cari board STM32F4, kalau yang mahal adalah board buatan STM32. Enaknya support lebih jelas dibandingkan board STM32F4 yang 3rd party.

 

 

 

 

 

 

ESP32 Lolin32 Lite Dengan Display LCD 20×4 (serial I2C)

Berikut ini percobaan menghubungkan ESP32 Lolin32 Lite dengan display LCD 20×4. Antar muka menggunakan komunikasi serial I2C. LCD 20×4 menggunakan protokol serial, sehingga perlu modul I2C.  ESP32 menggunakan tegangan 3,3 volt, sedangkan LCD 20×4 menggunakan tegangan 5 volt, sehingga perlu level converter antara I2C di ESP32 dan I2C di modul PCF8752. Pada LCD 20×4 dipasang modul serial to paralel PCF8574 untuk menghubungkan protokol I2C ke paralel input/output pada LCD.

ESP32 Lolin-32 dari WEMOS
ESP32 Lolin-32 dari WEMOS

Berikut ini blok diagram sistem

Skema Rangkaian

Berikut ini skema rangkaian lengkap.

Skema rangkaian ESP32 Lolin32 Lite dengan LCD I2C
Skema rangkaian ESP32 Lolin32 Lite dengan LCD I2C

Arduino Nano pada rangkaian tersebut hanya berfungsi untuk memberikan tegangan 5 volt, karena pada ESP32 Lolin32 Lite tidak ada pin 5V. Jika menggunakan ESP32 Devkit mestinya lebih enak, karena di ESP32 Devkit  ada pin 5V. Tegangan 5V ini dapat diganti dengan regulator / adaptor 5V lain.

Komunikasi I2C

ESP32 tidak memiliki pin I2C yang spesifik, jadi kita dapat memilih pin mana yang dipakai sebagai pin untuk I2C (SDA dan SCL). Pada percobaan ini dipilih pin 15 untuk SDA dan pin 13 untuk SCL. Konfigurasi ini dimasukkan di software dalam bentuk parameter I2C_SDA dan I2C SCL yang didefinisikan di awal software.

Semua pin pada ESP32 termasuk pin I2C  menggunakan tegangan kerja 3 volt, sedangkan display menggunakan tegangan 5 volt. Untuk itu tegangan kerja PCF8574 disamakan dengan display LCD (5 volt), sedangkan tegangan I2C diubah dari 3 volt (di ESP32) menjadi 5 volt (di PCF8574). Komunikasi harus 2 arah, karena protokol I2C mensyaratkan slave menjawab setiap kali ada pengiriman data. Untuk itu pada jalur I2C digunakan  komponen ‘bi directional level converter‘.

Power Supply

Sumber daya ESP32 menggunakan USB charger 5 volt. Pada board ESP32 sudah ada regulator 3,3 volt yang mengubah tegangan supply USB 5 volt menjadi 3,3 volt.

Sumber daya 5 volt untuk LCD dan PCF8574 diberikan melalui sebuah modul Arduino Nano yang  dipakai. Seharusnya dapat menggunakan power supply 5 volt apa saja. Kebetulan saja yang tersedia saat ini adalah board Arduino Nano.

Software

Berikut ini software yang dipakai untuk menghasilkan tampilan.

// Demo LCD dengan ESP32 I2C
#include <LiquidCrystal_I2C.h>
// https://www.makerguides.com/character-i2c-lcd-arduino-tutorial/
// Include the libraries:
// LiquidCrystal_I2C.h: https://github.com/johnrickman/LiquidCrystal_I2C

#include <Wire.h> // Library for I2C communication
#include <LiquidCrystal_I2C.h> // Library for LCD

//LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 16, 2); // Change to (0x27,16,2) for 16x2 LCD.
LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 20, 4); 

#define I2C_SDA 15
#define I2C_SCL 13
#define LED_BUILTIN 22 // LED built in pada ESP32 Lolin32 Lite

void setup() {
  Wire.begin(I2C_SDA, I2C_SCL);
  // Initiate the LCD:
  lcd.init();
  lcd.backlight();
  Serial.begin(115200);
  Serial.println("\nLCD Test");
  pinMode(LED_BUILTIN, OUTPUT);
}
int counter = 0;
void loop() {

  // Print 'Hello World!' on the first line of the LCD:

  lcd.setCursor(0, 0);
  lcd.print("Elektrologi");
  lcd.setCursor(0, 1);
  lcd.print("iptek.web.id");
  lcd.setCursor(0, 2);
  lcd.print("ESP32 Lolin32 Lite");
  lcd.setCursor(0, 3);
  lcd.print("31 Januari 2021");

  lcd.setCursor(12, 0); 
  lcd.print(counter);

  Serial.print("Send data: ");
  Serial.println(counter);
  delay(500);

  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(500);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);
  counter++;
}

Hasil

ESP32 dan LCD 20x4
ESP32 dan LCD 20×4

Referensi

Raspberry NOAA

Ada oprekan menarik , “Raspberry NOAA”.

Intinya adalah menangkap data cuaca yang dipancarkan oleh satelit NOAA dengan antena sederhana, RTL-SDR dan Raspberry PI.

137 MHz Weather SAT V-Dipole antenna
137 MHz Weather SAT V-Dipole antenna

Sementara dicatat dulu, menunggu waktu yang tepat untuk melaksanakannya.

Referensi