Tuesday, July 2, 2013

ATXRaspi = Automatic Power Switch for R-Pi

A while back, I did a video review of the ATXRaspi R1, but I wanted to circle back and fill in a few details on how I used the "P5" connector, instead of the GPIO pins.

But first I should mention that Felix reworked his circuit, replacing the relay with a power MOSFET, and dubbed it ATXRaspi R2.  

The (discontinued) R1 had an issue with some (whimpy!) power supplies.  When the relay closed, the immediate current draw by the R-Pi would sometimes cause the ATXRaspi to reset.  When/if this happened, you'd need to hold the power button for a second or two, the relay would click on/off/on a few times, and then everything was fine.

The new ATXRaspi R2 completely solves that issue, by using a slightly slower turn on rate, via the MOSFET.  On a related note, I posted a video about using power MOSFETs with Arduino or R-Pi, a while back.

OK, back to those build details I wanted to share.  I wanted to keep all GPIO pins open and available for other projects, Pi-Cobbler, etc.  So my solution was to use the P5 connector on the Raspberry Model B, Rev.2.  

The P5 connector is "unpopulated" which simply means they didn't install the header pins.  Which is fine by me, just made it easier to solder wires directly into the plated-through-holes.  

Here's how I connected the ATXRaspi to the Raspberry Pi P5:

  • Ground     <-> P5-7
  • +5V Output -> P5-1
  • Input           <- P5-4  (GPIO29)
  • Output        -> P5-3  (GPIO28)

And here's what it looks like:


(Observant readers might notice the ATXRaspi looks a little different.  This was an R1 board, that I retro-fitted with a power MOSFET instead of the relay.  You could call it R1.5 :-)

Note that the GPIO lines on P5 are different than any on P1, the main GPIO connector.  Which is good, that's what I wanted.  But that also meant I had to modify the shutdowncheck script:

#!/bin/bash

#original from www.lowpowerlab.com
#modified by MikeT to use P5 on Rev 2 Pi
#instead of using any GPIO on P1

PATH=/usr/bin:/home/pi/wiringPi/gpio

echo "ATXRaspi shutdowncheck script"
echo "(modified to use P5 on rev 2 Pi)"
echo "Setting P5-3 Input, Pull Down"
echo "Setting P5-4 Output, High"

gpio -g mode 28 in
gpio -g mode 28 down
gpio -g mode 29 out
gpio -g write 29 1

echo
echo "If/when P5-3 goes high, SYSTEM WILL HALT"
echo

COUNTER=0
while [ 1 ]; do
    if [ "$(/home/pi/wiringPi/gpio/gpio -g read 28)" = "1" ]; then
        echo "Pin P5-3 is High: SYSTEM WILL NOW HALT"
        sudo halt
        break
    fi
    sudo sleep 0.5
done

exit 0

By the way, Gordon's wiringPi library is excellent.  Kudos to Gordon!


Getting Started with Raspberry Pi

I've been working with the Raspberry Pi, or R-Pi, for a couple months now, and figured it was high time I blog about it.  As usual, my goal is to give you links and references that I found helpful, and to give you a few helpful nuggets that I learned the hard way, to save you time.

For starters, I got the Raspberry Pi Model B Revision 2.0 (512MB) and a Transcend 16GB Class 10 SDHC Flash Memory Card (TS16GSDHC10E).  

Although there's a ton of info on the internet, I still like books.  I took some time reading reviews and previews before settling on three books.  They've each been helpful in different ways:


Here are some lessons learned:

1) Make sure to get an SD card that is known to be R-Pi compatible: check this list Don't waste your time on a card that others had trouble with.    

2) The SD card socket on R-Pi is very cheap and sooner or later it'll break.  I thought I was being very careful, but I managed to break it, and it was a hassle to fix.

3) The Adafruit Pi-Cobbler is great way to connect the R-Pi to a solderless breadboard.  (Actually, I would have preferred the T-Cobbler, but they were out of stock at the time.)

4) This Adafruit R-Pi case is a great value and works fine, except that it doesn't hold the R-Pi down very securely.  

One time I was unplugging the Pi-Cobbler from the GPIO pins and didn't realize the R-Pi was lifting up inside the case.  The SD card was still plugged in, and that was the demise of the cheap plastic SD card socket. 

