Blog

Antar Muka ST7789

Fungsi pin #

  • GND : ground
  • VCC : VCC 3,3 volt
  • SCK : clock SPI
  • SDA : data SPI MOSI. Namanya (SDA) seperti pin pada protokol I2C, namun sebenarnya display ini menggunakan protokol SPI
  • RES : reset
  • DC : display data/command selection
  • BLK : backlight

Kode #

main()

Referensi #

Menampilkan Setting Default Pin SPI pada ESP32

SPI

Kode #

// cek default SPI pin
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  Serial.print("MOSI: ");
  Serial.println(MOSI);
  Serial.print("MISO: ");
  Serial.println(MISO);
  Serial.print("SCK: ");
  Serial.println(SCK);
  Serial.print("SS: ");
  Serial.println(SS);
}

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

Output #

ets Jun  8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0030,len:4744
load:0x40078000,len:15672
load:0x40080400,len:3164
entry 0x4008059c
MOSI: 23
MISO: 19
SCK: 18
SS: 5

Mengukur Waktu Pengukuran IMU MPU6500

Pertanyaan #

Berapa waktu yang diperlukan MPU6500 untuk menghasilkan pengukuran percepatan?

Solusi #

Library IMU menggunakan https://github.com/LiquidCGS/FastIMU/blob/main/examples/Calibrated_sensor_output/Calibrated_sensor_output.ino Library yang dipakai adalah FastIMU https://github.com/LiquidCGS/FastIMU Lakukan pengukuran akselerometer 1000 kali, catat waktu total yang diperlukan.

Kode #

// mengukur waktu konversi oleh MPU6500
// pakai delay sederhana saja
// https://github.com/LiquidCGS/FastIMU/blob/main/examples/Calibrated_sensor_output/Calibrated_sensor_output.ino


#include "FastIMU.h"
#include <Wire.h>
#include <ArduinoJson.h>
#include <HTTPClient.h>
#include <WiFiMulti.h>
#include "FS.h"
#include "SD.h"
#include "SPI.h"

#define IMU_ADDRESS 0x68  //Change to the address of the IMU
// #define PERFORM_CALIBRATION //Comment to disable startup calibration
//MPU9250 IMU;  //Change to the name of any supported IMU!
MPU6500 IMU;  //Change to the name of any supported IMU!

// Currently supported IMUS: MPU9255 MPU9250 MPU6886 MPU6500 MPU6050 ICM20689 ICM20690 BMI055 BMX055 BMI160 LSM6DS3 LSM6DSL QMI8658
calData calib = { 0 };  //Calibration data
AccelData accelData;    //Sensor data
//GyroData gyroData;
//MagData magData;

#define SDA 15  // sesuaikan dengan port yang dipakai untuk SDA dan SCL
#define SCL 13
#define LED 22  // Lolin32 Lite

// SD card configuratin
#define REASSIGN_PINS
int sck = 23;
int miso = 5;
int mosi = 18;
int cs = 19;

void setup() {
  Wire.begin(SDA, SCL);
  Wire.setClock(400000);  //400khz clock
  Serial.begin(115200);
  while (!Serial) {
    ;
  }

  int err = IMU.init(calib, IMU_ADDRESS);
  if (err != 0) {
    Serial.print("Error initializing IMU: ");
    Serial.println(err);
    while (true) {
      ;
    }
  }

  if (err != 0) {
    Serial.print("Error Setting range: ");
    Serial.println(err);
    while (true) {
      ;
    }
  }
}

void loop() {
  int i;
  unsigned long begin,end;
  // iterasi 1000x, ukur berapa waktunya
  begin = millis();
  for (i = 0; i < 1000; i++) {
    IMU.update();
    IMU.getAccel(&accelData);
  }
  end = millis();
  Serial.print("time: ");  
  Serial.println(end - begin); // durasi untuk 1000x pengukuran
  delay(1000);
}

Output #

time: 267
time: 266
time: 267
time: 267
time: 267
time: 267
time: 267
time: 267
time: 267

Referensi #

Deteksi Tipe IMU dengan ESP32

Deteksi tipe IMU yang dipakai menggunakan mikrokontroler ESP32 Library yang dipakai adalah FastIMU https://github.com/LiquidCGS/FastIMU

Kode #

// modifikasi dari https://github.com/LiquidCGS/FastIMU/blob/main/examples/IMUIdentifier/IMUIdentifier.ino
#include <Wire.h>
// Similar to https://github.com/Levi--G/IMU-WhoAmIVerifier

//Do be aware that MPU9150's will report as 6050s, this is because a 9150 is a 6050 with a magnetometer
//if you have a 9250 board and it reports as a 6050, it's most likely a 9150.

//This code will check for an IMU when reset and, if one is found, it will report what it is.
//To re run the check without resetting the Arduino, pull pin 4 to GND.

#define NUM_IMUS 47

bool errorflag;

typedef struct IMU {
  uint8_t Address1;
  uint8_t Address2;
  uint8_t Register;
  uint8_t ExpectedID;
  const char* IMUName PROGMEM;
  const char* IMUCapabilities PROGMEM;
  bool LibSupported;
};

const IMU IMUList[NUM_IMUS] = {
  { 0x68, 0x69, 0x75, 0x68, "MPU6050", "3A,3G", true },
  { 0x68, 0x69, 0x75, 0x70, "MPU6500", "3A,3G", true },
  { 0x68, 0x69, 0x75, 0x71, "MPU9250", "3A,3G,3M", true },
  { 0x68, 0x69, 0x75, 0x72, "Counterfeit IMU, use 'IMU_Generic'", "3A,3G, possibly 3M?", true },  //MPU9350? https://android.googlesource.com/kernel/msm/+/android-msm-dory-3.10-kitkat-wear/drivers/iio/imu/inv_mpu6515/inv_mpu_iio.h
  { 0x68, 0x69, 0x75, 0x73, "MPU9255", "3A,3G,3M", true },
  { 0x68, 0x69, 0x75, 0x74, "MPU6515", "3A,3G", true },
  { 0x68, 0x69, 0x75, 0x75, "Counterfeit IMU, use 'IMU_Generic'", "3A,3G, possibly 3M?", true },
  { 0x68, 0x69, 0x75, 0x19, "MPU6886", "3A,3G", true },
  { 0x69, 0x68, 0x00, 0xD1, "BMI160", "3A,3G", true },
  { 0x6B, 0x6A, 0x0F, 0x69, "LSM6DS3", "3A,3G", true },
  { 0x6B, 0x6A, 0x0F, 0x6A, "LSM6DSL or LSM6DS3TR-C", "3A,3G", true },
  { 0x68, 0x69, 0x75, 0x98, "ICM20689", "3A,3G", true },
  { 0x68, 0x69, 0x75, 0x20, "ICM20690", "3A,3G", true },
  { 0x6B, 0x6A, 0x00, 0x05, "QMI8658", "3A,3G", true },
  { 0x18, 0x19, 0x00, 0xFA, "BMI055 or BMX055", "3A,3G or 3A,3G,3M", true },
  { 0x1E, 0x1E, 0x0C, 0x33, "HMC5883L", "3M", true },
  { 0x0D, 0x0D, 0x0D, 0xFF, "QMC5883L", "3M", true },
  { 0x0C, 0x0D, 0x01, 0x09, "AK8975", "3M", false },
  { 0x0E, 0x0F, 0x01, 0x09, "AK8975", "3M", false },
  { 0x0C, 0x0D, 0x01, 0x9A, "AK8963", "3M", true },
  { 0x0E, 0x0F, 0x01, 0x9A, "AK8963", "3M", true },
  { 0x13, 0x10, 0x40, 0x32, "BMM150", "3M", false },
  { 0x12, 0x11, 0x40, 0x32, "BMM150", "3M", false },
  { 0x6B, 0x6A, 0x0F, 0x6B, "LSM6DSR", "3A,3G", false },
  { 0x6B, 0x6A, 0x0F, 0x6C, "LSM6DSO", "3A,3G", false },
  { 0x6B, 0x6A, 0x00, 0xFC, "QMI8610", "3A,3G", false },
  { 0x68, 0x69, 0x75, 0x92, "ICG20330", "3G", false },
  { 0x68, 0x69, 0x75, 0xB5, "IAM20380", "3A", false },
  { 0x68, 0x69, 0x75, 0xB6, "IAM20381", "3G", false },
  { 0x68, 0x69, 0x75, 0x11, "ICM20600", "3A,3G", false },
  { 0x68, 0x69, 0x75, 0xAC, "ICM20601", "3A,3G", false },
  { 0x68, 0x69, 0x75, 0x12, "ICM20602", "3A,3G", false },
  { 0x68, 0x69, 0x75, 0xAF, "ICM20608-G", "3A,3G", false },
  { 0x68, 0x69, 0x75, 0xA6, "ICM20609", "3A,3G", false },
  { 0x68, 0x69, 0x00, 0xE0, "ICM20648", "3A,3G", false },
  { 0x68, 0x69, 0x00, 0xE1, "ICM20649", "3A,3G", false },
  { 0x68, 0x69, 0x75, 0xA9, "ICG20660", "3A,3G", false },
  { 0x68, 0x69, 0x75, 0x91, "IAM20680", "3A,3G", false },
  { 0x68, 0x69, 0x00, 0xEA, "ICM20948", "3A,3G,3M", false },
  { 0x68, 0x69, 0x75, 0x6C, "IIM42351", "3A", false },
  { 0x68, 0x69, 0x75, 0x6D, "IIM42352", "3A", false },
  { 0x68, 0x69, 0x75, 0x4E, "ICM40627", "3A,3G", false },
  { 0x68, 0x69, 0x75, 0x42, "ICM42605", "3A,3G", false },
  { 0x68, 0x69, 0x75, 0x6F, "IIM42652", "3A,3G", false },
  { 0x68, 0x69, 0x75, 0x67, "ICM42670-P", "3A,3G", false },
  { 0x68, 0x69, 0x75, 0xDB, "ICM42688-V", "3A,3G", false },
  { 0x68, 0x69, 0x00, 0x68, "MPU3050", "3G", false }
};

