Flowchart

       Flowchart          

                                    



Listing Program

1. main.c

/* USER CODE BEGIN Header */

/**

******************************************************************************

* @file : main.c

* @brief : Main program body - EWS Banjir Bandang (I2C Migrated)

******************************************************************************

*/

/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/

#include "main.h"


/* Private includes ----------------------------------------------------------*/

/* USER CODE BEGIN Includes */

#include <stdio.h> // Diperlukan untuk fungsi sprintf (formatting teks LCD)

#include "i2c-lcd.h" // Driver LCD I2C berbasis HAL

/* USER CODE END Includes */zyt


/* 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 ---------------------------------------------------------*/

I2C_HandleTypeDef hi2c1;

TIM_HandleTypeDef htim2;


/* USER CODE BEGIN PV */

// Variabel Evaluasi Matriks Risiko

uint8_t risk_rain = 0;

uint8_t risk_distance = 0;

uint8_t risk_flow = 0;

uint8_t total_risk = 0;

uint8_t last_total_risk = 99; // Flag untuk deteksi perubahan status (anti-flicker LCD)


// Variabel Pengukuran Sensor

float distance = 0;

volatile uint32_t pulse_count = 0;

float water_flow_rate = 0.0; // Hasil kalkulasi debit dalam Liter/menit (L/min)


// Variabel Manajemen Waktu Non-Blocking (Menggantikan HAL_Delay agar tidak hang)

uint32_t last_sensor_time = 0;

uint32_t last_flow_time = 0;


// Buffer penampung teks LCD

char lcd_buffer[16];


// Fungsi delay mikrodetik manual menggunakan Timer 2 untuk Trigger Ultrasonic

void delay_us(uint32_t us) {

__HAL_TIM_SET_COUNTER(&htim2, 0);

while (__HAL_TIM_GET_COUNTER(&htim2) < us);

}

/* USER CODE END PV */


/* Private function prototypes -----------------------------------------------*/

void SystemClock_Config(void);

static void MX_GPIO_Init(void);

static void MX_TIM2_Init(void);

static void MX_I2C1_Init(void);

/* USER CODE BEGIN PFP */

/* USER CODE END PFP */


/* Private user code ---------------------------------------------------------*/

/* USER CODE BEGIN 0 */

/* 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_TIM2_Init();

MX_I2C1_Init();


/* USER CODE BEGIN 2 */

HAL_TIM_Base_Start(&htim2); // Menghidupkan Timer2 pembaca jarak

LCD_Init(); // Inisialisasi awal layar LCD via I2C

LCD_SendString("EWS SYSTEM READY");

HAL_Delay(1500);

LCD_Cmd(0x01); // Bersihkan Layar awal

/* USER CODE END 2 */


/* Infinite loop */

/* USER CODE BEGIN WHILE */

while (1)

{

uint32_t current_time = HAL_GetTick();


// =========================================================================

// 1. KALKULASI DEBIT WATER FLOW DARI PULSA CLOCK PROTEUS (TIAP 1 DETIK)

// =========================================================================

if (current_time - last_flow_time >= 1000) {

uint32_t frequency = pulse_count; // Frekuensi = Jumlah pulsa dalam 1 detik (Hz)

pulse_count = 0; // Reset counter untuk detik berikutnya

last_flow_time = current_time;


/* Menggunakan Rumus Sensor Aliran Air Populer (YF-S201): F = 7.5 * Q

* Di mana F adalah Frekuensi (Hz) dan Q adalah Debit Air (L/min)

* Maka: Q = F / 5.5

*/

if (frequency > 0) {

water_flow_rate = (float)frequency / 5.5;

} else {

water_flow_rate = 0.0;

}

}


// =========================================================================

// 2. AMBIL DATA SENSOR & UPDATE OUTPUT SECARA BERKALA (TIAP 200 ms)

// =========================================================================

if (current_time - last_sensor_time >= 200) {

last_sensor_time = current_time;


// A. BACA SENSOR HUJAN DIGITAL (PA0)

if (HAL_GPIO_ReadPin(RAIN_SENSOR_GPIO_Port, RAIN_SENSOR_Pin) == GPIO_PIN_RESET) {

risk_rain = 1; // Terdeteksi Hujan

} else {

risk_rain = 0; // Kondisi Kering

}


// B. BACA SENSOR JARAK ULTRASONIC DENGAN TIMEOUT (PA1 & PA2)

HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET); // Trigger HIGH

delay_us(10);

HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET); // Trigger LOW


uint32_t timeout1 = 0;

while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_2) == GPIO_PIN_RESET) {

timeout1++;

if(timeout1 > 5000) break;

}


__HAL_TIM_SET_COUNTER(&htim2, 0); // Mulai hitung durasi


uint32_t timeout2 = 0;

while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_2) == GPIO_PIN_SET) {

timeout2++;

if(timeout2 > 5000) break;

}


uint32_t duration = __HAL_TIM_GET_COUNTER(&htim2);

