How to use Timer1 library and intterupt Arduino1 + ethSchield???

Hi everyone,
In my project i must use arduino1 and Ethernet Shield for send data to a server.

pseudocode of first implementation:
every 10 seconds the arduino send data to the server.
These version works, but after several hours the module freezes and does not send data to the server.

-there isnt Serial.print in the ISR
-i declared as "volatile" each variable used in ISR
-the ISR is void

#include <TimerOne.h>
#include <Ethernet.h>

#define PULSE_PORT 2

byte mac[] = { mac };
IPAddress ip(arduinoIp);
IPAddress server(serverIp);

EthernetClient client;

volatile int pulses;
String request = "";

void setup() 
{ 
  Serial.begin(9600);
  
  if (Ethernet.begin(mac) == 0) 
  {
    Serial.println("Failed to configure Ethernet using DHCP");
    Ethernet.begin(mac, ip);
  }

  //set a timer of length 10000000 microseconds = 10 seconds
  Timer1.initialize(10000000);
  
  //attach the service routine here
  Timer1.attachInterrupt( timerIsr );

  attachInterrupt(digitalPinToInterrupt(PULSE_PORT), read_pulse, FALLING);
}

void loop() 
{
  // DO NOTHING
}

void timerIsr()
{ 
  //connect with server
  int connectionResult = client.connect(server, 80);
  if (connectionResult == 1)
  {
      request += "GET ";
      request += "fill the request...":

      client.println(request + " HTTP/1.1");
      client.println("Host: iparduino");
      client.println();
      client.stop();

      request = "";
  }
  else
  {
    pulses = 0;
    client.stop();
  }
  
}

void read_pulse()
{
  // digitalRead() of PULSE_PORT and enhance the variable pulses 
}

At these version i uploaded with a blinking led in the loop to debug the arduino freeze.

#define IS_ALIVE 8

void loop() 
{
  digitalWrite(IS_ALIVE, HIGH);   
  delay(1000);   
  digitalWrite(IS_ALIVE, LOW);    
  delay(1000);
}

During the freeze the led stop blinking and it remains off

then i try to change my firmware in tjese way:

-i removed the Timer1 and ISR
-every 10 second the arduino send data

#include <TimerOne.h>
#include <Ethernet.h>

#define GETMAC String(String(mac[0], HEX) + ":" + String(mac[1], HEX) + ":" + String(mac[2], HEX) + ":" + String(mac[3], HEX)+ ":" + String(mac[4], HEX) + ":" + String(mac[5], HEX))


#define PULSE_PORT 2

byte mac[] = {macArduino};
IPAddress ip(idArduino);

IPAddress server(IpServer);
EthernetClient client;

int packageNumber = 0;
int time_scale;
 int watt_scale;
volatile int pulse_input;
volatile int pulses;
volatile int totalPulses;
String request = "";
int interrCount = 0;

void setup() 
{ 
  Serial.begin(9600);
 
  time_scale = 1;
  watt_scale = 1;
  
  if (Ethernet.begin(mac) == 0) 
  {
    Serial.println("Failed to configure Ethernet using DHCP");
    Ethernet.begin(mac, ip);
  }

  attachInterrupt(digitalPinToInterrupt(PULSE_PORT), read_pulse, FALLING);
}

void loop() 
{ 
  delay(1000);   
  interrCount++;

  if ( interrCount == 10 )
  {
    int connectionResult = client.connect(server, 80);
    if (connectionResult == 1)
    {
        request += "GET ";
        request += "fill the request...with pulse and totalpulses value (in url format)"; 
  
        client.println(request + " HTTP/1.1");
        client.println("Host: ipArduino");
        client.println();
        client.stop();
  
        request = "";
    }
    interrCount=0;
  }
}

// these function counts the button push on a custom module attached to the eth shield
// while (i--); --> tto avoid too close input
// PULSE_PORT is pin n2
void read_pulse()
{
  volatile int i = 5;
  while (i--);
  pulse_input = digitalRead(PULSE_PORT);
  if (pulse_input == LOW) 
  {
    pulses++;
    totalPulses++;
    pulse_input = digitalRead(PULSE_PORT);
    
    while (pulse_input == LOW) 
    {
      pulse_input = digitalRead(PULSE_PORT);
    }
  } 
}