#define SDA 15  // sesuaikan dengan port yang dipakai untuk SDA dan SCL
#define SCL 13


void setup() {
  Serial.begin(115200);
  while (!Serial)
    ;
  errorflag = false;
  pinMode(4, INPUT_PULLUP);
  Wire.begin(SDA, SCL);
#ifdef WIRE_HAS_TIMEOUT
  Wire.setWireTimeout(3000);
#endif
  //wake sensors
  //BMM150
  writeByte(0x10, 0x4B, 0x01);
  writeByte(0x11, 0x4B, 0x01);
  writeByte(0x12, 0x4B, 0x01);
  writeByte(0x13, 0x4B, 0x01);
  //enable Magnetometer bypass on invsense IMUs
  writeByte(0x68, 0x37, 0x22);
  writeByte(0x69, 0x37, 0x22);

  Serial.println(F("\n=========== IMU Identifier ==========="));
}

void loop() {
  static int a = 0;
  while (digitalRead(4) && a != 0)
    ;  //do once
  a = 1;
  bool detected = false;
  for (int i = 0; i < NUM_IMUS; i++) {
#ifdef WIRE_HAS_TIMEOUT
    if (errorflag || Wire.getWireTimeoutFlag()) {
      Serial.print(F("Error while reading address 0x"));
      Serial.print(IMUList[i].Address1, HEX);
      Serial.print(F(": "));
      if (Wire.getWireTimeoutFlag()) {
        Serial.println(F("I2C bus timed out. (Bad IMU? check wiring.)"));
      } else {
        Serial.println(F("Unknown error while reading/writing"));
      }
      Serial.println(F("======================================"));
      Wire.clearWireTimeoutFlag();
      errorflag = false;
      delay(2000);
      return;
    }
#endif
    if (readByte(IMUList[i].Address1, IMUList[i].Register) == IMUList[i].ExpectedID) {
      detected = true;
      Serial.print(F("IMU Found: "));
      Serial.print(IMUList[i].IMUName);
      Serial.print(F(" On address: 0x"));
      Serial.println(IMUList[i].Address1, HEX);
      Serial.print(F("This IMU is capable of the following axis: "));
      Serial.println(IMUList[i].IMUCapabilities);
      if (IMUList[i].LibSupported) {
        Serial.println(F("This IMU is supported by the FastIMU library."));
      } else {
        Serial.println(F("This IMU is not supported by the FastIMU library."));
      }
      Serial.println(F("======================================"));
    } else if (readByte(IMUList[i].Address2, IMUList[i].Register) == IMUList[i].ExpectedID) {
      detected = true;
      Serial.print(F("IMU Found: "));
      Serial.print(IMUList[i].IMUName);
      Serial.print(F(" On address: 0x"));
      Serial.println(IMUList[i].Address2, HEX);
      Serial.print(F("This IMU is capable of the following axis: "));
      Serial.println(IMUList[i].IMUCapabilities);
      if (IMUList[i].LibSupported) {
        Serial.println(F("This IMU is supported by the FastIMU library."));
      } else {
        Serial.println(F(" This IMU is not supported by the FastIMU library."));
      }
      Serial.println(F("======================================"));
    }
  }
  if (!detected) {
    Serial.println(F("No IMU detected"));
    Serial.println(F("======================================"));
  }
  delay(1000);
}

