Electricity meter using function

Now it prints 1,2,3

What are you expecting decode_bit_stream() to return ? It looks like it is returning -1, which sounds suspiciously like the sort of value that would be returned to indicate failure of some kind.

If only you had posted your complete program we could see for ourselves.

/*
 Arduino code to read data from an Elster A100C electricity meter.

 Copyright (C) 2012 Dave Berkeley solar@rotwang.co.uk

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 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, write to the Free Software
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 USA
*/

// set pin numbers:
const int ledPin = 13;
const int intPin = 2;

String  incomingByte;   // for incoming serial data

#define BIT_PERIOD 416 // us
#define BIT_MARGIN 10 // us

  /*
   *  Buffer
   */

#define BUFF_SIZE 128

struct Buffer
{
  int data[BUFF_SIZE];
  int in;
  int out;
};

static void buff_init(struct Buffer* b)
{
  b->in = b->out = 0;
}

static int buff_full(struct Buffer* b)
{
  int next = b->in + 1;
  if (next >= BUFF_SIZE)
    next = 0;
  return next == b->out;
}

static int buff_add(struct Buffer* b, int d)
{
  int next = b->in + 1;
  if (next >= BUFF_SIZE)
    next = 0;
  if (next == b->out)
    return -1; // overfow error

  b->data[b->in] = d;
  b->in = next;  
  return 0;  
}

static int buff_get(struct Buffer* b, int* d)
{
  if (b->in == b->out)
    return -1;
  int next = b->out + 1;
  if (next >= BUFF_SIZE)
    next = 0;
  *d = b->data[b->out];
  b->out = next;
  return 0;  
}

  /*
   *  Called on every InfraRed pulse, ie. every '1' bit.
   */

typedef unsigned long stamp;

static stamp last_us;

#define BITS(t) (((t) + (BIT_PERIOD/2)) / BIT_PERIOD)

static struct Buffer bits;

void on_change(void)
{
  //  push the number of bit periods since the last interrupt to a buffer.
  const stamp us = micros();
  const int diff = us - last_us;
  last_us = us;

  const int bit_periods = BITS(diff);
  buff_add(& bits, bit_periods);
}

  /*
   *  Decode bit stream
   */

static struct Buffer bytes;

static int bit_data;
static int bit_index;

int add_bit(int state)
{
    bit_data >>= 1;

    if (state)
        bit_data += 0x200;

    if (bit_data)
        bit_index += 1;

    if (bit_index < 10)
        return 0;

    if (bit_data & 1) // start bit
    {
        if (!state) // stop bit
        {
            const int d = (bit_data >> 1) & 0xFF;
            // high represents '0', so invert the bits
            buff_add(& bytes, (d ^ 0xFF));
            bit_data = bit_index = 0;
            return 1;
        }
    }

    //  bad frame
    bit_data = bit_index = 0;
    return 0;
}

static void on_timeout()
{
  // too long since last bits count
  
  if (bit_index)
    while (bit_data) // flush with trailing '0' bits
      add_bit(0);  
  bit_data = bit_index = 0;
}

static void on_bits(int bits)
{
  // called on each bits count.
  // the bit periods represent a '1' followed by N '0's.

  if (bits < 1)
  {
    on_timeout();
    return;
  }

  // the elapsed bit periods since last interrupt
  // represents a '1' followed by 0 or more '0's.  
  add_bit(1);
  for (; bits > 1; bits--)
    add_bit(0);
}

  /*
   *
   */
   
static int decode_bit_stream(void)
{
  // look for a pause in the bit stream
  const stamp us = micros();
  const int diff = us - last_us;
  if (BITS(diff) > 20)
    on_timeout();

  // read the bit stream  
  int bit_count;
  if (buff_get(& bits, & bit_count) < 0)
    return -1;

  on_bits(bit_count);

  // read the byte stream decoded above
  int byte_data;
  if (buff_get(& bytes, & byte_data) < 0)
    return -1;

  return byte_data;
}

  /*
   *
   */

unsigned long bcdtol(const unsigned char* data, int bytes)
{
    unsigned long result = 0;
    for (int i = 0;  i < bytes; i++)
    {
        const unsigned char digit = *data++;
        result *= 100;
        result += 10 * (digit >> 4);
        result += digit & 0xF;
    }
    return result;
}

typedef void (*on_reading)(unsigned long reading);

