Laporan Akhir M4

    

        
  

MODUL 4

Automatic Solar Panel Cleaning System Pada PLTS Pasca Bencana Berbasis STM32BluePill




1. Pendahuluan [kembali]
    Pemanfaatan Pembangkit Listrik Tenaga Surya (PLTS) sebagai sumber energi alternatif semakin
    penting, terutama pada kondisi pascabencana ketika akses terhadap jaringan listrik konvensional
    terbatas. Namun, performa panel surya sangat dipengaruhi oleh kebersihan permukaannya. Debu,
    lumpur, abu vulkanik, dan berbagai kotoran lainnya yang sering muncul setelah bencana dapat
    menghalangi penyerapan cahaya matahari sehingga menurunkan efisiensi dan daya keluaran panel
    surya.

    Untuk mengatasi permasalahan tersebut, dirancang sebuah Automatic Solar Panel Cleaning System
    berbasis mikrokontroler STM32 Blue Pill yang mampu melakukan pembersihan panel secara
    otomatis. Sistem memanfaatkan sensor BH1750 untuk mengukur intensitas cahaya matahari, sensor
    INA219 untuk memantau tegangan keluaran panel surya, serta limit switch sebagai pendeteksi posisi
    akhir gerakan wiper. Data dari sensor-sensor tersebut digunakan sebagai dasar pengambilan
    keputusan dalam proses pembersihan panel.

    Sistem ini dilengkapi dengan motor wiper sebagai mekanisme pembersih, pompa air mini DC untuk
    membantu proses pencucian permukaan panel, serta LCD sebagai media monitoring kondisi sistem
    secara real-time. Dengan adanya sistem pembersihan otomatis ini, diharapkan performa panel surya
    dapat tetap optimal tanpa memerlukan pengawasan dan pembersihan manual secara terus-menerus,
    sehingga sangat sesuai diterapkan pada PLTS pascabencana.

2. Tujuan [kembali]
    1) Menerapkan konsep dan keterampilan yang diperoleh pada praktikum Mikroprosesor dan
        Mikrokontroler dalam pengembangan sistem otomatis berbasis STM32 untuk menyelesaikan
        permasalahan nyata pada pemeliharaan panel surya.
    2) Mengintegrasikan sensor BH1750 dan INA219 untuk memantau intensitas cahaya matahari serta
        tegangan keluaran panel surya sebagai indikator kondisi panel.
    3) Mengotomatisasi proses pembersihan panel surya menggunakan motor wiper dan pompa air
        berdasarkan hasil pembacaan sensor.
    4) Mengimplementasikan limit switch sebagai sensor pembatas untuk menghentikan pergerakan
        wiper pada posisi akhir pembersihan.
    5) Menampilkan kondisi panel surya, status sistem, dan data hasil pembacaan sensor secara real-time
        melalui LCD Display.

3. Alat dan Komponen [kembali]
    1) STM32 Blue Pill

    2) Sensor BH1750
        

    3) Sensor INA219

    4) Limit Switch Sensor

    5) LCD LM016L

    6) Driver Motor L298

    7) Pompa Air

    8) Motor DC

    9) Breadboard

    10) Jumper

