LA M3 COMMUNICATION





LAPORAN AKHIR M3 PERCOBAAN 7

1. Prosedur [kembali]

Percobaan 7

Persiapan Alat dan Bahan:

Pastikan Anda memiliki semua komponen berikut:

  • Raspberry Pi Pico

  • Microcontroller STM32F103C8 (Blue Pill)

  • OLED Display 0.96 inch (I2C)

  • 3 Push Button

  • Resistor 10 kΩ (untuk pull-down atau pull-up tombol)

  • Breadboard

  • Kabel jumper

Koneksi Rangkaian:

Raspberry Pi Pico:

  • Sambungkan pin 3V3 ke jalur power + pada breadboard.

  • Sambungkan pin GND ke jalur ground pada breadboard.

  • Sambungkan pin GPIO sesuai ke STM32F103C8 dan OLED sesuai gambar.

  • Sambungkan jalur data I2C OLED ke Raspberry Pi Pico: SDA dan SCL (biasanya GPIO 4 dan 5, sesuaikan dengan gambar).

STM32F103C8:

  • Sambungkan pin power dan ground sesuai breadboard.

  • Hubungkan pin PB12, PB13, PB14 ke masing-masing push button melalui resistor pull-down.

  • Hubungkan pin I2C OLED ke Raspberry Pi Pico (jika menggunakan STM32 juga berperan sebagai pengontrol OLED).

  • Sambungkan kabel komunikasi antara Raspberry Pi Pico dan STM32F103C8 (ground saling terhubung).

Push Button:

  • Sambungkan satu sisi push button ke pin input STM32F103C8 (PB12, PB13, PB14).

  • Sambungkan sisi lain ke ground melalui resistor 10 kΩ.

  • Pastikan konfigurasi pull-up atau pull-down sesuai pengaturan hardware dan software.

OLED Display:

  • Sambungkan pin VCC OLED ke 3.3V power.

  • Sambungkan pin GND OLED ke ground.

  • Sambungkan pin SDA dan SCL OLED ke pin I2C pada Raspberry Pi Pico (dan/atau STM32F103C8 sesuai rancangan).

Penyesuaian Variabel:

  • Jika diperlukan, sesuaikan nilai resistor pull-up/pull-down agar pembacaan tombol stabil.

  • Tentukan alamat I2C OLED sesuai dengan modul yang digunakan (biasanya 0x3C).

Pengaturan Sumber Daya:

  • Pastikan catu daya 3.3V stabil terhubung ke semua komponen yang membutuhkan.

  • Pastikan ground bersama untuk semua modul.

Pemrograman Microcontroller:

  • Program Raspberry Pi Pico untuk berkomunikasi dengan STM32F103C8 dan OLED melalui I2C atau UART.

  • Program STM32F103C8 untuk membaca status ketiga push button (PB0, PB1, PB2).

  • Ketika tombol ditekan, kirimkan perintah ke Raspberry Pi Pico untuk mengubah tampilan OLED (misal menampilkan teks atau ikon berbeda).

  • Buat logika untuk menampilkan informasi yang sesuai pada OLED berdasarkan input tombol.

Uji Coba:

  • Hidupkan rangkaian dan pastikan semua terhubung dengan baik.

  • Tekan masing-masing push button secara bergantian.

  • Amati perubahan tampilan pada OLED. Pastikan OLED menampilkan respon sesuai tombol yang ditekan.

  • Jika ada komunikasi antara STM32 dan Raspberry Pi Pico, pastikan data diterima dan diproses dengan benar.


2. Hardware dan Diagram Blok [kembali]
  • STM32
