Interrupt not working with PZEM004T

Hi, need help. I am using Arduino Mega 2560 to monitor power line voltage using PZEM004T power sensors. I am trying to use internet interrupt from Arduino, just to make sure that I can read the sensor reliably. Here is my code:

#include <SPI.h>
#include <PZEM004Tv30.h>


PZEM004Tv30 pzem1(&Serial2);
volatile int i=0;
volatile float lineVolt = 0;

void setup() {
  Serial.begin(9600);
  Serial.println("Testing interrupt");
  //==== this part for setting interrupt! 

  cli();//stop interrupts
  
  //set timer4 interrupt at 1Hz
  TCCR4A = 0;// set entire TCCR1A register to 0
  TCCR4B = 0;// same for TCCR1B
  TCNT4  = 0;//initialize counter value to 0
  // set compare match register for 1hz increments
  OCR4A = 15624/1;// = (16*10^6) / (1*1024) - 1 (must be <65536)
  // turn on CTC mode
  TCCR4B |= (1 << WGM12);
  // Set CS12 and CS10 bits for 1024 prescaler
  TCCR4B |= (1 << CS12) | (1 << CS10);  
  // enable timer compare interrupt
  TIMSK4 |= (1 << OCIE4A);

  sei();

}


ISR(TIMER4_COMPA_vect) {
  // this function will be executed very 1hz (or 1 second)

  Serial.println(i++);
  ineVolt = pzem1.voltage();
  Serial.println(lineVolt);
}


void loop() {
    
}

The line that accessing the pzem object is the culprit. I don't know how and why it can't work using the interrupt. Any idea?

Library can be downloaded here:

I am using hardware serial connection. Thank you in advance.

What is an "internet" interrupt?

Why do you think that will be more "reliable" than a millis()-based timing solution?

Your ISR should be very quick. Don't try to 'Serial.print()' inside it.

Have you checked the source code to ensure that the 'pzem1.voltage()' function can/should be called in interrupt context?

Interrupts don't do that.

For beginners, use of interrupts usually creates more problems. You have already discovered some of them.

Read and print the sensor in the loop() function. Use the milliseconds timer to do that at regular intervals.

1 Like

There are multiple problems using an interrupt to read this device. The primary problem is that you are communicating with the device using a serial port which needs interrupts and interrupts are disabled when you are in an ISR!!! Also, if you look in the library for this device, it only updates the values every 200ms.

The bottom line is, it makes no sense to use interrupts for this device.

1 Like

sorry for all the typos. not internet interrupt, but internal interrupt (not triggered externally). The serial.print is for debugging purposes only, just to know what causes the trouble, I just simplify the code inside the ISR, and I found out the call to pzem caused the problem. Yes, I tried to check the code, but I failed to see whether it can / can't be called using the interrupt.

Thanks to you and jremington, I think this is the limitation.
Here is my situation: I have an on-grid solar panel system to be monitored. So, I use the Arduino and 2 pzem to monitor the power line from the inverter line and the grid line to calculate the import, export, load power, etc. I also use a touch panel LCD to display the data. And starting from that, I was thinking of putting a nice graphical chart on LCD, and so on. The problem is that this chart takes time to render. So, in order to guarantee that the Arduino gets the data from the pzem precisely every 60 seconds, then I decided to use the interrupt to simplify the coding.

Originally I use an RTC call to determine whether a minute has elapsed in the loop() (similar to using milis()). I just think using the interrupt will simplify everything and make sure it won't miss every minute it elapses and I could write a code to render a chart without thinking of putting a code to check the time and calling the pzem here and there.

So, I think, my options are:
a. putting a code to read the pzem inside chart rendering's code here and there.
b. or, sending the data to the cloud and rendering the chart from it.
c. or, using another Arduino to draw the chart, and any other Arduino just taking data from pzem.

Is there any simpler and easier solution?

Nothing can be further from the true, as you've discovered. Interrupts are a Catch 22 ... You shouldn't try to use them unless you know what you're doing. But .... you'll never learn their proper usage unless you try and get burned a few times. So, you're on your way.

Before doing any of those things, I endeavor to rewrite the code that renders the chart to be nonblocking. There's no reason it must all be done in one shot. Divide it into smaller chunks and do a little bit on every iteration through the loop() function.

1 Like

yes gfvalvo, I think that's something I should do. Rewrite the code, and yes, I can do that. Thanks to all who respond. Appreciate it.

Surely it won't take 60 seconds to render a chart. How precise is "precisely"? Because if "precisely" is less than +/-200ms then the pzem library doesn't support that anyhow (at least in it's unmodified form because it is hardcoded).

If you are worried about the rendering time then just use some contrived data and measure the time it takes to render. In any case you should avoid code that blocks.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.