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

AC DC Voltage and Current Sensors Using PIC18F25K80

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
mcmsat



Joined: 25 May 2018
Posts: 51
Location: Nigeria

View user's profile Send private message

AC DC Voltage and Current Sensors Using PIC18F25K80
PostPosted: Sat Jun 29, 2024 12:02 pm     Reply with quote

Hello honorable members and admins!
I am sensing AC and DC current and voltage and frequency. Everything is working but the Dc_current swings a lot. AC Voltage, AC Current, Frequency and DC Voltage are as stable as they coul be but the Dc current cannot stay at one place! I don't have scope. but if I put mymeter on the ADC pin it seems stable so I instructed the LCD to display the ADC voltave of the DC Current, on the LCD the ADC coltave also seems to be swinging changing capacitors or different values and precitions could not help much.
Below is the code I am working with:

Code:

#include <18f25k80.h>
#device ADC = 12
#FUSES NOWDT,INTRC_IO, PUT, NOPROTECT, NOMCLR, NOCPD, BROWNOUT,NOIESO, FCMEN, NOCANC,NOCANB
#use delay(clock = 16000000)
#use I2C(master, I2C1, FAST = 100000,NOFLOAT_HIGH,FORCE_HW, STREAM = I2C_LCD)
#include <I2C_LCD.c>
#define ADC_RESOLUTION    4096   // max. ADC output
#define HIGH_START 0xFF -250 //500us INT_RTCC

#define sys_led      PIN_B6

#define VREF 5.0 // Reference voltage for ADC
#define R1 120000.0 // 120K Ohm resistor
#define R2 2200.0 // 2.2K Ohm resistor

//*************************** Non Blocking  Timer0 Delay Variables **************************
int display_dl;
int Sdisplay_dl;
int16 Cdisplay_dl,Counter_sys_1s;

// ******************************************************************************************
//******************************* other variables ********************************************
int  display;     
int16 mains;
float batt,ac_current,dc_current;
FLOAT adc_volt=0.0;
int16 avgResult_mains = 0;
int16 avgResult_ac_current = 0;


void init()
{
   setup_oscillator (OSC_INTRC|OSC_16MHZ|OSC_NORMAL|OSC_PLL_OFF);
   setup_adc (ADC_CLOCK_DIV_16);
   setup_adc_ports (sAN1|sAN2|sAN3|sAN4|VSS_VDD); // Select Analog Inputs
   setup_comparator (NC_NC_NC_NC); // disable comparator module
   SET_TIMER0 (HIGH_START);
   SETUP_TIMER_0 (T0_INTERNAL|T0_DIV_8|T0_8_BIT);
   enable_interrupts (INT_TIMER0);
   enable_interrupts (global);

   display_dl = 0;
   Sdisplay_dl = 0;
   
   //delay_ms (3000) ;
}

//   the timer is incremented (16000000/4)/16 or 500000 times a second (2 us).
//   250 x 2us = 500us
#INT_TIMER0
void clock_isr()
  {
   
   // Start Delay///////////////////////////////////////////////////////////

      IF (Sdisplay_dl)
      {
         IF (++Cdisplay_dl >= (1000 * 2))//1s
         {
            Sdisplay_dl = 0;
            display_dl = 1;
         }
      }

      ELSE Cdisplay_dl = 0;

   //**********************SYSTEM LED Flash Settings******************************

      IF (++Counter_SYS_1s >= (1000 * 2))//1s
      {
         Counter_sys_1s = 0;
         output_toggle (sys_led);
      }
  }

//*****************************************************************************/
//********* FUNCTIONS TO READ AC CURRENT ON CHANNEL 4 ***************************/
  FLOAT Get_ac_current ()
  {
     set_adc_channel (4); //Select AN4 as ADC Input FOR acs
     FLOAT acsHigh = 0;
     FLOAT acsLow = ADC_RESOLUTION;
     INT16 acs = 0; //variable to store analog reads
     
     for (INT i = 0; i < 40; i++)
     {
        delay_us (500);
        acs = read_adc (); // read ADC every time
        IF (acs > acsHigh)
           acsHigh = acs;

        IF (acs < acsLow)
           acsLow = acs;
     }

     RETURN (acsHigh - acsLow); // retutn value that was somehow averaged
  }

  //**************** FUNCTIONS TO READ MAINS VOLTAGE ON CHANNEL 1 *******************/
  INT16 Get_mains_voltage ()
  {
     set_adc_channel (1); //Select AN1 as ADC Input FOR ms
     INT16 mainsHigh = 0;
     INT16 mainsLow = ADC_RESOLUTION;
     INT16 ms = 0; //variable to store analog reads
     
     for (INT i = 0; i < 40; i++)
     {
        delay_us (500);
        ms = read_adc (); // read ADC every time
        IF (ms > mainsHigh)
           mainsHigh = ms;

        IF (ms < mainsLow)
           mainsLow = ms;
     }

     RETURN (mainsHigh - mainsLow); // retutn value that was somehow averaged
  }

  //****************** FUNCTIONS TO READ DC CURRENT ON CHANNEL 2 ***************************/
  float get_dc_current ()
  //FLOAT get_dc_current  ()
  {
     set_adc_channel (2); // Select channel AN2
     INT16 dcs_SENSE; //variable to store analog reads
          FLOAT dcs_SENSE_Average;
          FLOAT dcs_SENSE_Samples;
          //FLOAT adc_volt=0.0;
          FLOAT CURRENT;
          INT n_sample = 100;
     delay_us (500); // let ADC settle before next sample 500us
     dcs_SENSE = read_adc ();

     
     for (INT i = 0; i < n_sample; i++) //Get 100 dcs_SENSE_Samples
     {
        dcs_SENSE_Samples = dcs_SENSE_Samples += dcs_SENSE; //Add samples together
     }

     dcs_SENSE_Average = dcs_SENSE_Samples /= n_sample; //Taking Average of ac2 Sense Samples
     delay_us (500); // let ADC settle before next sample 500us
     adc_volt = dcs_SENSE_Average *(VREF/4095.0);
     
     current = (adc_volt)/50.0/0.001;// Gain 50 for INA139NA AND R001 SHUNT
   
     RETURN (current);

  }
//
  //************** FUNCTIONS TO READ BATTERY VOLTAGE ON CHANNEL 3 **************************/

float read_battery_voltage() {
    int16 adc_value;
    float batt_volt, adc_voltage, divider_ratio;

    set_adc_channel(3);
    delay_us(500);

    // Read ADC value
    adc_value = read_adc();

    // Calculate voltage divider ratio
    divider_ratio = (R1 + R2) / R2;

    // Convert ADC value to voltage
    adc_voltage = (adc_value * VREF) / 4095.0; // 12-bit ADC, so 2^12-1 = 4095

    // Calculate battery voltage
    batt_volt = adc_voltage * divider_ratio;

    return batt_volt;
}

  VOID lcd_display (void)
  {
     
     CHAR line1[21];
     CHAR line2[21];
     CHAR line3[21];
     CHAR line4[21];     


       
        sprintf (line1, "   AC  DC  SENSORS   ");
        lcd_GOTO (1, 1); // Go to column 1 row 1
        printf (lcd_out, line1);
       
        sprintf (line2, "BATTERY: %2.1gV %2.1gA ", batt, dc_current);
        lcd_GOTO (1, 2); // Go to column 1 row 2
        printf (lcd_out, line2);
       
       
        sprintf (line3, "MAINS %3LuV %2.1gA ", mains, ac_current);
        lcd_GOTO (1, 3); // Go to column 1 row 3
        printf (lcd_out, line3);
       
        sprintf (line4, " DC CURRENT  %2.3gV ", adc_volt);
        lcd_GOTO (1, 4); // Go to column 1 row 4
        printf (lcd_out, line4);
  }
  //********************************/
 
  VOID main (void)
  {
     init ();
     delay_ms (100);
     LCD_Begin (0x4E); //PCF8574 (111) // Initialize LCD module with I2C address = 0x4E

     delay_ms (2000) ;

     WHILE (TRUE)
     {

        //CCCCCCCCCCCCCCCCCCCCCCCCCCCCCC Parameter Calculations CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

           
           //AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA FOR Mains Voltage AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
           
           for (INT i = 0; i < 10; i++)
           {
              avgResult_mains += Get_mains_voltage ();
           }
           avgResult_mains = avgResult_mains / 10;
           mains = 0.0285 * avgResult_mains;
           avgResult_mains = 0;

           //AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA FOR CT AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
           for (INT i = 0; i < 10; i++)
           {
              avgResult_ac_current += Get_ac_current ();
           }
           avgResult_ac_current = avgResult_ac_current / 10;
           ac_current = (0.0050 * avgResult_ac_current);
           avgResult_ac_current = 0;
   
           // BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB FOR BATTERY BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
           
           Batt = read_battery_voltage();

           //DDDDDDDDDDDDDDDDDCCCCCCCCCCCCCCCCCC FOR DC CURRENT DDDDDDDDDDDDDCCCCCCCCCCCCCCCCCCCCC

           /*
           * INA139 Current (I) :
           * = ADC * ((5/4096) / 50 / Rshunt) // 50 IS GAIN
           */
                 dc_current = get_dc_current ();


        //*******************************************************************************
        //******************************** DISPLAY SETTINGS STARTS **************************
        display = 1;// Variable to cause non b,ocling delay 1000ms to start runing

        IF (display == 1)
        {
           Sdisplay_dl = 1;

           IF (display_dl)
           {
              lcd_display () ;

          display_dl = 0;
           }
        }

        ELSE Cdisplay_dl = 0;
     }
  }