4. Landasan Teori [kembali]
    A. Pembangkit Listrik Tenaga Surya (PLTS)
         Pembangkit Listrik Tenaga Surya (PLTS) merupakan sistem pembangkit energi listrik yang
         memanfaatkan energi radiasi matahari sebagai sumber energi utama. PLTS bekerja dengan
         mengubah energi cahaya matahari menjadi energi listrik menggunakan perangkat yang disebut
         panel surya atau photovoltaic (PV). Energi listrik yang dihasilkan dapat digunakan secara
         langsung untuk menyuplai beban listrik maupun disimpan terlebih dahulu pada baterai untuk
         digunakan pada waktu tertentu.

         PLTS menjadi salah satu sumber energi terbarukan yang banyak dikembangkan karena ramah
         lingkungan, tidak menghasilkan emisi gas buang, dan memanfaatkan sumber energi yang tersedia
         secara melimpah. Selain itu, PLTS sangat cocok digunakan pada daerah terpencil maupun wilayah
         pascabencana yang mengalami gangguan pasokan listrik dari jaringan utama.

         Kinerja PLTS dipengaruhi oleh beberapa faktor, seperti intensitas cahaya matahari, suhu
         lingkungan, sudut kemiringan panel, serta kondisi kebersihan permukaan panel surya. Semakin
         tinggi intensitas cahaya yang diterima panel, semakin besar energi listrik yang dapat dihasilkan.
         Sebaliknya, adanya debu, lumpur, abu vulkanik, atau kotoran lain yang menutupi permukaan panel
         dapat mengurangi jumlah cahaya yang diterima sel fotovoltaik sehingga menyebabkan penurunan
         tegangan dan daya keluaran panel. Oleh karena itu, diperlukan sistem pemeliharaan yang mampu
         menjaga kebersihan panel agar performanya tetap optimal.

    B. Mikrokontroler STM32 Blue Pill
         STM32 Blue Pill merupakan papan pengembangan berbasis mikrokontroler STM32F103C8T6
         yang menggunakan arsitektur ARM Cortex-M3 32-bit. Mikrokontroler ini memiliki kecepatan
         pemrosesan hingga 72 MHz, memori Flash sebesar 64 KB, SRAM sebesar 20 KB, serta berbagai
         periferal pendukung seperti GPIO, ADC, PWM, USART, SPI, dan I²C.

         STM32 Blue Pill banyak digunakan dalam sistem embedded karena memiliki performa yang
         tinggi, konsumsi daya yang relatif rendah, serta kemampuan komunikasi yang lengkap. Selain itu,
         STM32 dapat diprogram menggunakan bahasa C melalui perangkat lunak STM32CubeIDE.

         Pada sistem Automatic Solar Panel Cleaning System, STM32 Blue Pill berfungsi sebagai pusat
         pengendali yang bertugas membaca data dari sensor BH1750, sensor INA219, dan limit switch.
         Data tersebut kemudian diolah untuk menentukan kondisi panel surya. Berdasarkan hasil
         pengolahan data, STM32 akan mengendalikan motor wiper, pompa air, serta menampilkan
         informasi kondisi sistem pada LCD.

    C. Komunikasi I2C (Inter-integrated Circuit)
         Inter-Integrated Circuit (I²C) merupakan protokol komunikasi serial sinkron yang dikembangkan
         oleh Philips Semiconductor untuk memfasilitasi komunikasi antarperangkat elektronik
         menggunakan dua jalur komunikasi. Jalur tersebut terdiri dari Serial Data (SDA) dan Serial Clock
         (SCL).

         Pada sistem I²C terdapat perangkat master dan slave. Master bertanggung jawab mengendalikan
         jalannya komunikasi, sedangkan slave merespons perintah yang dikirim oleh master. Setiap
         perangkat slave memiliki alamat unik sehingga beberapa perangkat dapat dihubungkan dalam satu
         jalur komunikasi yang sama.

         Keunggulan I²C terletak pada efisiensi penggunaan pin mikrokontroler karena hanya
         membutuhkan dua jalur komunikasi meskipun digunakan oleh banyak perangkat. Selain itu, I²C
         mendukung komunikasi dua arah sehingga memungkinkan pertukaran data yang fleksibel antara
         mikrokontroler dan perangkat eksternal.

         Dalam penelitian ini, komunikasi I²C digunakan untuk menghubungkan STM32 Blue Pill dengan
         sensor BH1750, sensor INA219, dan LCD.

    D. Sensor Intensitas Cahaya BH1750
         BH1750 merupakan sensor digital yang digunakan untuk mengukur intensitas cahaya dalam
         satuan lux. Sensor ini dilengkapi dengan fotodioda dan ADC internal sehingga mampu mengubah
         intensitas cahaya menjadi data digital secara langsung.

         BH1750 memiliki tingkat akurasi yang cukup baik serta mampu melakukan pengukuran pada
         rentang intensitas cahaya yang luas. Sensor ini juga memiliki konsumsi daya yang rendah
         sehingga cocok digunakan pada sistem monitoring berbasis mikrokontroler.

         Pada sistem ini, BH1750 digunakan untuk mengukur intensitas cahaya matahari yang diterima
         panel surya. Data intensitas cahaya tersebut digunakan sebagai salah satu parameter dalam
         menentukan apakah penurunan tegangan panel disebabkan oleh kurangnya cahaya matahari atau
         karena adanya kotoran pada permukaan panel.

    E. Sensor Tegangan dan Arus INA219
         INA219 merupakan sensor digital yang digunakan untuk mengukur tegangan, arus, dan daya
         listrik. Sensor ini bekerja menggunakan resistor shunt yang berfungsi menghasilkan tegangan
         jatuh kecil ketika arus mengalir melaluinya. Tegangan tersebut kemudian diukur menggunakan
         penguat diferensial dan ADC internal.

         Selain mengukur arus, INA219 juga mampu mengukur tegangan bus dan menghitung daya listrik
         secara otomatis. Hasil pengukuran disimpan dalam register internal dan dapat dibaca oleh
         mikrokontroler melalui komunikasi I²C.

         Pada penelitian ini, INA219 digunakan untuk memantau tegangan keluaran panel surya. Nilai
         tegangan yang diperoleh akan dibandingkan dengan intensitas cahaya yang dibaca oleh BH1750
         untuk menentukan kondisi kebersihan panel surya.

    F. Limit Switch 
         Limit switch merupakan sensor mekanik yang digunakan untuk mendeteksi posisi atau batas
         gerakan suatu objek. Sensor ini bekerja melalui perubahan kondisi kontak listrik ketika
         aktuatornya mendapat tekanan.

         Dalam sistem pembersih panel surya otomatis, limit switch dipasang pada ujung lintasan wiper.
         Ketika wiper mencapai posisi akhir, limit switch akan mengirimkan sinyal ke STM32 sehingga
         motor dapat dihentikan secara otomatis.

    G. Driver Motor L298
         L298 merupakan driver motor tipe Dual H-Bridge yang digunakan untuk mengendalikan arah dan
         kecepatan motor DC. Driver ini memungkinkan mikrokontroler mengendalikan motor yang
         membutuhkan arus dan tegangan lebih besar daripada kemampuan keluaran mikrokontroler.

         Dalam penelitian ini, L298 digunakan untuk mengendalikan motor wiper yang bergerak sepanjang
         permukaan panel surya saat proses pembersihan berlangsung.

    H. Pulse Width Modulation (PWM)
         PWM merupakan teknik pengaturan daya listrik menggunakan sinyal digital dengan cara
         mengubah lebar pulsa dalam satu periode tertentu. Parameter utama PWM adalah duty cycle yang
         menunjukkan persentase waktu sinyal berada pada kondisi HIGH dalam satu periode.

         Semakin besar duty cycle, semakin besar daya rata-rata yang diberikan kepada beban. Teknik
         PWM banyak digunakan dalam pengendalian motor karena lebih efisien dibandingkan metode
         pengaturan tegangan secara langsung.

         Pada sistem ini, PWM digunakan untuk mengendalikan kecepatan motor wiper sehingga proses
         pembersihan panel dapat berlangsung lebih stabil dan efisien.

    I. LCD Display
        Liquid Crystal Display (LCD) merupakan perangkat output yang digunakan untuk menampilkan
        informasi dalam bentuk karakter, angka, maupun simbol. LCD bekerja dengan memanfaatkan sifat
        kristal cair yang dapat mengatur intensitas cahaya ketika diberikan medan listrik. Berbeda dengan
        OLED yang setiap pikselnya dapat memancarkan cahaya sendiri, LCD memerlukan sumber cahaya
        tambahan berupa backlight agar karakter yang ditampilkan dapat terlihat oleh pengguna.

        LCD LM016L merupakan salah satu jenis LCD karakter 16×2 yang mampu menampilkan 16
        karakter pada setiap baris dan terdiri dari dua baris tampilan. Modul ini menggunakan pengendali
        (controller) HD44780 yang telah menjadi standar pada sebagian besar LCD karakter. LCD
        LM016L memiliki 16 pin yang terdiri dari pin catu daya, pin pengatur kontras, pin kontrol, serta
        pin data. Komunikasi antara mikrokontroler dan LCD dapat dilakukan menggunakan mode 8-bit
        maupun 4-bit. Pada mode 4-bit, jumlah pin yang digunakan lebih sedikit sehingga lebih
        menghemat penggunaan pin mikrokontroler.

        Prinsip kerja LCD LM016L dimulai ketika mikrokontroler mengirimkan data atau perintah ke LCD
        melalui pin data dan pin kontrol. Data yang diterima akan diproses oleh pengendali HD44780 dan
        ditampilkan dalam bentuk karakter pada layar LCD. Karakter yang ditampilkan tersusun dari
        matriks titik (dot matrix) sehingga dapat membentuk huruf, angka, maupun simbol tertentu. Selain
        menampilkan data, LCD juga dapat digunakan untuk menampilkan status operasi sistem secara
        real-time sehingga memudahkan pengguna dalam melakukan pemantauan.

        Pada sistem Automatic Solar Panel Cleaning System, LCD LM016L digunakan sebagai media
        antarmuka pengguna (Human Machine Interface/HMI) untuk menampilkan informasi kondisi
        sistem secara langsung. Informasi yang ditampilkan meliputi nilai intensitas cahaya yang dibaca
        sensor BH1750, tegangan keluaran panel surya yang diukur oleh sensor INA219, status kondisi
        panel surya, serta status kerja motor wiper dan pompa air. Dengan adanya LCD, pengguna dapat
        memantau kondisi sistem secara real-time tanpa memerlukan perangkat tambahan seperti komputer
        atau smartphone.

    J. Sistem Pembersihan Panel Surya Otomatis
        Sistem pembersihan panel surya otomatis merupakan sistem yang dirancang untuk menjaga
        kebersihan panel surya tanpa intervensi pengguna. Sistem bekerja dengan memanfaatkan data dari
        sensor BH1750 dan INA219 untuk menentukan kondisi panel surya.

        Apabila intensitas cahaya yang diterima panel tinggi namun tegangan keluaran panel lebih rendah
        dari nilai referensi, maka sistem mengidentifikasi adanya penurunan performa akibat kotoran pada
        permukaan panel. Selanjutnya STM32 akan mengaktifkan pompa air untuk membasahi permukaan
        panel dan menggerakkan motor wiper untuk melakukan pembersihan. Setelah wiper mencapai
        ujung panel dan menekan limit switch, motor akan dihentikan sehingga proses pembersihan selesai.
        Dengan mekanisme tersebut, panel surya dapat dipertahankan dalam kondisi bersih sehingga
        efisiensi pembangkitan energi listrik tetap optimal.