Here's how I fixed it, without soldering.  I used some foam tape, with a smooth durable top layer, to build up the area inside the case, below the SD card slot:
 


Then I added a nylon standoff, to the right of the GPIO pins, to hold the R-Pi down inside the case:


Now my SD card makes good contact again.

Next up: ATX Raspi, and then direct serial com between R-Pi and Arduino...

Wednesday, June 26, 2013

Epson LabelWorks LW-400

I used to have an old Dymo Label Maker.  And I still have parts drawers with labels I made in the 70's.  But it's long gone, and who knows if they even make the tape anymore?

So when I finished my variable power supply, I started looking for new labeler, and decided to try the Epson LabelWorks LW-400. 

The verdict: pretty good for about $25.  It can print either 1/2" or 3/4" tape, 1 to 4 lines tall.  It can print horizontally or vertically.  It can even do barcodes and cable tags.  It has a few features I'll probably never use like fancy fonts and borders.  But I like it because it gets the job done and didn't cost too much.

It came with white on black tape, which is probably better on light colored items.


I ordered a white on black tape, for almost as much as the labeler.  So, that's how they make their money.  But I wanted to re-do the labels on the power supply:


I think it looks better.  There are a lot of tape and print colors to choose from, I think the white on black is probably the best for black plastic project boxes.  Then again, the gold on black might look pretty good too.



Sunday, June 9, 2013

Analog Detour: Variable Power Supply

It's been several weeks since my last post.  I've been busy with the Raspberry Pi, learning Linux, etc. building towards an RF base station, data logger, web server for the home energy monitor project.  I'll be posting about that soon, but first I've got a couple small analog projects to share.

I was at Radio Shack checking out their clearance table and came across a Velleman 1A variable power supply kit, for only $5, and couldn't resist.  I've already got several power supplies, but none are variable.  The kit includes a PCB, LM317 adjustable voltage regulator, resistors, caps, and bridge rectifier.  It came with a trimpot, that I upgraded to a front panel mini-pot with a knob.  The kit doesn't include a transformer, but I already had a 12.8 Vac, 1.2A transformer from my junk box.

The LM317 is an interesting twist on three terminal regulators: instead of Input, Common, and Output terminals, the LM317 has Input, Adjust, and Output terminals.  Here's a typical application, taken from the TI data sheet:



The LM317 adjusts the Output voltage to maintain 1.25V across R1.  IAdj is close to zero, so the current in R2 is essentially the same as the current in R1.  In other words there is no appreciable load on the voltage divider formed by R1 and R2.  Therefore the output voltage is very close to:

V0 = 1.25V * (1 + R2/R1)

I wanted my supply to have two output ranges, to make it easier to set the desired voltage.  After several iterations on the solderless breadboard, I settled on the circuit below.  I experimented with the values for R1, based on the the 10K linear mini pot I already had for the front panel. 

I also wanted an analog voltmeter, mostly because they look cool, and also because it's darn handy to adjust the output, without having to drag out a DVM.  I found this one on Amazon, and it worked out great.

I also added the protection diodes shown above and discussed in the TI data sheet.  These protect the LM317 from reverse currents, under various fault conditions, e.g. connecting a higher voltage supply in parallel with the output, or shorting the input.  Probably never needed, but they're cheap insurance!

Here's the complete schematic:


The LM317 does require a minimum load current, so I added the 1K resistor across the output.  Since meter is 10V, but the higher voltage range tops out at more than 15 volts, I added a range doubler switch for it.  Here are some photos of the build:



I used heavy-duty double sided 3M tape, to mount the top of the 2200uFd cap to the bottom of the mini-pot. 


The trimpot on the back of the meter is to adjust the 2X calibration.


Here the supply is set for 12 volts.  I also got a new Epson Labelwriter LW-400, and put it to good use.

Next up: a cellphone headset booster amp.

Wednesday, April 24, 2013

Moteino Kill-A-Watt: Hardware

Midway through my JeeNode Kill-A-Watt project, I came across the Moteino, and boy, I wish I'd found it sooner.  It's small, complete with RFM12B (or without if you prefer) and even has a two more Analog inputs than the Arduino Uno.  Here's a size comparison:


The Moteino on the left has the RFM12B on the back side; the JeeNode in the center has the radio to left of the Atmel micro; the Arduino Uno on the right has a custom custom proto-shield, with RFM12B.  

