////////////////////////////////////////////////////////////////////////////////
// PROJECT
////////////////////////////////////////////////////////////////////////////////
// PROJECT : Power Supply A3
// VERSION : 1.3 - 20/09/2025
// GROUP : Elias Bernabé Turchiéllo, João Vitor Iuncks, Kamilly Pereira de Castro
////////////////////////////////////////////////////////////////////////////////
// INCLUDES
////////////////////////////////////////////////////////////////////////////////
// DISPLAY I2C LIBRARY
#include <LiquidCrystal_I2C.h>
////////////////////////////////////////////////////////////////////////////////
// SETTINGS
//////////////////////////////////////////////////////////////////////////////
// INSTANTIATE DISPLAY 16X2
LiquidCrystal_I2C lcd(0x27, 16, 2); // I2C address, columns, rows
// PINS
const int out_relay = 2;
const int pwm_volt_pin = 3;
const int button_relay = 4;
const int volt_monitor_pin = A0;
const int amp_monitor_pin = A1;
const int volt_adjust_pin = A7;
const int amp_adjust_pin = A6;
// VARIABLES
bool mode_operation = true; // true = voltage. false = current
bool relay_on = false; //
bool relay_state_1 = LOW;
////////////////////////////////////////////////////////////////////////////////
// INITIAL CONFIGURATION
////////////////////////////////////////////////////////////////////////////////
void setup() {
// START SERIAL FOR DEBUG
Serial.begin(9600);
// INITIATE DISPLAY
lcd.init();
lcd.backlight();
lcd.clear();
// INITIATE PIN
pinMode(out_relay, OUTPUT);
pinMode(pwm_volt_pin, OUTPUT);
pinMode(button_relay, INPUT_PULLUP);
// SET OUTPUT RELAY
digitalWrite(out_relay, relay_state_1);
}
////////////////////////////////////////////////////////////////////////////////
// FUNCTIONS
////////////////////////////////////////////////////////////////////////////////
// SHOW INFORMATION ON DISPLAY +++++++++++++++++++++++++++++++++++++++++++++++++
void display_printer (float volts_output = 0.0, float amps_output = 0.0, bool mode_operation = true) {
// SHOW VOLTS OUTPUT
lcd.setCursor(0, 0);
lcd.print(" ");
lcd.setCursor(0, 0);
if (volts_output < 10) {
lcd.print(0);
}
lcd.print(volts_output);
lcd.print(" V");
// SHOW AMPERES OUTPUT
lcd.setCursor(0, 1);
lcd.print(" ");
lcd.setCursor(0, 1);
if (amps_output < 10) {
lcd.print(0);
}
lcd.print(amps_output);
lcd.print(" A");
// SHOW MODE OPERATION
if (mode_operation == true) {
lcd.setCursor(11, 0);
lcd.print("CONST");
lcd.setCursor(11, 1);
lcd.print(" ");
} else {
lcd.setCursor(11, 0);
lcd.print(" ");
lcd.setCursor(11, 1);
lcd.print("CONST");
}
}
// READ AVERAGE OF ANALOGIC INPUT ++++++++++++++++++++++++++++++++++++++++++++++
float get_anlogic_average(int pin) {
// INCREMENT VARIABLE
unsigned char i; // IT CAN'T BE INTEGER BECAUSE OVERFLOW
// RANGRE LIMIT
int range = 100.0;
// READ THE INPUT TOO MANY TIMES
float read_sum = 0;
for (i = 0; i < range; i++) {
read_sum += analogRead(pin);
}
// RETURN THE AVERAGE
return(read_sum / range);
}
////////////////////////////////////////////////////////////////////////////////
// RUN
////////////////////////////////////////////////////////////////////////////////
void loop() {
// READ INPUT PINS +++++++++++++++++++++++++++++++++++++++++++++++++++++
int volt_out_monitor = get_anlogic_average(volt_monitor_pin);
int ampe_out_monitor = get_anlogic_average(amp_monitor_pin);
// READ ADJUST VALUES ++++++++++++++++++++++++++++++++++++++++++++++++++
int volt_adjust = get_anlogic_average(volt_adjust_pin);
int ampe_adjust = get_anlogic_average(amp_adjust_pin);
// CONVERT THE AD VALUES +++++++++++++++++++++++++++++++++++++++++++++++
// ADJUST
float voltage_setpoint = volt_adjust * 0.0293255131965; // Voltage desired
float current_setpoint = ampe_adjust * 0.009775; // Current desired
// OUTPUT FOR DISPLAY
float volt_display = volt_out_monitor * 0.0293255131965; // Max voltage scale / max ad value (30 / 1023) 30V
float ampe_display = ampe_out_monitor * 0.00215053763441; // Max voltage scale / max ad value (2.2 / 1023) 10A Shunt 0,22R
// Serial.println("V: " + String(volt_display) + " A: " + String(ampe_display));
// Serial.println("AD: " + String(current_setpoint) + " OU: " + String(ampe_display));
// PWM CONTROL +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// INITIAL FROM OUTPUT
int pwm_val = map(volt_adjust, 0, 1023, 0, 255);
// CHECK CURRENT
if (ampe_display < current_setpoint) {
// MODE OPERATION
mode_operation = true;
// CHECK VOLTAGE
if (volt_display < voltage_setpoint) {
pwm_val += 1;
} else if (volt_display > voltage_setpoint) {
pwm_val -= 1;
}
} else {
// MODE OPERATION
mode_operation = false;
// REDUCE PWM
pwm_val -= 3;
}
// CHECK PWM RANGE 0 - 255
if (pwm_val > 255) {
pwm_val = 255;
}
if (pwm_val < 0) {
pwm_val = 0;
}
// APPLY PWM
// Serial.println(pwm_val);
analogWrite(pwm_volt_pin, pwm_val);
// GENERATE PWM
// int pwm_val = map(volt_adjust, 0, 1023, 0, 255);
// int pwm_val = map(volt_out_monitor, 0, 1023, 0, 255);
// analogWrite(pwm_volt_pin, pwm_val);
// SHOW INFORMATIN ON DISPLAY ++++++++++++++++++++++++++++++++++++++++++
display_printer(float(volt_display), float(ampe_display), mode_operation);
// MANIPULATE OUTPUT +++++++++++++++++++++++++++++++++++++++++++++++++++
// int btn_relay = digitalRead(4);
// if (btn_relay == 0) {
// int rl = digitalRead(out_relay);
// rl = !rl;
// digitalWrite(out_relay, rl);
// }
// READ BUTTON
bool relay_state_2 = digitalRead(button_relay);
// Detecta transição de HIGH para LOW (borda de descida)
if (relay_state_1 == HIGH && relay_state_2 == LOW) {
// Inverte o estado do relé
relay_on = !relay_on;
digitalWrite(out_relay, relay_on ? HIGH : LOW);
// DEBOUNCE
// delay(50);
}
relay_state_1 = relay_state_2;
// FOR DISPLAY COMFORT
// delay(50);
}
Tensão
Corrente
Tensão de saída
Corrente de saída