|
|
View previous topic :: View next topic |
Author |
Message |
coyotte4845
Joined: 16 Mar 2017 Posts: 4
|
MPPT type boost /16f883/ programmation |
Posted: Thu Mar 16, 2017 8:46 am |
|
|
Hello,
Can you help me with this code (16f883) ?
This code has to search for the mpp for a solar regulator type boost.
The PIC has a power supply fixed to 3v.
The pic has to measure 3 values from AN0(Upanel), AN1 (Ubatt), AN3(Ipanel pin5).
I used a max4376 and a current sensor, the output is directly connected to input AN3.
My problem is: impossible to read AN3.
Thanks for your help.
PCWH 4.0.38
Code: |
#include "C:\Documents and Settings\Moi\Bureau\PICC\MPPT citea 3V\main.h"
#bit godone=0x1F.1
#bit ADIF=0x0C.6
#byte ADCON0=0x1F
#byte ADCON1=0x9F
#byte ADRESL=0x9E
#byte ADRESH=0x1E
#byte ANSEL=0x188
#define LED pin_b7
#int_TIMER1
TIMER1_isr()
{
int i;
i++;
if(i>=30)
{output_high(LED);
delay_ms(100);
output_low(LED);
i=0;
}
}
void main()
{
unsigned int16 PWM=0,t=0,i=0;
unsigned int16 ADVp=0,ADVpt=0,CompADVp=0;
unsigned int16 ADVb=0,ADVbt=0;
unsigned int16 ADI=0,ADIt=0;
unsigned int16 SADI=0,SADVb=0,SADVp=0;
unsigned int32 Pow=0,CompPow=0;
float fADVp=0,fADVb=0,fADI=0;
Set_tris_b( 0b00000000 ); //Pin B0-B7 output
Set_tris_a( 0b11111111 ); //Pin A0-A1 input
setup_adc_ports(sAN0|sAN1|sAN3|VSS_VDD);
setup_adc(ADC_CLOCK_DIV_32);
setup_spi(SPI_SS_DISABLED);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_wdt(WDT_2304MS);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
setup_timer_2(T2_DIV_BY_1,62,1);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
setup_ccp1(CCP_PWM);
set_pwm1_duty(0);
output_low(LED);
while(1)
{
//Capture, traitement et envoi de Vpanel START
ADCON1=0b10000000; //Activation de l'ADC
delay_us(25);
ADCON0=0b10000101; //Choix du canal à échantillonner
delay_us(25);
while(i<10) //Capture de 10 mesures successives
{
godone=1;
while(godone);
ADVpt=read_adc();
SADVp=SADVp+ADVpt; //Somme des tensions
i++;
}
ADVp=SADVp/10; //Moyenne effectuée
SADVp=0;
ADVpt=0;
i=0;
if(t==4000)
{
fADVp=(float)ADVp/131.02; //Conversion en valeur décimale (float)
printf("\n\nSTART----------------------------------------");
printf("\n\nPanel voltage : %1.1fV",fADVp);
}
//Capture, traitement et envoi de Vpanel END
//____________________________________________________________
//Capture, traitement et envoi de Ipanel START
ADCON0=0b10001101; //Choix du canal
delay_us(25);
while(i<10) //Capture de 10 mesures successives
{
godone=1;
while(godone);
ADIt=read_adc();
SADI=SADI+ADIt; //Somme des courants
i++;
}
ADIt=0;
ADI=SADI/10; //Moyenne effectuée
SADI=0;
i=0;
if(t==4000)
{
fADI=(float)ADI/511;
printf("\n\nPanel current : %1.3fA",fADI);
}
//Capture, traitement et envoi de Ipanel END
//____________________________________________________________
//Capture, traitement et envoi de Vbatterie START
//____________________________________________________________
ADCON0=0b10000001; //Choix du canal
delay_us(25);
while(i<5) //Capture de 5 mesures successsives
{
godone=1;
while(godone);
ADVbt=read_adc();
SADVb=SADVb+ADVbt;
i++;
}
ADVb=SADVb/5;
ADVbt=0;
SADVb=0;
i=0;
if(t==4000)
{
fADVb=(float)ADVb/65.51;
printf("\n\nAccu voltage : %2.1fV",fADVb);
}
//Capture, traitement et envoi de Vbatterie END
//____________________________________________________________
//routine de comparaison des Pow calculées
Pow=ADVp*ADI;
if(ADVb>904) //Vb>13,8V
{set_pwm1_duty(0);}
else{
if((Pow>=CompPow)&&(ADVp>305)&&(PWM<230))
{ PWM++;
set_pwm1_duty(PWM);}
if(Pow<CompPow)
{ if((ADVp>CompADVp)&&(PWM<230)&&(ADVp>305)) //ADVp>3,1V
{ PWM++;
set_pwm1_duty(PWM);
}
else if((ADVp<CompADVp)&&(PWM>0))
{ PWM--;
set_pwm1_duty(PWM);
}
}
}
CompPow=Pow;
CompADVp=ADVp;
t++;
restart_wdt();
}
}
|
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9270 Location: Greensville,Ontario
|
|
Posted: Thu Mar 16, 2017 9:36 am |
|
|
Ok...
first there's no PIC type header... should (must) be 1st line of code...
2nd you probably have to disable the comparator that's ALSO on that AN3 pin
3rd there's a LOT of code that can be done a LOT 'cleaner' and easier to read using the CCS functions
4th disable the WDT ! Unless you're making a commercial product and 99.9999% finished with Real worlde testingyou do NOT 'need' the WDT feature of the PIC.
#5 NEVER EVER put a delay inside an ISR. ISRs are supposed to be fast,small and simple.
6th. averages. do 8,16 or 4 readings,it'll be a LOT faster.
7th do not use floating point.....takes a huge amount of time and NOT required.
that's a start.....
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19590
|
|
Posted: Thu Mar 16, 2017 9:44 am |
|
|
A lot of things wrong:
Now, first a question. How fast are you clocking the chip?. At 3v it is only rated for 10Mhz max.
Then Just use 'set_adc_channel(3);'. Get rid of all the code accessing the registers. Not necessary.
Then the setup_spi is wrong. This is enabling the SPI, with the slave select disabled. To disable the spi, you want setup_spi(FALSE);
Then you don't show your header, so there may be lots of problems here.
Then when sampling the ADC repeatedly, you need to delay for Tacq between each successive read.
Then as another comment, use 8, or 16 samples. /10, involves hundreds of lines of code. The binary divisions (2,4,8,16 etc.), will be done by simple rotations. Smaller code and faster....
Comparator is on that pin. Needs to be disabled.
Using FP maths in code is a sure sign of somebody not 'thinking embedded'...
You have a delay in an interrupt. Except for a tiny 'delay_cycles' type delay for specific chip timings, this should never be done. Much better to use another interrupt, or just a 'tick' wand wait for a cycle of this.
Ugly code. Learn to layout and comment. It'll make it easier for _you_. |
|
|
coyotte4845
Joined: 16 Mar 2017 Posts: 4
|
|
Posted: Thu Mar 16, 2017 1:17 pm |
|
|
Hello,
Many thanks for your suggests and also for your honesty,
i'm beginner in langage C
please follow the modified code:
Code: |
#include <16F883.h>
#device adc=10
#FUSES NOWDT //Watch Dog Timer
#FUSES INTRC_IO //Internal RC Osc, no CLKOUT
#FUSES PROTECT //Code protected from reading
#FUSES MCLR //Master clear Pin enabled
#FUSES NOCPD //No EE protection
#FUSES BROWNOUT //Reset when brownout detected
#FUSES BORV21 //Brownout reset at 2.1V
#FUSES NOIESO //Internal External Switch Over mode disabled
#FUSES NOFCMEN //Fail-safe clock monitor disabled
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NODEBUG //No Debug mode for ICD
#FUSES NOWRT //Program memory not write protected
#FUSES PUT //Power Up Timer
#use delay(clock=8000000)
#use rs232(baud=115200,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#define LED pin_b7
void main()
{
unsigned int16 PWM=0,t=0,i=0;
unsigned int16 CompADVp=0;
unsigned int16 ADVpt=0,ADIt=0,ADVbt=0;
unsigned int16 ADVb=0;
unsigned int16 ADI=0,ADVp=0;
unsigned int32 SADI=0,SADVb=0,SADVp=0;
unsigned int32 Pow=0,CompPow=0;
float fADVp=0,fADVb=0,fADI=0;
Set_tris_b( 0b00000000 ); //Pin B0-B7 output
Set_tris_a( 0b11111111 ); //Pin A0-A1 input
setup_oscillator(OSC_8MHZ);
setup_comparator(FALSE);
setup_adc_ports(sAN0|sAN1|sAN3|VSS_VDD);
setup_adc(ADC_CLOCK_DIV_32);
setup_spi(FALSE);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
setup_timer_2(T2_DIV_BY_1,24,1);
setup_ccp1(CCP_PWM);
set_pwm1_duty(PWM);
output_low(LED);
delay_us(25);
while(1)
{
//Capture, traitement et envoi de Vpanel START
set_adc_channel(1); //Choix du canal à échantillonner
delay_us(25);
while(i<16) //Capture de 10 mesures successives
{
ADVpt=read_adc();
SADVp=SADVp+ADVpt; //Somme des tensions
delay_us(5);
i++;
}
ADVp=SADVp/16; //Moyenne effectuée
SADVp=0;
ADVpt=0;
i=0;
if(t==4000)
{
fADVp=(float)ADVp/131.02; //Conversion en valeur décimale (float)
printf("\n\nSTART----------------------------------------");
printf("\n\nPanel voltage : %1.1fV",fADVp);
}
//Capture, traitement et envoi de Vpanel END
//______________________________________________________________________________________________________________
//Capture, traitement et envoi de Ipanel START
set_adc_channel(3); //Choix du canal
delay_us(25);
while(i<16) //Capture de 10 mesures successives
{
ADIt=read_adc();
SADI=SADI+ADIt; //Somme des courants
delay_us(5);
i++;
}
ADIt=0;
ADI=SADI/16; //Moyenne effectuée
SADI=0;
i=0;
if(t==4000)
{
fADI=(float)ADI/511;
printf("\n\nPanel current : %1.3fA",fADI);
}
//Capture, traitement et envoi de Ipanel END
//______________________________________________________________________________________________________________
//Capture, traitement et envoi de Vbatterie START
//______________________________________________________________________________________________________________
set_adc_channel(0); //Choix du canal
delay_us(25);
while(i<16) //Capture de 5 mesures successsives
{
ADVbt=read_adc();
SADVb=SADVb+ADVbt;
delay_us(5);
i++;
}
ADVb=SADVb/16;
ADVbt=0;
SADVb=0;
i=0;
if(t==4000)
{
fADVb=(float)ADVb/65.51;
printf("\n\nAccu voltage : %2.1fV",fADVb);
}
//Capture, traitement et envoi de Vbatterie END
//______________________________________________________________________________________________________________
//routine de comparaison des Pow calculées
Pow=ADVp*ADI;
if(ADVb>904) //Vb>13,8V
{ set_pwm1_duty(0);
}
else{
if((Pow>=CompPow)&&(ADVp>589)&&(PWM<230))
{ PWM++;
set_pwm1_duty(PWM);}
else if(Pow<CompPow)
{ if((ADVp>CompADVp)&&(PWM<230)&&(ADVp>589)) //ADVp>3,1V
{ PWM++;
set_pwm1_duty(PWM);
}
else if ((ADVp<CompADVp)&&(PWM>0))
{ PWM--;
set_pwm1_duty(PWM);
}
}
}
CompPow=Pow;
CompADVp=ADVp;
t++;
}
}
|
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19590
|
|
Posted: Fri Mar 17, 2017 3:32 am |
|
|
READ.
We have all been beginners, but you need to start by doing some basic exercises and actually starting to learn the language before trying to write more complex things. It's a bit like saying you don't start learning French and immediately try to give a lecture. Instead you work through often 'silly' things like "where is my aunt's pen"....
Actually look at some examples. Don't just put values into things, and when they don't work, come back here.
Is 'FALSE', the way to turn off the comparators (NO)....
Every command has it's own syntax. This is what the manual. Header file. Examples, C manual, and a search here will give.
As well as the comparator problem, you are still insisting on using float (not wanted or needed). Then is 1.3, actually a legal printf format?. (No - read a C textbook on what the value before the decimal actually is...).
I'll code part to show:
Code: |
int16 ADC_times16(int8 chan)
{
int16 sum=0; //initialise to zero
int8 loop_ctr;
set_adc_channel(chan); select channel
for (loop_ctr=0;loop_ctr<16;loop_ctr++)
{
delay_us(5); //Tacq
sum+=read_adc();
}
return sum;
}
//then one channel in main
int16 value;
//Then reading your first value becomes
value=ADC_times16(0); //Give 16* the ADC reading - channel _0_.
//Now basing this on your maths, which gives 7.0808 as the maximum
//value for 1023 from the ADC
value /=231;
//This will give (1023*16)/231 = 70.8 (but stored as an integer)
printf("\n\nSTART----------------------------------------");
printf("\n\nPanel voltage : %3.1LWV",value);
//display this as 7.0
|
Note no float. Just a suitably scaled integer.
't' doesn't seem to be reset anywhere after the start. |
|
|
coyotte4845
Joined: 16 Mar 2017 Posts: 4
|
|
Posted: Fri Mar 17, 2017 4:28 am |
|
|
Ok TT, understood ;)
i will work with your remark, i come back.
A question about max4376, can i connect directly the output on adc input?
needed for a low pass filter?
thanks, |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9270 Location: Greensville,Ontario
|
|
Posted: Fri Mar 17, 2017 6:49 am |
|
|
Yes, providing VCC is = to VDD
a low pass filter would be 'nice' to smooth out the readings. While it can be done in software a little 'help' from hardware is good !
If this is for battery monitoring then sampling say at a 1Hz rate is more than adequate.
On my remote equipment, I did a load test every 24 minutes to confirm batteries were 'good'.
A lot depends upon your actual application....
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19590
|
|
Posted: Fri Mar 17, 2017 8:00 am |
|
|
Yes.
However to get anything even remotely approaching 10bit accuracy, you need to be using an external Vref to the ADC. 2.2v min for the ADC (2.5v is a common value). |
|
|
coyotte4845
Joined: 16 Mar 2017 Posts: 4
|
|
Posted: Fri Mar 17, 2017 8:41 am |
|
|
Ttelmah wrote: | Yes.
However to get anything even remotely approaching 10bit accuracy, you need to be using an external Vref to the ADC. 2.2v min for the ADC (2.5v is a common value). |
Why Telmah?
i can't use Vdd as Vref? In my case, Vdd comes from Vpanel via regulator LDO 3v |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19590
|
|
Posted: Fri Mar 17, 2017 8:59 am |
|
|
Seriously. Regulator say 1% accuracy at best (10 bit is potentially 0.1%). Even this though you won't get. Every single device drawing power, _will_ introduce ripple and spikes onto the supply. The PIC itself, and every other device on the supply.
As a typical example, look at this thread:
<http://www.ccsinfo.com/forum/viewtopic.php?t=56005>
Now his situation was even worse (trying to get a 12bit ADC to work), but look what made it start to give sensible readings....
The supply is fine, if you are looking at large changes, and don't need great accuracies, but for anything better, you need to be using a more stable and accurate source, that is not being modulated by other things.
On chips that have a separate AVdd, what you can do is to improve the smoothing on this (series inductor, and extra capacitors), to get rid of the ripple (still leaves the poor actual accuracy, but at least improves the repeatability), but if you honestly need anything above perhaps 7bit operation, then 'think again' about using the supply as a reference..... |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1911
|
|
Posted: Fri Mar 17, 2017 9:06 am |
|
|
A regulator isn't designed to output a perfectly stable, low ripple (or ripple free) voltage. Just to contradict myself: a regulator can output a relatively "electrically quiet" and stable output, but only if it is driving just one load.
Your A/D compares a reference voltage and an input voltage and will output a digital number which tells you how many "counts" of the reference = your input. What happens if your reference isn't solid? What happens if it's fluctuating a little bit? What happens if it fluctuates a little bit more when your processor is also driving a relay or if it's generating CAN traffic?
Voltage regulators = designed to keep the output voltage relatively steady under widely varying loads. Good for supplying Vdd to a bunch of devices.
Voltage references = designed to keep the output voltage absolutely rock steady, but cannot drive much load current. Good for supplying a voltage reference to an A/D, but not for supplying Vdd power to anything. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|