Share My Creation Digital Adjustable Power Supply

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.

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
Serial Público1 Como Serial
Serial Público1 Como Serial
Timer_ADC Público Como Temporizador
Controle Público do Temporizador Como Temporizador

    ' -------- PINOS --------
Volt_Leitura público como Pin A0 (pino 14) - tensão
Ampe_Leitura público como pino A1 (pino 15) - corrente ACS712 30A
    Public Pwm1 As Pin          ' D11 - saída PWM
Buzzer Público Como Pin ' D8
    Public Modo As Pin          ' D9  - botão confirmar
Pwm_Mais público como Pin ' A2 (pino 16) - ajuste fino +1
Pwm_Menos público como Pin ' A3 (pino 17) - ajuste fino -1
Public EncoderPinA Como Pin ' D12
Codificador Público PinB Como Pin ' D10
Public Ventilador Como Pin ' D4
Protetor Público Como Pin ' D3
   
    ' -------- VALORES MEDIDOS --------
BatVolt Público Como Carro Alegórico
Amper Público Como Carro Alegórico
PWM_Value Pública Como Int
   
    ' -------- CALIBRAÇÃO CORRENTE --------
OffsetAmp Público Como Flutuador
    Public OffsetAmpCalibrado As Boolean = False

Público ÚltimoEstadoTempo Enquanto Tempo
Público ÚltimoMaisTempo Enquanto Tempo
Público ÚltimoMenos Tempo Enquanto Tempo

    ' -------- LCD --------
LCD público como LiquidCrystal_I2C
Pub bc Como ByteConverter
   
    ' ----- Leitura ntc -----
R_NTC Pública Como Carro Alegórico
Comunidade Pública de Direitos Aglomerados
InvT Público Como Carro Alegórico
TempK público como carro alegórico
TempC Público Como Carro Alegórico
    Public Vref As Double = 4.8        ' Referência de tensão do ADC (3.3V se for NodeMCU/Wemos)
VentLigado Público como Booleano
Ntc_Leitura Pública Como Pin
Beta pública Como Flutuador
Leitura pública As Int
Tensão pública Como carro alegórico
R0 Público Como Carro Alegórico
T0 Público Como Carro Alegórico
   
O Modo_Volte Público Como Int
   

Fim de Substituição

Sub-Início de Apps Privado
Serial1.Inicialize(115200)
    Log("AppStart")
