Digital Adjustable Power Supply
This project was developed using an Arduino Nano, providing precise output voltage control from 0 to 25V, with adjustment in both volts and millivolts through a rotary encoder.
This project was developed using an Arduino Nano, providing precise output voltage control from 0 to 25V, with adjustment in both volts and millivolts through a rotary encoder.
Project Features
- Adjustable output voltage from 0 to 25V
- Fine adjustment in volts and millivolts
- I2C LCD display for real-time information
- Rotary encoder control
- Temperature monitoring using an NTC sensor
- Automatic cooling fan control for transistor temperature management
- Short-circuit protection using transistor switching at the LM358 input
- Audible buzzer alarm for warnings and protection
- Real-time voltage and current monitoring
Tests Performed
A continuous test was conducted for approximately 30 minutes using an automotive lamp as the load, drawing about 1.7A. During the test, the system operated reliably and maintained stable voltage regulation while continuously monitoring the temperature of the power components.Applications
Ideal for electronics workbenches, equipment maintenance, circuit testing, and electronic project development.
B4R:
Sub Process_Globals
Public Serial1 As Serial
Public Serial1 As Serial
Public Timer_ADC As Timer
Public TimerControle As Timer
' -------- PINOS --------
Public Volt_Leitura As Pin ' A0 (pino 14) - tensão
Public Ampe_Leitura As Pin ' A1 (pino 15) - corrente ACS712 30A
Public Pwm1 As Pin ' D11 - saída PWM
Public Buzzer As Pin ' D8
Public Modo As Pin ' D9 - botão confirmar
Public Pwm_Mais As Pin ' A2 (pino 16) - ajuste fino +1
Public Pwm_Menos As Pin ' A3 (pino 17) - ajuste fino -1
Public EncoderPinA As Pin ' D12
Public EncoderPinB As Pin ' D10
Public Ventilador As Pin ' D4
Public Prot As Pin ' D3
' -------- VALORES MEDIDOS --------
Public BatVolt As Float
Public Amper As Float
Public PWM_Value As Int = 4
Public Amper2 As Float
Public Amper_Valor As Float
' -------- CALIBRAÇÃO CORRENTE --------
Public OffsetAmp As Float
Public OffsetAmp2 As Float
Public OffsetAmpCalibrado As Boolean = False
Public LastStateTime As Long
Public LastMaisTime As Long
Public LastMenosTime As Long
' -------- LCD --------
Public lcd As LiquidCrystal_I2C
Public bc As ByteConverter
' ----- Leitura ntc -----
Public R_NTC As Float
Public lnR As Float
Public invT As Float
Public tempK As Float
Public tempC As Float
Public Vref As Double = 4.8 ' Referência de tensão do ADC (3.3V se for NodeMCU/Wemos)
Public VentLigado As Boolean
Public Ntc_Leitura As Pin
Public beta As Float
Public leitura As Int
Public tensao As Float
Public R0 As Float
Public T0 As Float
Public Modo_Volte As Int
Public Modo_Set As Byte
Public Modo_Set2 As Boolean
End Sub
Private Sub AppStart
Serial1.Initialize(115200)
Log("AppStart")
Modo.Initialize(9, Modo.MODE_INPUT_PULLUP)'D9
Modo.AddListener("Menu_Modo")
Buzzer.Initialize(8, Buzzer.MODE_OUTPUT) 'D8
Pwm1.Initialize(11, Pwm1.MODE_OUTPUT) 'D11
Pwm1.AnalogWrite(0)
Volt_Leitura.Initialize(14, Volt_Leitura.MODE_INPUT) ' A0
Ampe_Leitura.Initialize(15, Ampe_Leitura.MODE_INPUT) ' A1
Ntc_Leitura.Initialize(21, Ntc_Leitura.MODE_INPUT) ' D7
Pwm_Mais.Initialize(16, Pwm_Mais.MODE_INPUT_PULLUP) ' A2
Pwm_Menos.Initialize(17, Pwm_Menos.MODE_INPUT_PULLUP) ' A3
EncoderPinA.Initialize(12, EncoderPinA.MODE_INPUT_PULLUP)' D12
EncoderPinB.Initialize(10, EncoderPinB.MODE_INPUT_PULLUP)' D10
EncoderPinA.AddListener("EncoderPinA_Changed")
Prot.Initialize(3, Prot.MODE_OUTPUT) ' D3
Prot.DigitalWrite(False)
Ventilador.Initialize(4, Ventilador.MODE_OUTPUT) ' D4
Ventilador.DigitalWrite(False)
Timer_ADC.Initialize("Read_ADC", 500)
Timer_ADC.Enabled = True
TimerControle.Initialize("Controle", 200)
TimerControle.Enabled = True
lcd.Initialize(0x27, 16, 2)
lcd.Backlight = True
lcd.Clear
lcd.SetCursor(0, 0)
lcd.Write("FONTE DE BANCADA")
lcd.SetCursor(0, 1)
lcd.Write(" Iniciando... ")
Delay(1500)
lcd.Clear
lcd.SetCursor(7, 0)
lcd.Write("V ")
lcd.SetCursor(10, 1)
lcd.Write(">")
Modo_Set = 0
End Sub
Sub Menu_Modo(State As Boolean)
If State = False Then
If Millis - LastMaisTime > 200 Then
LastMaisTime = Millis
Bipe2
Modo_Set = Modo_Set + 1
If Modo_Set > 2 Then Modo_Set = 0
End If
End If
Select Modo_Set
Case 0
lcd.SetCursor(10, 1)
lcd.Write(">")
lcd.SetCursor(7, 1)
lcd.Write(" ")
lcd.SetCursor(7, 0)
lcd.Write("V ")
Case 1
lcd.SetCursor(7, 0)
lcd.Write("mV ")
Case 2
lcd.SetCursor(7, 1)
lcd.Write("<")
lcd.SetCursor(10, 1)
lcd.Write(" ")
End Select
End Sub
' =============================================================
' ENCODER
' =============================================================
Sub EncoderPinA_Changed(State As Boolean)
Dim t As Long = Millis
If t - LastStateTime < 150 Then Return
LastStateTime = t
Dim Incremento As Float
If EncoderPinB.DigitalRead Then
Incremento = 1
Bipe2
Else
Incremento = -1
Bipe2
End If
Select Modo_Set
Case 0
Modo_Volte = Modo_Volte + Incremento
Select Modo_Volte
Case 1
PWM_Value = 15
Case 2
PWM_Value = 24
Case 3
PWM_Value = 34
Case 4
PWM_Value = 44
Case 5
PWM_Value = 53
Case 6
PWM_Value = 62
Case 7
PWM_Value = 72
Case 8
PWM_Value = 81
Case 9
PWM_Value = 90
Case 10
PWM_Value = 99
Case 11
PWM_Value = 109
Case 12
PWM_Value = 118
Case 13
PWM_Value = 128
Case 14
PWM_Value = 137
Case 15
PWM_Value = 146
Case 16
PWM_Value = 156
Case 17
PWM_Value = 167
End Select
Case 1
PWM_Value = PWM_Value + Incremento
Case 2
Amper_Valor = Amper_Valor + (Incremento * 0.01)
If Amper_Valor < 0 Then Amper_Valor = 0
If Amper_Valor > 5 Then Amper_Valor = 5
End Select
End Sub
' =============================================================
' LEITURA ADC (timer 500ms)
' =============================================================
Sub Read_ADC
'-------------Leitura da Voltagem 0 25v ---------------
' --- TENSÃO — R1=22k, R2=2k2, fator=10.57 ---
Dim rawBat As UInt = Volt_Leitura.AnalogRead
Dim vA0 As Float = rawBat * (5.0 / 1023.0)
BatVolt = vA0 * 10.50
'-------------Leitura da Amperagem ate 5 Amper ---------
' --- CORRENTE — ACS712 30A (66mV/A) ---
If OffsetAmpCalibrado = False Then
Dim SomaOffset As Float = 0
For i = 1 To 100
SomaOffset = SomaOffset + Ampe_Leitura.AnalogRead
Next
OffsetAmp = (SomaOffset / 100) * (5.0 / 1023.0)
OffsetAmpCalibrado = True
Amper = 0
Return
End If
Dim Soma As Float = 0
For i = 1 To 20
Soma = Soma + Ampe_Leitura.AnalogRead
Next
Dim rawAmp As Float = Soma / 20
Dim vAmp As Float = rawAmp * (5.0 / 1023.0)
Amper = Abs((vAmp - OffsetAmp) / 0.066)
If Amper < 0.10 Then Amper = 0
'-------------Leitura do ntc---------------
' ----- Parâmetros -----
beta = 3950 ' Constante Beta do NTC (ajuste fino depois)
R0 = 10000 ' Resistor fixo (10k)
T0 = 298.15 ' 25 °C em Kelvin
Vref = 3.3 ' ATENÇÃO: use 1.0 se seu A0 for de módulo “puro” (TOUT = 1.0V máx)
' ----- Leitura -----
leitura = Ntc_Leitura.AnalogRead ' 0..1023
tensao = leitura * Vref / 1023.0
' ----- Resistência do NTC (resistor no GND, NTC no +V) -----
' Fórmula correta para este esquema:
' R_NTC = R0 * (Vref - tensao) / tensao
If tensao <= 0 Then tensao = 0.001 ' evita divisão por zero
If tensao >= Vref Then tensao = Vref - 0.001
R_NTC = R0 * (Vref - tensao) / tensao
' ----- Temperatura (Lei Beta) -----
lnR = Logarithm(R_NTC / R0, 2.718281828)
invT = (1 / T0) + (1 / beta) * lnR
tempK = 1 / invT
tempC = tempK - 273.15
' ----- Calibração opcional -----
' correcao = 4.8
' tempC = tempC + correcao
' ----- Controle do ventilador -----
If tempC > 40 And VentLigado = False Then
Ventilador.DigitalWrite(True)
VentLigado = True
Else If tempC < 35 And VentLigado = True Then
Ventilador.DigitalWrite(False)
VentLigado = False
End If
Dim Grau() As Byte = Array As Byte(223)
Log("Temperatura: ", NumberFormat(tempC, 1,0)," °C")
' ' Linha 0: atualiza tensão
lcd.SetCursor(0, 0)
lcd.Write(NumberFormat(tempC, 2, 1))
lcd.Write(Grau)
lcd.Write("C")
'------------------Amperimetro---------------------------
Dim texto As String
If Amper < 1 Then
texto = NumberFormat(Amper * 1000, 1, 0)
Else
texto = NumberFormat(Amper, 1, 2)
End If
Dim textoBytes() As Byte = texto.GetBytes
Dim Pos As Int = bc.IndexOf(textoBytes, ".".GetBytes)
If Pos <> -1 Then
textoBytes(Pos) = ",".GetBytes(0)
End If
lcd.SetCursor(11, 1)
lcd.Write(bc.StringFromBytes(textoBytes))
If Amper < 1 Then
lcd.Write("mA ")
Else
lcd.Write("A ")
End If
'------------------ Limite de Amperímetro ---------------------------
Dim texto2 As String = NumberFormat(Amper_Valor, 1, 2)
Dim textoBytes2() As Byte = texto2.GetBytes
Dim Pos2 As Int = bc.IndexOf(textoBytes2, ".".GetBytes)
If Pos2 <> -1 Then
textoBytes2(Pos2) = ",".GetBytes(0)
End If
lcd.SetCursor(0, 1)
lcd.Write(bc.StringFromBytes(textoBytes2))
If Amper_Valor > 1 Then
lcd.Write("A ")
Else
lcd.Write("mA ")
End If
' Linha 0: atualiza tensão
lcd.SetCursor(10, 0)
lcd.Write(">")
'------------------Voltimetro---------------------------
Dim texto As String = NumberFormat(BatVolt, 2, 1)
Dim textoBytes() As Byte = texto.GetBytes
Dim Pos As Int = bc.IndexOf(textoBytes, ".".GetBytes)
If Pos <> -1 Then
textoBytes(Pos) = ",".GetBytes(0)
End If
lcd.SetCursor(11, 0)
lcd.Write(bc.StringFromBytes(textoBytes))
lcd.Write("V")
End Sub
' =============================================================
' CONTROLE (timer 200ms)
' =============================================================
Sub Controle
' --- Botão ajuste fino + ---
If Pwm_Mais.DigitalRead = False Then
If Millis - LastMaisTime > 200 Then
LastMaisTime = Millis
PWM_Value = PWM_Value + 1
Bipe2
If PWM_Value > 255 Then PWM_Value = 255
End If
End If
' --- Botão ajuste fino - ---
If Pwm_Menos.DigitalRead = False Then
If Millis - LastMenosTime > 200 Then
LastMenosTime = Millis
PWM_Value = PWM_Value - 1
Bipe2
If PWM_Value < 0 Then PWM_Value = 0
End If
End If
Pwm1.AnalogWrite(PWM_Value)
Log("VALOR PWM: ", PWM_Value)
End Sub
Sub Bipe2
Buzzer.DigitalWrite(True)
Delay(20)
Buzzer.DigitalWrite(False)
End Sub
Attachments
Last edited: