rangkaian simulasi dan prinsip kerja


Prinsip Kerja Sistem

Rangkaian Smart Clean Water Supply System bekerja dengan mengintegrasikan sensor ultrasonik HC-SR04, sensor turbidity, flow sensor YF-S201, relay module, pompa DC, OLED, LED, dan buzzer yang dikendalikan oleh mikrokontroler STM32F103C8T6 sebagai pusat pengolahan data. Sistem ini dirancang untuk mengambil air dari sungai, melakukan proses pengendapan menggunakan settling tank, memantau kualitas dan kuantitas air secara real-time, serta mengontrol pompa secara otomatis berdasarkan kondisi yang terdeteksi oleh sensor.

Pada bagian pemantauan level air, sensor ultrasonik HC-SR04 digunakan untuk mengukur ketinggian air di dalam settling tank. Sensor memancarkan gelombang ultrasonik yang dipantulkan oleh permukaan air, kemudian STM32 menghitung waktu pantulan untuk menentukan jarak permukaan air terhadap sensor. Data ini digunakan untuk mengetahui kapasitas air yang tersedia dalam tangki. Apabila level air berada di bawah batas minimum yang ditentukan, sistem akan memberikan peringatan melalui LED dan buzzer serta menghentikan operasi pompa untuk mencegah pompa bekerja tanpa air.

Pada bagian pemantauan kualitas air, sensor turbidity digunakan untuk mengukur tingkat kekeruhan air setelah proses pengendapan. Sensor menghasilkan tegangan analog yang nilainya berubah sesuai dengan jumlah partikel lumpur atau sedimen yang terkandung dalam air. Tegangan tersebut dibaca oleh ADC STM32 dan dikonversi menjadi nilai kekeruhan. Jika nilai kekeruhan masih berada di atas ambang batas yang telah ditentukan, sistem akan menganggap air belum layak digunakan sehingga pompa distribusi tidak diaktifkan. Sebaliknya, jika nilai kekeruhan berada di bawah batas yang ditentukan, air dianggap cukup bersih untuk dialirkan ke sistem irigasi.

Pada bagian pemantauan debit air, flow sensor YF-S201 dipasang pada saluran keluaran pompa. Sensor menghasilkan pulsa digital yang frekuensinya sebanding dengan laju aliran air. STM32 menghitung jumlah pulsa yang diterima setiap satuan waktu untuk memperoleh nilai debit dalam satuan liter per menit (L/min). Informasi debit digunakan untuk memastikan bahwa air benar-benar mengalir dan pompa bekerja dengan baik selama proses distribusi.

Seluruh data sensor kemudian ditampilkan pada OLED berupa informasi level air, tingkat kekeruhan, debit aliran, dan status pompa. Selain itu, LED digunakan sebagai indikator visual kondisi sistem, sedangkan buzzer berfungsi sebagai alarm ketika terjadi kondisi tertentu seperti air terlalu keruh, level air rendah, atau tidak adanya aliran air saat pompa aktif. Dengan demikian, sistem mampu melakukan proses monitoring dan pengendalian distribusi air secara otomatis untuk mendukung kebutuhan irigasi pascabencana.

 Rangkaian Proteus 




Listing Program 

/* USER CODE BEGIN Header */

/*

Project : Sistem Kontrol Air Bersih Berbasis STM32

MCU : STM32F103C8T6 / Blue Pill


Pin:

PA0 = Turbidity Sensor OUT / ADC1_IN0

PA1 = HC-SR04 TRIG

PA2 = HC-SR04 ECHO

PA3 = Flow Sensor OUT / EXTI3


PB0 = LED Hijau

PB1 = LED Kuning

PB2 = LED Merah

PB10 = Buzzer

PB12 = Relay Pompa / Motor


Prioritas:

1. Ultrasonic

2. Turbidity

3. Flow

*/

/* USER CODE END Header */


#include "main.h"

#include <stdio.h>

#include <string.h>


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


ADC_HandleTypeDef hadc1;

TIM_HandleTypeDef htim2;


/* ===================== SETTING BATAS SISTEM ===================== */


#define FLOW_LIMIT_LMIN 1.3f