The latest version freeze arduino approximately after one day!!!
However, i dont understand where is the problem.
I used a binked led before the delay in loop to debug the freeze.
During the freeze:

-the led is turned off
-in eth schield the led PWD, LINK, 100M, FULLD, COLL are on; the RX and TX bink every 8/10 seconds
-Arduino ide say me:
Sketch uses 15,592 bytes (48%) of program storage space. Maximum is 32,256 bytes.
Global variables use 770 bytes (37%) of dynamic memory, leaving 1,278 bytes for local variables. Maximum is 2,048 bytes.
-furthermore i used #include <MemoryFree.h> to study the arduino memory usage and it result constant during the tests

I do not understand how to debug the freeze
Could someone help me?

Sorry for my english

Could someone help me?

First, lose the timer interrupt. Timer interrupts are fine for things that need to happen every so many milliseconds. They are not appropriate for things that need to happen every 10 minutes.

Second, LOSE THE STRING CLASS. There is NOTHING that the String class does that c-style strings can't do. The ONLY thing that they do is dynamic memory allocation (over and over). If the largest allocation succeeds, then a static array of that same size is possible. So, use one.

After you make those changes, let us know how long the software runs before crashing.

Very bad news...

Before Your Answer i try to run the firmware with these changes:

#include <Ethernet.h>

#define GETMAC String(String(mac[0], HEX) + ":" + String(mac[1], HEX) + ":" + String(mac[2], HEX) + ":" + String(mac[3], HEX)+ ":" + String(mac[4], HEX) + ":" + String(mac[5], HEX))

#define PULSE_PORT 2
#define IS_ALIVE 8

//ID:4
byte mac[] = { mac };
IPAddress ip(ip);

IPAddress server(server);

EthernetClient client;

int packageNumber = 0;
volatile int time_scale;
volatile int watt_scale;
volatile int pulse_input;
volatile int pulses;
volatile int totalPulses;
int interrCount = 0;

void setup() 
{ 
  if (Ethernet.begin(mac) == 0) 
  {
    Serial.println("Failed to configure Ethernet using DHCP");
    Ethernet.begin(mac, ip);
  }

  //interrupt 0 (pin 2)
  attachInterrupt(0, read_pulse, FALLING);
}

void loop() 
{
  digitalWrite(IS_ALIVE, HIGH);   
  delay(500);   
  digitalWrite(IS_ALIVE, LOW);    
  delay(500);

  interrCount++;
  if ( interrCount == 10 )
  {
    /*
     DO NOTHING!!!
    */
    interrCount=0;
  } 
}

void read_pulse()
{
  volatile int i = 5;
  while (i--);
  pulse_input = digitalRead(PULSE_PORT);
  if (pulse_input == LOW) 
  {
    pulses++;
    totalPulses++;
    pulse_input = digitalRead(PULSE_PORT);
    
    while (pulse_input == LOW) 
    {
      pulse_input = digitalRead(PULSE_PORT);
    }
  } 
}

the arduino run for few hours than:

  • crash with LED ligth on
byte mac[] = { mac };

What the hell is this supposed to be doing? You have provided one initializer - the array that you are trying to create. How the hell is that supposed to work?

IPAddress ip(ip);

Same question.

IPAddress server(server);

Same question.

void read_pulse()
{
  volatile int i = 5;

Variables that are set in the ISR and used elsewhere need to be volatile. Variables that are local to the function do not.

    while (pulse_input == LOW)
    {
      pulse_input = digitalRead(PULSE_PORT);
    }

You do NOT do ANY kind of waiting in an ISR. EVER!

Im sorry...if I have not explained well:

before the set-up function i initialized the variables in these way:

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xBA }; //mac of eth shield
IPAddress ip(192, 168, 0, 3);                                           //ip
IPAddress server(192,168,0,100);                                   //server ip

in setup function:

// "set-up" for eth shield
if (Ethernet.begin(mac) == 0) 
{
    Serial.println("Failed to configure Ethernet using DHCP");
    Ethernet.begin(mac, ip);
}