STM32 adalah keluarga mikrokontroler berbasis arsitektur ARM Cortex yang dikembangkan oleh STMicroelectronics. Mikrokontroler ini memiliki performa tinggi, konsumsi daya rendah, serta fitur periferal yang lengkap, seperti ADC (Analog to Digital Converter), komunikasi serial (UART, SPI, I2C), dan GPIO yang dapat dikonfigurasi sesuai kebutuhan. STM32 sering digunakan dalam sistem tertanam (embedded systems) untuk berbagai aplikasi, termasuk otomasi, robotika, dan perangkat IoT.
  • Raspberry Pi Pico

  • Raspberry Pi Pico adalah mikrokontroler berbasis RP2040, yaitu chip buatan Raspberry Pi yang memiliki dual-core ARM Cortex-M0+ dengan kecepatan hingga 133 MHz. Mikrokontroler ini digunakan untuk berbagai proyek embedded system, seperti robotika, otomasi, dan pemrosesan sinyal, karena memiliki GPIO (General Purpose Input Output) yang fleksibel serta mendukung pemrograman dengan MicroPython dan C/C++.
  • Breadboard


  • Breadboard adalah sebuah papan yang digunakan untuk merancang dan menguji rangkaian elektronik secara sementara tanpa perlu menyolder komponen. Breadboard memungkinkan perakitan rangkaian secara cepat dan mudah, sehingga sangat berguna dalam prototyping dan eksperimen elektronik.

  • Jumper male to male


  • Kabel jumper Male to Male adalah kabel yang memiliki konektor jantan (male) di kedua ujungnya. Kabel ini biasanya digunakan untuk menghubungkan pin pada board elektronik, seperti Raspberry Pi, Arduino, atau breadboard, dengan komponen lainnya. Kabel jumper male to male sering digunakan dalam rangkaian prototyping atau percobaan karena fleksibilitas dan kemudahannya untuk digunakan.

  • Push Button
Push button adalah saklar atau tombol yang digunakan untuk menghubungkan atau memutuskan sirkuit listrik. Tombol ini biasanya bersifat sementara (momentary), yang berarti ketika tombol ditekan, arus listrik akan mengalir, dan ketika tombol dilepaskan, arus listrik akan terputus. Fungsi utama push button adalah untuk memberikan input atau perintah ke sistem. Dalam rangkaian ini, push button dapat digunakan untuk mengaktifkan atau mengubah status sistem, seperti memulai pembacaan sensor kelembaban tanah atau mengubah mode kerja rangkaian.


  • Resistor

Resistor adalah komponen elektronik yang digunakan untuk membatasi atau mengatur aliran arus listrik dalam suatu rangkaian. Resistor bekerja dengan cara menambah hambatan pada rangkaian, yang bergantung pada nilai resistansi yang diberikan (dalam ohm). Resistor berfungsi untuk mengatur arus listrik yang mengalir pada komponen lain, seperti LED RGB atau sensor. Dalam rangkaian ini, resistor digunakan untuk melindungi LED RGB dari aliran arus yang berlebihan, serta untuk menyesuaikan sinyal yang diterima oleh sensor kelembaban tanah.
  • Blok diagram


3. Rangkaian Simulasi dan Prinsip Kerja [kembali]

  • Rangkaian Simulasi


  • Prinsip Kerja

Rangkaian ini bekerja berdasarkan komunikasi serial UART antara microcontroller STM32F103C8 sebagai pengirim data dan Raspberry Pi Pico sebagai penerima data. Data yang dikirim berupa sinyal status tombol yang ditekan dalam bentuk string, kemudian ditampilkan pada LCD oleh Raspberry Pi Pico. Berikut prinsip kerja secara rinci:

  1. Pembacaan Status Tombol pada STM32F103C8:
    STM32F103C8 memantau tiga tombol yang terhubung ke pin GPIO PB12, PB13, dan PB14.
    Setiap tombol memiliki konfigurasi input dengan pull-up internal, sehingga saat tombol ditekan, pin akan membaca sinyal logika rendah (reset).
    STM32 akan membaca secara terus-menerus status ketiga tombol tersebut.

  2. Pengiriman Data melalui UART oleh STM32F103C8:
    Ketika sebuah tombol terdeteksi ditekan, STM32F103C8 akan mengirimkan string teks yang sesuai dengan tombol tersebut, yaitu "MERAH", "HIJAU", atau "BIRU" menggunakan protokol UART.
    Fungsi HAL_UART_Transmit digunakan untuk mengirimkan data string secara serial dengan baud rate 9600 bps, 8 bit data, 1 stop bit, dan tanpa parity.
    Data dikirim sebagai urutan karakter ASCII dengan tambahan karakter carriage return dan newline (\r\n) sebagai penanda akhir pesan.

  3. Penerimaan dan Pemrosesan Data UART oleh Raspberry Pi Pico:
    Raspberry Pi Pico menginisialisasi UART dengan konfigurasi baud rate yang sama (9600 bps) untuk menerima data serial dari STM32.
    Data yang masuk dibaca secara berkala dengan metode polling, yaitu memeriksa buffer UART apakah terdapat data yang tersedia.
    Setiap data yang diterima berupa baris string dibaca dan didekodekan dari format byte ke string UTF-8.
    Berdasarkan isi string, Raspberry Pi Pico memproses informasi dan mengupdate tampilan pada LCD I2C.

  4. Tampilan Informasi pada LCD oleh Raspberry Pi Pico:
    Jika data yang diterima adalah "MERAH", LCD menampilkan teks "Warna: Merah".
    Jika data "HIJAU", LCD menampilkan "Warna: Hijau".
    Jika data "BIRU", LCD menampilkan "Warna: Biru".
    Jika data lain diterima, LCD menampilkan data tersebut secara default.
    LCD memberikan umpan balik visual yang merepresentasikan status tombol yang ditekan pada STM32.

  5. Sinkronisasi dan Kehandalan Komunikasi:
    Kedua perangkat disinkronkan dalam hal konfigurasi UART agar data dapat dikirim dan diterima dengan benar tanpa kesalahan.
    Pengiriman data menggunakan metode blocking pada STM32 sehingga memastikan data terkirim sempurna sebelum membaca tombol berikutnya.
    Raspberry Pi Pico menggunakan metode polling dengan jeda singkat agar tidak mengganggu proses utama dan memproses data secara real-time.




4. Flowchart dan Listing Program [kembali]
  • Listing Program pada STM32

##include "main.h" #include <string.h> UART_HandleTypeDef huart1; // Fungsi prototipe void SystemClock_Config(void); void MX_GPIO_Init(void); void MX_USART1_UART_Init(void); // Fungsi kirim UART void send_uart(char *text) { HAL_UART_Transmit(&huart1, (uint8_t *)text, strlen(text), HAL_MAX_DELAY); } int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART1_UART_Init(); while (1) { if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12) == GPIO_PIN_RESET) { send_uart("MERAH\r\n"); HAL_Delay(300); while (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12) == GPIO_PIN_RESET); } else if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_13) == GPIO_PIN_RESET) { send_uart("HIJAU\r\n"); HAL_Delay(300); while (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_13) == GPIO_PIN_RESET); } else if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_14) == GPIO_PIN_RESET) { send_uart("BIRU\r\n"); HAL_Delay(300); while (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_14) == GPIO_PIN_RESET); } } } // Konfigurasi clock standar STM32F1 void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; __HAL_RCC_AFIO_CLK_ENABLE(); __HAL_RCC_PWR_CLK_ENABLE(); __HAL_AFIO_REMAP_SWJ_NOJTAG(); // Bebaskan PB3-PB4 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; HAL_RCC_OscConfig(&RCC_OscInitStruct); RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2); } // Inisialisasi UART1 (TX: PA9, RX: PA10) void MX_USART1_UART_Init(void) { huart1.Instance = USART1; huart1.Init.BaudRate = 9600; huart1.Init.WordLength = UART_WORDLENGTH_8B; huart1.Init.StopBits = UART_STOPBITS_1; huart1.Init.Parity = UART_PARITY_NONE; huart1.Init.Mode = UART_MODE_TX_RX; huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart1.Init.OverSampling = UART_OVERSAMPLING_16; HAL_UART_Init(&huart1); } // Inisialisasi GPIO PB12, PB13, PB14 sebagai input pull-up void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); // Konfigurasi input tombol dengan Pull-Up GPIO_InitStruct.Pin = GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); }

  • Raspberry Pi Pico
- Main Program
from machine import I2C, Pin, UART
import utime
from pico_i2c_lcd import I2cLcd

# Inisialisasi UART
uart = UART(0, baudrate=9600, tx=Pin(0), rx=Pin(1))

# Inisialisasi LCD I2C
i2c = I2C(0, scl=Pin(5), sda=Pin(4), freq=400000)
I2C_ADDR = 0x27  # Ganti dengan alamat LCD Anda
I2C_NUM_ROWS = 2
I2C_NUM_COLS = 16
lcd = I2cLcd(i2c, I2C_ADDR, I2C_NUM_ROWS, I2C_NUM_COLS)

# Tunggu LCD siap
utime.sleep_ms(100)
lcd.clear()
lcd.putstr("Menunggu input...")

def process_uart_data(data):
    try:
        decoded = data.decode('utf-8').strip()
        lcd.clear()
        if decoded == "MERAH":
            lcd.putstr("Warna: Merah")
        elif decoded == "HIJAU":
            lcd.putstr("Warna: Hijau")
        elif decoded == "BIRU":
            lcd.putstr("Warna: Biru")
        else:
            lcd.putstr(f"Data: {decoded}")
    except Exception as e:
        lcd.clear()
        lcd.putstr(f"Error: {str(e)}")

while True:
    if uart.any():
        data = uart.readline()
        if data:
            process_uart_data(data)
    utime.sleep_ms(100)  # Beri sedikit jeda

- Program LCD to I2C
# forked from https://github.com/T-622/RPI-PICO-I2C-LCD/
import utime
import gc

from lcd_api import LcdApi
from machine import I2C

# PCF8574 pin definitions
MASK_RS = 0x01       # P0
MASK_RW = 0x02       # P1
MASK_E  = 0x04       # P2

SHIFT_BACKLIGHT = 3  # P3
SHIFT_DATA      = 4  # P4-P7

class I2cLcd(LcdApi):
    
    #Implements a HD44780 character LCD connected via PCF8574 on I2C

    def _init_(self, i2c, i2c_addr, num_lines, num_columns):
        self.i2c = i2c
        self.i2c_addr = i2c_addr
        self.i2c.writeto(self.i2c_addr, bytes([0]))
        utime.sleep_ms(20)   # Allow LCD time to powerup
        # Send reset 3 times
        self.hal_write_init_nibble(self.LCD_FUNCTION_RESET)
        utime.sleep_ms(5)    # Need to delay at least 4.1 msec
        self.hal_write_init_nibble(self.LCD_FUNCTION_RESET)
        utime.sleep_ms(1)
        self.hal_write_init_nibble(self.LCD_FUNCTION_RESET)
        utime.sleep_ms(1)
        # Put LCD into 4-bit mode
        self.hal_write_init_nibble(self.LCD_FUNCTION)
        utime.sleep_ms(1)
        LcdApi._init_(self, num_lines, num_columns)
        cmd = self.LCD_FUNCTION
        if num_lines > 1:
            cmd |= self.LCD_FUNCTION_2LINES
        self.hal_write_command(cmd)
        gc.collect()

    def hal_write_init_nibble(self, nibble):
        # Writes an initialization nibble to the LCD.
        # This particular function is only used during initialization.
        byte = ((nibble >> 4) & 0x0f) << SHIFT_DATA
        self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E]))
        self.i2c.writeto(self.i2c_addr, bytes([byte]))
        gc.collect()
        
    def hal_backlight_on(self):
        # Allows the hal layer to turn the backlight on
        self.i2c.writeto(self.i2c_addr, bytes([1 << SHIFT_BACKLIGHT]))
        gc.collect()
        
    def hal_backlight_off(self):
        #Allows the hal layer to turn the backlight off
        self.i2c.writeto(self.i2c_addr, bytes([0]))
        gc.collect()
        
    def hal_write_command(self, cmd):
        # Write a command to the LCD. Data is latched on the falling edge of E.
        byte = ((self.backlight << SHIFT_BACKLIGHT) |
                (((cmd >> 4) & 0x0f) << SHIFT_DATA))
        self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E]))
        self.i2c.writeto(self.i2c_addr, bytes([byte]))
        byte = ((self.backlight << SHIFT_BACKLIGHT) |
                ((cmd & 0x0f) << SHIFT_DATA))
        self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E]))
        self.i2c.writeto(self.i2c_addr, bytes([byte]))
        if cmd <= 3:
            # The home and clear commands require a worst case delay of 4.1 msec
            utime.sleep_ms(5)
        gc.collect()

    def hal_write_data(self, data):
        # Write data to the LCD. Data is latched on the falling edge of E.
        byte = (MASK_RS |
                (self.backlight << SHIFT_BACKLIGHT) |
                (((data >> 4) & 0x0f) << SHIFT_DATA))
        self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E]))
        self.i2c.writeto(self.i2c_addr, bytes([byte]))
        byte = (MASK_RS |
                (self.backlight << SHIFT_BACKLIGHT) |
                ((data & 0x0f) << SHIFT_DATA))      
        self.i2c.writeto(self.i2c_addr, bytes([byte | MASK_E]))
        self.i2c.writeto(self.i2c_addr, bytes([byte]))
        gc.collect()

- Library LCD 
# forked from https://github.com/T-622/RPI-PICO-I2C-LCD/
import time

class LcdApi:
    
    # Implements the API for talking with HD44780 compatible character LCDs.
    # This class only knows what commands to send to the LCD, and not how to get
    # them to the LCD.
    #
    # It is expected that a derived class will implement the hal_xxx functions.
    #
    # The following constant names were lifted from the avrlib lcd.h header file,
    # with bit numbers changed to bit masks.
    
    # HD44780 LCD controller command set
    LCD_CLR             = 0x01  # DB0: clear display
    LCD_HOME            = 0x02  # DB1: return to home position

    LCD_ENTRY_MODE      = 0x04  # DB2: set entry mode
    LCD_ENTRY_INC       = 0x02  # DB1: increment
    LCD_ENTRY_SHIFT     = 0x01  # DB0: shift

    LCD_ON_CTRL         = 0x08  # DB3: turn lcd/cursor on
    LCD_ON_DISPLAY      = 0x04  # DB2: turn display on
    LCD_ON_CURSOR       = 0x02  # DB1: turn cursor on
    LCD_ON_BLINK        = 0x01  # DB0: blinking cursor

    LCD_MOVE            = 0x10  # DB4: move cursor/display
    LCD_MOVE_DISP       = 0x08  # DB3: move display (0-> move cursor)
    LCD_MOVE_RIGHT      = 0x04  # DB2: move right (0-> left)

    LCD_FUNCTION        = 0x20  # DB5: function set
    LCD_FUNCTION_8BIT   = 0x10  # DB4: set 8BIT mode (0->4BIT mode)
    LCD_FUNCTION_2LINES = 0x08  # DB3: two lines (0->one line)
    LCD_FUNCTION_10DOTS = 0x04  # DB2: 5x10 font (0->5x7 font)
    LCD_FUNCTION_RESET  = 0x30  # See "Initializing by Instruction" section

    LCD_CGRAM           = 0x40  # DB6: set CG RAM address
    LCD_DDRAM           = 0x80  # DB7: set DD RAM address

    LCD_RS_CMD          = 0
    LCD_RS_DATA         = 1

    LCD_RW_WRITE        = 0
    LCD_RW_READ         = 1

    def _init_(self, num_lines, num_columns):
        self.num_lines = num_lines
        if self.num_lines > 4:
            self.num_lines = 4
        self.num_columns = num_columns
        if self.num_columns > 40:
            self.num_columns = 40
        self.cursor_x = 0
        self.cursor_y = 0
        self.implied_newline = False
        self.backlight = True
        self.display_off()
        self.backlight_on()
        self.clear()
        self.hal_write_command(self.LCD_ENTRY_MODE | self.LCD_ENTRY_INC)
        self.hide_cursor()
        self.display_on()

    def clear(self):
        # Clears the LCD display and moves the cursor to the top left corner
        self.hal_write_command(self.LCD_CLR)
        self.hal_write_command(self.LCD_HOME)
        self.cursor_x = 0
        self.cursor_y = 0

    def show_cursor(self):
        # Causes the cursor to be made visible
        self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY |
                               self.LCD_ON_CURSOR)

    def hide_cursor(self):
        # Causes the cursor to be hidden
        self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY)

    def blink_cursor_on(self):
        # Turns on the cursor, and makes it blink
        self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY |
                               self.LCD_ON_CURSOR | self.LCD_ON_BLINK)

    def blink_cursor_off(self):
        # Turns on the cursor, and makes it no blink (i.e. be solid)
        self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY |
                               self.LCD_ON_CURSOR)

    def display_on(self):
        # Turns on (i.e. unblanks) the LCD
        self.hal_write_command(self.LCD_ON_CTRL | self.LCD_ON_DISPLAY)

    def display_off(self):
        # Turns off (i.e. blanks) the LCD
        self.hal_write_command(self.LCD_ON_CTRL)

    def backlight_on(self):
        # Turns the backlight on.
        
        # This isn't really an LCD command, but some modules have backlight
        # controls, so this allows the hal to pass through the command.
        self.backlight = True
        self.hal_backlight_on()

    def backlight_off(self):
        # Turns the backlight off.

        # This isn't really an LCD command, but some modules have backlight
        # controls, so this allows the hal to pass through the command.
        self.backlight = False
        self.hal_backlight_off()

    def move_to(self, cursor_x, cursor_y):
        # Moves the cursor position to the indicated position. The cursor
        # position is zero based (i.e. cursor_x == 0 indicates first column).
        self.cursor_x = cursor_x
        self.cursor_y = cursor_y
        addr = cursor_x & 0x3f
        if cursor_y & 1:
            addr += 0x40    # Lines 1 & 3 add 0x40
        if cursor_y & 2:    # Lines 2 & 3 add number of columns
            addr += self.num_columns
        self.hal_write_command(self.LCD_DDRAM | addr)

    def putchar(self, char):
        # Writes the indicated character to the LCD at the current cursor
        # position, and advances the cursor by one position.
        if char == '\n':
            if self.implied_newline:
                # self.implied_newline means we advanced due to a wraparound,
                # so if we get a newline right after that we ignore it.
                pass
            else:
                self.cursor_x = self.num_columns
        else:
            self.hal_write_data(ord(char))
            self.cursor_x += 1
        if self.cursor_x >= self.num_columns:
            self.cursor_x = 0
            self.cursor_y += 1
            self.implied_newline = (char != '\n')
        if self.cursor_y >= self.num_lines:
            self.cursor_y = 0
        self.move_to(self.cursor_x, self.cursor_y)

    def putstr(self, string):
        # Write the indicated string to the LCD at the current cursor
        # position and advances the cursor position appropriately.
        for char in string:
            self.putchar(char)

    def custom_char(self, location, charmap):
        # Write a character to one of the 8 CGRAM locations, available
        # as chr(0) through chr(7).
        location &= 0x7
        self.hal_write_command(self.LCD_CGRAM | (location << 3))
        self.hal_sleep_us(40)
        for i in range(8):
            self.hal_write_data(charmap[i])
            self.hal_sleep_us(40)
        self.move_to(self.cursor_x, self.cursor_y)

    def hal_backlight_on(self):
        # Allows the hal layer to turn the backlight on.
        # If desired, a derived HAL class will implement this function.
        pass

    def hal_backlight_off(self):
        # Allows the hal layer to turn the backlight off.
        # If desired, a derived HAL class will implement this function.
        pass

    def hal_write_command(self, cmd):
        # Write a command to the LCD.
        # It is expected that a derived HAL class will implement this function.
        raise NotImplementedError

    def hal_write_data(self, data):
        # Write data to the LCD.
        # It is expected that a derived HAL class will implement this function.
        raise NotImplementedError

    def hal_sleep_us(self, usecs):
        # Sleep for some time (given in microseconds)
        time.sleep_us(usecs)
  • Flowchart