#define TURBIDITY_LIMIT_NTU 25.0f

#define ULTRASONIC_LIMIT_CM 6.0f

#define ULTRASONIC_HYST_START_CM 8.0f


/*

Relay aktif HIGH:

1 = PB12 HIGH -> Pompa ON

PB12 LOW -> Pompa OFF


Kalau relay kamu aktif LOW, ubah menjadi 0.

*/

#define RELAY_ACTIVE_HIGH 1


/*

Flow sensor YF-S201:

Flow L/min = Frequency / 7.5

*/

#define FLOW_CALIBRATION_FACTOR 7.5f


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


volatile uint32_t flowPulseCount = 0;


uint32_t turbidityADC = 0;

float turbidityNTU = 0.0f;

float flowRate = 0.0f;

float distanceCM = 0.0f;

uint32_t lastFlowTick = 0;


uint8_t flowReady = 0;

uint8_t isTankFullFlag = 0;


char systemStatus[30];


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


void SystemClock_Config(void);

static void MX_GPIO_Init(void);

static void MX_ADC1_Init(void);

static void MX_TIM2_Init(void);


void delay_us(uint16_t us);


uint32_t Read_ADC_Turbidity(void);

float Read_Turbidity_NTU(void);

float Read_Ultrasonic_CM(void);

float Read_Flow_LMin(void);


void Pump_ON(void);

void Pump_OFF(void);


void Green_LED_ON(void);

void Green_LED_OFF(void);

void Yellow_LED_ON(void);

void Yellow_LED_OFF(void);

void Red_LED_ON(void);

void Red_LED_OFF(void);

void All_LED_OFF(void);


void Buzzer_ON(void);

void Buzzer_OFF(void);


void System_Logic(float flow, float turbidity, float distance);


void Error_Handler(void);


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


int main(void)

{

HAL_Init();


SystemClock_Config();


MX_GPIO_Init();

MX_ADC1_Init();

MX_TIM2_Init();


HAL_ADCEx_Calibration_Start(&hadc1);

HAL_TIM_Base_Start(&htim2);


Pump_OFF();

All_LED_OFF();

Buzzer_OFF();


strcpy(systemStatus, "START");


/* =================================================================

PROSES STABILISASI AWAL SIMULASI PROTEUS (ANTI-KEDIP STARTUP)

================================================================= */

HAL_Delay(100); // Berikan waktu model Proteus siap


lastFlowTick = HAL_GetTick(); // Inisialisasi sebelum loop

flowReady = 0;


while (1)

{

distanceCM = Read_Ultrasonic_CM();

turbidityNTU = Read_Turbidity_NTU();


if (HAL_GetTick() - lastFlowTick >= 1000)

{

flowRate = Read_Flow_LMin();

lastFlowTick = HAL_GetTick();

flowReady = 1;

}


if (flowReady == 1)

{

System_Logic(flowRate, turbidityNTU, distanceCM);

}

else

{

Pump_OFF();

All_LED_OFF();

Buzzer_OFF();

}


HAL_Delay(100);

}

}

/* ===================== DELAY MICROSECOND ===================== */


void delay_us(uint16_t us)

{

__HAL_TIM_SET_COUNTER(&htim2, 0);


while (__HAL_TIM_GET_COUNTER(&htim2) < us)

{

}

}


/* ===================== SENSOR TURBIDITY ===================== */


uint32_t Read_ADC_Turbidity(void)

{

uint32_t adcValue = 0;


HAL_ADC_Start(&hadc1);


if (HAL_ADC_PollForConversion(&hadc1, 100) == HAL_OK)

{

adcValue = HAL_ADC_GetValue(&hadc1);

}


HAL_ADC_Stop(&hadc1);


return adcValue;

}


float Read_Turbidity_NTU(void)