class ElsterA100C
{
    // see Appendix B of the product manual
    struct info {
        char product[12]; // eg. "Elster A100C..."
        char firmware[9];
        unsigned char mfg_serial[3];
        unsigned char config_serial[2];
        char utility_serial[16];
        unsigned char meter_definition[3];
        unsigned char rate_1_import_kWh[5]; // the reading we are interested in!
        unsigned char rate_1_reserved[5];
        unsigned char rate_1_reverse_kWh[5];
        unsigned char rate_2_import_kWh[5];
        unsigned char rate_2_reserved_kWh[5];
        unsigned char rate_2_reverse_kWh[5];
        unsigned char reserved_01[1];
        unsigned char status;
        unsigned char error;
        unsigned char anti_creep[3];
        unsigned char rate_1_time[3];
        unsigned char rate_2_time[3];
        unsigned char power_up[3];
        unsigned char power_fail[2];
        unsigned char watchdog;
        unsigned char reverse_warning;
        unsigned char reserved_02[10];
    };

    unsigned char data[sizeof(info)];
    unsigned int idx;
    int reading;
    unsigned char last_4[4];
    on_reading handler;
public:
    ElsterA100C(on_reading cb)
    : idx(0), reading(0), handler(cb)
    {
    }

    int good_cs(unsigned char cs, unsigned char check)
    {
      // note : should be 'cs == check', but I'm seeing
      // systematic 1-bit errors which I can't track down.      

      /*
      Serial.print("bcc=");
      Serial.print(check, HEX);
      Serial.print(" cs=");
      Serial.print(cs, HEX);
      Serial.print(" xor=");
      Serial.print(cs ^ check, HEX);
      Serial.print("\r\n");
      */

      int bits = 0;
      int delta = cs ^ check;
      for (; delta; delta >>= 1)
        if (delta & 0x01)
          bits += 1;

      return bits < 2;
    }

    void good_packet()
    {
        struct info* info = (struct info*) data;        
        handler(bcdtol(info->rate_1_import_kWh, 5));
    }

    unsigned char bcc(unsigned char cs, const unsigned char* data, int count)
    {
        for (int i = 0; i < count; ++i)
            cs += *data++;
        return cs;
    }

    void on_data(unsigned char c)
    {
        // match the packet header
        const unsigned char match[] = { 0x01, 0x00, sizeof(info), 0x02 };

        if (!reading)
        {
            // keep a log of the last 4 chars
            last_4[0] = last_4[1];
            last_4[1] = last_4[2];
            last_4[2] = last_4[3];
            last_4[3] = c;

            if (memcmp(match, last_4, sizeof(match)) == 0)
            {
                idx = 0;
                reading = 1;
                return;
            }

            return;
        }

        if (idx < sizeof(info))
        {
            data[idx++] = c;
            return;
        }

        const unsigned char etx = 0x03;
        if (idx == sizeof(info))
        {
            if (c != etx)
            {
                printf("etx=%02X\n", c);
                reading = idx = 0;
                return;
            }
            idx++;
            return;
        }                    

        unsigned char cs = 0x00; // why 0x40?
        cs = bcc(cs, match, sizeof(match));
        cs = bcc(cs, data, sizeof(data));
        cs = bcc(cs, & etx, 1);
            
        if (good_cs(cs, c))
          good_packet();

        reading = 0;
    }
};

  /*
   *
   */

void meter_reading(unsigned long reading)
{
  Serial.print(reading);
  Serial.print("\r\n");

  static int state = 0;
  digitalWrite(ledPin, state = !state);
}

ElsterA100C meter(meter_reading);

void setup() 
{
  buff_init(& bits);
  buff_init(& bytes);

  pinMode(ledPin, OUTPUT);
  pinMode(intPin, INPUT);

  attachInterrupt(0, on_change, RISING);

  Serial.begin(38400);
}
void loop()
{
    incomingByte = Serial.readString();
    if (incomingByte == "PRINT")
    {
        Serial.println("1");
        int byte_data = decode_bit_stream();
        Serial.println("2");
        if (byte_data == -1)
        {
           Serial.println("3"); 
           return;
           Serial.println("4"); 
        }
        Serial.println("5");
        meter.on_data(byte_data);
        Serial.println("6");
    }
}
static int decode_bit_stream(void)
{
  // look for a pause in the bit stream
  const stamp us = micros();
  const int diff = us - last_us;
  if (BITS(diff) > 20)
    on_timeout();
  // read the bit stream
  int bit_count;
  if (buff_get(& bits, & bit_count) < 0)
    return -1;
  on_bits(bit_count);
  // read the byte stream decoded above
  int byte_data;
  if (buff_get(& bytes, & byte_data) < 0)
    return -1;
  return byte_data;
}

It looks like the function is returning -1 to indicate a failure in the buff_get() function

Is there any command to read the Serial data before send them? I mean to read the buffer of the Serial before send them.

Is there any command to read the Serial data before send them? I mean to read the buffer of the Serial before send them.

If you are referring to the outgoing serial buffer, you know what you wrote to it. Why would you need to read that?

