Pages: [1]   Go Down
Author Topic: How to execute a function for "t" time without delay + using external interrupt  (Read 813 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 36
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi everybody,
After some research inside this forum and google, I've a lot of doubt about Time management with Arduino, so I've decide to ask you some help. The goal is to create a switch case loop inside "void loop()" that execute a certain subroutine for a certain time (for example 3 minutes). The pseudocode I've thought is:

Code:
void setup() {
  Serial.begin(9600);
  Serial.println("Waiting for command");
}
 
void loop() {
       
  // this is where the "polling" occurs
  if(Serial.available()){
    char ch=Serial.read();
    switch(ch)
    {
      case '1':
      // do something
      break;
     
      case '2':
      //do something
      break;
     
      case '3':
      void Tempfunct();
      break;
     
      default:
      Serial.print(ch);
      Serial.println(" : unknown command!");
    }   
}
}
 

// function to be called
void Tempfunct() {
 //do something for  3*60*60*1000 s and return to switch case selection
}

I consider this solution a starting point, because I think a solution involving interrupts would be a better solution. Specifically I expect something like this pseudocode:


Code:
void setup() {
  Serial.begin(9600);
  Serial.println("Waiting for command");
}
 
void loop() {
       
  // this is where the "polling" occurs
  if(Serial.available()){
    char ch=Serial.read();
    switch(ch)
    {
      case '1':
      // do something
      break;
     
      case '2':
      //do something
      break;
     
      case '3':
      void Tempfunct();
      break;
     
      default:
      Serial.print(ch);
      Serial.println(" : unknown command!");
    }   
}
}
 

// function to be called
void Tempfunct() {
 //do something until an interrupt condition is received from Serial (such a key pressed by user) and then return to switch case selection
}

Can someone help me?
Thank you all!
Logged

Dubuque, Iowa, USA
Offline Offline
Edison Member
*
Karma: 44
Posts: 2452
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Look in the example for the "TimeAlarms" addition in the [http://www.arduino.cc/playground/uploads/Code/Time.zip]Time[/url] library.

You topic subject mentions "+ using external interrupt"; I assume you meant for the timing only or is there something else you were trying to accomplish?
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 36
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi, thank for you soon reply!
I've got the library yet, but it's a little bit to understand to me how to use it to time a function. I'm trying to keep hard an eye on to understand it.
The interrupt I would try to set is only for the timed function. I.e.: pushing a key on the keyboard cause the start of a measurement (for a certain and yet set sensor); pushing another button cause the stop of the measurement. During the function I would like Arduino will get values from the sensor and send value to the serial port (simply using Serial.print(....)) using a set time period (for example one serial printing every two second). After every printing Arduino should search the serial port for the "stop key", used as interrupt. I would like to use the sensor data to plot a graph on Processing. Thank you very much!
Logged

Offline Offline
Edison Member
*
Karma: 116
Posts: 2205
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Easy:

Code:
void run_me(void) {
  static unsigned char execution_count=0; //execution counter

  if (++execution_counter > MAX_RUN) return; //if total number of runs exceed, do nothing

  //put your code here
}

All you need to do is to specify MAX_RUN.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 36
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@dhenry:
uhm... Can you explain your code???
Thank you very much! 
Logged

UK
Offline Offline
Shannon Member
****
Karma: 222
Posts: 12520
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


The interrupt I would try to set is only for the timed function. I.e.: pushing a key on the keyboard cause the start of a measurement (for a certain and yet set sensor); pushing another button cause the stop of the measurement. During the function I would like Arduino will get values from the sensor and send value to the serial port (simply using Serial.print(....)) using a set time period (for example one serial printing every two second). After every printing Arduino should search the serial port for the "stop key", used as interrupt. I would like to use the sensor data to plot a graph on Processing. Thank you very much!

You don't need interrupts for this. All you need is to set a flag when you detect that the measurement should start, and clear it when it should end. In loop(), use the techniques demonstrated in the 'blink without delay' example sketch to collect your sensor inputs at regular intervals while the flag is set.

I guess that the keyboard you refer to is the keyboard on the host PC. You need to use some application on the host PC to send the keyboard input to the Arduino. If you plan to use the Arduino IDE's serial monitor for this, bear in mind that the serial monitor input is line buffered so you would need to enter your command character(s) followed by the return key to send that command to the Arduino. In other words, two key presses. If you were thinking about using buttons directly connected to the Arduino instead, that would work fine too but you'd need to read (and debounce) the switch states instead of reading commands from the serial port.
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Dubuque, Iowa, USA
Offline Offline
Edison Member
*
Karma: 44
Posts: 2452
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Just FYI:

Code:
#include <Time.h>
#include <TimeAlarms.h>

void setup() {
  Serial.begin(9600);
  Serial.println("Waiting for command");
}
 
AlarmID_t temptimer;
 
void loop() {
       
  // this is where the "polling" occurs
  if(Serial.available()){
    char ch=Serial.read();
    switch(ch)
    {
      case '1':
      // start recording?
      temptimer = Alarm.timerRepeat(1, Tempfunct);
      break;
     
      case '2':
      // stop recording?
      Alarm.disable(temptimer);
      break;
           
      default:
      Serial.print(ch);
      Serial.println(" : unknown command!");
    }   
  }
}

// function to be called
void Tempfunct() {
   // do whatever reading
   Serial.println(analogRead(A0));
}

This is perhaps kinda heavy for what you appear to be doing (should use the "blink without delay" method), but just wanted to followup.

Also, TimeAlarms.cpp needs to be updated for Arduino 1.0.

Replace:
Code:
#include <WProgram.h>

With:
Code:
#if ARDUINO >= 100
#include <Arduino.h>
#else
#include <WProgram.h>
#endif
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 36
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


You don't need interrupts for this. All you need is to set a flag when you detect that the measurement should start, and clear it when it should end. In loop(), use the techniques demonstrated in the 'blink without delay' example sketch to collect your sensor inputs at regular intervals while the flag is set.

I guess that the keyboard you refer to is the keyboard on the host PC. You need to use some application on the host PC to send the keyboard input to the Arduino. If you plan to use the Arduino IDE's serial monitor for this, bear in mind that the serial monitor input is line buffered so you would need to enter your command character(s) followed by the return key to send that command to the Arduino. In other words, two key presses. If you were thinking about using buttons directly connected to the Arduino instead, that would work fine too but you'd need to read (and debounce) the switch states instead of reading commands from the serial port.

Hi PeteH, I will use Processing to control Arduino from PC. I would like to design an interface with some button, each one used to trigger Arduino to communicate with one of the sensors (using something like a "switch case" loop in the Arduino's sketch ). I have 4 sensors connected to Arduino: 3 of them will print one simple float value to the Serial port each other and these values will be printed on my Processing interface as numeric values. Instead, the 4th sensor, specifically the pressure sensor, will print automatically one value per second for (i.e.) 3 minutes on the serial port, when trigged (through Arduino) by pressing one button on the Processing interface. To realize the interrupt for the pressure sensor I thought to have two button (one to start the measurement and the other to stop it) dedicated in the Processing interface.


 
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 36
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Just FYI:

Code:
#include <Time.h>
#include <TimeAlarms.h>

void setup() {
  Serial.begin(9600);
  Serial.println("Waiting for command");
}
 
AlarmID_t temptimer;
  
void loop() {
      
  // this is where the "polling" occurs
  if(Serial.available()){
    char ch=Serial.read();
    switch(ch)
    {
      case '1':
      // start recording?
      temptimer = Alarm.timerRepeat(1, Tempfunct);
      break;
    
      case '2':
      // stop recording?
      Alarm.disable(temptimer);
      break;
          
      default:
      Serial.print(ch);
      Serial.println(" : unknown command!");
    }  
  }
}

// function to be called
void Tempfunct() {
   // do whatever reading
   Serial.println(analogRead(A0));
}

This is perhaps kinda heavy for what you appear to be doing (should use the "blink without delay" method), but just wanted to followup.

Also, TimeAlarms.cpp needs to be updated for Arduino 1.0.

Replace:
Code:
#include <WProgram.h>

With:
Code:
#if ARDUINO >= 100
#include <Arduino.h>
#else
#include <WProgram.h>
#endif


Thank you for your reply. I prefer to use every case to control a method and each method to control a sensor: so I imagine to have something like:


Code:
#include <Time.h>
#include <TimeAlarms.h>

void setup() {
  Serial.begin(9600);
  Serial.println("Waiting for command");
}
 
AlarmID_t temptimer;
  
void loop() {
      
  // this is where the "polling" occurs
  if(Serial.available()){
    char ch=Serial.read();
    switch(ch)
    {
      case '1':
      // control sensor 1
      sens1();
      break;
    
      case '2':
      // control sensor 2
      sens2();
      break;

      case'3':
      // control pressure sensor
      pressfunct();
      break;
    
      default:
      Serial.print(ch);
      Serial.println(" : unknown command!");
    }  
  }
}

void sens1(){
//do something;}
void sens2(){
//do something;}

// function to control pressure sensor (start/stop measurement)
void pressfunct() {
while(key==...){
//start measurement (i.e f=1 data for second);}
//measurement continue until i press another key : key2==...
//after Arduino receive key2, stop measurement and return to "void loop()", waiting for..

}
Logged

UK
Offline Offline
Shannon Member
****
Karma: 222
Posts: 12520
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

That sounds reasonable. I don't know what buffering the Processing interface applies when writing to the serial port - you would need to find out whether it is able to write single character commands as you are assuming; quite likely it is.

Nothing you're describing on the Arduino side requires your sketch to use interrupts - all the behaviour you're describing can be achieved by straight forward coding within loop().
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Offline Offline
Newbie
*
Karma: 0
Posts: 36
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

That sounds reasonable. I don't know what buffering the Processing interface applies when writing to the serial port - you would need to find out whether it is able to write single character commands as you are assuming; quite likely it is.

Nothing you're describing on the Arduino side requires your sketch to use interrupts - all the behaviour you're describing can be achieved by straight forward coding within loop().

Yes, Processing can write single character to serial port: this is what i do with Processing.
For me, this situation is like having a sort of "measurement loop" inside one of the "case". When Arduino receive a preset "start-key" (start character), it starts measuring. When the user press another button in the Processing interface, it send preset "stop-key" (stop character) to Arduino: Arduino feels like to have an external interrupt, stops the measurement and return to void loop(){...} cycle.
« Last Edit: November 27, 2012, 11:20:59 am by 8bit_Biker » Logged

UK
Offline Offline
Shannon Member
****
Karma: 222
Posts: 12520
-
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

For me, this situation is like having a sort of "measurement loop" inside one of the "case". When Arduino receive a preset "start-key" (start character), it starts measuring. When the user press another button in the Processing interface, it send preset "stop-key" (stop character) to Arduino: Arduino feels like to have an external interrupt, stops the measurement and return to void loop(){...} cycle.

No, that's NOT how I'd do it.

You want to avoid designing your code so that it stops and waits for something to happen (the command to end monitoring); that's a blocking design which would need you to replicate logic all over the place. The benefit of following the non-blocking approach demonstrated in the 'blink without delay' example is that your sketch can handle multiple actions and events in a consistent way without all your separate bits of code needing to explicitly cooperate or depend on each other; it gives you a nice simple architecture that scales very well.

In loop() add your code to receive commands from the serial port and set a 'monitoring enabled' flag to indicate whether the regular monitoring should be happening based on the commands received. Also in loop() test whether the 'monitoring enabled' flag is set and then whether it's time to collect a sample, and if it is then you collect and transmit the sample. Other pieces of code in loop() could deal with other things you might need to do concurrently such as blinking LEDs or whatever.
Logged

I only provide help via the forum - please do not contact me for private consultancy.

Offline Offline
Newbie
*
Karma: 0
Posts: 36
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset


No, that's NOT how I'd do it.

You want to avoid designing your code so that it stops and waits for something to happen (the command to end monitoring); that's a blocking design which would need you to replicate logic all over the place. The benefit of following the non-blocking approach demonstrated in the 'blink without delay' example is that your sketch can handle multiple actions and events in a consistent way without all your separate bits of code needing to explicitly cooperate or depend on each other; it gives you a nice simple architecture that scales very well.

In loop() add your code to receive commands from the serial port and set a 'monitoring enabled' flag to indicate whether the regular monitoring should be happening based on the commands received. Also in loop() test whether the 'monitoring enabled' flag is set and then whether it's time to collect a sample, and if it is then you collect and transmit the sample. Other pieces of code in loop() could deal with other things you might need to do concurrently such as blinking LEDs or whatever.


Thank you for your reply!This solution seems good, but I haven't understand it very well. Can you explain it to me with an example?
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 36
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Just FYI:

Code:
#include <Time.h>
#include <TimeAlarms.h>

void setup() {
  Serial.begin(9600);
  Serial.println("Waiting for command");
}
 
AlarmID_t temptimer;
 
void loop() {
       
  // this is where the "polling" occurs
  if(Serial.available()){
    char ch=Serial.read();
    switch(ch)
    {
      case '1':
      // start recording?
      temptimer = Alarm.timerRepeat(1, Tempfunct);
      break;
     
      case '2':
      // stop recording?
      Alarm.disable(temptimer);
      break;
           
      default:
      Serial.print(ch);
      Serial.println(" : unknown command!");
    }   
  }
}

// function to be called
void Tempfunct() {
   // do whatever reading
   Serial.println(analogRead(A0));
}

This is perhaps kinda heavy for what you appear to be doing (should use the "blink without delay" method), but just wanted to followup.

Also, TimeAlarms.cpp needs to be updated for Arduino 1.0.

Replace:
Code:
#include <WProgram.h>

With:
Code:
#if ARDUINO >= 100
#include <Arduino.h>
#else
#include <WProgram.h>
#endif


Hi, I've tried to use your method, but it seems it doesn't work for me! after the Tempfunct has been called, nothing happens! Why??
Logged

Pages: [1]   Go Up
Jump to: