SCT-013 - 100 A interface with pic16f877a

Hey

I’m using current sensor SCT-013 - 100 A with pic16f877a
and i can’t find library and code for pic16f877a , only it’s available for arduino
So
please help me to get
1- SCT-013 Library with code for pic16f877a (microc)
2- SCT-013 library for proteus

Thanks

Three ways to go:

  1. You probably need to ask this question in a PIC forum.
    or
  2. Read in the “Learn” section how to interface a SCT-013-000 to an Arduino, learn how to read an analogue input with your PIC, then change the analogRead( ) we do in emonLib to do it the PIC way, and write your own library based on emonLib
    or
  3. Search the “Archived” section, because I think someone has used a PIC, and you might find something to help you.
1 Like

Thanks Robert

If you use the “Search” next to the “Shop” icon in this page’s top bar, and search for “PIC”, there are a few links, most to items in the old forum.
using PIC microcontroller for energy monitor | Archived Forum looks quite helpful.

Thanks a lot

I developed an energy monitor for the PIC24EP256MC202 a few years ago. There was no library for a PIC, at least if there was no one told me. I doubt if there is a library now. So you would probably have to write your own.

This would not be a trivial task. You would have to understand the operation of your PIC in some detail, particularly the ADC component, then incorporate relevant code from emonLib.

What I did was to use the code for filtering and summing the ADC measurements using the articles in the Learn section on digital filters, and adapting the existing emonLib code that did the filtering and summing of the measurements. That was all I used from the openenergymonitor project. My monitor transmits data wirelessly to a PC, which saves the data in a SQL Server database for analysis.

There were a couple of main differences from EmonLib for the ADC retrieval and processing.

First the PIC24EP256MC202 provides simultaneous sampling of four analog pins rather than sequential sampling. So I didn’t do the phase correction in Explanation of the phase correction algorithm. From a quick look at the datasheet for the PIC16f877a the ADC module doesn’t provide simultaneous sampling, so you would have to do this phase correction.

The other major difference was that all my code was interrupt driven with nested interrupt levels. From memory the EmonLib code used the waveform shape to decide when to sample, or something like this. I didn’t need this code.

If you wanted to write ADC code for your PIC, you’d have to read chapter 11 of the PIC168F877A datasheet carefully. The operation of the ADC module is different from that in the PIC24EP256MC202. However to give a flavour of what you would have to do, I’ve included the section of my ISR code that handles an ADC interrupt, and also the calcVI module that does the filtering and summing (based on the module in the EmonLib code at that time).

