time based interrupt/multitasking/once every n loops

I am trying to set up a boost gauge/egt sensor with an LCD TFT display.

I have started working with a MAX6675 thermocouple board and have found that if it is sampled more than once a second the output stops working properly. I need to find a way to have the loop interrupted periodically to sample the temperature.

Could someone tell me how to achieve a time based interrupt, or a loop counter with reset function?

Don't you really just need to sample at some time units thru the loop?

lloyddean: Don't you really just need to sample at some time units thru the loop?

I need to sample the pressure transducer at a rate of at least 10Hz. Which means I need to sample the pressure much more frequently than the temperature. Also I need to display the outputs on the LCD screen with minimal latency. This means introducing any delays in the loop is not beneficial. If I set up the loop to run

I really would like to set this up as something simple like

every n loops (curVal2 = termocouple.readCelsius()) else (curVal2 = oldVal2)

Can we see your current code?

... YOUR INCLUDES HERE ...

const unsigned long     tmsSECOND               = 1000UL;
const unsigned long     tmsPRESSURE_REFERESH    = tmsSECOND / 100;
const unsigned long     tmsTEMPERATURE_REFERESH = tmsSECOND;

... YOUR CONSTANTS HERE ...

... YOUR GLOBALS HERE ...

class timerT
{
    bool             m_triggered;
    unsigned long    m_tmsTarget;

public:
    timerT(unsigned long tms) : m_triggered(false), m_tmsTarget(millis() + tms)
    {   }

    bool is_expired()
    {
        if ( ! m_triggered )
        {
            m_triggered = ((long)(millis() - m_tmsTarget) >= 0);
        }

        return m_triggered;
    }
};


void loop()
{
    static timerT   timerTemerature(tmsTEMPERATURE_REFERESH);
    static timerT   timerPressure(tmsPRESSURE_REFERESH);

    if ( timerPressure.is_expired() )
    {
        ... REPLACE WITH YOUR SAMPLE, AND PERHAPS PRINT CODE...

        // RESET THE TIMER PERIOD
        timerPressure = timerT(tmsPRESSURE_REFERESHsq);
    }
    
    if ( timerTemerature.is_expired() )
    {
        ... REPLACE WITH YOUR SAMPLE, AND PERHAPS PRINT CODE...

        // RESET THE TIMER PERIOD
        timerTemerature = timerT(tmsTEMPERATURE_REFERESH);
    }
    
    // ... PERHAPS ANY OTHER CODE TO RUN ....
}

void setup()
{
    ... REPLACE WITH YOUR INITIALIZATION CODE ...
}

thank you for this.

It works great. I have added the battery voltage sample to the temp sensor timing. Sorry it’s really messy.

// Libraries
#include <max6675.h>
#include <SPI.h>
#include <Adafruit_GFX.h>
#include <TFT_ILI9163C.h>
#include <Wire.h>
 
// Color definitions
#define  BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0  
#define WHITE   0xFFFF

#define __CS 10
#define __DC 9

TFT_ILI9163C tft = TFT_ILI9163C(__CS, __DC);


const unsigned long     tmsSECOND               = 1000UL;
const unsigned long     tmsPRESSURE_REFERESH    = tmsSECOND / 100;
const unsigned long     tmsTEMPERATURE_REFERESH = tmsSECOND;

int thermoDO = 4;
int thermoCS = 5;
int thermoCLK = 6;
int vccPin = 3;
int gndPin = 2;

volatile int16_t curVal1 = 0;
volatile int16_t oldVal1 = 0;
int curVal2 = 0;
int oldVal2 = 0;
volatile int16_t curVal3 = 0;
volatile int16_t oldVal3 = 0;
volatile int16_t numVal1 = 0;
volatile int16_t peak = 0;

MAX6675 thermocouple(thermoCLK, thermoCS, thermoDO);





class timerT
{
    bool             m_triggered;
    unsigned long    m_tmsTarget;

public:
    timerT(unsigned long tms) : m_triggered(false), m_tmsTarget(millis() + tms)
    {   }

