/* * Tool to capture the raw samples generated by the Atmega 328P processor * during one or more mains cycles. The data is displayed on the Serial Monitor, * and is also available for subsequent processing using a spreadsheet. * * This version is based on similar code that I posted in December 2012 on the * OpenEnergyMonitor forum. The original version, and other related material, * can be found on my Summary Page at www.openenergymonitor.org/emon/node/1757 * * The pin-allocations have been changed to suit my PCB-based hardware for the * Mk2 PV Router. The integral voltage sensor is fed from one of the secondary * coils of the transformer. Current can be measured via Current Transformers * at the CT1 and CT1 ports. * * Voltage samples are displayed as 'v' * Current samples via CT1 are displayed as '1' * Current samples via CT2 are displayed as '2' * * The display is more compact if not every set of samples is shown. This aspect * can be changed at the second of the two lines which contain a '%' character. * * Robin Emley * www.Mk2PVrouter.co.uk * February 2014 */ #define POSITIVE 1 #define NEGATIVE 0 #define CYCLES_PER_SECOND 50 byte sensorPin_V = 3; byte sensorPin_I1 = 5; byte sensorPin_I2 = 4; long cycleCount = 0; int samplesRecorded = 0; byte polarityNow; boolean beyondStartUpPhase = false; int lastSample_V; // stored value from the previous loop (HP filter is for voltage samples only) float lastFiltered_V; // voltage values after HP-filtering to remove the DC offset byte polarityOfLastSample_V; // for zero-crossing detection boolean recordingNow; boolean recordingComplete; byte cycleNumberBeingRecorded; byte noOfCyclesToBeRecorded; unsigned long recordingMayStartAt; boolean firstLoop = true; int settlingDelay = 5; // <<--- settling time (seconds) for HPF char blankLine[82]; char newLine[82]; int storedSample_V[100]; int storedSample_I1[100]; int storedSample_I2[100]; void setup() { delay(5000); // allow time for the Serial Window to be opened Serial.begin(9600); Serial.println(); Serial.println("-------------------------------------"); Serial.println("Sketch ID: RawSamplesTool_2chan.ino"); Serial.println(); // initialise each character of the display line blankLine[0] = '|'; blankLine[80] = '|'; for (int i = 1; i < 80; i++) { blankLine[i] = ' '; } blankLine[40] = '.'; Serial.print(">>free RAM = "); Serial.println(freeRam()); // a useful value to keep an eye on } /* Allow the system to run for several seconds so that the filtered * voltage waveform can settle down. This info is needed for determining * the start of each new mains cycle. During this period, a countdown * is displayed. * * After the settling period has expired, raw samples taken during * one complete mains cycle are stored in an array. The capacity of the * array needs to be sufficient for the number of sample pairs that may * appear. * * At the start of the following cycle, the data collected during the * previous cycle data is sent to the Serial window. */ void loop() // each iteration of loop is for one set of measurements only { if(firstLoop) { unsigned long timeNow = millis(); Serial.print ("millis() now = "); Serial.println (timeNow); recordingMayStartAt = timeNow + (settlingDelay * 1000); Serial.print ("recordingMayStartAt "); Serial.println (recordingMayStartAt); recordingNow = false; firstLoop = false; recordingComplete = false; noOfCyclesToBeRecorded = 1; // more array space may be needed if this value is >1 !!! cycleNumberBeingRecorded = 0; samplesRecorded = 0; } int sample_V = analogRead(sensorPin_V); // from the inbuilt voltage sensor int sample_I1 = analogRead(sensorPin_I1); // from CT1 int sample_I2 = analogRead(sensorPin_I2); // from CT float filtered_V = 0.996*(lastFiltered_V + sample_V - lastSample_V); byte polarityOfThisSample_V; if(filtered_V > 0) { polarityOfThisSample_V = POSITIVE; if (polarityOfLastSample_V != POSITIVE) { // This is the start of a new mains cycle cycleCount++; if (recordingNow == true) { if (cycleNumberBeingRecorded >= noOfCyclesToBeRecorded) { Serial.print ("No of cycles recorded = "); Serial.println (cycleNumberBeingRecorded); dispatch_recorded_data(); } else { cycleNumberBeingRecorded++; } } else if((cycleCount % CYCLES_PER_SECOND) == 1) { unsigned long timeNow = millis(); if (timeNow > recordingMayStartAt) { recordingNow = true; cycleNumberBeingRecorded++; } else { Serial.println((int)(recordingMayStartAt - timeNow) / 1000); } } } // end of specific processing for first +ve reading in each mains cycle } // end of specific processing of +ve cycles else { polarityOfThisSample_V = NEGATIVE; } if (recordingNow == true) { storedSample_V[samplesRecorded] = sample_V; storedSample_I1[samplesRecorded] = sample_I1; storedSample_I2[samplesRecorded] = sample_I2; samplesRecorded++; } polarityOfLastSample_V = polarityOfThisSample_V; lastSample_V = sample_V; lastFiltered_V = filtered_V; } // end of loop() void dispatch_recorded_data() { // display raw samples via the Serial Monitor // ------------------------------------------ Serial.print("cycleCount "); Serial.print(cycleCount); Serial.print(", samplesRecorded "); Serial.println(samplesRecorded); int V, I1, I2; int min_V = 1023, min_I1 = 1023, min_I2 = 1023; int max_V = 0, max_I1 = 0, max_I2 = 0; for (int index = 0; index < samplesRecorded; index++) { strcpy(newLine, blankLine); V = storedSample_V[index]; I1 = storedSample_I1[index]; I2 = storedSample_I2[index]; if (V < min_V){min_V = V;} if (V > max_V){max_V = V;} if (I1 < min_I1){min_I1 = I1;} if (I1 > max_I1){max_I1 = I1;} if (I2 < min_I2){min_I2 = I2;} if (I2 > max_I2){max_I2 = I2;} newLine[map(V, 0, 1023, 0, 80)] = 'v'; newLine[map(I1, 0, 1023, 0, 80)] = '1'; newLine[map(I2, 0, 1023, 0, 80)] = '2'; if ((index % 2) == 0) // change this to "% 1" for full resolution { Serial.println(newLine); } } Serial.print("min_V "); Serial.print(min_V); Serial.print(", max_V "); Serial.println(max_V); Serial.print("min_I1 "); Serial.print(min_I1); Serial.print(", max_I1 "); Serial.println(max_I1); Serial.print("min_I2 "); Serial.print(min_I2); Serial.print(", max_I2 "); Serial.println(max_I2); Serial.println(); // despatch raw samples via the Serial Monitor // ------------------------------------------- Serial.println("Raw data from stored cycle: , , [cr]"); Serial.print(samplesRecorded); Serial.println(", <<< No of sample sets"); for (int index = 0; index < samplesRecorded; index++) { Serial.print (storedSample_V[index]); Serial.print(", "); Serial.print (storedSample_I1[index]); Serial.print(", "); Serial.println (storedSample_I2[index]); } recordingNow = false; firstLoop = true; pause(); } void pause() { byte done = false; byte dummyByte; while (done != true) { if (Serial.available() > 0) { dummyByte = Serial.read(); // to 'consume' the incoming byte if (dummyByte == 'g') done++; } } } int freeRam () { extern int __heap_start, *__brkval; int v; return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); }