This is the ADC interrupt routine. The four channels I measure simultaneously are AC voltage (using an Ideal Power Adaptor and Grid Current, PV generated current and generated current diverted to my immersion heater (using SCT013s).

/*
 * ADC ISR
 * This is called every second sample. The sample data to be processed is in
 * one half of the ADC buffers while the other half is being filled.
 * calcVI(V,Igrid,Ipv,Iim) is called for each of the two samples to update running
 * totals.
 * Every 5 seconds the totals are saved and a flag set so the user code processes
 * the new measurement
 *
 */
void __attribute__((interrupt,  no_auto_psv)) _AD1Interrupt(void)
{
////  LogUS10();
  if (!readyToMeasure)  //Still waiting for hardware to stabilise?
  {
    ADCInterrupt=1;     //Let the ADC initialisation code handle it
    _AD1IF=0;
    return;
  }
  MoveBuffers(); //Copy from latest 8 ADC buffers

  //Update measurement counters
  //Accumulate values from V,I,PVI IMI samples (channels 1,2,3, channel 0)
  int i;
  for (i = 0; i < 8; i += 4) //For each of the two sample fours
  {
    calcVI(ADCValues[i+1], ADCValues[i + 2], 
            ADCValues[i + 3], ADCValues[i]); //(V,I,PVI,IMI)
  }
  _IPL=T1_PRIORITY;
  msNow=ms;
  _IPL=ADC_PRIORITY;

  //Return unless it's time to finalise this 5 second measurement
  if (msNow - countStart < MEASURETIME)
  {
//    LogUS10();
    _AD1IF=0;
    return;
  }

  //Initiate new measurement processing
  SaveTotals();               //Save the current measurement totals
  ResetMeasurementTotals();   //Clear totals for next set of samples
  newMeasurement=true;        //User code will process the measurement
//  LogUS10();
  _AD1IF=0; //Allow next ADC interrupt
}

This is the calcVI routine that does the filtering and summing.

/*
 * Based on OpenEnergyMonitor design. See their web site
 * Called from ADC ISR to update totals for new sample. The ISR is interrupted
 * every 90us for each pair of samples and calcVI is called for each sample.
 * The normal 2 sample pair processing was measured as 30us. Each 5 secs totals
 * are saved and reset taking 20us. So there is plenty of time spare out of the
 * 90us between interrupts. Should probably recheck once variable gain has been
 * added, but it's difficult to see there could be a problem.
 */
void calcVI(unsigned int NewV, unsigned int NewI, 
    unsigned int NewPVI, unsigned int NewIMI) {
  //-----------------------------------------------------------------------------
  //Apply digital high pass filters to remove 1.5V DC offset (centered on 0V).
  //-----------------------------------------------------------------------------
  numberOfSamples++;
  filteredV=(long)NewV-VOffset;  
  VShiftedOffset+=filteredV;
  VOffset=(int)((VShiftedOffset+FILTERROUNDING)>>FILTERSHIFT);
  filteredI=(long)NewI-IOffset;
  IShiftedOffset+=filteredI;
  IOffset=(int)((IShiftedOffset+FILTERROUNDING)>>FILTERSHIFT);
  filteredPVI=(long)NewPVI-PVIOffset;
  PVIShiftedOffset+=filteredPVI;
  PVIOffset=(int)((PVIShiftedOffset+FILTERROUNDING)>>FILTERSHIFT);
  filteredIMI=(long)NewIMI-IMIOffset;
  IMIShiftedOffset+=filteredIMI;
  IMIOffset=(int)((IMIShiftedOffset+FILTERROUNDING)>>FILTERSHIFT);
  sqV = filteredV * filteredV; //1) square voltage values
  sumV += sqV; //2) sum
  sqI = filteredI * filteredI; //1) square current values
  sqPVI = filteredPVI * filteredPVI; //1) square current values
  sqIMI = filteredIMI * filteredIMI; //1) square current values
  sumI += sqI; //2) sum
  sumPVI += sqPVI; //2) sum
  sumIMI += sqIMI; //2) sum
  instP = filteredV * filteredI; //Instantaneous Power
  sumP += instP; //Sum
  instPVP = filteredV * filteredPVI; //Instantaneous Power
  sumPVP += instPVP; //Sum
  instIMP = filteredV * filteredIMI; //Instantaneous Power
  sumIMP += instIMP; //Sum
}

I’m not a PIC expert. As Robert says, you can try the Microchip forums for help

Good luck!

I can add a few comments to this.

  1. The PHASECAL calculation corrects (or more properly “compensates”) for 3 errors: the phase error of the v.t., the phase error of the c.t., and finally the time difference between the samples. If you know what the relative errors are (converted to the same units), then you can arrange the order of reading the samples to make the total error smaller (emonLib gets it wrong, so it applies far more compensation than is necessary). If you sample rapidly enough, by storing some samples, you might be able to pick a pair of voltage & current samples that, after taking the errors into account, align closely. But bear in mind, unless you change this in response to changes of voltage and current, it will never be correct, because the transformer errors are dependent on the quantity being measured.
  2. There’s a better way to remove the offset. What I’ve done in the upcoming release of emonLibCM is to first remove the nominal offset (only to make the numbers smaller), then over the sampling/reporting period accumulate the sum of voltage, voltage2, current, current2 & voltage × current. The sums of voltage and current should be zero if all the offset has been removed accurately, by they won’t be. We’ll use this later when you come to calculate the averages. For power it’s easy: subtract the “offset power” (average voltage × average current) from the average real power (the average of (voltage × current)). For voltage and current, you use the property of the components of the wave: the rms value is the square root of the sum of the squares of each component. So working that backwards, the actual rms is the root of (sum(V2) - (averageV)2). Likewise, current. Of course, all these averages are the accumulated sum divided by the number of samples.
    (What you’ve done in effect is make a filter with an averaging time equal to the reporting period.)
  3. If you do decide you need phasecal, then if you recognise that the coefficient you multiply the delayed sample by is a constant, you can take that out of the summation and do that multiplication per reporting period too. You’re trading the time to do the arithmetic against summing two “partial” powers, which is a good trade-off.

I’m hoping we can release emonLibCM before too long, it’s undergoing real-life testing at present, but I’m confident the maths is correct.