    bool is_expired()
    {
        if ( ! m_triggered )
        {
            m_triggered = ((long)(millis() - m_tmsTarget) >= 0);
        }

        return m_triggered;
    }
};


void setup()
{
   Serial.begin(9600);
  tft.begin();
  drawGauge(63,63,63);


 pinMode(vccPin, OUTPUT); digitalWrite(vccPin, HIGH);  // power up thermocouple
  pinMode(gndPin, OUTPUT); digitalWrite(gndPin, LOW);
delay(1000);

 tft.setCursor(0, 0);            // Permanent writing on the screen
  tft.setTextColor(WHITE);  
  tft.setTextSize(2);
  tft.println();
  tft.println();
  tft.println();
  tft.println();
  tft.println();
  tft.println();
  tft.setTextSize(1);
  tft.println("          PSI");  
  tft.println();
  tft.println("            o");
  tft.println("             C      V");}



void loop()
{
    static timerT   timerTemerature(tmsTEMPERATURE_REFERESH);
    static timerT   timerPressure(tmsPRESSURE_REFERESH);

    if ( timerPressure.is_expired() )
    {
        
      curVal1 = random(1,210); 

      if (oldVal1 != curVal1){
      drawNeedle(curVal1,63,63,63,GREEN,BLACK);     //move the indicator needle
      writeboost();
      oldVal1 = curVal1;}

      if(curVal1>0 && curVal1>peak) {
      drawNeedle2(peak,63,63,63,RED,BLACK);      // move the max boost needle
      peak = curVal1;}




  
        // RESET THE TIMER PERIOD
        timerPressure = timerT(tmsPRESSURE_REFERESH);
    }
    
    if ( timerTemerature.is_expired() )
    {
        
    curVal2 = thermocouple.readCelsius();
   
    if (oldVal2 != curVal2){
    bargauge();
    writetemp();   
    oldVal2 = curVal2;}  


 curVal3 = random(10.1,15.5);      // change this to your analogue input voltage sensor reading 

  if (oldVal3 != curVal3){
    writevoltage();
    oldVal3 = curVal3;}

     

        // RESET THE TIMER PERIOD
        timerTemerature = timerT(tmsTEMPERATURE_REFERESH);
    }
    
    {
    
      
 // any untimed loop code can go here
  
    
    }}






void drawGauge(uint8_t x,uint8_t y,uint8_t r) {
  tft.drawCircle(x, y, r,WHITE);//draw instrument container
tft.drawCircle(x, y, 62,BLUE);
tft.drawCircle(x, y, 61,BLUE);
tft.drawCircle(x, y, 60,WHITE);


  faceHelper2(x,y,59,330,390,1.1);//draw over boost 

  faceHelper(x,y,60,150,390,1.3);//draw major ticks
  if (r > 15) faceHelper(x,y,60,157.5,382.5,1.1);//draw minor ticks

tft.fillRect(0, 95, 126, 32,BLACK);   //x,y,w,h
}

void faceHelper(uint8_t x,uint8_t y,uint8_t r,int from,int to,float dev){
  float dsec,fromSecX,fromSecY,toSecX,toSecY;
  int i;
  for (i = from;i <= to;i += 15) {
    dsec = i * (PI / 180);
    fromSecX = cos(dsec) * (r / dev);
    fromSecY = sin(dsec) * (r / dev);
    toSecX = cos(dsec) * r;
    toSecY = sin(dsec) * r;
    tft.drawLine(1 + x + fromSecX,1 + y + fromSecY,1 + x + toSecX,1 + y + toSecY,WHITE);
  }
}


void faceHelper2(uint8_t x,uint8_t y,uint8_t r,int from,int to,float dev){
  float dsec,fromSecX,fromSecY,toSecX,toSecY;
  int i;
  for (i = from;i <= to;i += 1) {
    dsec = i * (PI / 180);
    fromSecX = cos(dsec) * (r / dev);
    fromSecY = sin(dsec) * (r / dev);
    toSecX = cos(dsec) * r;
    toSecY = sin(dsec) * r;
    tft.drawLine(1 + x + fromSecX,1 + y + fromSecY,1 + x + toSecX,1 + y + toSecY,RED);
  }
}