Modo.Inicialize(9, Modo.MODE_INPUT_PULLUP)'D9
Buzzer.Inicialize(8, Buzzer.MODE_OUTPUT) 'D8
pwm1.Inicialize(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(Falso)
   
Ventilador.Inicialize(4, Ventilador.MODE_OUTPUT) ' D4
    Ventilador.DigitalWrite(False)
   
Timer_ADC. Inicializar("Read_ADC", 500)
Timer_ADC. Ativado = Verdadeiro
   
    TimerControle.Initialize("Controle", 200)
    TimerControle.Enabled = True

lcd.Inicialize(0x27, 16, 2)
    lcd.Backlight = True
LCD. Limpo
    lcd.SetCursor(0, 0)
LCD.Write ("FONTE DE BANCADA")
    lcd.SetCursor(0, 1)
    lcd.Write("  Iniciando...  ")
Atraso (1500)
LCD. Limpo
Fim de Substituição

' =============================================================
' ENCODER
' =============================================================
Sub EncoderPinA_Changed (Declara como booleano)
    Dim t As Long = Millis
Se t - LastStateTime < 150 Então Retorne
ÚltimoEstadoTempo = t

Se EncoderPinB.DigitalRead então
        Modo_Volte = Modo_Volte + 1
        Bipe2
    Else
        Bipe2
        Modo_Volte = Modo_Volte - 1
Fim Se
Selecione Modo_Volte
Caso 1
            PWM_Value = 15
Caso 2
            PWM_Value = 24
Caso 3
            PWM_Value = 34
Caso 4
            PWM_Value = 44
Caso 5
            PWM_Value = 53
Caso 6
            PWM_Value = 62
Caso 7
            PWM_Value = 72
Caso 8
            PWM_Value = 81
Caso 9
            PWM_Value = 90
Caso 10
            PWM_Value = 99
Caso 11
            PWM_Value = 109
Caso 12
            PWM_Value = 118
Caso 13
            PWM_Value = 128
Caso 14
            PWM_Value = 137
Caso 15
            PWM_Value = 146
Caso 16
            PWM_Value = 156
Caso 17
            PWM_Value = 167
Fim Seleção
   
Se Modo_Volte > 17 Então Modo_Volte = 1
Se Modo_Volte < 1 Então Modo_Volte = 17

Fim de Substituição

' =============================================================
' LEITURA ADC (temporizador 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) ---
Se OffsetAmpCalibrado = False então
Dim SomaOffset como flutuante = 0
Para i = 1 a 100
    SomaOffset = SomaOffset + Ampe_Leitura.AnalogRead
Próximo
    OffsetAmp = (SomaOffset / 100) * (5.0 / 1023.0)
    OffsetAmpCalibrado = True
    Amper = 0
Retorno
Fim Se
Dim Soma Como Flutuante = 0
Para i = 1 a 20
        Soma = Soma + Ampe_Leitura.AnalogRead
Próximo
    Dim rawAmp As Float = Soma / 20
    Dim vAmp As Float = rawAmp * (5.0 / 1023.0)
Amper = Abs((vAmp - OffsetAmp) / 0,066)
Se Amper < 0,10, então Amper = 0
   
    '-------------Leitura do ntc---------------
    ' ----- Parâmetros -----
    beta = 3950        ' Constante Beta do NTC (ajuste fino depois)
R0 = 10000' Fixo do resistor (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
tensão = leitura * Vref / 1023.0

' ----- Resistência do NTC (resistor sem GND, NTC no +V) -----
    ' Fórmula correta para este esquema:
    ' R_NTC = R0 * (Vref - tensao) / tensao
Se tensao <= 0 então tensao = 0,001' evita divisão por zero
Se tensao >= Vref, então tensao = Vref - 0,001

R_NTC = R0 * (Vref - tensão) / tensão

    ' ----- Temperatura (Lei Beta) -----
lnR = Logaritmo(R_NTC / R0, 2,718281828)
    invT = (1 / T0) + (1 / beta) * lnR
    tempK = 1 / invT
tempC = tempK - 273,15

    ' ----- Calibração opcional -----
' correção = 4,8
' tempC = tempC + correção

    ' ----- Controle do ventilador -----
Se tempC > 40 E VentLigado = False Então
        Ventilador.DigitalWrite(True)
VentLigado = Verdadeiro
Caso contrário, se a temperatura C < 35 e VentLigado = verdadeiro, então
        Ventilador.DigitalWrite(False)
        VentLigado = False
Fim Se
   
   
Dim grau() como byte = array como byte(223)
    Log("Temperatura: ", NumberFormat(tempC, 1, 2), " °C")
    ' Linha 0: atualiza tensão
    lcd.SetCursor(0, 0)
    lcd.Write(NumberFormat(tempC, 2, 1))
LCD.Write (Grau)
    lcd.Write("C")
   

   
Texto escuro Como Corda
Se Amper < 1 então
        texto = NumberFormat(Amper * 1000, 1, 0)
    Else
        texto = NumberFormat(Amper, 1, 2)
Fim Se
Dim textoBytes() As Byte = texto. GetBytes
Dim Pos As Int = bc. IndexOf(textoBytes, ".". GetBytes)
Se Pos <> -1 então
textoBytes(Pos) = ",". GetBytes(0)
Fim Se
    lcd.SetCursor(11, 1)
LCD. Escrever(a.C. StringFromBytes(textoBytes))
Se Amper < 1 então
lcd.Write("mA")
    Else
lcd.Write("A")
Fim Se
   
    ' Linha 0: atualiza tensão
    lcd.SetCursor(10, 0)
LCD.Write(">")
    lcd.SetCursor(10, 1)
LCD.Write(">")

Texto dim As String = NumberFormat(BatVolt, 2, 1)
Dim textoBytes() As Byte = texto. GetBytes
Dim Pos As Int = bc. IndexOf(textoBytes, ".". GetBytes)
Se Pos <> -1 então
textoBytes(Pos) = ",". GetBytes(0)
Fim Se
    lcd.SetCursor(11, 0)
LCD. Escrever(a.C. StringFromBytes(textoBytes))
    lcd.Write("V")

Fim de Substituição


' =============================================================
' CONTROLE (temporizador 200ms)
' =============================================================
Sub Controle
    ' --- Botão ajuste fino + ---
Se Pwm_Mais.DigitalRead = False então
Se Millis - LastMaisTime > 200, então
            LastMaisTime = Millis
            PWM_Value = PWM_Value + 1
            Bipe2
Se PWM_Value > 255 Então PWM_Value = 255
Fim Se
Fim Se

    ' --- Botão ajuste fino - ---
Se Pwm_Menos.DigitalRead = False então
Se Millis - LastMenosTime > 200, então
            LastMenosTime = Millis
            PWM_Value = PWM_Value - 1
            Bipe2
Se PWM_Value < 0 Então PWM_Value = 0
Fim Se
Fim Se
   
    Pwm1.AnalogWrite(PWM_Value)
    Log("VALOR PWM: ", PWM_Value)

Fim de Substituição

Sub Bipe2
    Buzzer.DigitalWrite(True)
Atraso(20)
    Buzzer.DigitalWrite(False)
Fim Sub

 

Cableguy

Expert
Licensed User
Longtime User
Hi Cesar,

Great project you got here...
But be ware, your system automatically translatted the code to Portuguese, rendering it unusable for someone who does not understand the language.
 
Top