Sunteți pe pagina 1din 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 **************************************

S-ar putea să vă placă și