5. Video Demo [kembali]



6. Analisa [kembali]

1. Analisa bagaimana konfigurasi rangkaian dan program dari percobaan yang telah dilakukan!
Jawab :
1. Rangkaian:
  • STM32F103C8 menggunakan tiga tombol yang terhubung ke pin GPIO PB12, PB13, dan PB14 dengan konfigurasi input pull-up.
  • UART1 STM32 dikonfigurasikan pada pin TX (PA9) dan RX (PA10) dengan baud rate 9600, 8 bit data, 1 stop bit, tanpa parity.
  • Raspberry Pi Pico menggunakan UART0 pada pin GPIO0 (TX) dan GPIO1 (RX) juga dengan baud rate 9600 untuk komunikasi serial.
  • OLED LCD I2C terhubung ke Raspberry Pi Pico melalui pin SDA dan SCL (GPIO4 dan GPIO5) dengan alamat I2C 0x27.

2. Program:
  • STM32 memonitor status tombol secara terus menerus. Saat tombol ditekan, STM32 mengirimkan string teks warna ("MERAH", "HIJAU", "BIRU") melalui UART.
  • Raspberry Pi Pico membaca data UART secara polling, mengubah data byte menjadi string, lalu menampilkan hasilnya pada LCD I2C sesuai isi pesan.
  • Program STM32 menggunakan HAL library dengan fungsi HAL_UART_Transmit untuk pengiriman data.
  • Program Raspberry Pi Pico menggunakan modul UART bawaan MicroPython dan library LCD I2C untuk menampilkan karakter.