[/b]
_________________
All is well even in the well!
mcmsat



Joined: 25 May 2018
Posts: 51
Location: Nigeria

View user's profile Send private message

PostPosted: Sat Jun 29, 2024 12:18 pm     Reply with quote

I started this topic; Please could any one here tell me what is wrong with this code. I forgot to mention that I attached the circuit on a battery charger between the dc bus voltage, It measures current for the high side. My clamp meter at the same wire does not swing. It is ver stable. It decreases and increases accordingnly the way it should be for a battery charger.
_________________
All is well even in the well!
temtronic



Joined: 01 Jul 2010
Posts: 9243
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sat Jun 29, 2024 2:28 pm     Reply with quote

Your DMM ,if like 99.44% of the others, ONLY samples every 3 reading per second, so you should adjust your DC amps function to be similar.

Also, instead of taking 100 samples, take 64 or 128. Makes it a LOT faster on the divide math.

Perhaps do 'Olympic' averaging ( 10 readings,delete highest,lowest, avg the remaining 8 ) it may give better results.

what is the current sensor device ( link ? ) ,may have wrong interface to it ??
mcmsat



Joined: 25 May 2018
Posts: 51
Location: Nigeria

View user's profile Send private message

PostPosted: Sat Jun 29, 2024 3:52 pm     Reply with quote

This is the link to the current sensor page:
https://www.ti.com/lit/gpn/INA139
_________________
All is well even in the well!
mcmsat



Joined: 25 May 2018
Posts: 51
Location: Nigeria

View user's profile Send private message

PostPosted: Sat Jun 29, 2024 3:57 pm     Reply with quote

As I am using for ADCs, can I apply the Olympic Averaging only to the dc_current measurements. Can others still work the way they are?
_________________
All is well even in the well!
mcmsat



Joined: 25 May 2018
Posts: 51
Location: Nigeria

View user's profile Send private message

PostPosted: Sat Jun 29, 2024 4:05 pm     Reply with quote

As I am using four ADCs, can I apply the Olympic Averaging only to the dc_current measurements. Can others still work the way they are?
_________________
All is well even in the well!
mcmsat



Joined: 25 May 2018
Posts: 51
Location: Nigeria

View user's profile Send private message

PostPosted: Sat Jun 29, 2024 6:00 pm     Reply with quote

Ok. I have applied the Olympic Averaging in simulator only for DC Current and other sensors are working. In the morning I will do it in hardware
_________________
All is well even in the well!
temtronic



Joined: 01 Jul 2010
Posts: 9243
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Sat Jun 29, 2024 6:27 pm     Reply with quote

I had a quick look at the sensor and T suggests using a unity gain 'buffer' between it and the ADC as well as a 'low pass ' filter.
You should do as they say, in order to get accurate readings.
Ttelmah



Joined: 11 Mar 2010
Posts: 19539

View user's profile Send private message

PostPosted: Sun Jun 30, 2024 3:01 am     Reply with quote

