100% found this document useful (2 votes)
464 views0 pages

PIC Power Supply

This document describes a PIC16F876A controlled power supply that can operate in either constant voltage or constant current mode. It has adjustable output voltage from 0 to 25V at 0.1V resolution and one of four current ranges: 0-1A, 0-2A, 0-4A, or 0-8A. The power supply uses a 2 line LCD to display the set and measured voltage and current values and indicates whether it is operating in voltage or current control mode. Adjustments can be made using buttons to change the set voltage and current values.

Uploaded by

aqdus
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (2 votes)
464 views0 pages

PIC Power Supply

This document describes a PIC16F876A controlled power supply that can operate in either constant voltage or constant current mode. It has adjustable output voltage from 0 to 25V at 0.1V resolution and one of four current ranges: 0-1A, 0-2A, 0-4A, or 0-8A. The power supply uses a 2 line LCD to display the set and measured voltage and current values and indicates whether it is operating in voltage or current control mode. Adjustments can be made using buttons to change the set voltage and current values.

Uploaded by

aqdus
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 0

General purpose PIC16F876A controlled power supply

CONSTANT VOLTAGE, 0<25V OR CONSTANT CURRANT, 1, 2, 4 and 8 Amp ver.



SPECIFICATIONS
VOLTAGE: - Ajustable from 0 < 25 Volts at a resolution of 100 mV.
CURRENT: choice of 4 ranges;
- 0 < 1.000A at a resolution of 1 mA.
JP1 and JP2 open, C1 = 2000uF filter cap., R7 = 0.5 Ohm, T1 = 24V, 1Amp.
- 0 < 2.000A at a resolution of 2 mA.
JP1 ground and JP2 open, C1 = 4000uF filter cap., R7 = 0.25 Ohm, T1 = 24V, 2Amp.
- 0 < 4.000A at a resolution of 4 mA.
JP1 open and JP2 ground, C1 = 8000uF filter cap., R7 = 0.125 Ohm, T1 = 24V, 4Amp.
- 0 < 8.000A at a resolution of 8 mA.
JP1 and JP2 ground, C1 = 16000uF filter cap., R7 = 0.0625 Ohm, T1 = 24V, 8Amp.
2 lignes LCD display:
- The top line shows the settings, the maximum current stays displayed at all times,
it is not necessary to short the output terminals to set the maximum current.
- The bottom line shows the measured values.
- The arrows at the bottom center line show who is in control, the voltage or the current.
Ajustments:
- Voltage, steps of 1 V and 0.1 V.
- Current, steps of 1, 2, 4, 8 mA and 50, 100, 200, 400 mA depending on the Amp range.
- Memorisation of the last settings before power off, restarting with thoses same settings.
View the schematic
Parts list
C1 = 2000uF per AMP, 40V (adjust capacity to power supply amps)
C2,C3,C12,C15,C18,C21 = 0.1uF CER
C4 = 0.01uF CER
C5A,C5B,C5C,C5D = 0.01uF CER
C6,C7 = 0.05uF CER
C8 = Not used
C9,C11,C19,C20 = 1uF CER
C10 = 470uF 15V EL RADIAL
C13 = 4.7F 50V EL RADIAL
C14 = 0.001uF CER
C16,C17 = 22pF CER
D1,D2,D4,D5 = 1N4148
D3 = 1N4004
Br1 = 1<10A BRIDGE RECTIFIER (adjust seize to power supply amps)
DZ1 = 1N4751 30V ZENER
IC1 = LM317KCS TO220
IC2 = LM337LZ TO92
IC3 = LT1491CN special HV opamp, do not substitute
IC4 = PIC16F876A
Q1 = 2N3906
Q2A to Q2D = TIP142TU 1 to 5 transistors (adjust quantity to power supply amps)
Q3A to Q3D = 2N3904 (adjust quantity to power supply amps)
X1 = 20 mHz HC49 DigiKey PN: 300-6042-ND
LED1 = T1 3/4 RED OR GREEN LED
LCD = LCD, 2X16, HD44780 intelligent controller DigiKey PN: 67-1758-ND insulate from case
P1 = 500 Ohms
P2 = 10 kOhms
P3,P4 = 5 kOhms
R1 = 1 kOhms 10W
R2 = 1.5 kOhms
R3,R11,R12,R13,R14,R16,R17,R25,R26,R27 = 10 kOhms
R4 = 56 Ohms
R5A to R5D = 0.22 Ohms (adjust quantity to power supply amps)
R6,R28,R29 = 47k Ohms
R7 = as per schematic (adjust value to power supply amps)
R8 = 240 Ohms
R9 = 270 Ohms
R10 = 390 Ohms
R15 = 39 kOhms
R18 = 39 kOhms
R19 = 8.2 kOhms
R20,R22,R23,R32 = 1 kOhms
R21 = 5.6 kOhms
R24 = 33 Ohms 1/2W
R30,R31 = 4.7 kOhms
SW1 = SPST min toggle
SW2,SW3,SW4,SW5,SW6,SW7,SW8,SW9 = NO_SP push button
T1 = 24 V 1<8A (adjust seize to power supply amps)
T2 = 6.3 V, 150 mA
MISC: 3 Terminals, Transistors Heat Sink, up to: 1A = 30W, 2A = 60W, 4A = 120W, 8A = 240W to dissipate
Line filter, Case PCB, IC sockets...
View the PCB
View the PCB + parts
CALIBRATION
LCD:
- Adjust P2 near ground for a nice contrast.
VOLTAGE:
- Adjust P1 for a supply of 5.12V.
- Measure the voltage output terminals, adjust P3 to for the same voltage reading on the
PS LCD and the meter.
CURRENT:
- Install a 10 Ohm resistor in series with an ammeter in series on the output terminals.
- adjust P4 for a correct Amp reading on the LCD.
NOTE
I recommand the use of a PIC16F876A, it is lower in cost and has a better EEDATA
memory.
The source program in "C" and the object code (HEX) for the PIC16F876A in
alim_v3.zip.
//-------------------------- ALIM V3 ----------------------------------------
// ALIMENTATION VARIABLE CONSTANT VOLTAGE, CONSTANT COURANT, 0 < 25V
// choix de 4 gammes de courant, 0<1A, 2A, 4A et 8A VERSION: 3.0
// PAR VE2EMM avril 04
//---------------------------------------------------------------------------
#include <16F876a.h>
#device ADC=16 // les 10 bits de gauche sont valable
#use delay(clock=20000000)
#fuses HS,NOWDT,PUT,BROWNOUT,NOPROTECT,NOLVP,NOCPD,NOWRT
//#rom 0x2100={0x00,0x00,0x00,0x00,0x00} // zero les premieres 4 cases du EEDATA
#use fast_io(A)
#use fast_io(B)
#use fast_io(C)
//------------------------- VARIABLES -------------------
INT8 i; // 0 < + 255
int8 commande; // 0 < + 255
int8 car; // 0 < + 255
int8 nibble; // 0 < + 255
int8 boutons; // 0 < + 255
int8 bit_status; // 0 < + 255
int16 disp_a; // pour gamme de l'affichage Amp
int8 disp_ma; // pour gamme de l'affichage mAmp
//-----------
signed int16 volt_moy[16];
signed int16 amp_moy[16];
signed int16 volt_set=0; // -32768 < +32767
signed int16 volt_lue=0; // " "
signed int16 amp_set=0; // " "
signed int16 amp_lue=0; // " "
//------------------------- FONCTIONS ---------------
void pic_ini(void);
void lcd_ini(void);
void write_cmd_lcd(int8); // LCD
void write_car_lcd(INT8); // LCD
void send_nibble(int8); // LCD
void busy_status(void); // LCD
void lire_voltage(void); // lire et afficher E
void lire_courant(void); // lire et afficher I
void lire_PB(void); // lire les boutons, changer les consignes de voltage et de courant
void set_range(void);
void comparer_Iset_Ilue(void); // determiner qui est en controle, E ou I
//********************************* MAIN ***********************************
void main(void)
{
pic_ini();
lcd_ini();
for(i=0;i<=15;i++) volt_moy[i]=0;
for(i=0;i<=15;i++) amp_moy[i]=0;
//------- afficher ecran d"acceuil -------
write_cmd_lcd(128); // adresse du debut de la 1 re ligne
printf(write_car_lcd,"ALIMENTATION V3 ");
write_cmd_lcd(192); // adresse du debut de la 2 ie ligne
printf(write_car_lcd," PAR VE2EMM ");
for(i=0;i<4;i++) delay_ms(250); // laisser affichage 1 1/2 seconde
//---- charger les valeurs du eedata
for(i=0;i<2;i++) *(&volt_set+i)=read_eeprom(10+i); // reprendre les consignes
if((volt_set>1023)||(volt_set<0))volt_set=0;
for(i=0;i<2;i++) *(&amp_set+i)=read_eeprom(12+i); // du dernier usage
if((amp_set>1023)||(amp_set<0))amp_set=0;
//---- programme principal
while(true)
{
set_range();// choisir la gamme du courant, 1, 2, 4 ou 8 Amp
lire_PB(); // lire les boutons et placer les consignes de voltage et de courant
write_cmd_lcd(128); // adresse du debut de la 1ere ligne
printf(write_car_lcd,"%01ld,%03ldA SET
%02ld,%01ldV",amp_set/disp_a,amp_set*disp_ma,volt_set/40,volt_set/4);
SET_PWM1_duty(amp_set); // amp_set
SET_PWM2_duty(volt_set); // volt_set
lire_voltage(); // lire et afficher
lire_courant(); // lire et afficher
comparer_Iset_Ilue(); // lire et afficher qui est en controle, E ou I
}
}
//********************************* FIN MAIN ******************************
//************************************ FONCTIONS *****************************
void pic_ini(void)
{
//-- PORTS
output_A(0x00);
output_B(0x00);
output_C(0x00);
set_tris_A(0b11011111);
port_B_pullups(true);
set_tris_B(0b11111111);
set_tris_C(0b00000000);
//--- ADC
setup_adc_ports(RA0_RA1_RA3_ANALOG);
setup_adc(ADC_CLOCK_INTERNAL);
//--- PWM
SET_PWM1_duty(0); // amp_set
SET_PWM2_duty(0); // volt_set
setup_timer_2(t2_div_by_16,255,1);
setup_ccp1(CCP_PWM_PLUS_3);
setup_ccp2(CCP_PWM_PLUS_3);
}
//-------------------------------------------------
void lcd_ini(void)
{
delay_ms(100); // attendre que le 5V soit stabilise
output_bit(PIN_A5,0); // E clock
output_bit(PIN_C0,0); // R/W R=1,W=0
output_bit(PIN_C3,0); // R/S 0 pour commande, 1 pour data
for(i=1;i<=4;i++) {send_nibble(0x30); delay_ms(5);} // reset du LCD
send_nibble(0x20); // interface 4 bits
delay_us(43);
write_cmd_lcd(0x28); // interface 4 bits, 5X7
write_cmd_lcd(0x08); // display off
write_cmd_lcd(0x0C); // display on
write_cmd_lcd(0x06); // increment no display shift
}
//*********************** Fonctions du LCD *****************************
void write_cmd_lcd(commande)
{
busy_status(); // LCD pret?
output_bit(PIN_C3,0); // R/S 0 pour commande
send_nibble(commande); // placer commande dans LCD
swap(commande);
send_nibble(commande); // placer commande dans LCD
}
//-------------- afficher un caractere sur le LCD --------------------------
void write_car_lcd(car)
{
busy_status(); // LCD pret?
output_bit(PIN_C3,1); // R/S 1 pour data
send_nibble(car); // placer commande dans LCD
swap(car);
send_nibble(car); // placer commande dans LCD
}
//-------------------- Envoyer un nibble ----------------
void send_nibble(nibble)
{
output_bit(PIN_C0,0); // R/W R=1, W=0
output_bit(PIN_A5,0); // E line low
delay_cycles(3);
output_bit(PIN_A5,1); // pulser E high
nibble=nibble&0xF0; // vider les 4 bits du bas de la byte
nibble=nibble|(input_C()&0x0F); // charger C0-C3
output_C(nibble);
delay_cycles(3);
output_bit(PIN_A5,0); // E low
}
//-----------------------
void busy_status() // tester si le LCD est pret a accepter un data
{
do
{
set_tris_C(0b11110000);
output_bit(PIN_A5,0); // E off
output_bit(PIN_C0,1); // R/W R=1,W=0
output_bit(PIN_C3,0); // R/S 0 pour commande, 1 pour data
delay_cycles(3);
output_bit(PIN_A5,1); // pulser E high
delay_cycles(3);
bit_status=input_C()&0X80; // lire status
delay_us(2);
output_bit(PIN_A5,0); // E off
delay_cycles(3);
output_bit(PIN_A5,1); // pulser E high
delay_us(1); // faire semblant de lire les 4 bits de status du bas
output_bit(PIN_A5,0); // E off
delay_cycles(3);
}
while(bit_status==0x80);
set_tris_C(0b00000000);
}
//***************************** Fin des fonctions LCD ********************************
//************************************************************************************
void lire_voltage() // lire et afficher
{
SET_ADC_CHANNEL(0);
delay_ms(1);
for(i=15;i>=1;i--) volt_moy[i]=volt_moy[i-1];
volt_moy[0]=READ_ADC()/64; // tasser a droite la lecture dans les 2 bytes, 6 bits
volt_lue=0;
for(i=0;i<=15;i++) volt_lue=volt_lue+volt_moy[i];
volt_lue=volt_lue/16;
volt_lue=volt_lue+2;// compenser pour le restant de la division a l'affichage
//if(volt_lue<=7)volt_lue=0;
write_cmd_lcd(203); // adresse du 3/4 de la 2ie ligne
printf(write_car_lcd,"%02ld,%01ldV",volt_lue/40,volt_lue/4);
}
//----------------------------
void lire_courant() // lire et afficher, tester si I depasse la limite et est en controle
{
SET_ADC_CHANNEL(1);
delay_ms(1);
for(i=15;i>=1;i--) amp_moy[i]=amp_moy[i-1];
amp_moy[0]=READ_ADC()/64; // tasser a droite la lecture dans les 2 bytes, 6 bits
amp_lue=0;
for(i=0;i<=15;i++) amp_lue=amp_lue+amp_moy[i];
amp_lue=amp_lue/16;
amp_lue=amp_lue+1;
write_cmd_lcd(192); // adresse du debut de la 2ie ligne
printf(write_car_lcd,"%01ld,%03ldA",amp_lue/disp_a,amp_lue*disp_ma);
}
//----------------------------
void set_range()
{
if((input(pin_A2)==1)&&(input(pin_A4)==1)){disp_a=1000;disp_ma=1;}
if((input(pin_A2)==0)&&(input(pin_A4)==1)){disp_a=500;disp_ma=2;}
if((input(pin_A2)==1)&&(input(pin_A4)==0)){disp_a=250;disp_ma=4;}
if((input(pin_A2)==0)&&(input(pin_A4)==0)){disp_a=125;disp_ma=8;}
}
//--------------------------------------------------------------
void lire_PB() // lire les boutons et setter voltage et le courant
{
boutons=input_b();
if(boutons!=0xFF)
{
switch(boutons)
{
case 0b01111111: // grande reduction du voltage *************
volt_set=volt_set-40;
if(volt_set<=0) volt_set=0;
break;
case 0b10111111: // grande reduction du courant
amp_set=amp_set-50;
if(amp_set<=0) amp_set=0;
break;
case 0b11011111: // grande augmentation du voltage **********
volt_set=volt_set+40;
if(volt_set>=1000) volt_set=1000;
break;
case 0b11101111: // grande augmentation du courant
amp_set=amp_set+50;
if(amp_set>=1000) amp_set=1000;
break;
case 0b11110111: // petite augmentation du voltage **********
volt_set=volt_set+4;
if(volt_set>=1000) volt_set=1000;
break;
case 0b11111011: // petite augmentation du courant
amp_set=amp_set+1;
if(amp_set>=1000) amp_set=1000;
break;
case 0b11111101: // petite reduction du voltage *************
volt_set=volt_set-4;
if(volt_set<=0) volt_set=0;
break;
case 0b11111110: // petite reduction du courant
amp_set=amp_set-1;
if(amp_set<=0) amp_set=0;
break;
default: // plus qu'un bouton pese
break;
}
for(i=0;i<2;i++) write_eeprom(10+i,*(&volt_set+i));
for(i=0;i<2;i++) write_eeprom(12+i,*(&amp_set+i));
delay_ms(350); // taux de repetition
}
}
//-------------------------------
comparer_Iset_Ilue()
{
write_cmd_lcd(198); // milieu de la 2ie ligne
if (amp_lue<(amp_set-1)) printf(write_car_lcd," >>> ");
else printf(write_car_lcd," <<< ");
}
//******************************** Fin des fonctions **************************************

You might also like