CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

reading volt with pic16f877 ADC
Goto page Previous  1, 2
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Thu Jan 03, 2013 3:37 pm     Reply with quote

I've had a look at the data sheet. It doesn't give any indication of the nature of the sensor output signal.

Have a look at the output signal with a 'scope and tell us (or show us) what you see.

At this stage I can only make wild guesses to explain your readings.

Mike
ssaakmnt



Joined: 03 Dec 2011
Posts: 27

View user's profile Send private message

PostPosted: Sat Jan 05, 2013 4:11 am     Reply with quote

this is the code that I did for pic ammeter :
Code:
#include <16F877.h>
#device ADC=10
#FUSES NOWDT                    //No Watch Dog Timer
#FUSES XT                       
#FUSES NOPUT                    //No Power Up Timer
#use delay(clock=20.160MHz)
#use rs232(baud=9600,xmit=pin_C6,rcv=PIN_C7)
#include <float.h>

main() {
setup_adc_ports(ALL_ANALOG);
setup_adc( ADC_CLOCK_INTERNAL );  // result1=((volt1/273)-0.004)/0.0032/0.1;
set_adc_channel( 0 );
float value1,result1,volt1;
while (TRUE)
{
value1 = read_adc();
volt1=value1/204.6;//1023/5=204.6
result1=(volt1/250)/0.004/0.1;//this case ratio from 50A T to 5A T
// some indications that code is right
if(result1<=12.599)//12.599A
output_high(pin_d0);
if(result1>=12.6)//12.6A
output_low(pin_d0);
if(result1>=13)//13A careful to overload
printf("\a");
printf("\f\%2.2f A"result1);
delay_ms(1000);}
}
Ttelmah



Joined: 11 Mar 2010
Posts: 19539

View user's profile Send private message

PostPosted: Sat Jan 05, 2013 4:55 am     Reply with quote

Some comments:

First:
setup_adc_ports(ALL_ANALOG);

Don't do this. Only enable the ADC multiplexer on the channels you are actually going to use. Every pin that is connected to the multiplexer, potentially increases the likelyhood of noise from other signals. This is 'why' the PIC has the options to only enable the ADC multiplexer on certain pins.

Then:
setup_adc( ADC_CLOCK_INTERNAL );

This is _not_ a recommended clock source, for CPU operation above 1MHz, unless you are putting the processor to sleep for the conversion - read the data sheet. This degrades the accuracy of your result. With this clock selected, the ADC clock is not synchronous to the processor clock, so you will get a beat effect between the processor clock and the ADC clock, resulting in spikes in the result.
ADC_CLOCK_DIV_32
Is the clock for your system.

Then a general comment. 'C' requires variables to be declared at the start of the function block. CCS, 'semi allows' you to get away with ignoring this, _but_ it sometimes gives problems. Better to stick to the correct C syntax.

Then:
volt1=value1/204.6;//1023/5=204.6

This is not (quite) the correct transfer function for the PIC ADC. It is a common mistake. Historically, standard ADC's using an R2R ladder, give equally spaced steps across the voltage range, so an ADC with 1024 steps, gives 1023 'risers' across the range, symmetrically placed around a line from 0v to Vref, and for these this is the correct function. However the PIC ADC does not behave like this. On the PIC ADC, the ADC behaves as if it starts displaced downwards by half a bit. It'll not switch to reading '1' till 1/1023rd the input range, so this function is effectively always rounded 'down' by half a bit. A tiny difference, but if you want to get a really accurate transfer, you need to add this tiny offset.

Then, remember it takes significant time to do a float comparison. Why do two, when one will do?. ELSE statement?.

Now, on the reading. Remember a motor that draws 10A (say), won't draw a steady current at this level. Depending on the motor design, there _will_ be pulses in the current as the poles go round. You need to be reading a _lot_ faster (so you are reading several times in each cycle of the motor), and then average these readings to give a value to display. Otherwise since you only sample once per second or so, there will be pulses up and down, as your sample 'point' beats with the current pulses.....

Best Wishes
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Sat Jan 05, 2013 7:02 am     Reply with quote

We need to know what kind of signal we are dealing with.

Is the output from your sensor a smooth DC representation of the current, or a full wave rectified version?

If its smooth, an average of several readings should suffice.

If its raw rectified AC, you have a different problem. Many DVMs are of the dual slope integrating variety. They integrate the incoming signal for a period, then compare to a reference. The integrating time is often chosen to be an integer multiple of a full mains period, as that's what they're likely to be used for. An integration period of 200ms is 10 of 50Hz cycles, or 12 of 60Hz cycles, so it suits either mains standard. The PIC A2D samples the input signal for a short period then does a conversion.

To emulate the behaviour I've just outlined, you need to take regular A2D samples over one, or several, complete mains cycles. Or you could simply connect a large capacitor in parallel with your 250R burden resistor. 1000uF will give a 250ms time constant, it will remove most of the ripple but make the response rather sluggish. You need a time constant which is several mains periods, you pays your money and takes your choice.

Mike
ssaakmnt



Joined: 03 Dec 2011
Posts: 27

View user's profile Send private message

PostPosted: Sat Jan 05, 2013 12:10 pm     Reply with quote

Ttelmah good you joined us, ok I will do all that but to be honest I didn't quite understand every thing you say, I have some questions:
Quote:
so this function is effectively always rounded 'down' by half a bit. A tiny difference, but if you want to get a really accurate transfer, you need to add this tiny offset.

if you just post an example of this tiny offset or modification on:
Code:
volt1=value1/204.6; //1023/5=204.6

Quote:
Then, remember it takes significant time to do a float comparison. Why do two, when one will do?. ELSE statement?.

what you mean by ELSE statement? code please.

And code for reading several times and then average these readings. Thank you all.
Ttelmah



Joined: 11 Mar 2010
Posts: 19539

View user's profile Send private message

PostPosted: Sat Jan 05, 2013 12:46 pm     Reply with quote

Code:

if(result1<12.6)//12.599A
   output_high(pin_d0);
else
   output_low(pin_d0);


Not exactly hard....

On the conversion offset, only matters if you are after the best accuracy, but technically:
Code:

volt1=(value1+0.5)/204.6;//1023/5=204.6


Microchip have a detailed application note on the ADC.

Best Wishes
ssaakmnt



Joined: 03 Dec 2011
Posts: 27

View user's profile Send private message

PostPosted: Sat Jan 05, 2013 2:01 pm     Reply with quote

Thank you very much.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page Previous  1, 2
Page 2 of 2

 
Jump to:  
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