2. ⁠Jelaskan bagaimana proses komunikasi yang terjadi pada percobaan (UART/SPI/ 2C) !
Jawab :

1. Komunikasi UART (Universal Asynchronous Receiver Transmitter)
-Fungsi dan Peran pada Percobaan
UART berperan sebagai media komunikasi serial asinkron antara dua mikrokontroler, yaitu STM32F103C8 sebagai pengirim data dan Raspberry Pi Pico sebagai penerima data. Tujuan utama komunikasi ini adalah mengirimkan informasi status tombol yang ditekan pada STM32 dalam bentuk string teks, yang nantinya akan diproses dan ditampilkan pada LCD yang terhubung ke Raspberry Pi Pico.
-Proses Pengiriman Data
STM32 terus-menerus memonitor tiga tombol di pin PB12, PB13, dan PB14. Ketika salah satu tombol ditekan (dengan konfigurasi pull-up internal), pin input membaca level logika rendah (active low). Setelah tombol terdeteksi ditekan, STM32 memanggil fungsi send_uart() yang menggunakan HAL_UART_Transmit untuk mengirimkan string teks berisi nama warna yang sesuai ("MERAH", "HIJAU", "BIRU"). Data string tersebut dikonversi menjadi rangkaian byte ASCII dan dikirim secara serial melalui pin TX STM32 (PA9) ke jalur komunikasi UART. Setiap pengiriman diakhiri dengan karakter carriage return dan newline (\r\n) sebagai penanda akhir pesan agar penerima dapat membedakan satu pesan dengan pesan berikutnya.
- Proses Penerimaan Data
Raspberry Pi Pico yang terhubung pada jalur RX (GPIO1) secara periodik mengecek buffer UART menggunakan uart.any() untuk mengetahui apakah ada data yang masuk. Ketika data tersedia, Raspberry Pi Pico membaca satu baris data menggunakan uart.readline(), yang membaca byte hingga karakter newline. Data byte yang diterima didekode menjadi string UTF-8 dan diproses untuk menentukan perintah tampilan pada LCD.

