Calculation of logarithm based on digital analog conversion input

Thread Starter

tomaytos

Joined May 18, 2014
2
I try to simulate a solar cell and I want to calculate the voltage of the cell based on its current. This is done with the formula:
k*Tc/e*log((Iph+I0- Ic/1000)/I0)+Rc*Ic.
Since the calculation of a logarithm is needed, i have to work with variables of the type double.

The code below won't run. (Light at port RD7 remains off) I discovered that it runs if I don't use the measured value of the D/A conversion module but replace it with a fixed value.
If I shorten the code, it also works.

I don't know what the problem might be.

I use a pic18f4550, the coding is done with mikroc and the testing is done with proteus.

Rich (BB code):
unsigned long read_analog_channel(unsigned char ch);
double Tc;
double doub;
unsigned long lon;
unsigned char ch;
unsigned int answer;
unsigned char leds;
unsigned long test;

// Input
unsigned char  idf=1; // ideality factor
double Iph=8.57; // Photo current
double I0=1e-10; // reverse saturation current
double Rs=0.01; // Shunt resistance
double Ic;

// Constants
double kde = 8.617332e-5; // boltzmann constant divided through Electron charge

 // Output
double Vc; // Desired output of cell.

main(void) {

  TRISD = 0x00 ;                  // PORT B Setting: Set all the pins in port B to Output.

  Tc=(double)64;

  ADCON0.ADON = 1; // Turns adc on

  ADCON1 |= 0x00; // last 4 bits: configure all A input parts as analog.
  ADCON2.ADFM = 1; // 0= left justified
  ADCON2 |= 0x38; // bit 5-3: 111: acquisition time = 20 Tad
  ADCON2 |= 0x06; // last 3 bits: Fosc/16

  while(1){
//Vc=(double) k*Tc/e*log(((double) Iph+I0- Ic/1000)/I0)+Rc*Ic; formula to calculate

         Ic=read_analog_channel(0);

        doub=(Iph-Ic/1000.0)/I0+1.0;
         Vc=kde*Tc*log(doub)+Rs*Ic;// This only works when I don't use the measured Ic.
         
         //The following steps are always excecuted with Ic from the adc input.
          //Vc=log(Iph-Ic*1e-3); // Here the led is 1 second on and then stays off.
                                 // when I divide through 1e3 it doesn't work.
          // Vc=log(Iph-Ic*1e-3+1.0); //same
          // Vc=kde*Tc*log(Iph); // led is 1 second on and then very short off...
          // Vc=Tc*log(Iph-Ic*1e-3+1.0); // This doesn't work

        PORTD=0b10000000;
        delay_ms(1000);
        PORTD=0;
        delay_ms(1000);

}

 unsigned long read_analog_channel(unsigned char ch)
    {
    ADCON0 |= 0x0F&ch; // select chanel
    //Auto acquisition time
    ADCON0.GO = 1;   //Starts ADC conversion

    while (ADCON0.GO) continue;   //wait till ADC conversion is over
    answer=0x0000;

    answer=(char) ADRESH;
    answer=(answer << 8) + (char) ADRESL;   //Merging the MSB and LSB

    return (unsigned long) 5000*answer/1023   ;
    // return 5000*answer/1023; // This one works but then the output is wrong. (tread as integer)
    //return 0x0DAC;  // 3500 mA, This one works too.
    }
 

Attachments

ErnieM

Joined Apr 24, 2011
8,377
First off I would suggest seeking any way possible to avoid using any float types. Since the input comes from a 10 bit A2B you have a maximum possible 1024 outcomes from your measurement and calculation. A table read would certainly be faster and possibly even shorter then doing such calculations.

I've never used Proteus but it seems it has "extensive debugging features, including breakpoints, single stepping and variable display for a neat design prior to hardware prototyping."

You should single step your code and see what values are being produced. This may entail breaking the equation into many many little pieces to see which one is going wrong.
 
Top