uint8_t readByte(uint8_t address, uint8_t subAddress) {
  uint8_t data;                         // `data` will store the register data
  Wire.beginTransmission(address);      // Initialize the Tx buffer
  Wire.write(subAddress);               // Put slave register address in Tx buffer
  int i = Wire.endTransmission(false);  // Send the Tx buffer, but send a restart to keep connection alive
  if (i == 5) {
    return 0;
    errorflag = true;
  }
  i = Wire.requestFrom(address, (uint8_t)1, true);  // Read one byte from slave register address
  if (i == 0) {
    return 0;
    errorflag = true;
  }
  if (Wire.available()) {
    data = Wire.read();  // Fill Rx buffer with result
  }
  return data;  // Return data read from slave register
}

void writeByte(uint8_t address, uint8_t subAddress, uint8_t data) {
  Wire.beginTransmission(address);  // Initialize the Tx buffer
  Wire.write(subAddress);           // Put slave register address in Tx buffer
  Wire.write(data);                 // Put data in Tx buffer
  Wire.endTransmission();           // Send the Tx buffer
}

Output #

Berikut ini contoh output ketika dipakai mendeteksi MPU-6050 Ternyata tipenya sebenarnya adalah MPU6500

Arus Maksimum Basis pada Transistor

Berapakah arus maksimum Basis pada Transistor tipe Bipolar (Bipolar Junction Transistor)?

Pada datasheet transistor umumnya arus maksimum basis tidak disebut. Namun di beberapa artikel/application note ada yang mencantumkan best practice untuk menentukan arus basis. Aturan yang ada di antaranya:

  • 1/2 sampai dengan 1/6 arus kolektor maksimum (Ic max), menurut situs Toshiba
  • 1/10 arus kolektor untuk transistor Darlington, menurut situs ROHMS

Kutipan dari situs ROHMS:

“The maximum Base current rating is 1/3rd the Collector current (1/10th in the case of Darlington transistors). In the case of 2SD2656: IC max is 1A for DC and 2A for pulse. Therefore, the max. ratings for Base current is 333mA for DC and 666mA pulse. Digital transistors are designed to ensure that the input current will be within the rated value as long as Vin is within the normal range.”

Mengirim Data dari ESP32 dengan HTTP POST

Berikut ini contoh mengirim data dari ESP32 ke web server sederhana. Protokol yang dipakai adalah HTTP POST

Kode di ESP32:

// urlencoded
// https://randomnerdtutorials.com/esp32-http-get-post-arduino/#http-post
// https://docs.arduino.cc/libraries/httpclient/
// receiving JSON POST https://www.geeksforgeeks.org/how-to-receive-json-post-with-php/

#include <ArduinoJson.h>
#include <HTTPClient.h>
#include <WiFiMulti.h>

const char *AP_SSID = "AP Name";
const char *AP_PWD = "AP password";

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

  WiFi.begin(AP_SSID, AP_PWD);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }
  Serial.println("Connected to WiFi");
  Serial.print("ESP32 Web Server's IP address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  postDataToServer();
  delay(10000);  // delay 10 seconds
}
int counter = 0;
void postDataToServer() {
  Serial.println("Posting POST data to server...");
  // Block until we are able to connect to the WiFi access point
  if (WiFi.status() == WL_CONNECTED) {
    HTTPClient http;
    http.begin("http://192.168.0.139/post.php");
    http.addHeader("Content-Type", "application/x-www-form-urlencoded");
    
    // parameter POST dummy, kecuali counter yang diupdate teratur

    String httpRequestData = "api_key=tPmAT5Ab3j7F9&sensor=BME280&value1=24.25&value2=49.54&value3=1005.14&counter=" + String(counter);
    int httpResponseCode = http.POST(httpRequestData);
    if (httpResponseCode > 0) {
      String response = http.getString();
      Serial.println(httpResponseCode);
      Serial.println(response);  // cek untuk debugging

    } else {
      Serial.print("error code");
      Serial.print(httpResponseCode);
      // error codes from https://github.com/amcewen/HttpClient/blob/master/HttpClient.h
      // static const int HTTP_ERROR_CONNECTION_FAILED =-1;
      // static const int HTTP_ERROR_API =-2;
      // static const int HTTP_ERROR_TIMED_OUT =-3;
      // static const int HTTP_ERROR_INVALID_RESPONSE =-4;
    }
  }
  counter++;
}

Berikut ini kode PHP di web server

Coding Standard

Coding standard: AUTOSAR C++14

MISRA

CERT Coding Standards

CWE

Static Analysis tools

Open-Source Tools with MISRA Support

Cppcheck #

Cppcheck: A popular open-source static analysis tool for C/C++ that includes an addon (a Python script) for checking a number of MISRA C:2012 rules. The script provides rule IDs for violations, although it does not contain the full MISRA rule text due to copyright restrictions (the MISRA documents are proprietary).