distance = duration * 0.034 / 2; // Konversi waktu ke jarak (cm)


// C. EVALUASI MATRIKS RISIKO INDIVIDU SENSOR

// 1. Batas Jarak Luapan Air Sungai

if (distance > 25.0 || distance <= 2.0) {

risk_distance = 0;

}

else if (distance >= 12.0) {

risk_distance = 1; // Ketinggian Sedang (Siaga)

}

else {

risk_distance = 2; // Kritis meluap (Bahaya)

}


// 2. Batas Kecepatan Debit Air (Water Flow)

if (water_flow_rate < 5.0) {

risk_flow = 0;

}

else if (water_flow_rate <= 30.0) {

risk_flow = 1; // Arus Sedang (Siaga)

}

else {

risk_flow = 2; // Arus Sangat Deras (Bahaya)

}


// Akumulasi Total Skor Risiko

total_risk = risk_rain + risk_distance + risk_flow;


// D. MANAJEMEN RESET LAYAR LCD (Anti-Flicker I2C)

if (total_risk != last_total_risk) {

LCD_Cmd(0x01);

last_total_risk = total_risk;

}


// Tampilkan Data Sensor di Baris 2 LCD

LCD_SetCursor(2, 1);

sprintf(lcd_buffer, "J:%2d Q:%2d R:%1d", (int)distance, (int)water_flow_rate, total_risk);

LCD_SendString(lcd_buffer);


// E. EKSEKUSI INDIKATOR OUTPUT (LED, BUZZER, & STATUS BARIS 1 LCD)

LCD_SetCursor(1, 1);

if (total_risk <= 1) {

/* ------ KONDISI 1: AMAN ------ */

HAL_GPIO_WritePin(GPIOB, LED_HIJAU_Pin, GPIO_PIN_SET);

HAL_GPIO_WritePin(GPIOB, LED_KUNING_Pin, GPIO_PIN_RESET);

HAL_GPIO_WritePin(GPIOB, LED_MERAH_Pin, GPIO_PIN_RESET);

HAL_GPIO_WritePin(GPIOB, BUZZER_Pin, GPIO_PIN_RESET);


LCD_SendString("STATUS: AMAN ");

}

else if (total_risk == 2 || total_risk == 3) {

/* ------ KONDISI 2: SIAGA ------ */

HAL_GPIO_WritePin(GPIOB, LED_HIJAU_Pin, GPIO_PIN_RESET);

HAL_GPIO_WritePin(GPIOB, LED_KUNING_Pin, GPIO_PIN_SET);

HAL_GPIO_WritePin(GPIOB, LED_MERAH_Pin, GPIO_PIN_RESET);


// Membuat Buzzer berbunyi intermiten pelan (Toggle tiap loop 200ms)

HAL_GPIO_TogglePin(GPIOB, BUZZER_Pin);


LCD_SendString("STATUS: SIAGA ");

}

else if (total_risk >= 4) {

/* ------ KONDISI 3: BAHAYA ------ */

HAL_GPIO_WritePin(GPIOB, LED_HIJAU_Pin, GPIO_PIN_RESET);

HAL_GPIO_WritePin(GPIOB, LED_KUNING_Pin, GPIO_PIN_RESET);

HAL_GPIO_WritePin(GPIOB, LED_MERAH_Pin, GPIO_PIN_SET);


// Buzzer berbunyi konstan tanpa putus

HAL_GPIO_WritePin(GPIOB, BUZZER_Pin, GPIO_PIN_SET);


LCD_SendString("FLASH FLOOD!! ");

}

}

/* USER CODE END WHILE */


/* USER CODE BEGIN 3 */

}

/* 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_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;

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_PLLCLK;

RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;

RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;

RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;


if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)

{

Error_Handler();

}

}


/**

* @brief I2C1 Initialization Function

* @param None

* @retval None

*/

static void MX_I2C1_Init(void)

{

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();

}

}


/**

* @brief TIM2 Initialization Function

* @param None

* @retval None

*/

static void MX_TIM2_Init(void)

{

TIM_ClockConfigTypeDef sClockSourceConfig = {0};

TIM_MasterConfigTypeDef sMasterConfig = {0};


htim2.Instance = TIM2;

// FIXED: Menggunakan Prescaler 72-1 karena clock sistem berjalan di 72MHz (HSE PLL)

htim2.Init.Prescaler = 72-1;

htim2.Init.CounterMode = TIM_COUNTERMODE_UP;

htim2.Init.Period = 65535;

htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;

if (HAL_TIM_Base_Init(&htim2) != HAL_OK)

{

Error_Handler();

}

sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;

if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)

{

Error_Handler();

}

sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;

sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;

if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)

{

Error_Handler();

}

}


/**

* @brief GPIO Initialization Function

* @param None

* @retval None

*/

static void MX_GPIO_Init(void)

