Pendahuluan
Skill yang paling mendasar untuk embedded development adalah memahami general purpose I/O (GPIO) untuk membaca output dari sensor dan melakukan kontrol terhadap actuators.
Sensor sendiri adalah alat yang menghasilkan output ketika dihadapkan pada suatu fenomena, contoh temperature, humidity, cahaya, vibrasi dan lainnya. Output yang dihasilkan berupa sinyal listrik. Sensor umumnya sudah menggunakan signal conditioner, untuk melakukan konversi menjadi bentuk yang dapat dibaca oleh microcontroller sebagai input.
Actuators adalah sisi output dari IoT solutions. Actuators akan berubah state bedasarkan signal analog atau digital dari microcontroller, dan menghasilkan output untuk lingkungkan. Contoh buzzer untuk menghasilkan suara, LED untuk menghasilkan cahaya, relay untuk switch on/off dan motor untuk membuat motion.
TIPS : Sediakan diagram dari devkit board yang Anda gunakan dalam jangkuan. Untuk memudahkan Anda dalam mengetahui posisi pin dan fungsi pin. Pada tutorial ini akan digunakan ESP32 Devkitc ver 4.
Latihan Basic I/O
Untuk latihan Basic I/O kita akan menyalakan dan mematikan led menggunakan saklar.
Component
- LED, 5 millimeters (mm)
- Resistor, >220 ohm
- Tactile switch
Diagram Sirkuit
Perhatian, pastikan kaki pendek (cathode) dari LED terhubung ke GND dan kaki yang lebih panjang (anode) dihubungkan ke GPIO2.
Terminal dari saklar terhubung ke GPIO5 dan GND. Ketika saklar (button) ditekan, ESP32 akan membaca LOW value.
LED menggunakan GPIO2 sebagai output pin. Digunakan resistor untuk membatasi arus agar LED tidak rusak.
Source Code
Masukan kode berikut pada main.c
//import libray yang digunakan #include <stddef.h> #include "driver/gpio.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" //macro untuk mendefinisikan pins #define GPIO_LED 2 #define GPIO_LED_PIN_SEL (1ULL << GPIO_LED) #define GPIO_BUTTON 5 #define GPIO_BUTTON_PIN_SEL (1ULL << GPIO_BUTTON) #define ESP_INTR_FLAG_DEFAULT 0 //fungsi inisialisasi hardware static void button_handler(void *arg); static void init_hw(void) { gpio_config_t io_conf; io_conf.mode = GPIO_MODE_OUTPUT; io_conf.pin_bit_mask = GPIO_LED_PIN_SEL; io_conf.intr_type = GPIO_INTR_DISABLE; io_conf.pull_down_en = 0; io_conf.pull_up_en = 0; gpio_config(&io_conf); io_conf.mode = GPIO_MODE_INPUT; io_conf.pin_bit_mask = GPIO_BUTTON_PIN_SEL; io_conf.intr_type = GPIO_INTR_NEGEDGE; io_conf.pull_up_en = 1; gpio_config(&io_conf); gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT); gpio_isr_handler_add(GPIO_BUTTON, button_handler, NULL); } //fungsi button_handler static TickType_t next = 0; static bool led_state = false; static void IRAM_ATTR button_handler(void *arg) { TickType_t now = xTaskGetTickCountFromISR(); if (now > next) { led_state = !led_state; gpio_set_level(GPIO_LED, led_state); next = now + 500 / portTICK_PERIOD_MS; } } //fungsi utama void app_main() { init_hw(); vTaskSuspend(NULL); }
Penjelasan Code
Bagian inisialisasi hardware
static void button_handler(void *arg);
static void init_hw(void)
{
gpio_config_t io_conf;
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.pin_bit_mask = GPIO_LED_PIN_SEL;
io_conf.intr_type = GPIO_INTR_DISABLE;
io_conf.pull_down_en = 0;
io_conf.pull_up_en = 0;
gpio_config(&io_conf);
io_conf.mode = GPIO_MODE_INPUT;
io_conf.pin_bit_mask = GPIO_BUTTON_PIN_SEL;
io_conf.intr_type = GPIO_INTR_NEGEDGE;
io_conf.pull_up_en = 1;
gpio_config(&io_conf);
gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
gpio_isr_handler_add(GPIO_BUTTON, button_handler, NULL);
}
Pada init_hw, akan dilakukan konfigurasi LED sebagai output dan button sebagai input.
gpio_config_t adalah structure untuk mengatur configuration parameters dari GPIO
pin.
Pertama, set configuration values untuk LED menggunakan gpio_config library function.
Kemudian kita lakukan konfigurasi saklar, digunakan internal pull-up resistor untuk membaca value dari saklar GPIO pin. Ketika saklar ditekan, signal akan berubah dari high menjadi low karena terminal lainnya terhubung dengan ground. ISR akan ter-trigger karena interrupt type adalah GPIO_INTR_NEGEDGE.
Perhatian Tidak semua GPIO pins memiliki internal pull-up atau pull-down resistors. Silakan cek datasheet.
Terkahir, inisialisasi ISR service menggunakan gpio_install_isr_service function dan menambahkan saklar handler menggunakan gpio_isr_handler_add function.
Bagian fungsi button_handler.
static TickType_t next = 0;
static bool led_state = false;
static void IRAM_ATTR button_handler(void *arg)
{
TickType_t now = xTaskGetTickCountFromISR();
if (now > next)
{
led_state = !led_state;
gpio_set_level(GPIO_LED, led_state);
next = now + 500 / portTICK_PERIOD_MS;
}
}
Digunakan IRAM_ATTR attribute untuk memerintahkan compiler untuk menyimpan code pada internal random-access memory (RAM) dari ESP32. Karena fungsi adalah ISR dan harus dikerjakan secara cepat, jika tidak hardware akan mencoba load code dari flash, yang dapat menyebabkan aplikasi crash.
xtaskGetTickCountFromISR adalah fungsi dari FreeRTOS task.h library. Mengembalikan count of ticks sejak FreeRTOS scheduler dijalankan. Informasi ini kita gunakan untuk mencegah button-debouncing effect.
Debouncing akan menyebabkan LED flickering ketika button (saklar) ditekan. Idenya disinia adalah menggunakan time
buffer antara dua penekanan untuk memastikan aksi tersebut berbeda, jadi kita dapat mengetahui button memang ditekan bukan debouncing.
Sebetulnya adalah solusi yang lebih baik untuk mencegah efek tersebut, namun untuk saat ini, kita gunakan pendekatan. Pada code digunakan Time buffer adalah 500 milliseconds (ms).
portTICK_PERIOD_MS berisi value dari tick period dalam ms.
Bagian fungsi utama.
void app_main()
{
init_hw();
vTaskSuspend(NULL);
}
fungsi utama akan memanggil fungsi init_hw, kemudian memanggil vTaskSuspend function dari FreeRTOS untuk susped main task dan mencegah exit dari aplikasi.
Sampai disini kita sudah mempelajari menggukan GPIO.