2. Komunikasi I2C (Inter-Integrated Circuit)
- Fungsi dan Peran pada Percobaan
I2C digunakan untuk komunikasi antara Raspberry Pi Pico dan modul LCD I2C 16x2 yang dipasang pada percobaan. Raspberry Pi Pico berperan sebagai master yang mengontrol dan mengirim data serta perintah ke slave yaitu LCD, menggunakan hanya dua jalur: SDA (Serial Data) dan SCL (Serial Clock).
- Proses Komunikasi
Raspberry Pi Pico memulai komunikasi dengan mengirimkan sinyal start pada bus I2C. Pico mengirimkan alamat slave LCD (0x27 pada percobaan) dengan bit read/write. Setelah LCD merespon dengan ACK (acknowledge), Raspberry Pi Pico mengirim data perintah atau data karakter secara berurutan. Data yang dikirim berupa perintah untuk mengatur mode layar, posisi kursor, atau karakter yang ingin ditampilkan. Setiap data diikuti oleh sinyal clock (SCL) untuk sinkronisasi penerimaan oleh LCD. Raspberry Pi Pico menggunakan library pico_i2c_lcd untuk memudahkan kontrol layar dan pemformatan teks.
- Alur Penggunaan I2C pada Percobaan
Raspberry Pi Pico menerima data warna dari STM32 melalui UART. Setelah data diproses dan diinterpretasi, Raspberry Pi Pico memanggil fungsi library I2C LCD untuk membersihkan layar (lcd.clear()) dan menampilkan teks baru (lcd.putstr()) sesuai warna yang diterima. Semua perintah dan data ini dikirim melalui protokol I2C yang terhubung fisik pada jalur SDA dan SCL dengan LCD.

3. ⁠Jelaskan bagaimana proses data dikirimkan hingga dapat tampil sebagai karakter pada LCD!
Jawab :
  • STM32 membaca status tombol dan saat tombol ditekan mengirimkan string warna melalui UART.
  • Data string dikirim byte per byte melalui pin TX STM32, melalui kabel ke pin RX Raspberry Pi Pico.
  • Raspberry Pi Pico melakukan pembacaan data byte secara serial di buffer UART.
  • Setelah satu baris data lengkap diterima (berdasarkan karakter newline), data didekode dari byte menjadi string UTF-8.
  • String hasil decode ini diproses dalam program Python pada Raspberry Pi Pico untuk menentukan teks yang akan ditampilkan.
  • Library I2C LCD dipanggil untuk membersihkan layar dan menampilkan teks baru yang sesuai (misal "Warna: Merah").
  • Dengan demikian, status tombol pada STM32 dapat terlihat secara visual di LCD Raspberry Pi Pico.

4. ⁠Analisa penyebab kesalahan yang terjadi saat diawal percobaan!
Jawab :
Berdasarkan percobaan yang dilakukan, kesalahan pada awal percobaan diakibatkan oleh :
  • Ketidaksesuaian nilai baudrate antara STM32F103C8 dengan Raspberry Pi Pico, dimana nilai baudrate raspberry pi pico bernilai 9600 sedangkan STM32 bernilai 115200. Nilai baudrate antara kedua mikrokontroler harus disesuaikan agar data dapat diterima dengan benar. Oleh karena itu, nilai baudrate kedua mikrokontroler dijadikan 9600.
  • Kesalahan pada program main raspberry pi pico, dimana transmitt (Tx) diberikan pin 0 dan receiver (Rx) pin 1. Sehingga, nilai pin harus disesuaikan yaitu Tx = pin(1) dan Rx = pin (0)



7. Download file [kembali]

Komentar

Postingan populer dari blog ini

KELEBIHAN DAN KEKURANGAN MENJADI SEORANG PEMIMPIN

KOMITMEN TERHADAP KESELAMATAN DAN RESIKO DALAM PEKERJAAN