Combine interrupt with S0 pin from kWh meter

I’m trying to read the number of pulses generated from a kWh meter using it’s S0 collector.
The kWh meter is a finder 7e.13.8.230 ( http://www.findernet.com/media/series/7E/EN/S7EEN.pdf )

this is the way I connected kWh to my arduino:

Image hosted for free at CtrlV.in

Here is the code I’m using:

In setup:

  attachInterrupt(1, S0interrupt, RISING);

Function S0interrupt:

////////////////////////
//   INTERRUPT PART   //
////////////////////////

void S0interrupt()
{
  long currentMillis = millis();
  if (currentMillis - previousInterruptMillis > minimumInteruptDifference)
  {
    S0Counter++;
    previousInterruptMillis = currentMillis;
    confirmLedBlinks++;
  }
}

This is what I tried:

  • making the connection manually between 5V en pin 3 (interrupt 1) => works
  • connecting just a led + resistor + 12V power supply to the S0. => works the led flashes when the meter generates a pulse
  • connecting the above circuit => doesn’t work. The interrupt pin seems to be always HIGH. When i break and reestablish the connection with the S0 the interrupt gets triggered.

What Am i doing wrong here?
Do i need an optocoupler to make this work?
Is 5v on the S0 to low?

That unit has an open collector output so you can't wire it up the way you have done. Connect the switch between input and ground and have an external pull up resistor or enable the internal ones.

Thanks mike!

so this should do it?

Circuit: Image hosted for free at CtrlV.in

in setup:

pinMode(pin, INPUT);
digitalWrite(pin, HIGH);
attachInterrupt(1, S0interrupt, FALLING);

Function S0interrupt:

////////////////////////
//   INTERRUPT PART   //
////////////////////////

void S0interrupt()
{
  long currentMillis = millis();
  if (currentMillis - previousInterruptMillis > minimumInteruptDifference)
  {
    S0Counter++;
    previousInterruptMillis = currentMillis;
    confirmLedBlinks++;
  }
}

Yes that is right. Make sure the ground of the output is connected to the ground of the arduino. You might want to put that resistor as a pull up for extra noise immunity but it should work like that.

Like so i presume?

Image hosted for free at CtrlV.in

I suppose the resistor should be 10K Ohm?

Yes that's it. The resistor value is fine, it will offer noise protection that a 10K one.

looks like the one I used in a project few years ago, check - http://playground.arduino.cc/Main/EEM12L-32AKWhMonitoring -

robtillaart:
looks like the one I used in a project few years ago, check - http://playground.arduino.cc/Main/EEM12L-32AKWhMonitoring -

Yes, in my case I’m monitorring solar panel production.
But the project goes a little further:
First stage:

  1. Measuring solar panel production using S0 on kWh Meter (finder 7e.13.8.230)
  2. Measuring /managing solar inverter (sma sunny boy 2500) temperature using DS12B20, a TIP122 and some fans.
  3. logging data onto an SD card (using SD card shield + DS3231 for time keeping)
  4. broadcasting data over RF using a 433mhz transmitter

I’m currently still waiting for the DS12B20 and RF module to arrive

Second stage:
Building a low power mobile receiver that captures the RF data and displays it.

Third stage:
Building a second RF receiver that is connected to the internet to post data online

Here is my current code for stage 1 (still in progress).

/*
 //    ______ ____   __       _____         __                __                                       _    __   ___   ____ 
 //   /_  __// __ \ / /      / ___/ ____   / /____ _ _____   / /   ____   ____ _ ____ _ ___   _____   | |  / /  <  /  / __ \
 //    / /  / / / // /       \__ \ / __ \ / // __ `// ___/  / /   / __ \ / __ `// __ `// _ \ / ___/   | | / /   / /  / / / /
 //   / /  / /_/ // /___    ___/ // /_/ // // /_/ // /     / /___/ /_/ // /_/ // /_/ //  __// /       | |/ /   / /_ / /_/ / 
 //  /_/  /_____//_____/   /____/ \____//_/ \__,_//_/     /_____/\____/ \__, / \__, / \___//_/        |___/   /_/(_)\____/  
 //                                                                    /____/ /____/                                        
  
 
 Requirements:
 =============
 Hardware:
 ---------
 - SD card shield
 - DS3231 shield
 - RED and GREEN led
 - Atmega 328
 
 Non-standard libraries:
 -----------------------
 - DS3231 by Eric Ayars updated By John Hubert http://pastebin.com/k2Urc7DJ
 
 
 HOW TO:
 =======
 - Format SD card to FAT32. (http://www.ridgecrop.demon.co.uk/index.htm?guiformat.htm)
 - If the SD card shield contains a 3.3V voltageregulator (such as AMS1117 3.3), the shield only needs 5V.
 - If the SD card shield has multiple rows of pins, use the one.
 - Some SD card shields use a different CS/SS pin 
 
 - SD card shield pin out:
 MISO/DO to PIN 12
 SCK/CLK to PIN 13
 MOSI/DI to PIN 11
 CS/SS to PIN 10 
 
 - DS3231 pin out
 SDA to Analog input 4
 SCL to Analog input 5
 
 
 ERROR CODES:
 ============
 # blinks     Error
 1            SD card failed, or not present
 2            Reading time failed
 
 */

#include <SD.h>
#include <DS3231.h>
#include <Wire.h>
#include <VirtualWire.h>

//Pin settings
//============
//SD
const byte chipSelectPin = 10;
//LEDs
const byte errorLedPin = 4;
const byte confirmLedPin = 5;
//RF module
const byte rfPin = 3;
//Fan Switching
const byte fanPin = 6;


//Settings
//========
//DS3231
DS3231 Clock;


//Confirm led variables
const int confirmLedInterval = 100;
volatile int confirmLedBlinks = 0;
int confirmLedState = LOW;
long confirmLedPreviousMillis = 0;

//Error led variables
const int errorLedInterval = 250;

//Interrupt Variables
const int minimumInteruptDifference = 200;
volatile long previousInterruptMillis = 0;
volatile int S0Counter = 0;

//Time variables
byte Year, Month, Date, DoW, Hour, Minute, Second;

//RF variables
const int rfTransmissionrate = 2000;

//Debug variables
int maxTime = 0;

//Temperatures
int temp1;
int temp2;
int temp3;

//UNTESTED CODE
#include <OneWire.h>
#include <DallasTemperature.h>

// Data wire is plugged into port 2 on the Arduino
#define ONE_WIRE_BUS 2

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature. 
DallasTemperature sensors(&oneWire);

void setup()
{
  //Set pinmodes
  pinMode(errorLedPin,OUTPUT);  
  pinMode(confirmLedPin,OUTPUT);  
  pinMode(chipSelectPin, OUTPUT);

  //Start wire for DS3221
  Wire.begin();

  //Start Serial
  Serial.begin(9600);

  // Start SD
  if (!SD.begin(chipSelectPin)) {
    errorLoop(1,true);
  }
  else
  {
    confirmLedBlinks++;
  }

  //Attach interupt to interupt pin 0 = pin 2 on the arduino
  pinMode(S0interrupt+2, INPUT);
  digitalWrite(S0interrupt+2, HIGH);
  attachInterrupt(0, S0interrupt, FALLING);

  //Setup RF
  vw_set_ptt_inverted(true);  // Required by the RF module
  vw_setup(rfTransmissionrate);            // bps connection speed
  vw_set_tx_pin(rfPin);         // Arduino pin to connect the receiver data pin

    //DS18B20
  sensors.begin();
}

void loop()
{
  long oldmillis = millis();
  long newmillis = 0;

  getTemps();
  logger();
  confirmBlinks();

  newmillis = millis();
  if ((newmillis - oldmillis) > maxTime)
  {
    maxTime = newmillis - oldmillis;
    Serial.println("Maxmillis " +  String(maxTime) + " ms");
  }
}

////////////////////////
//   INTERRUPT PART   //
////////////////////////

void S0interrupt()
{
  long currentMillis = millis();
  if (currentMillis - previousInterruptMillis > minimumInteruptDifference)
  {
    S0Counter++;
    previousInterruptMillis = currentMillis;
    confirmLedBlinks++;
  }
}

/////////////////////
//   LOGGER PART   //
/////////////////////

void logger()
{
  if (S0Counter > 0)
  {
    getNewTime();
    String stringToLog;
    String fileName;

    //Compose string to log
    stringToLog += String(Year, DEC) + ";" + String(Month, DEC) + ";" + String(Date, DEC) + ";" + String(Hour, DEC) + ";" + String(Minute, DEC) + ";" + String(Second, DEC) + ";" + temp1 + ";" + temp2 + ";" + temp3;

    //compose fileName
    fileName += "20" + String(Year, DEC);

    if (Month < 10) fileName += "0";
    fileName += String(Month, DEC);

    if (Date < 10) fileName += "0";
    fileName += String(Date, DEC);

    fileName += ".csv";

    writeToSdCard(stringToLog,fileName);
    sendRfMessage(stringToLog);
    S0Counter--;
  } 
}

void sendRfMessage(String strMessage)
{
  char charMessage[strMessage.length()+1];
  strMessage.toCharArray(charMessage,strMessage.length()+1);
  vw_send((uint8_t *)charMessage, strlen(charMessage));
  vw_wait_tx();
  confirmLedBlinks++;
}

void writeToSdCard(String strMessage, String strFilename)
{
  char charFilename[strFilename.length()+1];
  boolean fileExists;   

  //Create charArray from Filename
  strFilename.toCharArray(charFilename, strFilename.length()+1);

  fileExists = SD.exists(charFilename);
  //Log data
  File dataFile = SD.open(charFilename, FILE_WRITE);
  if (!fileExists)
  {
    dataFile.println("YEAR;MONTH;DAY;HOUR;MINUTE;SECOND;TEMP1;TEMP2;TEMP3");
  }
  dataFile.println(strMessage);
  dataFile.close();
  confirmLedBlinks++;
}

///////////////////////////////////
//   GET TIME FROM DS3231 PART   //
///////////////////////////////////

void getNewTime(int retries)
{
  Clock.getTime(Year, Month, Date, DoW, Hour, Minute, Second);
  if (Year > 0 && Month > 0 && Date > 0 && DoW > 0)
  {
    confirmLedBlinks++;
  }
  else
  {
    errorLoop(2, false);
    retries--;
    getNewTime(retries);
  }
}

void getNewTime()
{
  getNewTime(5);
}

///////////////////////////
//   BLINKING LED PART   //
///////////////////////////

void errorLoop(int blinks, boolean criticalError)
{
  while (criticalError)
  {
    for (int i = 0; i < blinks; i++)
    {
      digitalWrite(errorLedPin, HIGH);
      delay(errorLedInterval);
      digitalWrite(errorLedPin, LOW);
      delay(errorLedInterval);
    }
    delay(2000);
  }
}

void confirmBlinks()
{
  unsigned long currentMillis = millis();
  if(currentMillis - confirmLedPreviousMillis > confirmLedInterval && confirmLedBlinks > 0) 
  {
    // save the last time you blinked the LED 
    confirmLedPreviousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    // if it's turned off reduce the number of blinks to go
    if (confirmLedState == LOW)
    {
      confirmLedState = HIGH;
    }
    else
    {
      confirmLedState = LOW;
      confirmLedBlinks--;
    }

    // set the LED with the ledState of the variable:
    digitalWrite(confirmLedPin, confirmLedState);
  }
}

//////////////////////
//   DS18B20 PART   //
//////////////////////

void getTemps()
{
  sensors.requestTemperatures(); // Send the command to get temperatures
  //add 0.5 because float to iny truncates the value
  temp1 = sensors.getTempCByIndex(0) + 0.5;
  temp2 = sensors.getTempCByIndex(1) + 0.5;
  temp3 = Clock.getTemperature() + 0.5;
  confirmLedBlinks++;
}