5. Flowchart dan Listing Program [kembali]
    A. Flowchart
    B. Listing Program
        #include "main.h"

        /* ===================== HANDLE ===================== */

        ADC_HandleTypeDef hadc1;

        /* ===================== LCD LM016L PIN ===================== */

        #define LCD_RS_PORT GPIOB
        #define LCD_RS_PIN  GPIO_PIN_10

        #define LCD_E_PORT  GPIOB
        #define LCD_E_PIN   GPIO_PIN_11

        #define LCD_D4_PORT GPIOB
        #define LCD_D4_PIN  GPIO_PIN_12

        #define LCD_D5_PORT GPIOB
        #define LCD_D5_PIN  GPIO_PIN_13

        #define LCD_D6_PORT GPIOB
        #define LCD_D6_PIN  GPIO_PIN_14

        #define LCD_D7_PORT GPIOB
        #define LCD_D7_PIN  GPIO_PIN_15

        /* ===================== L298 PIN ===================== */
        /*
           OUT1-OUT2 = Motor Wiper
           OUT3-OUT4 = Motor Pompa
        */

        #define MOTOR1_IN1_PORT GPIOA
        #define MOTOR1_IN1_PIN  GPIO_PIN_3

        #define MOTOR1_IN2_PORT GPIOA
        #define MOTOR1_IN2_PIN  GPIO_PIN_4

        #define MOTOR1_EN_PORT  GPIOA
        #define MOTOR1_EN_PIN   GPIO_PIN_5

        #define MOTOR2_IN3_PORT GPIOA
        #define MOTOR2_IN3_PIN  GPIO_PIN_6

        #define MOTOR2_IN4_PORT GPIOA
        #define MOTOR2_IN4_PIN  GPIO_PIN_7

        #define MOTOR2_EN_PORT  GPIOB
        #define MOTOR2_EN_PIN   GPIO_PIN_0

        /* ===================== BUTTON PIN ===================== */

        #define BUTTON_PORT GPIOA
        #define BUTTON_PIN  GPIO_PIN_2

        /* ===================== THRESHOLD ===================== */

        /*
           LDR pull-up:
           Banyak cahaya = nilai ADC kecil.
           Jika LDR kamu terlalu sensitif, ubah nilai ini.
        */
        #define LDR_BANYAK_CAHAYA_THRESHOLD   800

        /*
           Potensiometer:
           60% dari ADC 12-bit = 0.6 x 4095 = 2457.
           POT < 60% berarti nilai ADC PA1 kurang dari 2457.
        */
        #define POT_60_PERCENT_THRESHOLD      2457

        /* ===================== KONDISI STATUS LCD ===================== */

        /*
           4 kondisi status sistem:

           STATUS_AMAN_BERSIH        : Cahaya TERANG + Tegangan TINGGI
                                       → Panel bersih, tidak perlu pembersihan
                                       → Semua motor OFF

           STATUS_AMAN_MENDUNG       : Cahaya GELAP  + Tegangan RENDAH
                                       → Kemungkinan malam/mendung
                                       → Semua motor OFF

           STATUS_AMAN_TIDAK_PERLU   : Cahaya GELAP  + Tegangan TINGGI
                                       → Malam/gelap tapi panel masih bagus
                                       → Semua motor OFF

           STATUS_KOTOR              : Cahaya TERANG + Tegangan RENDAH
                                       → Panel kotor, butuh pembersihan
                                       → Motor Wiper ON (kecuali button ditekan)
                                       → Motor Pompa ON jika button ditekan
        */    

        typedef enum {
            STATUS_AMAN_BERSIH      = 0,
            STATUS_AMAN_MENDUNG     = 1,
            STATUS_AMAN_TIDAK_PERLU = 2,
            STATUS_KOTOR            = 3
        } StatusSistem;

        /* ===================== VARIABEL ===================== */

        uint16_t ldr_value = 0;
        uint16_t pot_value = 0;

        StatusSistem status_lama = 255;   // nilai awal tidak valid, supaya LCD update pertama kali

        /*
           Flag pompa_aktif:
           Di-set 1 saat button ditekan ketika panel kotor.
           Di-reset 0 saat status sudah bukan kotor lagi.
           Tujuannya agar motor pompa tetap menyala meski button sudah dilepas,
           sampai kondisi panel benar-benar bersih.
        */
        uint8_t pompa_aktif = 0;

        /* ===================== PROTOTYPE ===================== */

        void SystemClock_Config(void);
        static void MX_GPIO_Init(void);
        static void MX_ADC1_Init(void);

        uint16_t Read_ADC_Channel(uint32_t channel);

        void LCD_Enable(void);
        void LCD_Send4Bit(uint8_t data);
        void LCD_SendCommand(uint8_t cmd);
        void LCD_SendData(uint8_t data);
        void LCD_Init(void);
        void LCD_Clear(void);
        void LCD_SetCursor(uint8_t row, uint8_t col);
        void LCD_Print(const char *str);
        void LCD_PrintLine(uint8_t row, const char *str);
        void LCD_ShowStatus(StatusSistem status);

        void Motor1_ON(void);
        void Motor1_OFF(void);
        void Motor2_ON(void);
        void Motor2_OFF(void);
        void All_Motor_OFF(void);

        void Error_Handler(void);

        /* ===================== MAIN ===================== */

        int main(void)
        {
            HAL_Init();
            SystemClock_Config();

            MX_GPIO_Init();
            MX_ADC1_Init();

            HAL_ADCEx_Calibration_Start(&hadc1);

            All_Motor_OFF();

            LCD_Init();
            LCD_Clear();

            LCD_PrintLine(0, "SOLAR CLEANER");
            LCD_PrintLine(1, "SYSTEM READY");
            HAL_Delay(1500);
            LCD_Clear();

            while (1)
            {
                ldr_value = Read_ADC_Channel(ADC_CHANNEL_0);   // PA0 = LDR
                pot_value = Read_ADC_Channel(ADC_CHANNEL_1);   // PA1 = POT

                GPIO_PinState button_state = HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN);

                /*
                   LDR pull-up:
                   Banyak cahaya = ADC kecil.
                */
                uint8_t ldr_terang = (ldr_value < LDR_BANYAK_CAHAYA_THRESHOLD);

                /*
                   Potensiometer:
                   Tegangan tinggi = ADC >= 2457 (>= 60%).
                   Tegangan rendah = ADC < 2457 (< 60%).
                */
                uint8_t pot_tegangan_tinggi = (pot_value >= POT_60_PERCENT_THRESHOLD);

                /*
                   Button pull-down eksternal:
                   Tidak ditekan = LOW (GPIO_PIN_RESET)
                   Ditekan       = HIGH (GPIO_PIN_SET)
                */
                uint8_t button_ditekan = (button_state == GPIO_PIN_SET);

                /* ---- Tentukan status sistem dari kombinasi sensor ---- */

                StatusSistem status_sekarang;

                if (ldr_terang && pot_tegangan_tinggi)
                {
                    /*
                       Cahaya TERANG + Tegangan TINGGI
                       → Panel bersih, kondisi normal
                    */
                    status_sekarang = STATUS_AMAN_BERSIH;
                }
                else if (!ldr_terang && !pot_tegangan_tinggi)
                {
                    /*
                       Cahaya GELAP + Tegangan RENDAH
                       → Kemungkinan malam atau mendung tebal
                    */
                    status_sekarang = STATUS_AMAN_MENDUNG;
                }
                else if (!ldr_terang && pot_tegangan_tinggi)
                {
                    /*
                       Cahaya GELAP + Tegangan TINGGI
                       → Malam/gelap, panel masih dalam kondisi baik
                    */
                    status_sekarang = STATUS_AMAN_TIDAK_PERLU;
                }
                else
                {
                    /*
                       Cahaya TERANG + Tegangan RENDAH
                       → Panel kotor, butuh pembersihan segera
                    */
                    status_sekarang = STATUS_KOTOR;
                }

                /* ---- Update LCD hanya jika status berubah ---- */
                LCD_ShowStatus(status_sekarang);

                /* ---- Kontrol motor berdasarkan status ---- */

                if (status_sekarang == STATUS_KOTOR)
                {
                    if (button_ditekan)
                    {
                        /*
                           Button ditekan saat panel kotor:
                           Tandai flag pompa_aktif supaya pompa tetap menyala
                           meski button nanti dilepas.
                        */
                        pompa_aktif = 1;
                    }

                    if (pompa_aktif)
                    {
                        /*
                           Flag pompa_aktif sudah di-set:
                           Motor Wiper (OUT1-OUT2) berhenti.
                           Motor Pompa (OUT3-OUT4) menyala dan tetap menyala.
                        */
                        Motor1_OFF();
                        Motor2_ON();
                    }
                    else
                    {
                        /*
                           Panel kotor, button belum pernah ditekan:
                           Motor Wiper (OUT1-OUT2) menyala.
                           Motor Pompa (OUT3-OUT4) mati.
                        */
                        Motor1_ON();
                        Motor2_OFF();
                    }
                }
                else
                {
                    /*
                       Status sudah AMAN:
                       Reset flag pompa_aktif dan matikan semua motor.
                       Siklus pembersihan berikutnya dimulai dari awal.
                    */
                    pompa_aktif = 0;
                    All_Motor_OFF();
                }

                HAL_Delay(100);
            }
        }

        /* ===================== ADC FUNCTION ===================== */

        uint16_t Read_ADC_Channel(uint32_t channel)
        {
            ADC_ChannelConfTypeDef sConfig = {0};
            uint16_t adc_value = 0;

            sConfig.Channel = channel;
            sConfig.Rank = ADC_REGULAR_RANK_1;
            sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;

            if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
            {
                Error_Handler();
            }

            HAL_ADC_Start(&hadc1);

            if (HAL_ADC_PollForConversion(&hadc1, 100) == HAL_OK)
            {
                adc_value = HAL_ADC_GetValue(&hadc1);
            }

            HAL_ADC_Stop(&hadc1);

            return adc_value;
        }

        /* ===================== LCD FUNCTION ===================== */

        void LCD_Enable(void)
        {
            HAL_GPIO_WritePin(LCD_E_PORT, LCD_E_PIN, GPIO_PIN_SET);
            HAL_Delay(1);
            HAL_GPIO_WritePin(LCD_E_PORT, LCD_E_PIN, GPIO_PIN_RESET);
            HAL_Delay(1);
        }

        void LCD_Send4Bit(uint8_t data)
            {
            HAL_GPIO_WritePin(LCD_D4_PORT, LCD_D4_PIN, (data & 0x01) ? GPIO_PIN_SET :
        GPIO_PIN_RESET);
            HAL_GPIO_WritePin(LCD_D5_PORT, LCD_D5_PIN, (data & 0x02) ? GPIO_PIN_SET :
        GPIO_PIN_RESET);
            HAL_GPIO_WritePin(LCD_D6_PORT, LCD_D6_PIN, (data & 0x04) ? GPIO_PIN_SET :
        GPIO_PIN_RESET);
            HAL_GPIO_WritePin(LCD_D7_PORT, LCD_D7_PIN, (data & 0x08) ? GPIO_PIN_SET :
        GPIO_PIN_RESET);

            LCD_Enable();
        }

        void LCD_SendCommand(uint8_t cmd)
        {
            HAL_GPIO_WritePin(LCD_RS_PORT, LCD_RS_PIN, GPIO_PIN_RESET);

            LCD_Send4Bit(cmd >> 4);
            LCD_Send4Bit(cmd & 0x0F);

            HAL_Delay(2);
        }

        void LCD_SendData(uint8_t data)
        {
            HAL_GPIO_WritePin(LCD_RS_PORT, LCD_RS_PIN, GPIO_PIN_SET);

            LCD_Send4Bit(data >> 4);
            LCD_Send4Bit(data & 0x0F);

            HAL_Delay(1);
        }

        void LCD_Init(void)
        {
            HAL_Delay(50);

            HAL_GPIO_WritePin(LCD_RS_PORT, LCD_RS_PIN, GPIO_PIN_RESET);

            LCD_Send4Bit(0x03);
            HAL_Delay(5);

            LCD_Send4Bit(0x03);
            HAL_Delay(5);

            LCD_Send4Bit(0x03);
            HAL_Delay(1);

            LCD_Send4Bit(0x02);
            HAL_Delay(1);

            LCD_SendCommand(0x28);   // 4-bit, 2 line
            LCD_SendCommand(0x0C);   // display ON, cursor OFF
            LCD_SendCommand(0x06);   // entry mode
            LCD_SendCommand(0x01);   // clear display

            HAL_Delay(2);
        }

        void LCD_Clear(void)
        {
            LCD_SendCommand(0x01);
            HAL_Delay(2);
        }

        void LCD_SetCursor(uint8_t row, uint8_t col)
        {
            if (row == 0)
            {
                LCD_SendCommand(0x80 + col);
            }
            else
            {
                LCD_SendCommand(0xC0 + col);
            }
        }

        void LCD_Print(const char *str)
        {
            while (*str)
            {
                LCD_SendData((uint8_t)(*str));
                str++;
            }
        }

        void LCD_PrintLine(uint8_t row, const char *str)
        {
            char buffer[17];
            uint8_t i;

            for (i = 0; i < 16; i++)
            {
                if (str[i] != '\0')
                {
                    buffer[i] = str[i];
                }
                else
                {
                    buffer[i] = ' ';
                }
            }

            buffer[16] = '\0';

            LCD_SetCursor(row, 0);
            LCD_Print(buffer);
        }

        void LCD_ShowStatus(StatusSistem status)
        {
            /*
               LCD hanya di-update kalau status berubah,
               supaya tulisan tidak flicker.
            */
            if (status == status_lama)
            {
                return;
            }

            status_lama = status;

            LCD_Clear();

            switch (status)
            {
                case STATUS_AMAN_BERSIH:
                    /*
                       Cahaya TERANG + Tegangan TINGGI
                       Baris 1: "STATUS AMAN"
                       Baris 2: "PANEL BERSIH"
                    */
                    LCD_PrintLine(0, "STATUS AMAN");
                    LCD_PrintLine(1, "PANEL BERSIH");
                    break;

                case STATUS_AMAN_MENDUNG:
                    /*
                       Cahaya GELAP + Tegangan RENDAH
                       Baris 1: "STATUS AMAN"
                       Baris 2: "MENDUNG/MALAM"
                    */
                    LCD_PrintLine(0, "STATUS AMAN");
                    LCD_PrintLine(1, "MENDUNG/MALAM");
                    break;

                case STATUS_AMAN_TIDAK_PERLU:
                    /*
                       Cahaya GELAP + Tegangan TINGGI
                       Baris 1: "STATUS AMAN"
                       Baris 2: "TDK PERLU BERSIH"
                    */
                    LCD_PrintLine(0, "STATUS AMAN");
                    LCD_PrintLine(1, "TDK PERLU BERSIH");
                    break;

                case STATUS_KOTOR:
                    /*
                       Cahaya TERANG + Tegangan RENDAH
                       Baris 1: "PANEL KOTOR"
                       Baris 2: "MEMBERSIHKAN..."
                    */
                    LCD_PrintLine(0, "PANEL KOTOR");
                    LCD_PrintLine(1, "MEMBERSIHKAN...");
                    break;

                default:
                    LCD_PrintLine(0, "STATUS UNKNOWN");
                    LCD_PrintLine(1, "                ");
                    break;
            }
        }    

        /* ===================== MOTOR FUNCTION ===================== */

        void Motor1_ON(void)
        {
            /*
               Motor Wiper (OUT1-OUT2) ON
            */
            HAL_GPIO_WritePin(MOTOR1_EN_PORT, MOTOR1_EN_PIN, GPIO_PIN_SET);
            HAL_GPIO_WritePin(MOTOR1_IN1_PORT, MOTOR1_IN1_PIN, GPIO_PIN_SET);
            HAL_GPIO_WritePin(MOTOR1_IN2_PORT, MOTOR1_IN2_PIN, GPIO_PIN_RESET);    
        }

        void Motor1_OFF(void)
        {
            /*
               Motor Wiper (OUT1-OUT2) OFF
            */
            HAL_GPIO_WritePin(MOTOR1_EN_PORT, MOTOR1_EN_PIN, GPIO_PIN_RESET);
            HAL_GPIO_WritePin(MOTOR1_IN1_PORT, MOTOR1_IN1_PIN, GPIO_PIN_RESET);
            HAL_GPIO_WritePin(MOTOR1_IN2_PORT, MOTOR1_IN2_PIN, GPIO_PIN_RESET);
        }

        void Motor2_ON(void)
        {
            /*
               Motor Pompa (OUT3-OUT4) ON
            */
            HAL_GPIO_WritePin(MOTOR2_EN_PORT, MOTOR2_EN_PIN, GPIO_PIN_SET);
            HAL_GPIO_WritePin(MOTOR2_IN3_PORT, MOTOR2_IN3_PIN, GPIO_PIN_SET);
            HAL_GPIO_WritePin(MOTOR2_IN4_PORT, MOTOR2_IN4_PIN, GPIO_PIN_RESET);
        }

        void Motor2_OFF(void)
        {
            /*
               Motor Pompa (OUT3-OUT4) OFF
            */
            HAL_GPIO_WritePin(MOTOR2_EN_PORT, MOTOR2_EN_PIN, GPIO_PIN_RESET);
            HAL_GPIO_WritePin(MOTOR2_IN3_PORT, MOTOR2_IN3_PIN, GPIO_PIN_RESET);
            HAL_GPIO_WritePin(MOTOR2_IN4_PORT, MOTOR2_IN4_PIN, GPIO_PIN_RESET);
        }

        void All_Motor_OFF(void)
        {
            Motor1_OFF();
            Motor2_OFF();
        }

        /* ===================== CLOCK CONFIG ===================== */

        void SystemClock_Config(void)
        {
            RCC_OscInitTypeDef RCC_OscInitStruct = {0};
            RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
            RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};

            RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
            RCC_OscInitStruct.HSIState = RCC_HSI_ON;
            RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
            RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;

            if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
            {
                Error_Handler();
            }

            RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK |
                                          RCC_CLOCKTYPE_SYSCLK |
                                          RCC_CLOCKTYPE_PCLK1 |
                                          RCC_CLOCKTYPE_PCLK2;

            RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
            RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
            RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
            RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

            if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
            {
                Error_Handler();
            }

            PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
            PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV2;

            if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
            {
                Error_Handler();
            }
        }

        /* ===================== ADC INIT ===================== */

        static void MX_ADC1_Init(void)
        {
            hadc1.Instance = ADC1;
            hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
            hadc1.Init.ContinuousConvMode = DISABLE;
            hadc1.Init.DiscontinuousConvMode = DISABLE;
            hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
            hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
            hadc1.Init.NbrOfConversion = 1;

            if (HAL_ADC_Init(&hadc1) != HAL_OK)
            {
                Error_Handler();
            }
        }

        /* ===================== GPIO INIT ===================== */

        static void MX_GPIO_Init(void)
        {
            GPIO_InitTypeDef GPIO_InitStruct = {0};

            __HAL_RCC_GPIOA_CLK_ENABLE();
            __HAL_RCC_GPIOB_CLK_ENABLE();
            __HAL_RCC_ADC1_CLK_ENABLE();

            HAL_GPIO_WritePin(GPIOA,
                              GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 |
                              GPIO_PIN_6 | GPIO_PIN_7,
                              GPIO_PIN_RESET);

            HAL_GPIO_WritePin(GPIOB,
                              GPIO_PIN_0 | GPIO_PIN_10 | GPIO_PIN_11 |
                              GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 |
                              GPIO_PIN_15,
                              GPIO_PIN_RESET);

            /*
               PA0 = LDR
               PA1 = POT
            */
            GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1;
            GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
            HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

            /*
               PA2 = BUTTON pull-down eksternal
               Tidak ditekan = LOW, Ditekan = HIGH
            */
            GPIO_InitStruct.Pin = GPIO_PIN_2;
            GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
            GPIO_InitStruct.Pull = GPIO_NOPULL;
            HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

            /*
               PA3 = IN1 (Motor Wiper)
               PA4 = IN2 (Motor Wiper)
               PA5 = ENA (Motor Wiper)
               PA6 = IN3 (Motor Pompa)
               PA7 = IN4 (Motor Pompa)
            */
            GPIO_InitStruct.Pin = GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 |
                                  GPIO_PIN_6 | GPIO_PIN_7;
            GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
            GPIO_InitStruct.Pull = GPIO_NOPULL;
            GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
            HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

            /*
               PB0  = ENB (Motor Pompa)
               PB10 = LCD RS
               PB11 = LCD E
               PB12 = LCD D4
               PB13 = LCD D5
               PB14 = LCD D6
               PB15 = LCD D7
            */
            GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_10 | GPIO_PIN_11 |
                                  GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 |
                                  GPIO_PIN_15;
            GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
            GPIO_InitStruct.Pull = GPIO_NOPULL;
            GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
            HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
        }

        /* ===================== ERROR HANDLER ===================== */

        void Error_Handler(void)
        {
            __disable_irq();

            while (1)
            {
                All_Motor_OFF();
            }
        }

        #ifdef USE_FULL_ASSERT
        void assert_failed(uint8_t *file, uint32_t line)
        {
        }
        #endif