While the JeeNode just barely fits inside the KAW, the Moteino has room to spare:


In a prior post, I analyzed the Kill-A-Watt circuit, using a great schematic by Kevin Timmerman.  Armed with that knowledge, I created an accurate, true RMS, power-factor-corrected, watt-meter.  Here's the gist of my design:

  • Uses a Moteino, with built-in RFM12B
  • Measures 50 samples during one AC line cycle
  • Computes calibrated Volts, Amps, Watts
  • Transmits those values once per second

The Moteino operates at 3.3V, so the KAW signals need to be attenuated, using simple resistor voltage dividers.  Here's the interface between KAW and Moteino:


U3, the LM2902 quad op-amp, is on the bottom of the KAW display board.  I added three wires:


I used 30 AWG wire-wrap wire, and hot-glue to secure them.  Pin 14 (white wire) is the voltage signal, pin 1 (yellow wire) is the high current range signal and pin 8 (blue wire) is the low current range signal.


Those three wires go to Moteino analog inputs.  The 4.7K and 10K resistors are mounted on the Moteino.  The bus wire across the top of the Moteino is connected to the two ground pads.

Q3 is near the center of the picture.  A red wire-wrap wire is soldered to the collector.  This is the 60 Hz square wave, connected via series 1K resistor to the Moteino INT1 interrupt input.

The Moteino is held in place with some heavy duty 3M mounting tape, on top of the piezo transducer:


The power supply design was not trivial.  The KAW has two regulated voltage supplies: +5V and +6.1V.  Neither one has much current to spare, and any load greater than about 10 mA will prevent the KAW from powering up properly: the display will just flicker with all segments on.

So I went back to the unregulated +13.9V supply, and added a new dedicated supply for the Moteino.  I took advantage of D1, a 6.8V zener already in the KAW, and added Q100 (2N3904) to charge C100, 1000 uFd, providing plenty of reserve power for the once per second RF transmission.  The average voltage is about 5.5 V, with about 0.5 volts ripple, at about 1 Hz.  The Moteino's onboard 3.3V regulator handles that ripple, no problem.
Q101 (2N3906) is there to quickly discharge C100 when the KAW is unplugged, to ensure a full reset on the Moteino.  While characterizing the circuit, I discovered I had to power down for about 10 seconds to allow C100 to discharge, or short it myself with a wire jumper.  Q101 simply automates that process.  When the KAW is unplugged, C11 discharges quickly, bringing the base of Q101 close to ground, rapidly discharging C100.  R102 and R103 limit the charge and discharge current.

Although this extra power supply circuitry complicates the build somewhat, I think it's well worth it to have a robust circuit.  Other hackers have reported problems getting their circuits to work reliably, and I felt their pain, so to speak.  

Here's how I built it up, with the charging circuit, Q100, on the left, and the discharge circuit, Q101 on the right:


First, I hot-glued C100 (1000 uFd) to the display board.  C100 negative is connected to KAW neutral, the PCB wire jumper just below the green wire, which goes to Moteino ground.  R101 (100K) connects between Q101 base and collector.  The right end of R101 connects to C100 negative.  A red wire-wrap wire connects Q101 base to R100 (47K), over on the left. R103 (220) connects C100 positive to Q101 emitter and R102 (220).  The red wire connects C100 positive to Moteino Vin.

Q100 is on the left, just above the 6 conductor ribbon cable.  Q100 is piggy backed on Q1, with their collectors and bases connected together.  The emitter of Q101 rises up and connects to R102 (220).  The lower end of R100 (47K) connects to Q1 collector.

And finally, there's an activity LED, with 220 ohm series resistor, from Moteino D5 to ground.  It flashes on briefly, right after the radio transmission, about once per second.

So that's it.  If you're thinking about an Arduino compatible Kill-A-Watt hack, a.k.a. Tweet-A-Watt, I highly recommend the Moteino.  In my next post, I'll present the sketch, explain the math and calibration process.

Download sketches and other files on GitHub

I finally took the plunge, and got myself setup on GitHub.  I've uploaded several files from this blog:

https://github.com/MikeTranch/MikesMicroMania

This will make it easy for you to download the files, instead of trying to select text in the blog post, copy to clipboard and paste into a new file.

