Hookup suggestions for connecting a Photon to a pulsing energy meter

I like to connect my Garo GM3D energy meter (that is measuring the heater consumption).

The documentation shows this:

Would it be enough to connect Out1 to a digital pin and GND/VDC to GND/3.3V and setting the digital pin to pinMode(pin, INPUT_PULLDOWN) or do I need the Rc? In that case, what is the suggested value of Rc (would a 10k do it)?
Which of the sketches is recommended?

I’m thinking of using something like this to calculate the current watt usage:

unsigned long pulseTime=0;
unsigned int pulseCount=0;
unsigned long pulsePower=0;
    
void blink() {
  pulseCount++;
  //GM3D outputs 10 pulses/W
  pulsePower = 360000000 / (millis() - pulsetime); 
  Spark.publish("heater power", String(pulsePower));
  pulsetime = millis();
}

void setup() {
  attachInterrupt(D0, blink, FALLING);
}

Any thoughts on that?

@fredrike, the best and safest method, as you surmised, is to use the open-collector method. I would not rely on the internal pull-up/down resistors. The way open-collector works is when it is inactive, the external pull-up, say 10K ohms connected to 3V3, will provide a HIGH (rising edge) to the Photon. When it is active, the transistor will “connect” the output to GND, effectively providing a LOW (falling edge) to the Photon. So, configure your pinMode() to just INPUT. I highly recommend NOT doing a Spark.publish() in the blink() ISR. The way you have blink() is to publish on EVERY pulse. Instead, count your pulses and sample the count in loop() at 1 sec (or more) intervals for example and then publish. Remember, there is a fixed 1 publish/sec limit on Spark.publish()!

2 Likes

Yep. That's what I would do too. Keep pulseCount++ in the ISR and move all other logic to loop.

Make sure you disable interrupts in loop when copy pulseCount into a local variable and set pulseCount back to 0, then re-enable interrupts.

1 Like

@jvanier, I always debate (with myself) about stopping interrupts, especially if you declare pulseCount as a volatile and the operation is very short (eg. x = pulseCount). Nonethless, it still remains good pratice to do so. It is important to note that noInterrupts() only disables user interrupts and not system interrupts. :smile:

1 Like

Ended upp with the following hookup,with an Active High circuit (following the left figure).

GND ---\
       |
       O 10k
       |
D3 ----+------ 41

3v3 -----------42
```

This is my code:
```cpp
/* 
Pulse counter to measure used kWh and calculate current W usage from a GM3D
*/

// According to EN62052-31 pulse lenght are ≥100ms <120 msec (ON)
byte minPulseWidth = 99;

unsigned long pulseTime=0;
volatile unsigned int pulseCount=0;
volatile unsigned long pulsePower=0;


    
void blink() {
  if ( (millis() - pulseTime) > minPulseWidth) {
    pulseCount++;
    //GM3D outputs 100 pulses/kWh (60m*60s*1000ms*10 = 36'000'000)
    pulsePower = 36000000 / (millis() - pulseTime); 
    pulseTime = millis();
  }
}

void setup() {
  pinMode(D3, INPUT);  
  attachInterrupt(D3, blink, RISING);
}

void loop() {
String data = "power:" + String(pulsePower) 
    + ",count:" + String(pulseCount)
  Spark.publish("data", data);
  delay(5000);
}
```

The results looks pretty promising. 

Thank you for all help!

Just one more question.

What is best practice to handle overflowing millis()?

Is this on the right track?

void blink() {
  if ( millis() < pulseTime ) { //Handle overflowing millis() ~45 days
      pulseTime = millis();
      pulseCount++;
      return;
  }
  if ( (millis() - pulseTime) > minPulseWidth) {
    pulseCount++;
    //GM3D outputs 10 pulses/W (1h = 60m*60s*1000ms*10 = 36'000'000)
    pulsePower = 36000000l / (millis() - pulseTime);
    timeD = millis() - pulseTime; 
    pulseTime = millis();
  }
}

Since millis() is unsigned long an overflow does not need extra care (in this use case).
With signed types you’d end up with a negative result, with unsigned you just get the result you want :wink:

You could play it through for yourself by doing 4bit unsigned binary subtractions (or google :sunglasses:).

https://en.wikipedia.org/wiki/Modular_arithmetic

I’m thinking small number - very large number = large number I. E. The consumption will look very small that reading.

It might be counterintuitive but a small number - very large number = small number since you’ll be missing the extra bit to produce the large number you’d expect normally.

So you only get the small portion of the large number that exceedes the value represented by the “missing” bit.