//listening the  interrupt 0 (pin 2) by the function read_pulse
attachInterrupt(0, read_pulse, FALLING);

Theoretically the function read_pulse must valorize the volatile int pulses
and the main loop should send data by http every 10 seconds.

In final firmware version i removed the connection/send data from the loop
but it crash anyway

Do you suggest to clean the ISR in these way?

void read_pulse()
{
  // pulses is volatile int declared before the setup
  pulses = digitalRead(PULSE_PORT);
}

Theoretically the function read_pulse must valorize the volatile int pulses

I think it would be best if you explained what the function should do without using programming terms.

Do you suggest to clean the ISR in these way?

What I suggest that you do is post the real code that is causing the problem. If that code includes that crappy interrupt service routine, then, yes, I suggest that you rethink what the ISR is supposed to do.

the full code:

but I have not thought about how to replace the class string with array of characters

#include <Ethernet.h>

#define GETMAC String(String(mac[0], HEX) + ":" + String(mac[1], HEX) + ":" + String(mac[2], HEX) + ":" + String(mac[3], HEX)+ ":" + String(mac[4], HEX) + ":" + String(mac[5], HEX))

//#define DEBUG_MODE 1

#define PULSE_PORT 2
#define IS_ALIVE 8

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xBA };
IPAddress ip(192, 168, 0, 3);

IPAddress server(192,168,0,100);
EthernetClient client;

int packageNumber = 0;
int time_scale;
int watt_scale;
volatile int pulse_input;
volatile int pulses;
volatile int totalPulses;
String request = "";
int interrCount = 0;

void setup() 
{ 
  #ifdef DEBUG_MODE 
    Serial.begin(9600);
    Serial.println("\n\nINIT");
    Serial.print("Memory=");
    Serial.print(freeMemory());
    Serial.print(" ");
    Serial.println(freeRam()); 
    Serial.flush();
  #endif
  
  time_scale = 1;
  watt_scale = 1;
  
  if (Ethernet.begin(mac) == 0) 
  {
    Serial.println("Failed to configure Ethernet using DHCP");
    Ethernet.begin(mac, ip);
  }

  //interrupt 0 (pin 2)
  attachInterrupt(0, read_pulse, FALLING);
}

void loop() 
{
  digitalWrite(IS_ALIVE, HIGH);   
  delay(500);   
  digitalWrite(IS_ALIVE, LOW);    
  delay(500);

  interrCount++;
  if ( interrCount == 10 )
  {
    
    int connectionResult = client.connect(server, 80);
    if (connectionResult == 1)
    {
        request += "GET ";
        request += "/pulse_counter/test.php?";
        request += "pulses=" + String(pulses);
        request += "&tot_pulses="+ String(totalPulses);
        request += "&mac=" + GETMAC;
        request += "&time=1";
        request += "&time_scale=" + String(time_scale);
        request += "&watt_scale=" + String(watt_scale);
        request += "&packageNumber=" + String(packageNumber); 
  
        packageNumber++;
        
        #ifdef DEBUG_MODE   
          Serial.println(request);
          Serial.print("Memory=");
          Serial.print(freeMemory());
          Serial.print(" ");
          Serial.println(freeRam());
          Serial.print("packageNumber ");
          Serial.print(packageNumber);
          Serial.println();
          Serial.flush();
        #endif
  
        client.println(request + " HTTP/1.1");
        client.println("Host: 192.168.0.3");
        client.println();
        client.stop();
  
        request = "";

        cli();//disable interrupts
        pulses = 0;
        sei();//enable interrupts      
    }
    
    interrCount=0;
  } 
}

//read_pulse() counts pressures of a button
void read_pulse()
{
  int i = 5;
  while (i--);
  pulse_input = digitalRead(PULSE_PORT);
  if (pulse_input == LOW) 
  {
    pulses++;
    totalPulses++;
    pulse_input = digitalRead(PULSE_PORT);
    
    while (pulse_input == LOW) 
    {
      pulse_input = digitalRead(PULSE_PORT);
    }
  } 
}

