Laporan Akhir Modul 4
LAPORAN AKHIR
a. Rangkaian Simulasi dan Prinsip Kerja [kembali]
Pada sistem monitoring drainase berbasis STM32 Blue Pill, prinsip kerja rangkaian didasarkan pada pembacaan tiga parameter utama, yaitu kondisi hujan, level air, dan debit aliran air. Ketiga parameter tersebut digunakan untuk menentukan status saluran drainase, apakah berada dalam kondisi aman, waspada, bahaya, atau potensi luapan.
Sensor hujan FC-37 dipasang pada bagian luar saluran drainase. Sensor ini berfungsi untuk mendeteksi adanya air hujan. Ketika permukaan sensor dalam keadaan kering, sistem membaca kondisi tidak hujan. Ketika sensor terkena air, nilai keluaran sensor berubah dan sistem mendeteksi bahwa hujan sedang terjadi. Data dari sensor hujan digunakan sebagai tanda awal bahwa volume air pada drainase berpotensi meningkat.
Sensor VL53L0X V2 digunakan untuk membaca level air pada saluran drainase. Sensor ini dipasang di bagian atas pipa ukur transparan dan diarahkan ke bawah. Di dalam pipa ukur terdapat pelampung styrofoam yang bergerak naik dan turun mengikuti permukaan air. Ketika level air rendah, posisi styrofoam berada jauh dari sensor sehingga jarak yang terbaca besar. Ketika level air naik, styrofoam ikut naik mendekati sensor sehingga jarak yang terbaca semakin kecil. Data jarak tersebut kemudian diolah oleh STM32 untuk menentukan level air.
Sensor water flow YF-S201 dipasang pada jalur pipa drainase. Sensor ini bekerja dengan menghasilkan pulsa ketika air mengalir melewati bagian dalam sensor. Semakin besar debit air yang mengalir, semakin banyak pulsa yang dihasilkan. Pulsa dari sensor dibaca oleh STM32 melalui pin input digital atau interrupt, kemudian dihitung untuk memperoleh nilai debit air dalam liter per menit.
Setelah data dari ketiga sensor terbaca, STM32 Blue Pill akan memproses data tersebut untuk menentukan status sistem. Apabila tidak hujan, level air rendah, dan debit air normal, maka sistem berada pada kondisi aman. Pada kondisi ini LED hijau menyala, buzzer mati, dan LCD menampilkan status aman.
Apabila sensor hujan mendeteksi adanya hujan atau level air mulai naik, maka sistem masuk ke kondisi waspada. Pada kondisi ini LED kuning menyala dan buzzer dapat berbunyi lambat sebagai peringatan awal. LCD menampilkan informasi bahwa sistem berada pada status waspada.
Apabila level air sudah tinggi, maka sistem masuk ke kondisi bahaya. Pada kondisi ini LED merah menyala dan buzzer berbunyi lebih cepat. Status bahaya menunjukkan bahwa air pada saluran drainase sudah meningkat dan perlu diperhatikan.
Kondisi paling berbahaya terjadi ketika level air sangat tinggi, tetapi debit air rendah. Kondisi ini menunjukkan bahwa air pada saluran meningkat, tetapi aliran air tidak lancar. Hal tersebut dapat menandakan adanya penyumbatan atau potensi luapan pada saluran drainase. Pada kondisi ini LED merah berkedip dan buzzer menyala sebagai alarm peringatan.
Secara umum, alur kerja sistem dimulai dari pembacaan sensor hujan, sensor level air, dan sensor debit air. Data sensor kemudian diproses oleh STM32 untuk menentukan status drainase. Hasil pemrosesan ditampilkan pada LCD, sedangkan LED dan buzzer digunakan sebagai indikator visual dan suara.
b. Flowchart dan Listing Program [kembali]
Flowchart
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body for Smart
Drainage Prototype (30cm)
******************************************************************************
*/
/* USER CODE END Header */
/* Includes
------------------------------------------------------------------*/
#include "main.h"
/* Private includes
----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include <string.h>
#include "i2c_lcd.h"
#include "VL53L0X.h"
/* USER CODE END Includes */
/* Private typedef
-----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define
------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro
-------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables
---------------------------------------------------------*/
ADC_HandleTypeDef hadc1;
I2C_HandleTypeDef hi2c1;
I2C_HandleTypeDef hi2c2;
/* USER CODE BEGIN PV */
volatile uint32_t flowPulse = 0;
uint32_t flowHz = 0;
float debitLpm = 0.0;
uint16_t rainValue = 0;
uint16_t jarakAir = 0;
uint8_t jarakCm = 0;
char statusDrainase[20] = "AMAN";
uint32_t previousMillis = 0;
uint32_t lcdMillis = 0;
/* USER CODE END PV */
/* Private function prototypes
-----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);
static void MX_I2C1_Init(void);
static void MX_I2C2_Init(void);
/* USER CODE BEGIN PFP */
uint16_t Read_ADC(uint32_t channel);
void CheckDrainageStatus(void);
void UpdateOutputs(void);
/* USER CODE END PFP */
/* Private user code
---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if (GPIO_Pin == GPIO_PIN_2)
// PA2 untuk Flow Sensor
{
flowPulse++;
}
}
uint16_t Read_ADC(uint32_t channel)
{
ADC_ChannelConfTypeDef
sConfig = {0};
sConfig.Channel = channel;
sConfig.Rank =
ADC_REGULAR_RANK_1;
sConfig.SamplingTime =
ADC_SAMPLETIME_71CYCLES_5;
HAL_ADC_ConfigChannel(&hadc1, &sConfig);
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 100);
uint16_t value =
HAL_ADC_GetValue(&hadc1);
HAL_ADC_Stop(&hadc1);
return value;
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU
Configuration--------------------------------------------------------*/
/* Reset of all peripherals,
Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock
*/
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured
peripherals */
MX_GPIO_Init();
MX_ADC1_Init();
MX_I2C1_Init();
MX_I2C2_Init();
/* USER CODE BEGIN 2 */
lcd_init();
lcd_clear();
lcd_put_cur(0, 0);
lcd_send_string("Sistem
Drainase");
lcd_put_cur(1, 0);
lcd_send_string("Inisialisasi...");
HAL_Delay(1000);
if (!initVL53L0X(true,
&hi2c2))
{
lcd_clear();
lcd_put_cur(0, 0);
lcd_send_string("Error: Laser!");
HAL_Delay(2000);
}
else
{
setSignalRateLimit(0.1);
setVcselPulsePeriod(VcselPeriodPreRange, 18);
setVcselPulsePeriod(VcselPeriodFinalRange, 14);
lcd_clear();
lcd_put_cur(0, 0);
lcd_send_string("Laser Ready");
HAL_Delay(1000);
}
lcd_clear();
previousMillis =
HAL_GetTick();
lcdMillis = HAL_GetTick();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
uint32_t currentMillis =
HAL_GetTick();
rainValue =
Read_ADC(ADC_CHANNEL_0);
jarakAir =
readRangeSingleMillimeters(0);
jarakCm = jarakAir / 10;
if (currentMillis -
previousMillis >= 1000)
{
previousMillis =
currentMillis;
flowHz = flowPulse;
flowPulse = 0;
debitLpm =
(float)flowHz / 7.5;
CheckDrainageStatus();
}
UpdateOutputs();
if (currentMillis -
lcdMillis >= 500)
{
lcdMillis =
currentMillis;
char line1[21];
char line2[21];
sprintf(line1,
"Air:%2dcm D:%3.1fL", jarakCm, debitLpm);
lcd_put_cur(0, 0);
lcd_send_string(line1);
sprintf(line2,
"%-16s", statusDrainase);
lcd_put_cur(1, 0);
lcd_send_string(line2);
}
/* USER CODE END 3 */
}
}
/**
* @brief System Clock
Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef
RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef
RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef
PeriphClkInit = {0};
/** Initializes the RCC
Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef
structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState =
RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if
(HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB
and APB buses clocks
*/
RCC_ClkInitStruct.ClockType =
RCC_CLOCKTYPE_HCLK |
RCC_CLOCKTYPE_SYSCLK |
RCC_CLOCKTYPE_PCLK1 |
RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE;
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();
}
}
/**
* @brief ADC1 Initialization
Function
* @param None
* @retval None
*/
static void MX_ADC1_Init(void)
{
/* USER CODE BEGIN ADC1_Init
0 */
/* USER CODE END ADC1_Init 0
*/
ADC_ChannelConfTypeDef
sConfig = {0};
/* USER CODE BEGIN ADC1_Init
1 */
/* USER CODE END ADC1_Init 1
*/
/** Common config
*/
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();
}
/** Configure Regular Channel
*/
sConfig.Channel =
ADC_CHANNEL_0;
sConfig.Rank =
ADC_REGULAR_RANK_1;
sConfig.SamplingTime =
ADC_SAMPLETIME_1CYCLE_5;
if
(HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC1_Init
2 */
/* USER CODE END ADC1_Init 2
*/
}
/**
* @brief I2C1 Initialization
Function
* @param None
* @retval None
*/
static void MX_I2C1_Init(void)
{
/* USER CODE BEGIN I2C1_Init
0 */
/* USER CODE END I2C1_Init 0
*/
/* USER CODE BEGIN I2C1_Init
1 */
/* USER CODE END I2C1_Init 1
*/
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed =
100000;
hi2c1.Init.DutyCycle =
I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode =
I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode =
I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode =
I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode =
I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1)
!= HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN I2C1_Init
2 */
/* USER CODE END I2C1_Init 2
*/
}
/**
* @brief I2C2 Initialization
Function
* @param None
* @retval None
*/
static void MX_I2C2_Init(void)
{
/* USER CODE BEGIN I2C2_Init
0 */
/* USER CODE END I2C2_Init 0
*/
/* USER CODE BEGIN I2C2_Init
1 */
/* USER CODE END I2C2_Init 1
*/
hi2c2.Instance = I2C2;
hi2c2.Init.ClockSpeed =
100000;
hi2c2.Init.DutyCycle =
I2C_DUTYCYCLE_2;
hi2c2.Init.OwnAddress1 = 0;
hi2c2.Init.AddressingMode =
I2C_ADDRESSINGMODE_7BIT;
hi2c2.Init.DualAddressMode =
I2C_DUALADDRESS_DISABLE;
hi2c2.Init.OwnAddress2 = 0;
hi2c2.Init.GeneralCallMode =
I2C_GENERALCALL_DISABLE;
hi2c2.Init.NoStretchMode =
I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c2)
!= HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN I2C2_Init
2 */
/* USER CODE END I2C2_Init 2
*/
}
/**
* @brief GPIO Initialization
Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef
GPIO_InitStruct = {0};
/* USER CODE BEGIN
MX_GPIO_Init_1 */
/* USER CODE END
MX_GPIO_Init_1 */
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/* Configure GPIO pin Output
Level */
HAL_GPIO_WritePin(GPIOB,
LED_Kuning_Pin | LED_Merah_Pin | Buzzer_Pin, GPIO_PIN_RESET);
/* Configure GPIO pin :
sensor_flow_Pin */
GPIO_InitStruct.Pin =
sensor_flow_Pin;
GPIO_InitStruct.Mode =
GPIO_MODE_IT_RISING;
GPIO_InitStruct.Pull =
GPIO_NOPULL;
HAL_GPIO_Init(sensor_flow_GPIO_Port, &GPIO_InitStruct);
/* Configure GPIO pin :
LED_Hijau_Pin */
GPIO_InitStruct.Pin =
LED_Hijau_Pin;
GPIO_InitStruct.Mode =
GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed =
GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LED_Hijau_GPIO_Port, &GPIO_InitStruct);
/* Configure GPIO pins :
LED_Kuning_Pin LED_Merah_Pin Buzzer_Pin */
GPIO_InitStruct.Pin =
LED_Kuning_Pin | LED_Merah_Pin | Buzzer_Pin;
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);
/* Configures the port and
pin on which the EVENTOUT Cortex signal will be connected */
HAL_GPIOEx_ConfigEventout(AFIO_EVENTOUT_PORT_B, AFIO_EVENTOUT_PIN_12);
/* Enables the Event Output
*/
HAL_GPIOEx_EnableEventout();
/* EXTI interrupt init */
HAL_NVIC_SetPriority(EXTI2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI2_IRQn);
/* USER CODE BEGIN
MX_GPIO_Init_2 */
/* USER CODE END
MX_GPIO_Init_2 */
}
/* USER CODE BEGIN 4 */
void CheckDrainageStatus(void)
{
if (jarakCm < 10)
{
if (rainValue <= 1500
&& debitLpm > 2.0)
{
strcpy(statusDrainase, "LUAPAN");
}
else
{
strcpy(statusDrainase, "BAHAYA");
}
}
else if (jarakCm >= 10
&& jarakCm <= 20)
{
if (rainValue <= 3000)
{
strcpy(statusDrainase, "WASPADA");
}
else
{
strcpy(statusDrainase, "AMAN");
}
}
else
{
strcpy(statusDrainase,
"AMAN");
}
}
void UpdateOutputs(void)
{
static uint32_t beepMillis =
0;
static uint32_t blinkMillis =
0;
uint32_t currentMillis =
HAL_GetTick();
if (strcmp(statusDrainase,
"AMAN") == 0)
{
HAL_GPIO_WritePin(GPIOB,
GPIO_PIN_12, GPIO_PIN_SET); // Hijau
aktif
HAL_GPIO_WritePin(GPIOB,
GPIO_PIN_13, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,
GPIO_PIN_14, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,
GPIO_PIN_15, GPIO_PIN_RESET); // Buzzer mati
}
else if
(strcmp(statusDrainase, "WASPADA") == 0)
{
HAL_GPIO_WritePin(GPIOB,
GPIO_PIN_12, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,
GPIO_PIN_13, GPIO_PIN_SET); // Kuning
aktif
HAL_GPIO_WritePin(GPIOB,
GPIO_PIN_14, GPIO_PIN_RESET);
if (currentMillis -
beepMillis >= 600)
{
beepMillis =
currentMillis;
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_15);
}
}
else if
(strcmp(statusDrainase, "BAHAYA") == 0)
{
HAL_GPIO_WritePin(GPIOB,
GPIO_PIN_12, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,
GPIO_PIN_13, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,
GPIO_PIN_14, GPIO_PIN_SET); // Merah
aktif
if (currentMillis -
beepMillis >= 150)
{
beepMillis =
currentMillis;
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_15);
}
}
else if
(strcmp(statusDrainase, "LUAPAN") == 0)
{
HAL_GPIO_WritePin(GPIOB,
GPIO_PIN_12, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,
GPIO_PIN_13, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,
GPIO_PIN_15, GPIO_PIN_SET); // Buzzer
aktif terus
if (currentMillis -
blinkMillis >= 150)
{
blinkMillis =
currentMillis;
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_14); // Merah berkedip
}
}
}
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error
occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN
Error_Handler_Debug */
/* User can add his own
implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END
Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the
source line number
* where the assert_param error has
occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own
implementation to report the file name and line number,
ex: printf("Wrong
parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
c. Video Demo [kembali]
d. Kesimpulan dan Saran [kembali]
Berdasarkan perancangan dan simulasi sistem monitoring drainase berbasis STM32 Blue Pill, dapat disimpulkan bahwa:
- Sistem monitoring drainase berhasil dirancang menggunakan STM32 Blue Pill sebagai mikrokontroler utama untuk membaca sensor, mengolah data, dan mengendalikan output.
- Sensor hujan FC-37 digunakan untuk mendeteksi kondisi hujan pada lingkungan sekitar saluran drainase. Sensor ini berfungsi sebagai indikator awal adanya potensi peningkatan volume air pada drainase.
- Sensor jarak laser VL53L0X V2 digunakan untuk mengukur level air pada saluran drainase. Sensor ini membaca jarak terhadap pelampung styrofoam yang diletakkan di dalam pipa ukur. Semakin tinggi level air, maka jarak antara sensor dan pelampung semakin kecil.
- Sensor water flow YF-S201 digunakan untuk membaca debit aliran air pada saluran drainase. Sensor ini menghasilkan pulsa digital yang kemudian dihitung oleh STM32 untuk memperoleh nilai debit air dalam liter per menit.
- Output sistem berupa LCD 16x2 I2C, LED indikator, dan buzzer dapat digunakan untuk menampilkan kondisi drainase. LCD menampilkan data sensor dan status sistem, LED menunjukkan kondisi aman, waspada, atau bahaya, sedangkan buzzer memberikan peringatan suara ketika kondisi drainase berbahaya.
- Sistem mampu membedakan beberapa kondisi drainase, yaitu aman, waspada, bahaya, dan potensi luapan. Kondisi paling berbahaya terjadi ketika level air sangat tinggi tetapi debit air rendah, karena kondisi tersebut menunjukkan kemungkinan adanya penyumbatan pada saluran drainase.
- Prototipe ini dapat digunakan sebagai simulasi awal sistem pemantauan drainase sederhana yang bekerja secara otomatis berdasarkan pembacaan sensor hujan, level air, dan debit air.
Adapun saran untuk pengembangan sistem ini adalah sebagai berikut:
- Pada pengembangan selanjutnya, sistem dapat ditambahkan modul komunikasi seperti Wi-Fi, LoRa, atau GSM agar data kondisi drainase dapat dikirim ke pengguna secara jarak jauh.
- Sensor VL53L0X V2 sebaiknya dikalibrasi terlebih dahulu sesuai tinggi pipa ukur yang digunakan agar hasil pembacaan level air lebih akurat.
- Pelampung styrofoam perlu dibuat dengan ukuran yang sesuai dengan diameter pipa ukur agar dapat bergerak naik dan turun dengan stabil tanpa tersangkut.
- Sensor hujan FC-37 dan rangkaian elektronik sebaiknya diberi pelindung agar tidak terkena percikan air secara langsung, kecuali bagian permukaan sensor yang memang digunakan untuk mendeteksi hujan.
- Sensor YF-S201 sebaiknya dipasang pada jalur pipa yang alirannya stabil agar pembacaan debit air lebih baik dan tidak terlalu banyak gangguan.
- Untuk penerapan nyata, sistem dapat dikembangkan dengan menambahkan sumber daya cadangan seperti baterai agar tetap dapat bekerja ketika listrik padam.
- Sistem dapat ditingkatkan dengan menambahkan penyimpanan data atau database agar riwayat level air, debit air, dan kondisi hujan dapat dianalisis lebih lanjut.
e. Download file [kembali]
Komentar
Posting Komentar