void writeboost() {
  String stringOne = "    ";
  String stringThree = stringOne + curVal1;  // I did this to get curVal1 output number centred in the screen
  String stringTwo = stringOne + oldVal1;
  
  tft.setCursor(0, 0);                    //clear boost pressure value for refresh
  tft.setTextColor(BLACK);  
  tft.setTextSize(2);
  tft.println();
  tft.println();
  tft.println();
  tft.println();
  tft.println();
  tft.println(stringTwo);
    
     tft.setCursor(0, 0);            // write boost value on screen
  tft.setTextColor(WHITE);  
  tft.setTextSize(2);
  tft.println();
  tft.println();
  tft.println();
  tft.println();
  tft.println();
  tft.println(stringThree);}


void writetemp() {
  String stringOne = "   ";
  String stringThree = stringOne + curVal2;  // I did this to get curVal1 output number centred in the screen
  String stringTwo = stringOne + oldVal2;
  
  tft.setCursor(0, 0);                    //clear boost pressure value for refresh
  tft.setTextColor(BLACK);  
  tft.setTextSize(2);
  tft.println();
  tft.println();
  tft.println();
  tft.println();
  tft.println();
  tft.println();
  tft.println();
  tft.println(stringTwo);

if (curVal2 < 300){
    
     tft.setCursor(0, 0);            // write boost value on screen
  tft.setTextColor(WHITE);  
  tft.setTextSize(2);
  tft.println();
  tft.println();
  tft.println();
  tft.println();
  tft.println();
  tft.println();
  tft.println();
  tft.println(stringThree);}
  else {
    
     tft.setCursor(0, 0);            // write boost value on screen
  tft.setTextColor(RED);  
  tft.setTextSize(2);
  tft.println();
  tft.println();
  tft.println();
  tft.println();
  tft.println();
  tft.println();
  tft.println();
  tft.println(stringThree);}
  
  }

Hi,
I am new to Arduino so apologies if the question sounds silly. I want to return values from ISR to main program. I am using attachInterrupt() to measure current and voltage values. I want to return current value to main program to perform some more operations.I read Gammon’s notes but could not understand properly. Below is my code. Will declaring Irms as a volatile variable help? Thank you.

#include <EmonLib.h>
EnergyMonitor emon1; 
int d=2;
void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
pinMode(2,INPUT);
attachInterrupt(digitalPinToInterrupt(2), measure, FALLING);
pinMode(5,OUTPUT);
digitalWrite(5,HIGH);
emon1.voltage(2, 176.5, 7.2);  // Voltage: input pin, calibration, phase_shift
emon1.current(1, 12.2);}

void loop() {
  // put your main code here, to run repeatedly:
Serial.println("oFF");
delay(2000);
Serial.println(Irms);}
void measure (){
while (digitalRead(2)==LOW)
{
digitalWrite(5, LOW);

emon1.calcVI(20,2000);         // Calculate all. No.of half wavelengths (crossings), time-out
emon1.serialprint();           // Print out all variables (realpower, apparent power, Vrms, Irms, power factor)
   float realPower       = emon1.realPower;     //extract Real Power into variable
float apparentPower   = emon1.apparentPower;    //extract Apparent Power into variable
  float powerFActor     = emon1.powerFactor;      //extract Power Factor into Variable
  float supplyVoltage   = emon1.Vrms;             //extract Vrms into Variable
  float Irms            = emon1.Irms; }
  digitalWrite(5, HIGH);}

Moving it from ISR local to global space and adding volatile will allow it to read be any other code.

  1. Fix your style, that’s atrocious. Indenting and brace placement doesn’t matter to the compiler, but it does for people. Legibility is important when asking for help.
    1a) Closing curly braces ( } ) always go on their own line for execution blocks.

  2. delay(2000); ← Get rid of this. Delay is the creepy stranger driving around in a windowless van enticing children with candy. Don’t use it. Discipline yourself to forget that it even exists, and learn how to time events asynchronously using the millis() or micros() timers. llyoddean has given you a great skeleton to work with. Study and understand his example.

I hate delay.