What is generating the pulses that you are reading? Why are you waiting in the ISR until the pin goes HIGH again?

  int i = 5;
  while (i--);

Please explain what this is trying to do. The compiler is smart enough to see that this does nothing, and will remove it.

  pulse_input = digitalRead(PULSE_PORT);
  if (pulse_input == LOW)

Well, of course it will be LOW. That is what triggered the ISR. So, why are you reading the pin state?

These project consists in
-arduino1
-eth shiels
-custom board attached above eth shiels

the custom board generate pulses by one button pressure,
then i want count by interrupt how much time the button is pressed.

every time i push the button one led (on the custom board) lights up

then i want count by interrupt how much time the button is pressed.

So, use CHANGE as the interrupt trigger. That way, the interrupt will happen when the switch becomes pressed AND when the switch becomes released. In the ISR, determine which change triggered the interrupt, and use millis() (or micros()) to record when the change happens. Do NOT just wait around for the really ssslllooowww human to release the switch.

Hi, :frowning:

I remove the custom board and i tried to run a firmware without ISR
to count the pulses and i used delay to synchronize the requests (every 10seconds).
The version below run from 2017-Gen-05 to 2017-Gen-09.
Now the module doesnt send data to server and the led (IS_ALIVE) doent bilnk, it remain ligth up.

I dont undertand whats happening, because the only feature implemented is the data sending every 10 sec.
The only interrupt triggered could be the interrupt due to the delay in loop

#include <Ethernet.h>

#define GETMAC String(String(mac[0], HEX) + ":" + String(mac[1], HEX) + ":" + String(mac[2], HEX) + ":" + String(mac[3], HEX)+ ":" + String(mac[4], HEX) + ":" + String(mac[5], HEX))

//#define DEBUG_MODE 1

#define PULSE_PORT 2
#define IS_ALIVE 8

//ID:4
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xBA };
IPAddress ip(192, 168, 0, 3);

IPAddress server(192,168,0,100);

EthernetClient client;

int packageNumber = 0;
int time_scale;
int watt_scale;
volatile int pulse_input;
volatile int pulses;
volatile int totalPulses;
String request = "";
int interrCount = 0;

void setup() 
{ 
  #ifdef DEBUG_MODE 
    Serial.begin(9600);
    Serial.println("\n\nINIT");
    Serial.print("Memory=");
    Serial.print(freeMemory());
    Serial.print(" ");
    Serial.println(freeRam()); 
    Serial.flush();
  #endif
  
  time_scale = 1;
  watt_scale = 1;
  
  if (Ethernet.begin(mac) == 0) 
  {
    Serial.println("Failed to configure Ethernet using DHCP");
    Ethernet.begin(mac, ip);
  }

  //interrupt 0 (pin 2)
  //attachInterrupt(0, read_pulse, FALLING);
}

void loop() 
{
  digitalWrite(IS_ALIVE, HIGH);   
  delay(500);   
  digitalWrite(IS_ALIVE, LOW);    
  delay(500);

  interrCount++;
  if ( interrCount == 10 )
  {
    
    int connectionResult = client.connect(server, 80);
    if (connectionResult == 1)
    {
        request += "GET ";
        request += "/pulse_counter/test.php?";
        request += "pulses=" + String(pulses);
        request += "&tot_pulses="+ String(totalPulses);
        request += "&mac=" + GETMAC;
        request += "&time=1";
        request += "&time_scale=" + String(time_scale);
        request += "&watt_scale=" + String(watt_scale);
        request += "&packageNumber=" + String(packageNumber); 
  
        packageNumber++;
        
        #ifdef DEBUG_MODE   
          Serial.println(request);
          Serial.print("Memory=");
          Serial.print(freeMemory());
          Serial.print(" ");
          Serial.println(freeRam());
          Serial.print("packageNumber ");
          Serial.print(packageNumber);
          Serial.println();
          Serial.flush();
        #endif
  
        client.println(request + " HTTP/1.1");
        client.println("Host: 192.168.0.3");
        client.println();
        client.stop();
  
        request = "";

        cli();//disable interrupts
        pulses = 0;
        sei();//enable interrupts      
    }
    
    interrCount=0;
  } 
}