{

uint32_t adcValue;

float ntu;


adcValue = Read_ADC_Turbidity();

turbidityADC = adcValue;


/*

Mapping Proteus:

ADC 0 = 0 NTU -> air bersih

ADC 4095 = 100 NTU -> air sangat keruh


Jika sensor turbidity kamu terbaca terbalik, pakai rumus alternatif

yang ada di komentar bawah.

*/


ntu = ((float)adcValue * 100.0f) / 4095.0f;


/*

Rumus alternatif jika sensor terbaca terbalik:


ntu = ((4095.0f - (float)adcValue) * 100.0f) / 4095.0f;

*/


if (ntu < 0.0f)

{

ntu = 0.0f;

}


if (ntu > 100.0f)

{

ntu = 100.0f;

}


return ntu;

}


/* ===================== SENSOR ULTRASONIC HC-SR04 (REVISI) ===================== */

float Read_Ultrasonic_CM(void)

{

uint32_t echoTime = 0;

float distance = 999.0f;


HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);

delay_us(5);


HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);

delay_us(20);

HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);


/*

Tunggu ECHO HIGH

*/

__HAL_TIM_SET_COUNTER(&htim2, 0);


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

{

if (__HAL_TIM_GET_COUNTER(&htim2) > 30000)

{

return 999.0f;

}

}


/*

Hitung durasi ECHO HIGH

*/

__HAL_TIM_SET_COUNTER(&htim2, 0);


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

{

if (__HAL_TIM_GET_COUNTER(&htim2) > 30000)

{

return 999.0f;

}

}


echoTime = __HAL_TIM_GET_COUNTER(&htim2);


distance = echoTime / 58.0f;


return distance;

}

/* ===================== SENSOR FLOW ===================== */


void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)

{

if (GPIO_Pin == GPIO_PIN_3)

{

flowPulseCount++;

}

}


float Read_Flow_LMin(void)

{

uint32_t pulseCopy = 0;

float flow = 0.0f;


__disable_irq();

pulseCopy = flowPulseCount;

flowPulseCount = 0;

__enable_irq();


flow = (float)pulseCopy / FLOW_CALIBRATION_FACTOR;


return flow;

}

/* ===================== OUTPUT CONTROL ===================== */


void Pump_ON(void)

{

#if RELAY_ACTIVE_HIGH

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET);

#else

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET);

#endif

}


void Pump_OFF(void)

{

#if RELAY_ACTIVE_HIGH

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_RESET);

#else

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, GPIO_PIN_SET);

#endif

}


void Green_LED_ON(void)

{

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET);

}


void Green_LED_OFF(void)

{

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET);

}


void Yellow_LED_ON(void)

{

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET);

}


void Yellow_LED_OFF(void)

{

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET);

}


void Red_LED_ON(void)

{

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_SET);

}


void Red_LED_OFF(void)

{

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2, GPIO_PIN_RESET);

}


void All_LED_OFF(void)

{

Green_LED_OFF();

Yellow_LED_OFF();

Red_LED_OFF();

}


void Buzzer_ON(void)

{

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET);

}


void Buzzer_OFF(void)

{

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET);

}


/* ===================== LOGIKA SISTEM PRIORITAS ===================== */


void System_Logic(float flow, float turbidity, float distance)

{

All_LED_OFF();


/*

PRIORITAS 1: ULTRASONIC

Jika jarak <= 3 cm:

Motor mati

LED merah ON

Buzzer ON

*/

if (distance > 0.0f && distance <= ULTRASONIC_LIMIT_CM)

{

Pump_OFF();

Red_LED_ON();

Buzzer_ON();


strcpy(systemStatus, "Penuh");

return;

}


/*

PRIORITAS 2: TURBIDITY

Jika turbidity > 25 NTU:

Motor mati

LED kuning ON

Buzzer ON

*/

if (turbidity > TURBIDITY_LIMIT_NTU)

{

Pump_OFF();


Green_LED_OFF();

Yellow_LED_ON();

Red_LED_OFF();


Buzzer_ON();


strcpy(systemStatus, "AIR KERUH");

return;

}


/*

PRIORITAS 3: FLOW

Jika flow < 1.3 L/min:

Motor mati

LED merah ON

Buzzer ON

*/

if (flow < FLOW_LIMIT_LMIN)

{

Pump_OFF();


Green_LED_OFF();

Yellow_LED_OFF();

Red_LED_ON();


Buzzer_ON();


strcpy(systemStatus, "FLOW KECIL");

return;

}


/*

NORMAL

Jika ultrasonic > 3 cm,

turbidity <= 25 NTU,

flow >= 1.3 L/min

*/

Pump_ON();


Green_LED_ON();

Yellow_LED_OFF();

Red_LED_OFF();


Buzzer_OFF();


strcpy(systemStatus, "NORMAL");

}


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


