Skip to content

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
JChristensen committed Aug 1, 2018
0 parents commit fda62c0
Show file tree
Hide file tree
Showing 10 changed files with 974 additions and 0 deletions.
18 changes: 18 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# A GitHub Manifesto
### Notes on contributing to my repositories
Jack Christensen
Jan 2018

Surely Git and GitHub are wonderful tools. They make coding and collaboration so much easier. I'm equally impressed with the open source movement, and with the Arduino ecosystem in particular.

I'm just one guy, mostly a hobbyist. Posting my projects to GitHub is my way of giving back a little to the community. It's very gratifying that some of my code has received a modicum of popularity.

Like many things, this has been somewhat of a double-edged sword. Especially since I tend to be a pretty busy guy with many varied interests.

First, I am always interested in bug reports. Please raise an issue in the appropriate repository and please please please include a good, concise description of the issue and a Short, Self Contained, Correct (Compilable), Example (see [sscce.org](http://www.sscce.org/)). I will need to be able to reproduce the issue, with minimal hardware, and without installing a dozen other libraries. I work exclusively with the AVR architecture so most times I will not be able to reproduce issues on other platforms. (There have been one or two occasions where relatively simple changes have been made to accommodate another platform; I am not necessarily averse to these.)

Second, bug reports should always be for problems with *my* code. I will not use GitHub to help you with *your* code, even if you happen to be using one of my libraries. Please use the [Arduino forum](https://forum.arduino.cc/) or other such venue instead.

Finally, pull requests can be problematic, especially if they represent enhancements rather than fixes. I seldom intend my code to be all things to all people. This is mostly a hobby activity and I have very limited bandwidth. Reviewing and managing PRs requires time that I do not often have. Sometimes a PR will take a library in a direction that I'm not interested in. Sometimes a PR will be counter to my original design intent. No doubt the author of a PR thinks that their new feature is the best thing since canned beer, but if I don't happen to share that opinion, then I'll decline it. OTOH, I am certainly capable of making stupid mistakes and missing absolutely fundamental things, and I do appreciate it when these are pointed out.

All this to say, that if I do decline a request, please do not take it personally. Feel free to consider it my problem, not yours. At the end of the day, it's my code, and I reserve the right to decline issues or PRs for any reason, or for no reason at all. But here is the beauty of open source. You can always fork the repository and have your way with it.
675 changes: 675 additions & 0 deletions LICENSE.md

Large diffs are not rendered by default.

84 changes: 84 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Arduino CurrentTransformer Library
https://github.com/JChristensen/CurrentTransformer
README file

## License
Arduino CurrentTransformer Library Copyright (C) 2018 Jack Christensen GNU GPL v3.0

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License v3.0 as published by the Free Software Foundation.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/gpl.html>

## Introduction
The CurrentTransformer library measures RMS current values in a 50/60Hz AC circuit using current transformers. Each call to `read()` causes the analog-to-digital converter (ADC) to measure a single AC cycle. The data gathered is processed using the [standard RMS calculation](https://en.wikipedia.org/wiki/Root_mean_square#Definition) and the result in amperes is returned to the caller.

Since each call to `read()` measures only a single cycle, it may be desirable, depending on the application and the nature of the electrical load, to make several calls, perhaps averaging the results, removing transients, etc. Each call to `read()` only takes about as long as one AC cycle, so there is not a lot of overhead or delay in taking several measurements.

Because measuring AC causes the current transformer to output positive and negative currents, a DC bias must be applied to ensure that below-ground voltages are not applied to the microcontroller's ADC input. It is also necessary to ensure that peak voltages do not exceed the microcontroller's supply voltage (Vcc). Do the math to ensure that your circuit operates within safe limits; also see the example below.

This library is specific to the AVR microcontroller architecture and will not work on others. Timer/Counter1 is used to trigger the ADC conversions and so is not available for other purposes.

## Example Design Calculations

The TA17L-03 current transformer is rated at 10A maximum and has a 1000:1 turns ratio. A 200Ω burden resistor is recommended. A 10A RMS current in the primary will generate a 10mA current in the secondary and therefore 2V across the burden resistor. However the peak voltage will then be √2 * 2V = ±2.8V (assuming a sine wave) which exceeds the 2.5V DC bias provided by the circuit below. Therefore the measured current should be limited to about 8.5A RMS (giving ±2.4V P-P) or perhaps a smaller burden resistor could be used if larger currents need to be measured.

## Typical Circuit

## Enumeration
### ctFreq_t
##### Description
Operating frequency for the current transformer.
##### Values
- CT_FREQ_50HZ
- CT_FREQ_60HZ

## Constructor

### CurrentTransformer(uint8_t channel, float ratio, float burden, float vcc, ctFreq_t freq)
##### Description
The constructor defines a CurrentTransformer object.
##### Syntax
`CurrentTransformer(channel, ratio, burden, vcc, freq);`
##### Required parameters
**channel:** ADC channel number that the current transformer is connected to. (Arduino pin numbers can also be used, i.e. A0-A5). *(uint8_t)*
**ratio:** Secondary:Primary turns ratio for the current transformer. *(float)*
**burden:** Current transformer burden resistor value in ohms. *(float)*
##### Optional parameters
**vcc:** Microcontroller supply voltage. For best accuracy, measure the actual microcontroller supply voltage and provide it using this parameter. Defaults to 5.0V if not given. *(float)*
**freq:** AC line frequency, either CT_FREQ_50HZ or CT_FREQ_60HZ. Defaults to CT_FREQ_60HZ if not given. *(ctFreq_t)*
##### Example
```c++
CurrentTransformer myCT(0, 1000, 200, 5.08, CT_FREQ_50HZ);
```
## Library Functions
### void begin()
##### Description
Initializes the AVR timer and ADC. If more than one CurrentTransformer object is defined, `begin()` only needs to be called for one of the objects, although calling it on more than one object will not cause an issue.
##### Syntax
`myCT.begin();`
##### Parameters
None.
##### Returns
None.
##### Example
```c++
myCT.begin();
```
### float read()
##### Description
Measures the RMS current value for one AC cycle and returns the value in amperes.
##### Syntax
`myCT.read();`
##### Parameters
None.
##### Returns
RMS current value in amperes *(float)*
##### Example
```c++
float rmsCurrent;
rmsCurrent = myCT.read();

```
38 changes: 38 additions & 0 deletions examples/CT2_Serial/CT2_Serial.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Arduino Current Transformer Library
// https://github.com/JChristensen/CurrentTransformer
// Copyright (C) 2018 by Jack Christensen and licensed under
// GNU GPL v3.0, https://www.gnu.org/licenses/gpl.html
//
// Example sketch to read two current transformers every five seconds
// and print the measurements to Serial.
// Tested with TA17L-03 current transformers (10A max), Arduino Uno,
// Arduino v1.8.5.

#include <CurrentTransformer.h> // https://github.com/JChristensen/CurrentTransformer
#include <Streaming.h> // http://arduiniana.org/libraries/streaming/

const float ctRatio(1000); // current transformer winding ratio
const float rBurden(200); // current transformer burden resistor value
const float vcc(5.120); // adjust to actual value for best accuracy
const uint32_t MS_BETWEEN_SAMPLES(5000); // milliseconds
const int32_t BAUD_RATE(115200);

CurrentTransformer ct0(A0, ctRatio, rBurden, vcc);
CurrentTransformer ct1(A1, ctRatio, rBurden, vcc);

void setup()
{
delay(1000);
Serial.begin(BAUD_RATE);
ct0.begin();
}

void loop()
{
uint32_t msStart = millis();
float i0 = ct0.read();
float i1 = ct1.read();
Serial << millis() << F(" ") << _FLOAT(i0, 3) << F(" A ") << _FLOAT(i1, 3) << F(" A\n");
while (millis() - msStart < MS_BETWEEN_SAMPLES); // wait to start next measurement
}

37 changes: 37 additions & 0 deletions examples/CT_Serial/CT_Serial.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Arduino Current Transformer Library
// https://github.com/JChristensen/CurrentTransformer
// Copyright (C) 2018 by Jack Christensen and licensed under
// GNU GPL v3.0, https://www.gnu.org/licenses/gpl.html
//
// Example sketch to read a current transformer every five seconds
// and print the measurement to Serial.
// Tested with TA17L-03 current transformer (10A max), Arduino Uno,
// Arduino v1.8.5.

#include <CurrentTransformer.h> // https://github.com/JChristensen/CurrentTransformer
#include <Streaming.h> // http://arduiniana.org/libraries/streaming/

const uint8_t ctChannel(0); // adc channel
const float ctRatio(1000); // current transformer winding ratio
const float rBurden(200); // current transformer burden resistor value
const float vcc(5.120); // adjust to actual value for best accuracy
const uint32_t MS_BETWEEN_SAMPLES(5000); // milliseconds
const int32_t BAUD_RATE(115200);

CurrentTransformer ct0(ctChannel, ctRatio, rBurden, vcc);

void setup()
{
delay(1000);
Serial.begin(BAUD_RATE);
ct0.begin();
}

void loop()
{
uint32_t msStart = millis();
float i0 = ct0.read();
Serial << millis() << ' ' << _FLOAT(i0, 3) << F("A\n");
while (millis() - msStart < MS_BETWEEN_SAMPLES); // wait to start next measurement
}

3 changes: 3 additions & 0 deletions keywords.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CurrentTransformer KEYWORD1
begin KEYWORD2
read KEYWORD2
9 changes: 9 additions & 0 deletions library.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
name=CurrentTransformer
version=1.0.0
author=Jack Christensen <[email protected]>
maintainer=Jack Christensen <[email protected]>
sentence=Arduino Library for measuring current in 50/60Hz circuits using current transformers.
paragraph=Each call to read() returns the RMS current in amperes measured for a single AC cycle.
category=Sensors
url=https://github.com/JChristensen/CurrentTransformer
architectures=avr
77 changes: 77 additions & 0 deletions src/CurrentTransformer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Arduino Current Transformer Library
// https://github.com/JChristensen/CurrentTransformer
// Copyright (C) 2018 by Jack Christensen and licensed under
// GNU GPL v3.0, https://www.gnu.org/licenses/gpl.html

#include <CurrentTransformer.h>

CurrentTransformer::CurrentTransformer(uint8_t adcChannel, float turnsRatio,
float rBurden, float vcc, ctFreq_t freq)
: m_ratio(turnsRatio), m_rBurden(rBurden), m_vcc(vcc)
{
if (adcChannel >= 14) adcChannel -= 14; // if user passed A0-A5, adjust accordingly
m_channel = adcChannel & 0x07; // ruthlessly coerce to an acceptable value
tcOCR1 = (freq == CT_FREQ_50HZ) ? 4922 : 4102;
}

volatile bool CurrentTransformer::adcBusy;
volatile int CurrentTransformer::adcVal;
const int CurrentTransformer::sampleSize(65); // number of samples to cover one cycle

void CurrentTransformer::begin()
{
// set up the timer
TCCR1B = 0; // stop the timer
TCCR1A = 0;
TIFR1 = 0xFF; // ensure all interrupt flags are cleared
OCR1A = tcOCR1; // set timer output compare value
OCR1B = tcOCR1;
cli();
TCNT1 = 0; // clear the timer
TIMSK1 = _BV(OCIE1B); // enable timer interrupts
sei();
TCCR1B = _BV(WGM12) | _BV(CS10); // start the timer, ctc mode, prescaler divide by 1

// set up the adc
ADMUX = _BV(REFS0) | m_channel; // set channel, and AVcc as reference
ADCSRA = _BV(ADEN) | _BV(ADATE) | _BV(ADIE); // enable ADC, auto trigger, interrupt when conversion complete
ADCSRA |= _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0); // ADC clock prescaler: divide by 128 (for 125kHz)
ADCSRB = _BV(ADTS2) | _BV(ADTS0); // trigger ADC on Timer/Counter1 Compare Match B
}

float CurrentTransformer::read()
{
uint8_t n(0); // sample count
int32_t sumsq(0); // sum of squares
while (adcBusy); // if a conversion is in progress, wait for it to complete
ADMUX = _BV(REFS0) | m_channel; // set channel, and AVcc as reference

do {
while (!adcBusy); // wait for next conversion to start
while (adcBusy); // wait for conversion to complete
cli();
int32_t v = adcVal; // get the reading, promote to 32 bit
sei();
// accumulate the sum of squares,
// subtract 512 (half the adc range) to remove dc component
sumsq += (v - 512) * (v - 512);
} while (++n < sampleSize);

// calculate rms voltage and current
float Vrms = m_vcc * sqrt(static_cast<float>(sumsq) / static_cast<float>(sampleSize - 1)) / 1024;
return m_ratio * Vrms / m_rBurden;
}

// adc conversion complete, pass the value back to the main code
ISR(ADC_vect)
{
CurrentTransformer::adcBusy = false;
CurrentTransformer::adcVal = ADC;
}

// adc starts conversion when the timer interrupt fires
ISR(TIMER1_COMPB_vect)
{
CurrentTransformer::adcBusy = true;
}

33 changes: 33 additions & 0 deletions src/CurrentTransformer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Arduino Current Transformer Library
// https://github.com/JChristensen/CurrentTransformer
// Copyright (C) 2018 by Jack Christensen and licensed under
// GNU GPL v3.0, https://www.gnu.org/licenses/gpl.html

#ifndef CURRENT_TRANSFORMER_H_INCLUDED
#define CURRENT_TRANSFORMER_H_INCLUDED
#include <Arduino.h>

// Line frequencies
enum ctFreq_t {CT_FREQ_50HZ, CT_FREQ_60HZ};

class CurrentTransformer
{
public:
CurrentTransformer(uint8_t adcChannel, float turnsRatio,
float rBurden, float vcc=5.0, ctFreq_t freq=CT_FREQ_60HZ);
void begin(); // initializations
float read(); // read the rms value of one cycle
static volatile bool adcBusy; // adc busy flag
static volatile int adcVal; // value returned from adc
static const int sampleSize; // number of samples to cover one cycle

private:
uint8_t m_channel; // adc channel
float m_ratio; // current transformer turns ratio
float m_rBurden; // current transformer burden resistor value, ohms
float m_vcc; // mcu supply voltage
uint16_t tcOCR1; // compare value for timer
};

#endif

Binary file added typical-circuit.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit fda62c0

Please sign in to comment.