6. Rangkaian Simulasi dan Prinsip Kerja [kembali]

    Prinsip Kerja:
    Sistem Automatic Solar Panel Cleaning System bekerja dengan memanfaatkan mikrokontroler
    STM32 Blue Pill sebagai pusat kendali yang menerima data dari sensor BH1750, sensor INA219, dan
    limit switch. Setelah sistem dinyalakan, STM32 melakukan inisialisasi seluruh komponen, kemudian
    secara berkala membaca nilai intensitas cahaya matahari dan tegangan keluaran panel surya. Hasil
    pembacaan sensor ditampilkan secara real-time pada LCD LM016L sehingga pengguna dapat
    memantau kondisi sistem secara langsung.

    Sensor LDR digunakan sebagai simulasi untuk sensor BH1750 dikarenakan adanya keterbatasan
    library pada software proteus. Sensor ini digunakan untuk mengukur intensitas cahaya yang diterima
    panel surya. Ketika intensitas cahaya berada di bawah ambang batas yang telah ditentukan, sistem
    menganggap kondisi lingkungan sedang mendung atau malam hari sehingga proses pembersihan
    tidak dilakukan. Pada kondisi ini, sistem hanya melakukan pemantauan dan menampilkan informasi
    pada LCD.

    Apabila sensor BH1750 mendeteksi intensitas cahaya yang tinggi, STM32 akan membaca data
    tegangan keluaran panel surya dari sensor INA219. Nilai tegangan tersebut kemudian dibandingkan
    dengan nilai referensi yang telah ditentukan. Jika tegangan panel masih berada pada kondisi normal,
    sistem menganggap panel surya dalam keadaan bersih sehingga tidak diperlukan proses pembersihan.

    Sebaliknya, apabila intensitas cahaya tinggi tetapi tegangan keluaran panel berada di bawah nilai
    referensi, sistem mengindikasikan bahwa terjadi penurunan performa panel akibat adanya debu atau
    kotoran pada permukaannya. STM32 kemudian mengaktifkan pompa air untuk membasahi
    permukaan panel dan menggerakkan motor wiper melalui driver motor L298N untuk melakukan
    proses pembersihan secara otomatis.

    Selama proses pembersihan berlangsung, wiper akan bergerak hingga mencapai ujung panel surya.
    Pada posisi tersebut, limit switch akan tertekan dan mengirimkan sinyal ke mikrokontroler. Setelah
    sinyal limit switch diterima, STM32 akan menghentikan motor wiper dan mematikan pompa air
    sehingga proses pembersihan selesai. Status pembersihan dan kondisi panel kemudian ditampilkan    
    pada LCD LM016L, selanjutnya sistem kembali ke mode pemantauan untuk melakukan pembacaan   
    sensor secara berulang.

7. Video Simulasi [kembali]






8. Download File [kembali]
  • Download rangkaian simulasi project disini
  • Download listing program project disini




Komentar

Postingan populer dari blog ini