If you are referring to the incoming serial buffer, that is not sent.

So, really, your question does not make sense.

Of course it makes sence, since the code is not mine, I took it from the website I posted previously. I have only changed the setup() to make it work when giving the command "PRINT". The code does not have enough comments so as to understand how it works. So I search a way to read the number it writes on the serial...

Is there a way to use serial (interrupt) along with pin (interrupt)? Because as I can see from the code, this may be the fault, the Arduino does not understand the interrupt in the pin, when I send commands through the serial.

What do you mean by serial(interrupt) ?

According to this: http://gammon.com.au/interrupts

 1  Reset 
 2  External Interrupt Request 0  (pin D2)          (INT0_vect)
 3  External Interrupt Request 1  (pin D3)          (INT1_vect)
 4  Pin Change Interrupt Request 0 (pins D8 to D13) (PCINT0_vect)
 5  Pin Change Interrupt Request 1 (pins A0 to A5)  (PCINT1_vect)
 6  Pin Change Interrupt Request 2 (pins D0 to D7)  (PCINT2_vect)
 7  Watchdog Time-out Interrupt                     (WDT_vect)
 8  Timer/Counter2 Compare Match A                  (TIMER2_COMPA_vect)
 9  Timer/Counter2 Compare Match B                  (TIMER2_COMPB_vect)
10  Timer/Counter2 Overflow                         (TIMER2_OVF_vect)
11  Timer/Counter1 Capture Event                    (TIMER1_CAPT_vect)
12  Timer/Counter1 Compare Match A                  (TIMER1_COMPA_vect)
13  Timer/Counter1 Compare Match B                  (TIMER1_COMPB_vect)
14  Timer/Counter1 Overflow                         (TIMER1_OVF_vect)
15  Timer/Counter0 Compare Match A                  (TIMER0_COMPA_vect)
16  Timer/Counter0 Compare Match B                  (TIMER0_COMPB_vect)
17  Timer/Counter0 Overflow                         (TIMER0_OVF_vect)
18  SPI Serial Transfer Complete                    (SPI_STC_vect)
19  USART Rx Complete                               (USART_RX_vect)
20  USART, Data Register Empty                      (USART_UDRE_vect)
21  USART, Tx Complete                              (USART_TX_vect)
22  ADC Conversion Complete                         (ADC_vect)
23  EEPROM Ready                                    (EE_READY_vect)
24  Analog Comparator                               (ANALOG_COMP_vect)
25  2-wire Serial Interface  (I2C)                  (TWI_vect)
26  Store Program Memory Ready                      (SPM_READY_vect)

And also it says this:

When writing an Interrupt Service Routine (ISR):


Keep it short
Don't use delay ()
Don't do serial prints
Make variables shared with the main code volatile
Variables shared with main code may need to be protected by "critical sections" (see below)
Don't try to turn interrupts off or on

So I expect that there is something wrong when using serial in the same code with pin interrupt...

I expect that there is something wrong when using serial in the same code with pin interrupt...

Nothing wrong with using Serial in code that also uses interrupts, just don't use Serial in the ISR. Serial uses interrupts. Interrupts are automatically turned off in ISRs. Can you see the problem ?

This problem is not present in later versions of the IDE but it is still regarded as a bad idea by most people here.

What you mean by this:

Nothing wrong with using Serial in code that also uses interrupts, just don't use Serial in the ISR.

When I use serial,doesn't automatically enable the ISR?

When I use serial,doesn’t automatically enable the ISR?

Sorry, but that question makes no sense to me.

Ok.

Something else, which version of Arduino IDE to download so as not to have this problem?

which version of Arduino IDE to download so as not to have this problem?

There are no versions of the IDE that can help with a fundamental lack of understanding.

It is strange, I have a program that works, I just put a Serial.println and the program doesn't work...

360modena_cs: It is strange, I have a program that works, I just put a Serial.println and the program doesn't work...

Nothing strange about it. You have program that works. You put a Serial.print() [u]in the ISR[/u] and it doesn't work.

Which version of the IDE are you using ?

UKHeliBob: Nothing strange about it. You have program that works. You put a Serial.print() [u]in the ISR[/u] and it doesn't work.

Which version of the IDE are you using ?

1.6.9

I don't know which release made the use of Serial in ISRs safe and I cannot find it in the IDE release notes. I read about in a post on this forum but as it held no interest for me I did not really take any notice.

You could try upgrading to release 1.8.2 which seems to be the latest stable release.

In order not to put Serial.println() on ISR, how I do that? Do I have to look on assembly or any C/C++ command?

Use the ISR to set a boolean variable to true, then in loop() test the variable. If it is true then do your printing and set the variable to false.