void SystemClock_Config(void)

{

RCC_OscInitTypeDef RCC_OscInitStruct = {0};

RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};


/*

Menggunakan HSI internal.

Cocok untuk Proteus tanpa crystal eksternal.


HSI = 8 MHz

PLL Source = HSI / 2 = 4 MHz

PLL x16 = 64 MHz

SYSCLK = 64 MHz

*/


RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;

RCC_OscInitStruct.HSIState = RCC_HSI_ON;

RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;


RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;

RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;

RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16;


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

}


/*

ADC Clock = 64 MHz / 6 = 10.67 MHz

*/

PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;

PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;


if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)

{

Error_Handler();

}

}


/* ===================== ADC1 INIT ===================== */


static void MX_ADC1_Init(void)

{

ADC_ChannelConfTypeDef sConfig = {0};


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

}


sConfig.Channel = ADC_CHANNEL_0;

sConfig.Rank = ADC_REGULAR_RANK_1;

sConfig.SamplingTime = ADC_SAMPLETIME_55CYCLES_5;


if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)

{

Error_Handler();

}

}


/* ===================== TIM2 INIT ===================== */


static void MX_TIM2_Init(void)

{

TIM_ClockConfigTypeDef sClockSourceConfig = {0};

TIM_MasterConfigTypeDef sMasterConfig = {0};


/*

SYSCLK = 64 MHz

TIM2 Prescaler = 63

Timer clock = 1 MHz

1 count = 1 us

*/


htim2.Instance = TIM2;

htim2.Init.Prescaler = 63;

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

}

}


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


static void MX_GPIO_Init(void)

{

GPIO_InitTypeDef GPIO_InitStruct = {0};


__HAL_RCC_GPIOA_CLK_ENABLE();

__HAL_RCC_GPIOB_CLK_ENABLE();


/*

Kondisi awal output

*/

HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);


HAL_GPIO_WritePin(GPIOB,

GPIO_PIN_0 |

GPIO_PIN_1 |

GPIO_PIN_2 |

GPIO_PIN_10 |

GPIO_PIN_12,

GPIO_PIN_RESET);


/*

PA0 = Turbidity ADC input

*/

GPIO_InitStruct.Pin = GPIO_PIN_0;

GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;

HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);


/*

PA1 = Ultrasonic TRIG

*/

GPIO_InitStruct.Pin = GPIO_PIN_1;

GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

GPIO_InitStruct.Pull = GPIO_NOPULL;

GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);


/*

PA2 = Ultrasonic ECHO

*/

GPIO_InitStruct.Pin = GPIO_PIN_2;

GPIO_InitStruct.Mode = GPIO_MODE_INPUT;

GPIO_InitStruct.Pull = GPIO_PULLDOWN; /* ← ganti dari GPIO_NOPULL */

HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);


/*

PA3 = Flow sensor interrupt

*/

GPIO_InitStruct.Pin = GPIO_PIN_3;

GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;

GPIO_InitStruct.Pull = GPIO_PULLUP;

HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);


/*

PB0 = LED Hijau

PB1 = LED Kuning

PB2 = LED Merah

PB10 = Buzzer

PB12 = Relay Pompa

*/

GPIO_InitStruct.Pin = GPIO_PIN_0 |

GPIO_PIN_1 |

GPIO_PIN_2 |

GPIO_PIN_10 |

GPIO_PIN_12;


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


/*

Interrupt PA3 untuk flow sensor

*/

HAL_NVIC_SetPriority(EXTI3_IRQn, 0, 0);

HAL_NVIC_EnableIRQ(EXTI3_IRQn);

}


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


void Error_Handler(void)

{

__disable_irq();


while (1)

{

HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_2);

HAL_Delay(300);

}

}

Rangkaian demo 


Komentar

Postingan populer dari blog ini