void read_pulse()
{
  int i = 5;
  while (i--);
  pulse_input = digitalRead(PULSE_PORT);
  if (pulse_input == LOW) 
  {
    pulses++;
    totalPulses++;
    pulse_input = digitalRead(PULSE_PORT);
    
    while (pulse_input == LOW) 
    {
      pulse_input = digitalRead(PULSE_PORT);
    }
  } 
}

Hi i think to reach a stable version .

i read from these sources:
-Timer interrupts – Arduino, ESP8266, ESP32 & Raspberry Pi stuff
-Gammon Forum : Electronics : Microprocessors : Interrupts
-your support

#include <avr/io.h>
#include <avr/interrupt.h>
#include <Ethernet.h>

#define IS_ALIVE 8
#define DEBUG 3
#define PULSE_PORT 2
#define GETMAC String(String(mac[0], HEX) + ":" + String(mac[1], HEX) + ":" + String(mac[2], HEX) + ":" + String(mac[3], HEX)+ ":" + String(mac[4], HEX) + ":" + String(mac[5], HEX))

//ID:2
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xEA };
IPAddress ip(192, 168, 0, 2);
IPAddress server(192,168,0,100);
EthernetClient client;

volatile int seconds;
volatile int pulse_input;
volatile int pulses;
volatile int totalPulses;
int connectionResult;
int ledState = LOW;
unsigned long previousMillis = 0;
unsigned long currentMillis = 0;
const long interval = 500; 

void setup()
{
  pinMode(IS_ALIVE, OUTPUT);
  pinMode(DEBUG, OUTPUT);
  
  // initialize Timer1
  cli();          // disable global interrupts
  TCCR1A = 0;     // set entire TCCR1A register to 0
  TCCR1B = 0;     // same for TCCR1B
  
  // set compare match register to desired timer count:
  OCR1A = 15624;
  
  // turn on CTC mode:
  TCCR1B |= (1 << WGM12);
  
  // Set CS10 and CS12 bits for 1024 prescaler:
  TCCR1B |= (1 << CS10);
  TCCR1B |= (1 << CS12);
  
  // enable timer compare interrupt:
  TIMSK1 |= (1 << OCIE1A);
  
  // enable global interrupts:
  sei();

  seconds=0;
  pulses=0;
  totalPulses=0;
  connectionResult=0;

  Ethernet.begin(mac, ip);

  attachInterrupt(digitalPinToInterrupt(PULSE_PORT), readSensor, RISING);
}

void loop()
{
  currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW) {
      ledState = HIGH;
    } else {
      ledState = LOW;
    }

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

ISR(TIMER1_COMPA_vect)
{
  seconds++;
  if(seconds == 3)
  {
    seconds = 0;
    sendData();    
    return;
  }
  else
  {
    //reading from sensor;
    return;
  }
}

void sendData()
{  
  connectionResult = client.connect(server, 80);

  if (connectionResult == 1)
  { 
    digitalWrite(DEBUG, HIGH);
    client.println("GET /pulse_counter/test.php?pulses=1&tot_pulses=1&mac=de:ad:be:ef:fe:ea HTTP/1.1");
    client.println("Host: 192.168.0.2");
    client.println();
    client.stop();

    cli();//disable interrupts
    pulses = 0;
    sei();//enable interrupts     

    if(totalPulses == 10)
    {
      cli();//disable interrupts
      totalPulses = 0;  
      sei();//enable interrupts
    }
    digitalWrite(DEBUG, LOW);  
  }
  
}

void readSensor() 
{
  pulses++;
  totalPulses++;
}

these version is under testing, the next step consist
in substitute the static request with the counted values
of pulses and totalPulses

There is not a hope in hell that that code will work. When the timer interrupt happens, and ISR(TIMER1_COMPA_vect) is called, interrupts are disabled. Trying to connect to the internet while interrupts are disable is not going to work.

:sob:

this is my Prototype:

arduino + eth + customboard

and these is the screen of batabase

sceen badabase

sorry but i dont undestand, if i press the button on custom board pulses and totpulses are incremented