Pendahuluan
UART adalah komuniskasi asynchronous dimana kecepatan data transmisi (baud rate) sudah ditentukan.
I2C dan SPI disebut synchronous karena terdapat common clock yang disediakan bus master (MCU), seluruh device akan menggunakan common clock untuk send/receive data.
Sementara pada UART, masing-masing device memiliki clock terpisah dan transmisi data dicapai dengan common UART setting pada aplikasi. UART parameter yang digunakan adalah:
- Baud reate: kecepatan yang digunakan untuk pertukaran data. Contoh 9600 baud berart 9600 bits data per second.
- Packet definition
- Jumlah bits paket data.
- Parity bits, berfungsi untuk memastikan tidak bit yang berubah selama transmisi.
- Angka stop bits, 1 atau 2.
Misalnya, UART communication 9600, 8N1, berarti baud rate adalah 9600, terdapat 8 bits dalam sebuah paket, tidak ada parity dan 1 stop bit.
Baik I2C dan SPI mendukung bus communication, oleh karena itu, dapat terdapat lebih dari dua device dalam satu jalur. Sedangkan untuk UART hanya terdapat 2 yang dapat melakukan pertukaran data. Untuk signal lines, TX untuk transmit, dan RX untuk receive, lihat diagram dibawah.
Project UART Communication
ESP32 terdapat tiga UART controllers, berarti, kita dapat menggunakan tiga koneksi UART. Pada ESP32 devkit, salah satu dari UART controllers tersebut dicadangkan untuk serial communication dengan PC melalui USB untuk keperluan programming dan serial print. Contohnya printf function menggunakan UART controller.
Untuk keperluan modul ini, kita gunakan dua devkit boards, yang akan kita hubungkan melalui UART. Salah satu terdapat sensor DHT11 dan akan mengirim pembacaan temperature ke devkit lainnya.
Devkit kedua akan menampilkan data tersebut lewt USB dan kita monitor melalui aplikasi serial monitor yang disediakan PlatformIO
Diagram
Code
Kita perlu membuat 2 buah code. ESP32-1 untuk sender, dan ESP32-2 untuk receiver.
ESP32-1 akan membaca data dari DHT11 kemudian mengirimkan data tersebut melalui UART2-TX pin. ESP32-2 akan menunggu data melalui UART2-RX pin dan akan print data tersebut ke serial monitor
Code ESP32-1
Mari kita mulai membuat program untuk ESP32-1. Buka file main.c, tambahkan code berikut:
//esp32-1 //bagian import library #include "dht.h" #include <freertos/FreeRTOS.h> #include <freertos/task.h> #include <stdint.h> #include "driver/uart.h" #define DHT11_PIN 18 #define UART_PORT UART_NUM_2 #define TXD_PIN 17 #define RXD_PIN 16 #define UART_BUFF_SIZE 1024 //bagian hardware init static void init_hw(void) { const uart_config_t uart_config = { .baud_rate = 9600, .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, .source_clk = UART_SCLK_APB, }; uart_driver_install(UART_PORT, UART_BUFF_SIZE, 0, 0, NULL,0); uart_param_config(UART_PORT, &uart_config); uart_set_pin(UART_PORT, TXD_PIN, RXD_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); } //bagian read dht11 static void read_dht11(void *arg) { int16_t humidity = 0, temperature = 0; char buff[1]; while (1) { vTaskDelay(2000 / portTICK_PERIOD_MS); dht_read_data(DHT_TYPE_DHT11, (gpio_num_t)DHT11_PIN, &humidity, &temperature); buff[0] = (char)(temperature / 10); uart_write_bytes(UART_PORT, buff, 1); } } //bagian main function void app_main() { init_hw(); xTaskCreate(read_dht11, "dht11", configMINIMAL_STACK_SIZE * 8, NULL, 5, NULL); }
Penjelasan Code Untuk ESP32-1
Pada init_hw, kita definisikan configuration variable, uart_config, yang berisi setting untuk UART communication; yaitu 9600,8N1.
Fungsi uart_driver_install akan mencadangkan UART controller dan RX/TX buffer memories. Untuk TX buffer size digunakan nilai 0, yang berarti transmit function akan mem-block task sampai data selesai dikirim. Hal ini tidak masalah untuk keperluan pada aplikasi ini.
Kemudian, kita set parameter UART communication dengan memanggil uart_param_config dengan parameter uart_config. Terakhir kita set RX/TX pin dengan fungsi uart_set_pin.
Pada read_dht11, kita baca temperature setiap 2 seconds. Kemudian update buffer dengan hasil bacaan sensor dan panggil uart_write_bytes dengan paramter UART channel, buffer, dan buffer size.
Pada app_main, kita panggil init_hw dan buat task untuk pass control ke fungsi read_dht11.
Code ESP32-2
//bagian import library #include <freertos/FreeRTOS.h> #include <freertos/task.h> #include <stdint.h> #include "driver/uart.h" #include <stdio.h> #define UART_PORT UART_NUM_2 #define TXD_PIN 17 #define RXD_PIN 16 #define UART_BUFF_SIZE 1024 static void init_hw(void) { const uart_config_t uart_config = { .baud_rate = 9600, .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, .source_clk = UART_SCLK_APB, }; uart_driver_install(UART_PORT, UART_BUFF_SIZE, 0, 0, NULL,0); uart_param_config(UART_PORT, &uart_config); uart_set_pin(UART_PORT, TXD_PIN, RXD_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); } //bagian read uart static void read_uart(void *arg) { uint8_t buff[UART_BUFF_SIZE]; while (1) { if (uart_read_bytes(UART_PORT, buff, UART_BUFF_SIZE, 2000 / portTICK_PERIOD_MS) > 0) { printf("temp: %d\n", (int)buff[0]); } } } //bagian main function void app_main() { init_hw(); xTaskCreate(read_uart, "uart", configMINIMAL_STACK_SIZE *8, NULL, 5, NULL); }
Penjelasan Code ESP32-2
Pada bagian import library, proses inisialisasi sama persis dengan code sender. Pada prakteknya kita dapat gunakan UART controller yang berbeda, misal UART_NUM_1, atau menggunakan pin TX dan RX yang berbeda. Yang penting adalah konfigurasi baud rate, data bits, parity dan stop bit harus sama dengan sender.
//bagian import library #include <freertos/FreeRTOS.h> #include <freertos/task.h> #include <stdint.h> #include "driver/uart.h" #include <stdio.h> #define UART_PORT UART_NUM_2 #define TXD_PIN 17 #define RXD_PIN 16 #define UART_BUFF_SIZE 1024 static void init_hw(void) { const uart_config_t uart_config = { .baud_rate = 9600, .data_bits = UART_DATA_8_BITS, .parity = UART_PARITY_DISABLE, .stop_bits = UART_STOP_BITS_1, .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, .source_clk = UART_SCLK_APB, }; uart_driver_install(UART_PORT, UART_BUFF_SIZE, 0, 0, NULL,0); uart_param_config(UART_PORT, &uart_config); uart_set_pin(UART_PORT, TXD_PIN, RXD_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); } //bagian read uart static void read_uart(void *arg) { uint8_t buff[UART_BUFF_SIZE]; while (1) { if (uart_read_bytes(UART_PORT, buff, UART_BUFF_SIZE, 2000 / portTICK_PERIOD_MS) > 0) { printf("temp: %d\n", (int)buff[0]); } } } //bagian main function void app_main() { init_hw(); xTaskCreate(read_uart, "uart", configMINIMAL_STACK_SIZE *8, NULL, 5, NULL); }
Penjelasan Code ESP32-2
Pada fungsi read_uart, kita panggil uart_read_bytes dengan paramter buff, dimana kita akan menerima data. Fungsi uart_read_bytes akan menunggu selama 2 seconds, jika ada data yang diterima, print ke serial monitor.
Kita dapat mengatur timeout value berapa saja, namun, kita mengetahui sender mengrim data setiap 2 seconds.
Sampai disini kita sudah mempelajari menggukana UART communication, yang penting untuk digunakan jika kita akan menghubungkan dua MCU yang berbeda. Tidak harus menggunakan model yang sama, yang penting adalah konfigurasi UART sama.