It's worth understanding that the ADC's used on 99% of low priced DMM's
are what are knows as "dual slope integrating ADC's". These are one of the
few ADC's giving high accuracy at low price, but do this by actually
integrating the incoming source for a time, then comparing this to an
integration the 'other way', from the reference, till the value gets back to
zero. The time taken, then gives a nice accurate value, but a value for the
integrated voltage (so over time), not the instantaneous value.
'Fast reading' DMM's, cost dozens of times what the normal DMM costs.
I have a 5 1/2 digit Fluke unit, that does 25 readings per second, versus
my normal one that manages 4. This actually allows several million samples
per second to be recorded, but not displayed. The former costs nearly
£2000, when my equivalent accuracy normal DMM, is about £100. The
fast unit also requires much more frequent calibration to remain certified.
A couple of my more reasonably priced units do have a low accuracy 'bar
graph' display below the main reading that responds quickly, and this is a
common way of giving the quick response.
This is a huge 'caveat' about such DMM's!. Sad

For many years (when DMM's first appeared), the speed was even worse,
and this was one of the reasons why adoption of DVM's was slow. A simple
old AVO meter, would show a signal fluctuating, with the needle wobbling,
when the DMM was saying the voltage was stable......

The slow speed of units is actually in part deliberate!. The 250mSec
sample rate provides an inherent 'notch' filter for multiples of the
mains frequencies used worldwide (50/60Hz). Also an update at 4Hz,
is readable, while if (for instance) the display was updating at 20Hz,
and flickering between 201, and 101, you could see this as 301.

Some nicer modern units actually allow the reading speed to be set
(Agilent for example have units that do this). Generally really fast speeds
are only workable on units that have PC connections, or memories, so
you can step back to look at readings.
mcmsat



Joined: 25 May 2018
Posts: 51
Location: Nigeria

View user's profile Send private message

PostPosted: Sun Jun 30, 2024 4:13 am     Reply with quote

Ttelmah wrote:
It's worth understanding that the ADC's used on 99% of low priced DMM's
are what are knows as "dual slope integrating ADC's". These are one of the
few ADC's giving high accuracy at low price, but do this by actually
integrating the incoming source for a time, then comparing this to an
integration the 'other way', from the reference, till the value gets back to
zero. The time taken, then gives a nice accurate value, but a value for the
integrated voltage (so over time), not the instantaneous value.
'Fast reading' DMM's, cost dozens of times what the normal DMM costs.
I have a 5 1/2 digit Fluke unit, that does 25 readings per second, versus
my normal one that manages 4. This actually allows several million samples
per second to be recorded, but not displayed. The former costs nearly
£2000, when my equivalent accuracy normal DMM, is about £100. The
fast unit also requires much more frequent calibration to remain certified.
A couple of my more reasonably priced units do have a low accuracy 'bar
graph' display below the main reading that responds quickly, and this is a
common way of giving the quick response.
This is a huge 'caveat' about such DMM's!. Sad

For many years (when DMM's first appeared), the speed was even worse,
and this was one of the reasons why adoption of DVM's was slow. A simple
old AVO meter, would show a signal fluctuating, with the needle wobbling,
when the DMM was saying the voltage was stable......

The slow speed of units is actually in part deliberate!. The 250mSec
sample rate provides an inherent 'notch' filter for multiples of the
mains frequencies used worldwide (50/60Hz). Also an update at 4Hz,
is readable, while if (for instance) the display was updating at 20Hz,
and flickering between 201, and 101, you could see this as 301.

Some nicer modern units actually allow the reading speed to be set
(Agilent for example have units that do this). Generally really fast speeds
are only workable on units that have PC connections, or memories, so
you can step back to look at readings.



It's true, especially the AVO meter you mentioned.
_________________
All is well even in the well!
mcmsat



Joined: 25 May 2018
Posts: 51
Location: Nigeria

View user's profile Send private message

PostPosted: Tue Jul 09, 2024 1:05 am     Reply with quote

temtronic wrote:
Your DMM ,if like 99.44% of the others, ONLY samples every 3 reading per second, so you should adjust your DC amps function to be similar.

Also, instead of taking 100 samples, take 64 or 128. Makes it a LOT faster on the divide math.

Perhaps do 'Olympic' averaging ( 10 readings,delete highest,lowest, avg the remaining 8 ) it may give better results.

what is the current sensor device ( link ? ) ,may have wrong interface to it ??


I'm sorry for the late reply. I was away from the house, engaged in something that never allow a spare time to attend other things.
The Olympic Averaging worked for me and with some filterations. Thanks everyone who helped
_________________
All is well even in the well!
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
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