{

GPIO_InitTypeDef GPIO_InitStruct = {0};


/* 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(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);


/*Configure GPIO pin Output Level */

HAL_GPIO_WritePin(GPIOB, LED_HIJAU_Pin|LED_KUNING_Pin|LED_MERAH_Pin|BUZZER_Pin, GPIO_PIN_RESET);


/*Configure GPIO pin : RAIN_SENSOR_Pin */

GPIO_InitStruct.Pin = RAIN_SENSOR_Pin;

GPIO_InitStruct.Mode = GPIO_MODE_INPUT;

GPIO_InitStruct.Pull = GPIO_PULLDOWN;

HAL_GPIO_Init(RAIN_SENSOR_GPIO_Port, &GPIO_InitStruct);


/*Configure GPIO pin : PA1 */

GPIO_InitStruct.Pin = GPIO_PIN_1;

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);


/*Configure GPIO pin : PA2 */

GPIO_InitStruct.Pin = GPIO_PIN_2;

GPIO_InitStruct.Mode = GPIO_MODE_INPUT;

GPIO_InitStruct.Pull = GPIO_NOPULL;

HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);


/*Configure GPIO pin : FLOW_PIN_Pin */

GPIO_InitStruct.Pin = FLOW_PIN_Pin;

GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;

GPIO_InitStruct.Pull = GPIO_PULLDOWN;

HAL_GPIO_Init(FLOW_PIN_GPIO_Port, &GPIO_InitStruct);


/*Configure GPIO pins : LED_HIJAU_Pin LED_KUNING_Pin LED_MERAH_Pin BUZZER_Pin */

GPIO_InitStruct.Pin = LED_HIJAU_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);


/* EXTI interrupt init*/

HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);

HAL_NVIC_EnableIRQ(EXTI0_IRQn);

}


/* USER CODE BEGIN 4 */

// Callback EXTI0: Menangkap pulsa dari CLOCK Generator Proteus secara real-time

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {

if (GPIO_Pin == FLOW_PIN_Pin) { // Menggunakan alias Pin Name yang sesuai dengan .ioc kamu

pulse_count++;

}

}

/* USER CODE END 4 */


void Error_Handler(void)

{

/* USER CODE BEGIN Error_Handler_Debug */

while(1)

{

}

/* USER CODE END Error_Handler_Debug */

}


Library

2.l2c_lcd.c

#include "main.h"

#include "i2c-lcd.h"

extern I2C_HandleTypeDef hi2c1; // Mengambil handle I2C dari main.c

#define SLAVE_ADDRESS_LCD 0x4E // Alamat I2C default PCF8574 (0x27 << 1)


void LCD_Cmd(char cmd) {

char data_u, data_l;

uint8_t data_t[4];

data_u = (cmd & 0xf0);

data_l = ((cmd << 4) & 0xf0);

data_t[0] = data_u | 0x0C; // en=1, rs=0

data_t[1] = data_u | 0x08; // en=0, rs=0

data_t[2] = data_l | 0x0C; // en=1, rs=0

data_t[3] = data_l | 0x08; // en=0, rs=0

HAL_I2C_Master_Transmit(&hi2c1, SLAVE_ADDRESS_LCD, (uint8_t *)data_t, 4, 100);

}


void LCD_Data(char data) {

char data_u, data_l;

uint8_t data_t[4];

data_u = (data & 0xf0);

data_l = ((data << 4) & 0xf0);

data_t[0] = data_u | 0x0D; // en=1, rs=1

data_t[1] = data_u | 0x09; // en=0, rs=1

data_t[2] = data_l | 0x0D; // en=1, rs=1

data_t[3] = data_l | 0x09; // en=0, rs=1

HAL_I2C_Master_Transmit(&hi2c1, SLAVE_ADDRESS_LCD, (uint8_t *)data_t, 4, 100);

}


void LCD_Init(void) {

HAL_Delay(50);

LCD_Cmd(0x30);

HAL_Delay(5);

LCD_Cmd(0x30);

HAL_Delay(1);

LCD_Cmd(0x32);

HAL_Delay(10);

LCD_Cmd(0x28); // Mode 4-bit, 2 Baris

HAL_Delay(1);

LCD_Cmd(0x0C); // Display ON, Cursor OFF

HAL_Delay(1);

LCD_Cmd(0x06); // Auto-increment kursor

HAL_Delay(1);

LCD_Cmd(0x01); // Clear Screen

HAL_Delay(2);

}


void LCD_SendString(char *str) {

while (*str) LCD_Data(*str++);

}


void LCD_SetCursor(uint8_t row, uint8_t col) {

uint8_t address = (row == 1) ? (0x80 + col - 1) : (0xC0 + col - 1);

LCD_Cmd(address);

}



3.i2c_lcd.h

#ifndef INC_I2C_LCD_H_

#define INC_I2C_LCD_H_


#include "main.h"


void LCD_Init(void);

void LCD_Cmd(char cmd);

void LCD_Data(char data);

void LCD_SendString(char *str);

void LCD_SetCursor(uint8_t row, uint8_t col);


#endif /* INC_I2C_LCD_H_ */

 

Komentar

Postingan populer dari blog ini

Tugas Besar