GitHub is popular and powerful way to share and collaborate on software projects.  I'll be the first to admit I don't understand all that it has to offer, and I probably won't use use 85% of its capabilities.  I had used it several times in the past to download Arduino libraries, and even that wasn't as simple and obvious as I'd like it to be.  But if you poke around a bit, you can figure it out.  And no worries, the link above will give you read-only access, so you can't break anything.

If you want to open your own (free) GitHub account and create your own repositories to share your code, you'll have to deal with even more complexity.  If you read the GitHub online help, you'll either feel right at home (if you speak Linux in your sleep) or you'll be like WTF? (if you're like me.)  Right off the bat they got you doing shell commands.  Even though there are numerous GUI programs available, on GitHub and elsewhere.  Also, the GitHub GUI for Mac OSX requires at least 10.7, but I'm still at 10.6 and don't want to upgrade because it would break some other programs I use (and don't want to pay $$$ to upgrade.)

Fortunately, I found this free GitHub GUI called SourceTree and it took away a lot of the pain navigating GitHub.

Tower is another popular Git GUI for Mac.  It's free to try for 30 days, then $59 to purchase.

And here's a great video that I came across when I googled "GitHub for dummies"

Let's Suck at GitHub Together

It's about 18 minutes long, but it was worth it, because Chris does a great job of making you feel better about yourself, and shows that yes it can be done, you can actually upload your files to your repo.

Tuesday, April 23, 2013

Hacking a small AC power transformer


I needed a small transformer for my next project, with 4.5 Vrms at 300 mA.  I have dozens of old “wall-warts” and one was just begging to be hacked: it was already cracked open; probably got dropped on the cement floor.  It was 9 Vrms nominal output, twice what I wanted.  I considered my options.   I could just use it as is, with a series power resistor, wasting power and generating heat.  Or find a more suitable wall-wart and cut it open.  Or buy a new transformer online or locally. 

I decided I’d try to take it apart, remove about half the secondary winding wire, and put it back together.  The transformer core is made of metal plates that look like the letter "E" and "I," arranged like this:



I used a razor blade to score the enamel between the plates.  The first E plate was hard to get out.  I used a piece of thin metal, to push it down, inside the plastic bobbin.  It was in there pretty tight, but once I moved it an 1/8 inch or so, I could grab it from the other side with a pair of pliers and pull it out. The rest of the plates were much easier to remove.  


That left me with the plastic bobbin with the primary and secondary coils.  I carefully removed the plastic tape around the secondary coil, then removed what I guessed was about a third of the enamel covered magnet wire.  I put the plates back in, fired it up and checked the output.  It was still higher than I wanted, so I repeated that process a few more times, until I got the output I wanted.

A couple lessons: the inductance of the primary winding is very low without the metal core.  At one point I fired it up, very briefly, with no core plates and it got very warm, very quickly.  It would have burnt out if I hadn’t killed the AC power right away.  So don’t do that.

Then I installed just the E plates, all facing the same way, without the "I" plates.  That way I could easily remove a few turns off the secondary coil, test and repeat.  But the metal core was open on one end, so the waveshape was distorted, and the peak to peak voltage was about 5% less than with the complete core.  But the primary coil didn’t overheat, and it made it a lot easier to remove a few turns of wire at a time.


The yellow trace is with the complete core assembled.  The wave-shape matches the input wave-shape (not shown).  The white trace is with the E plates only, all facing the same way.  The magnetic circuit is not complete and causes the wave-shape to be distorted.  The peak to peak voltage is reduced by about 5%.  The rms voltage is reduced about 18% percent.

Once I got the output voltage I wanted, I trimmed the copper wire back, scrapped the enamel coating off the ends of the wires, soldered on some suitable plastic insulated wires.  I wrapped the secondary coil and leads with several layers of electrical tape.  Since the plates still had a fair amount of enamel on them, it would hard to get them all back into the plastic bobbin.  So I cleaned them up with a Dremel tool, barrel sander, and they all slid in easily.  

All together this took about 2 hours, so not really worth it economically, but satisfying none the less.

Tuesday, April 16, 2013

JeeNode Kill-A-Watt Receiver Sketch

Here's a simple sketch you can use as a receiver for the JeeNode Kill-A-Watt:


// Version 0.707

// JeeNode_KAW_Rx
// receiver for JeeNode Kill-A-Watt, using JeeLib
// www.mikesmicromania.com

#include <RF12.h> // from jeelabs.org

const int AVG = 3; // # running averages

#define CALMODE false // true to xmit raw values (to establish cal factors)

struct payload { // payload structure for RFM12B packet 
  int Status;    // 0: OK, 1: first reading, -1: low line voltage 
  int      N;    // # of readings (over one line cycle)
  float    V;    // AC RMS voltage
  float    A;    // AC RMS current, coarse scale
  float    W;    // average watts, coarse current scale
#if CALMODE
  float    a;    // AC RMS current, fine scale
  float    w;    // average watts, fine current scale
#endif
} KAW;  

const int Node = 30;            // local node ID (range 1-30)
const int network = 210;        // network group (range 1-212)
const int myFreq = RF12_433MHZ; // must match RFM12B hardware
const int myCS = 9;             // RFM12B chip select, AKA SS
                                // 9 on my shields
                                // 10 on JeeNodes
void setup() {
  rf12_set_cs(myCS); // note this is before rf12_initialize()
  rf12_initialize(Node, myFreq, network); 
  Serial.begin(57600);
  //Serial.setTimeout(1000); // ms, timeout for Serial.readBytesUntil()
  Serial.println("\nJeeNode Kill-A-Watt Receiver");
}

int n=0;
float avgV=0, avgA=0, avgVA, avgW, AVGa=0, AVGva, AVGw;

void loop() { // listen for broadcast from JeeNode_KAW
  if (rf12_recvDone() && rf12_crc == 0 ) { // got data with good CRC?
    KAW = *(payload*)rf12_data;
    n = min(n+1, AVG);
    if(n==1){ // first readings received
      avgV = KAW.V;
      avgA = KAW.A;
      avgW = KAW.W;
#if CALMODE        
      AVGa = KAW.a;
      AVGw = KAW.w; 
#endif
    }else{ // calc running average
      avgV = (avgV * (n-1) + KAW.V) / n;
      avgA = (avgA * (n-1) + KAW.A) / n;
      avgW = (avgW * (n-1) + KAW.W) / n;
#if CALMODE 
      AVGa = (AVGa * (n-1) + KAW.a) / n;
      AVGw = (AVGw * (n-1) + KAW.w) / n;
#endif        
    }
    avgVA = avgV * avgA; // Volt-Amps, ignoring Power Factor
#if CALMODE 
    AVGva = avgV * AVGa; // same, but on the fine current scale
#endif
    Serial.print(KAW.Status); Serial.print(" Status, ");
    Serial.print(KAW.N);      Serial.print(" N, ");
    Serial.print(avgV);       Serial.print(" V, ");
    Serial.print(avgA);       Serial.print(" A, ");
    Serial.print(avgVA);      Serial.print(" VA, ");
    Serial.print(avgW);       Serial.print(" W, ");
    Serial.print(AVGa);       Serial.print(" a");
#if CALMODE       
                              Serial.print(", ");
    Serial.print(AVGva);      Serial.print(" Va, ");
    Serial.print(AVGw);       Serial.print(" w");
#endif      
    Serial.println();
  } 
}

JeeNode Kill-A-Watt: Software Walk-Through

In yesterday's post I described the JeeNode Kill-A-Watt hardware build.  Today we'll look at the software, and explain the math used and also the calibration.  For this build, I used the JeeLib library, available here.  JeeLib provides support for the RFM12B radio and the low power mode, which is essential for keeping the KAW power supply from getting bogged down.  In fact, the JeeNode spends most of its time asleep.  About once per second, it wakes up, measures voltage and current over one AC line cycle, does some calculations, transmits the results, flashes the LED, and goes back to sleep.

I'll present the entire sketch in separate post, for easy copying.  But here I'll present it in sections, explaining along the way:

// VERSION 1.414

// JeeNode_Kill_A_Watt (using JeeLib)
// works with JeeNode or Moteino.  (Moteino easier to fit inside KAW)
// www.mikesmicromania.com
// activity LED on DIO2 (Arduino Digital 5)
// Kill-A-Watt coarse current sensor to AIO1 (Arduino A0)
// Kill-A-Watt voltage sensor to AIO2 (Arduino A1)
// Kill-A-Watt frequency signal to INT (Arduino D3)
// Kill-A-Watt fine current sensor to AIO4 (Arduino A3)

#include <JeeLib.h> // jeelabs.org

#define CALMODE false // true to xmit raw values (to establish cal factors)
CALMODE should be set true during calibration, explained below.
typedef struct { // payload structure for RFM12B packet 
  int Status;    // 0: OK, 1: first reading, -1: low voltage 
  int      N;    // # of readings
  float    V;    // average AC RMS voltage
  float    A;    // average AC RMS current, coarse scale
  float    W;    // average watts, coarse current scale
  float    a;    // average AC RMS current, fine scale 
  float    w;    // average watts, fine current scale
} payload; // typedef

payload KAW;

The payload struct defines the radio transmission, and the receiver software should use the same data structure.  KAW is an instance variable of type payload.
 
// cal factors for map() 
const float CFrawVlo = 248.2; // raw value from A2D 
const float CFrawVhi = 270.9; 
const float CFcalVlo = 115.2; // scaled Voltage
const float CFcalVhi = 125.1; 
const float CFrawAlo = 36.5;  // A2D
const float CFrawAhi = 131.9; 
const float CFcalAlo = 2.18;  // Amps (coarse scale current)
const float CFcalAhi = 8.07;  
const float CFrawalo = 49.7;  // A2D
const float CFrawahi = 361.0; 
const float CFcalalo = 0.29;  // amps (fine scale current)
const float CFcalahi = 2.18;  
I'll explain these cal factors below.  
// radio settings
const int NODE      =  1; // this node ID
const int BROADCAST = 31; // send to node 31: broadcast
const int GROUP    = 210; // Rx must be on same group to receive
const int myCS = 10;      // RFM12B chip select, AKA SS
                          // 9 on my shields
                          // 10 on JeeNodes, Moteinos
Constants for radio settings are used in the setup() function.  
// pin assignments    JeeNode   Arduino
const int LED    = 6; // DIO3 = D6
const int ASENS  = 0; // AI01 = A0 (Yellow wire from pin 1, coarse current)
const int VSENS  = 1; // AI02 = A1 (White wire from pin 14, voltage)
const int aSENS  = 3; // AI04 = A3 (Blue wire from pin 8, fine current)
const int HzSENS = 3; // IRQ  = D3 (Red wire from Q3 collector, 60Hz)
const int HzINT  = 1; //        INT1
const int MaxN  = 65; // max # readings (good down to 48 Hz)
const int NAP  = 925; // nap time in milliseconds
// boilerplate for low-power waiting
ISR(WDT_vect) { Sleepy::watchdogEvent(); }

ISR variable is required for the "Sleepy" (power save) methods.  Details on http://jeelabs.org/  
void setup () {   // turn the radio off in the most power-efficient manner   Sleepy::loseSomeTime(32);   rf12_set_cs(myCS); // note this is before rf12_initialize()   rf12_initialize(NODE, RF12_433MHZ, GROUP);   rf12_sleep(RF12_SLEEP);   pinMode(HzSENS,INPUT); // IRQ1 input, D3   pinMode(LED,OUTPUT);   digitalWrite(LED,LOW); // off   // speed up ADC to minimize phase measurment error   bitClear(ADCSRA,ADPS0);   bitClear(ADCSRA,ADPS1);   bitSet(ADCSRA,ADPS2);   //wait another 2s for the power supply to settle   Sleepy::loseSomeTime(2000); }

When setup() begins, the JeeNode has just powered up, and the KAW has just come up as well.  We need to quickly initialize the radio and then turn it off ASAP.  The LED pin connects to the activity LED.  The 60 Hz square wave is connected to HzSENS pin (D3) which is INT1.  The standard analogRead function is too slow, so we speed it up by a factor of 8, to minimize the delay between measuring voltage and current.
boolean First = true; // the very 1st reading int V[MaxN], A[MaxN], a[MaxN]; // waveform arrays volatile int unsigned measState; // state machine, clocked by line frequency boolean toggle; // alternate maeasurements on + or - cycle
First is a flag, to mark the first reading after power-up.  Three arrays V[], A[], and a[] hold the waveform samples taken over one cycle.  measState is incremented by the interrupt service routine, triggered by the 60 Hz square wave.  toggle is a variable that alternates the measurement: one time it will start on a positive half cycle, the next time it will start on a negative half cycle.

Next we enter the main loop:
void loop () {
  // acquire voltage and current samples
  int n = 0;
  measState = 0; // 0 is partial half cycle
  toggle = !toggle;
  if (toggle){
    attachInterrupt(HzINT,AC60HZ,RISING);
  }else{
    attachInterrupt(HzINT,AC60HZ,FALLING);
  }
  while(measState < 2);              // skip partial cycle

n is the index for the waveform arrays.  MeasState starts at 0, and is incremented by either rising or falling edges of the 60 Hz square wave.  The code above skips the partial AC line cycle already in progress.  Then the code below starts at the exact beginning of a new AC line cycle: 
  //digitalWrite(LED,HIGH);
  while(measState < 3 && n < MaxN) { // measure 1 cycle
    //digitalWrite(LED,HIGH);
    A[n] = analogRead(ASENS); // 20.4 us
    V[n] = analogRead(VSENS); // 20.4 us
    a[n] = analogRead(aSENS); // 20.4 us
    //digitalWrite(LED,LOW);
    n++;
    // 20.4 us is about 0.44 degrees at 60 Hz
    // 3 * 20.4 us * 100 = 6.12 ms
    // (2/60) - 6.12 ms = 27.2 ms
    // 27.2 ms / 100 = 272 us
    // so delay about 272 us
    delayMicroseconds(280); // fine tuned for 50 readings
  } 
  //digitalWrite(LED,LOW);
  detachInterrupt(HzINT);

The while() loop above executes over one period of the AC line cycle.  analogRead is called three times, once each for the coarse current waveform A[], the voltage waveform V[], and the fine current waveform a[].  Those reads take about 60 uS, followed by a delay of 280 uS.  This works out to 50 sets of readings, over one AC line cycle.  (The commented digitalWrites were used to flash the LED and verify the operation of this time-critical portion of the code, as described in this prior post.) 
     KAW.N = n; // number of readings

n is now equal to 50, and KAW.N is the first field in the radio transmission packet.  
     // compute offset levels   float VSum=0, ASum=0, aSum=0, WSum=0, wSum=0;   for(int i=0; i<n; i++){     VSum += V[i];     ASum += A[i];       aSum += a[i];   }   float aV, aA, aa; // averages   aV = VSum/n;   aA = ASum/n;   aa = aSum/n;
A[], V[], and a[] are the waveforms, with 50 samples each.  At this point, we don't know yet whether we'll use the coarse current scale A[] or the fine current scale a[], so we'll calculate both and decide later.  

Recall that the KAW quad op-amp operates with a single supply, with a reference voltage of about 2.33V.  After the resistor divider, this becomes 2.33 x 10K/14.7k, or about 1.59 volts.  So the waveforms are centered around this level, and we want to remove that level, so we can work with the AC waveshape only.  Since we measured over exactly one cycle, we can simply compute the mean, or average level.  aV is the average voltage level. aA is the average coarse current scale.  aa is the average fine current scale.
  
  // compute std.dev. = AC RMS
  VSum = ASum = aSum = 0;
  for(int i=0; i<n; i++){
    VSum += (V[i]-aV)*(V[i]-aV);
    ASum += (A[i]-aA)*(A[i]-aA);
    aSum += (a[i]-aa)*(a[i]-aa);
    WSum += (V[i]-aV)*(A[i]-aA);
    wSum += (V[i]-aV)*(a[i]-aa);
  }
  KAW.V = sqrt(VSum/n);
  KAW.A = sqrt(ASum/n);
  KAW.a = sqrt(aSum/n);
  KAW.W = WSum/n;
  KAW.w = wSum/n;

Now we can calculate the standard deviation, which in this case is the same as the RMS, root mean square.  At each sample point, we square the difference between the sample and the mean.  We sum all those squares, find the average or mean, and then take the square root.  Thus, the (square) root of the mean of the squares (of the differences).  We do that for the V[], A[] and a[] waveforms, and while we're at it, calculate the instantaneous power, W[] and w[], at each sample, for both the fine and coarse current scales.  

If the load is reactive, there will be a phase difference between the voltage and current waveforms.  The power waveforms correctly account for that phase difference.

At this point, the KAW data structure has linearized values for RMS voltage, current and power, but they are not yet scaled in volts, amps and watts.

When we want to calibrate, we set CALMODE true, and those unscaled RMS values are transmitted.  We pick them up on the receiver, and record them, along with the measurements displayed on the KAW itself.  That's how I determined the values for the cal factor constants above, and used in the next block of code:
#if not CALMODE  // apply cal factors   // voltage   KAW.V = map(KAW.V, CFrawVlo, CFrawVhi, CFcalVlo, CFcalVhi);      // coarse current scale, above 2 A   KAW.A = map(KAW.A, CFrawAlo, CFrawAhi, CFcalAlo, CFcalAhi);      // coarse wattage scale, Current above 2 A   KAW.W = map(KAW.W, CFrawVlo*CFrawAlo, CFrawVhi*CFrawAhi, CFcalVlo*CFcalAlo, CFcalVhi*CFcalAhi);      // fine current scale, below 2 A   KAW.a =  map(KAW.a, CFrawalo, CFrawahi, CFcalalo, CFcalahi);      // fine wattage scale, Current below 2 A   KAW.w = map(KAW.w, CFrawVlo*CFrawalo, CFrawVhi*CFrawahi, CFcalVlo*CFcalalo, CFcalVhi*CFcalahi);

The code above uses the familiar Arduino map() function to scale the RMS values into calibrated volts, amps and watts.  (Actually, as shown below, it's an overloaded map() function.)
    // prevent negative values (e.g. no low load current, noise)   KAW.a = max(KAW.a, 0);   KAW.w = max(KAW.w, 0);   KAW.A = max(KAW.A, 0);   KAW.W = max(KAW.W, 0);

This code prevents negative values for current and power, caused by no load (0 A) and the presence of small noise signals. Note, during calibration, this code is disabled, so the negative values (if any) are displayed.  I verified that these negative values are very small and occasional, of no real consequence.  
 
  // use fine current scale for 2A or less load current
  if(KAW.a <= 2.0) {
    KAW.A = KAW.a;
    KAW.W = KAW.w;
  } 
#endif

Now that we have calibrated current values, we can decide whether to use the coarse (>2A) or fine (<=2A) current scale.  The receiver doesn't have to choose, it simply uses KAW.A and KAW.W.
  if (First) {
    First = false;
    KAW.Status = 1;          // 1st reading     
  } else if (KAW.V < 115 ) { // KAW analog supply sags
    KAW.Status = -1;         // accuracy warning
  } else {
    KAW.Status = 0;          // OK
  }
  
KAW.Status lets the receiver know if this is the first measurement.  This would be useful for example when plugging a new appliance into the KAW.  Just cycle power the KAW and Status byte will mark that event.  I also defined a status of -1 to indicate if the AC line voltage was less than 115V.  I found that the KAW analog linearity is not so good below 115V.
  rf12_sleep(RF12_WAKEUP);   while (!rf12_canSend()) // wait for xmit ready     rf12_recvDone(); // advance RF12 driver state machine   rf12_sendStart(BROADCAST, &KAW, sizeof(KAW)); // send payload   rf12_sendWait(0); // wait (2 = in standby) for xmit done   rf12_sleep(RF12_SLEEP);
Finally, it's time to transmit!  The code above is a bit cryptic but gets the job done, in a couple ms.  
  digitalWrite(LED,HIGH); // flash LED so we know we're alive
  delay(10);              // 10 ms visable
  digitalWrite(LED,LOW);  // save power!
  
  Sleepy::loseSomeTime(NAP);
}

Then all we need to do is flash the LED for 10 ms, and go to sleep.  All the code above takes about 75 ms, so we sleep for 925 ms, giving a total repetition rate of about 1 second.
Here's the interrupt handler.  All it has to do is increment measState: 

void AC60HZ(){ 
  measState++;
}
And finally, here's a new version of the map function, that works with floats instead of ints.
// overload Arduino int map() function to support floats float map(float x, float in_min, float in_max, float out_min, float out_max) {   return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; }

So that's it.  I hope this code walk-through has been useful, feel free to post questions or comments.  And look to the next post for the complete sketch that you can easily copy and paste into a text file.  I'm sorry I don't know how (or if) I can attach a file to this blog.