Interrupt conflict

Hi
When adding frequency count library to a program for control motor speed which use pid library, the frequency count results not exact one (sometimes 0 and sometimes very big number)
Could you help me please prevent timers interrupt conflict . For uno
FreqCount-master_024359.zip (11.3 KB)
freq.ino (8.7 KB)

Hello sakr199

We need some additional information.

Post your sketch, well formated, with well-tempered comments and in so called code tags "< code >" and a detailed circuit diagram to see how we can help.

Have a nice day and enjoy coding in C++.

1 Like

Hi, @sakr199

Thanks.. Tom.. :grinning: :+1: :coffee: :australia:

1 Like

Thanks for your interest
About The circuit diagram
The circuit diagram for frequency measure uses operational amplifier and it was tested with an example named serial output in the library folder and gives good results .
Also for The Motor speed control circuit which includes zero crossing detector and tacho speed measurement and phase angle control with moc3021 All of them was tested with a program and gives good results with various speed.
About The comments, I already included
My problem appears when merging or mixing The two programs,the frequency results in serial monitor gives bad results.
I think this because the interrupt conflict between the frequency library and the timers interrupt in the speed control program.
The program in the attachment is the Motor speed control program as it is with only add including frequency library,if statement to turn on led when freq <22khz
Thanks again for your help

Is it possible to use cli and sei functions

Yes, on avr-type targets using the avr-gcc compiler. There are hardware independent Arduino functions called interrupts() and noInterrupts(). But this won't help solving a timer interrupts conflict, neither.

1 Like

Hi,

To add code please click this link;

Thanks... Tom... :grinning: :+1: :coffee: :australia:

Your code:

#include <avr/io.h>
#include <avr/interrupt.h>
#include <PID_v1.h>
#include <FreqCount.h>
#define TACHO 3            // tacho signals input pin
#define DETECT 2           // zero cross detect pin
#define GATE 17            // TRIAC gate pin
#define BUTTON 4           // rottary encoder button pin
#define RELAY 5            // relay pin
#define PULSE 2            // number of triac trigger pulse width counts. One count is 16 microseconds
#define TACHOPULSES 8      // number of pulses per revolution 
#define  a  13
unsigned int RPM;                   // real rpm variable
unsigned int count;                 // tacho pulses count variable
unsigned int lastcount = 0;         // additional tacho pulses count variable
unsigned long lastcounttime = 0;
unsigned long lastflash;
unsigned long lastpiddelay = 0;
unsigned long previousMillis = 0;
unsigned long lastDebounceTime = 0;

const int sampleRate = 1;           // Variable that determines how fast our PID loop
const int rpmcorrection = 86;       // sito kazkodel reikia, kad realus rpm atitiktu matuojamus
const int protection = 2000;        // protection will switch on when real rpm exceeds desired by value
const int debounceDelay = 50;       // the debounce time; increase if the output flickers
const int minoutputlimit = 80;      // limit of PID output
const int maxoutputlimit = 540;     // limit of PID output
const int mindimminglimit = 80;     // the shortest delay before triac fires
const int maxdimminglimit = 625;    // for 60Hz will be 520
const int risetime = 100;           // RPM rise time delay in microseconds (risetime x RPM)
const int desiredRPM = 1000;        // ENTER DESIRED RPM HERE

int dimming = 540;                  // this should be the same as maxoutputlimit
int tempcounter = 100;

byte relayState = LOW;              // the current state of the relay pin
byte buttonState;                   // the current reading from the input pin
byte lastButtonState = HIGH;        // the previous reading from the input pin

bool loopflag = false;              // flag for soft start
bool startflag = false;             // flag for motor start delay
bool runflag = false;               // flag for motor running state

double Setpoint, Input, Output;       // define PID variables
double sKp = 0.1, sKi = 0.2, sKd = 0; // PID tuning parameters for starting motor
double rKp = 0.25, rKi = 1, rKd = 0;  // PID tuning parameters for runnig motor

PID myPID(&Input, &Output, &Setpoint, sKp, sKi, sKd, DIRECT); // define PID variables and parameters

void setup() {
    FreqCount.begin(1000);
    pinMode ( a , OUTPUT );
  Serial.begin(115200);
  // set up pins
  pinMode(BUTTON, INPUT);             // set the button pin
  pinMode(RELAY, OUTPUT);             // set the relay  pin
  pinMode(DETECT, INPUT);             // set the zero cross detect pin
  pinMode(GATE, OUTPUT);              // set the TRIAC gate control pin
  pinMode(TACHO, INPUT);              // set the tacho pulses detect pin
  digitalWrite(BUTTON, HIGH);         // turn on pullup resistors
  digitalWrite(RELAY, relayState);    // initialize relay output

  Input = 200;                        // asiign initial value for PID
  Setpoint = 200;                     // asiign initial value for PID

  //turn the PID on
  myPID.SetMode(AUTOMATIC);
  myPID.SetOutputLimits(minoutputlimit, maxoutputlimit);
  myPID.SetSampleTime(sampleRate);    // Sets the sample rate

  // set up Timer1
  OCR1A = 100;                        // initialize the comparator
  TIMSK1 = 0x03;                      // enable comparator A and overflow interrupts
  TCCR1A = 0x00;                      // timer control registers set for
  TCCR1B = 0x00;                      // normal operation, timer disabled

  // set up zero crossing interrupt IRQ0 on pin 2.
  // set up tacho sensor interrupt IRQ1 on pin3
  attachInterrupt(0, zeroCrossingInterrupt, RISING);
  attachInterrupt(1, tacho, FALLING);
}

// Interrupt Service Routines
void zeroCrossingInterrupt() { // zero cross detect
  TCCR1B = 0x04;               // start timer with divide by 256 input
  TCNT1 = 0;                   // reset timer - count from zero
  OCR1A = dimming;             // set the compare register brightness desired.
}

ISR(TIMER1_COMPA_vect) {       // comparator match
  if (startflag == true) {     // flag for start up delay
    digitalWrite(GATE, HIGH);  // set TRIAC gate to high
    TCNT1 = 65536 - PULSE;     // trigger pulse width
  }
}

ISR(TIMER1_OVF_vect) {         // timer1 overflow
  digitalWrite(GATE, LOW);     // turn off TRIAC gate
  TCCR1B = 0x00;               // disable timer stops unintended triggers
}

// RPM counting routine
void tacho() {
  count++;
  unsigned long time = micros() - lastflash;
  float time_in_sec  = ((float)time + rpmcorrection) / 1000000;
  float prerpm = 60 / time_in_sec;
  RPM = prerpm / TACHOPULSES;
  lastflash = micros();
}

void loop() {
 unsigned long level = FreqCount.read(); //freq. mewasure
    Serial.println(level);
 if ( level < 22000)
 {digitalWrite (a , HIGH );}
 else { digitalWrite ( a , LOW); }
  // check the start / stop button state
  int reading = digitalRead(BUTTON);  // read the state of the switch into a local variable:
  if (reading != lastButtonState) {   // If the switch changed, due to noise or pressing
    lastDebounceTime = millis();      // reset the debouncing timer
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {     // if the button state has changed:
      buttonState = reading;
      if (buttonState == LOW) {       // only toggle the relay if the new button state is LOW
        relayState = !relayState;
        if (relayState == HIGH) {
          loopflag = true;
          digitalWrite(RELAY, relayState); // set the Relay:
          delay (300);                     // delay to prevent sparks on relay contacts
          startflag = true;                // flag to start motor
        }
        if (relayState == LOW) {
          Setpoint = 200;
          Input = 200;
          runflag = false;
          startflag = false;
          delay (300);                     // delay to prevent sparks on relay contacts
          digitalWrite(RELAY, relayState); // set the Relay:
        }
      }
    }
  }
  lastButtonState = reading;               // save the reading. Next time through the loop, it'll be the lastButtonState:

  //soft start
  if (loopflag == true) {
    myPID.SetTunings(sKp, sKi, sKd);        // Set the PID gain constants and start
    int i = (desiredRPM - tempcounter);
    for (int j = 1; j <= i; j++) {
      Input = RPM;
      Setpoint = tempcounter;
      myPID.Compute();
      dimming = map(Output, minoutputlimit, maxoutputlimit, maxoutputlimit, minoutputlimit); // inverse the output
      dimming = constrain(dimming, mindimminglimit, maxdimminglimit);     // check that dimming is in 20-625 range
      tempcounter++;
      delayMicroseconds (risetime);
    }
    if (tempcounter >= desiredRPM) {
      lastcounttime = millis();
      lastpiddelay = millis();
      loopflag = false;
      runflag = true;
      tempcounter = 100;
    }
  }

  // normal motor running state
  if (relayState == HIGH && loopflag == false) {
    unsigned long piddelay = millis();

    if ((piddelay - lastpiddelay) > 1000) {     // delay to switch PID values. Prevents hard start
      myPID.SetTunings(rKp, rKi, rKd);          // Set the PID gain constants and start
      lastpiddelay = millis();
    }

    Input = RPM;
    Setpoint = desiredRPM;
    myPID.Compute();
    dimming = map(Output, minoutputlimit, maxoutputlimit, maxoutputlimit, minoutputlimit); // reverse the output
    dimming = constrain(dimming, mindimminglimit, maxdimminglimit);     // check that dimming is in 20-625 range
  }

  // diagnose a fault and turn on protection
  unsigned long counttime = millis();
  if (counttime - lastcounttime >= 1000) {
    if (count == 0 && relayState == HIGH && runflag == true) {
      startflag = false;            // flag to turn off triac before relay turns off
      delay (300);                  // delay to prevent sparks on relay contacts
      digitalWrite(RELAY, LOW);
      relayState = LOW;
    }
    lastcount = count;
    count = 0;
    lastcounttime = millis();
  }

  //reset rpm after motor stops
  if (count == 0 && relayState == LOW) {
    RPM = 0;
  }

  // protection against high rpm. i e triac damage
  if (relayState == HIGH && RPM > desiredRPM + protection) {
    startflag = false;            // flag to turn off triac before relay turns off
    delay (300);                  // delay to prevent sparks on relay contacts
    digitalWrite(RELAY, LOW);
    relayState = LOW;
  }
}

You have conflict between the FreqCount library and the triac phase cutting which are both trying to use Timer1 in different, incompatible modes. You indeed have a problem using the uno which has only one 16 bit timer.

Is something else connected to pin5 which is the input pin for FreqCount?

If you converted to a Mega, the Frequent Library will use Timer5 and there will be no conflict.

What is FreqCount measuring.
How is it different from what you collect on the Tacho interrupt?

Thanks for your interest

Pin5 only connected to the freqcount from op_amp circuit (circuit which tested with serial output program in the examples of the library,and works good)

The tacho is for measuring motor speed as feedback for PID controller to have constant speed.
Frequency count is another sensor for measuring pressure of a liquid in khz output.

The freqcount measuring with its timers interrupt is working at stop of the motor.meaning no need for freqcount library while motor running and when motor stop activate the library and measure the frequency .
The motor run and stop for different intervals.

I need help now.
how to deactivate freqcount library at apart of the code (at motor running) ?
And how to activate the library again at motor stop?

FreqCount.begin() and FreqCount.end() should activate and deactivate the library using Timer1 for counting. It sets up the Timer1 with the parameters it needs to count.

To use Timer1 for the motor control you will have to reset the Timer1 parameters back to what you use for the phase control. When you are not set up for phase control, I think you want to detach the zero cross interrupt, and reattach when you go back to motor control.

// set up Timer1
  OCR1A = 100;                        // initialize the comparator
  TIMSK1 = 0x03;                      // enable comparator A and overflow interrupts
  TCCR1A = 0x00;                      // timer control registers set for
  TCCR1B = 0x00;                      // normal operation, timer disabled

It's not clear to me if you will be successful switching back and forth between the two operations.

Is it possible to set timer1 in void loop instead of void setup ?

Also use freqcount.begin() in void loop instead of void setup and put it at start of frequency measuring and freqcount.end() when finishing measuring.
then to run motor put timer1 registers setting ( lines timsk tccr and. ) before starting motor

Yes.

I tried to put freqcount.begin() in void loop instead of void setup , gives 0
It seems that freqcount.begin() must be in void setup
Is there is any way to activate or deactivate freqcount library in some part of the code?

Please post the code which returns the 0 value. Please post it in your reply using code tags.

Can you also post a hand drawn schematic of what is connected where.

EDIT: I would also suggest that you try and run a simplified sketch with just FreqCount and where you stop and start it in loop without the other timer interrupts involved.

Exactly I tried like what you said
Example in the library folder

#include <FreqCount.h>

/* FreqCount - Example with serial output
 * http://www.pjrc.com/teensy/td_libs_FreqCount.html
 *
 * This example code is in the public domain.
 */

void setup() {
  Serial.begin(115200);
 // FreqCount.begin(1000);  // when ferqcount.begin in void seyup it gives good results

}

void loop() {
 FreqCount.begin(1000); // when it moved here in void loop it gives 0

    unsigned long count = FreqCount.read();
    Serial.println(count);
    }


About The circuit it just opp amp lm 393 and it gives good results with the could here

I tried to put freqcount.begin() in void loop instead of void setup , gives 0
It seems that freqcount.begin() must be in void setup

This is not correct. Here's an example of starting and stopping FreqCount in loop(). I have jumpered a pwm signal from pin 6 to pin 5 as a test signal.

/* FreqCount - Example with serial output
  http://www.pjrc.com/teensy/td_libs_FreqCount.html
*/
#include <FreqCount.h>

void setup() {
  Serial.begin(57600);
  //FreqCount.begin(1000);
  pinMode(6, OUTPUT);
  analogWrite(6, 127); //980Hz signal jumper 6 to 5
}

void loop() {

  static boolean readingEnabled = false;
  static unsigned long lastReadingTime;
  if (millis() - lastReadingTime >= 5000 and !readingEnabled)
  {
    Serial.println("FreqCount.begin");
    FreqCount.begin(1000);
    lastReadingTime = millis();
    readingEnabled = true;
  }

  if (readingEnabled)
  {
    if (FreqCount.available()) {
      unsigned long count = FreqCount.read();
      Serial.println(count);
      readingEnabled = false;
      FreqCount.end();
      Serial.println("FreqCount.end");
    }
  }
}

Output:

12:02:24.201 -> FreqCount.begin
12:02:25.229 -> 976
12:02:25.229 -> FreqCount.end
12:02:29.260 -> FreqCount.begin
12:02:30.244 -> 976
12:02:30.244 -> FreqCount.end
12:02:34.274 -> FreqCount.begin
12:02:35.258 -> 976
12:02:35.258 -> FreqCount.end

i tried your code, gives good results
but still conflict of interrupt
i merg your code with the code of motor speed control it gives 0
i tried to use function like cli() , sei() ,

#include <avr/io.h>
#include <avr/interrupt.h>
#include <PID_v1.h>
#include <FreqCount.h>

#define TACHO 3            // tacho signals input pin
#define DETECT 2           // zero cross detect pin
#define GATE 17            // TRIAC gate pin
#define BUTTON 4           // rottary encoder button pin
#define RELAY 5            // relay pin
#define PULSE 2            // number of triac trigger pulse width counts. One count is 16 microseconds
#define TACHOPULSES 8      // number of pulses per revolution 

unsigned int RPM;                   // real rpm variable
unsigned int count;                 // tacho pulses count variable
unsigned int lastcount = 0;         // additional tacho pulses count variable
unsigned long lastcounttime = 0;
unsigned long lastflash;
unsigned long lastpiddelay = 0;
unsigned long previousMillis = 0;
unsigned long lastDebounceTime = 0;

const int sampleRate = 1;           // Variable that determines how fast our PID loop
const int rpmcorrection = 86;       // sito kazkodel reikia, kad realus rpm atitiktu matuojamus
const int protection = 2000;        // protection will switch on when real rpm exceeds desired by value
const int debounceDelay = 50;       // the debounce time; increase if the output flickers
const int minoutputlimit = 80;      // limit of PID output
const int maxoutputlimit = 540;     // limit of PID output
const int mindimminglimit = 80;     // the shortest delay before triac fires
const int maxdimminglimit = 625;    // for 60Hz will be 520
const int risetime = 100;           // RPM rise time delay in microseconds (risetime x RPM)
const int desiredRPM = 1000;        // ENTER DESIRED RPM HERE

int dimming = 540;                  // this should be the same as maxoutputlimit
int tempcounter = 100;

byte relayState = LOW;              // the current state of the relay pin
byte buttonState;                   // the current reading from the input pin
byte lastButtonState = HIGH;        // the previous reading from the input pin

bool loopflag = false;              // flag for soft start
bool startflag = false;             // flag for motor start delay
bool runflag = false;               // flag for motor running state

double Setpoint, Input, Output;       // define PID variables
double sKp = 0.1, sKi = 0.2, sKd = 0; // PID tuning parameters for starting motor
double rKp = 0.25, rKi = 1, rKd = 0;  // PID tuning parameters for runnig motor

PID myPID(&Input, &Output, &Setpoint, sKp, sKi, sKd, DIRECT); // define PID variables and parameters

void setup() {
  Serial.begin(115200);
  // set up pins
  pinMode(BUTTON, INPUT);             // set the button pin
  pinMode(RELAY, OUTPUT);             // set the relay  pin
  pinMode(DETECT, INPUT);             // set the zero cross detect pin
  pinMode(GATE, OUTPUT);              // set the TRIAC gate control pin
  pinMode(TACHO, INPUT);              // set the tacho pulses detect pin
  digitalWrite(BUTTON, HIGH);         // turn on pullup resistors
  digitalWrite(RELAY, relayState);    // initialize relay output

  Input = 200;                        // asiign initial value for PID
  Setpoint = 200;                     // asiign initial value for PID

  //turn the PID on
  myPID.SetMode(AUTOMATIC);
  myPID.SetOutputLimits(minoutputlimit, maxoutputlimit);
  myPID.SetSampleTime(sampleRate);    // Sets the sample rate

  // set up Timer1           //i tried to comment these setup
  OCR1A = 100;                        // initialize the comparator
  TIMSK1 = 0x03;                      // enable comparator A and overflow interrupts
  TCCR1A = 0x00;                      // timer control registers set for
  TCCR1B = 0x00;                      // normal operation, timer disabled

  // set up zero crossing interrupt IRQ0 on pin 2.
  // set up tacho sensor interrupt IRQ1 on pin3
  attachInterrupt(0, zeroCrossingInterrupt, RISING); //i tried to comment this line
  attachInterrupt(1, tacho, FALLING);                //i tried to comment this line
}

// Interrupt Service Routines
void zeroCrossingInterrupt() { // zero cross detect
  TCCR1B = 0x04;               // start timer with divide by 256 input
  TCNT1 = 0;                   // reset timer - count from zero
  OCR1A = dimming;             // set the compare register brightness desired.
}

ISR(TIMER1_COMPA_vect) {       // comparator match
  if (startflag == true) {     // flag for start up delay
    digitalWrite(GATE, HIGH);  // set TRIAC gate to high
    TCNT1 = 65536 - PULSE;     // trigger pulse width
  }
}

ISR(TIMER1_OVF_vect) {         // timer1 overflow
  digitalWrite(GATE, LOW);     // turn off TRIAC gate
  TCCR1B = 0x00;               // disable timer stops unintended triggers
}

// RPM counting routine
void tacho() {
  count++;
  unsigned long time = micros() - lastflash;
  float time_in_sec  = ((float)time + rpmcorrection) / 1000000;
  float prerpm = 60 / time_in_sec;
  RPM = prerpm / TACHOPULSES;
  lastflash = micros();
}

void loop() {
 for (int k = 0; k <= 255; k++) {
  // noInterrupts();              // i tried with interrupt() at end of for
  //cli();                         // i tried with sei() at end of for
detachInterrupt(digitalPinToInterrupt(2));
detachInterrupt(digitalPinToInterrupt(3));  
  static boolean readingEnabled = false;
  static unsigned long lastReadingTime;
  if (millis() - lastReadingTime >= 5000 and !readingEnabled)
  {
    Serial.println("FreqCount.begin");
    FreqCount.begin(1000);
    lastReadingTime = millis();
    readingEnabled = true;
  }

 // if (readingEnabled)
  //{
    if (FreqCount.available()) {
      unsigned long count = FreqCount.read();
      Serial.println(count);
      readingEnabled = false;
      FreqCount.end();
      Serial.println("FreqCount.end");
  //  }
  }
//  interrupts();
 // sei();
  }
  // check the start / stop button state
  int reading = digitalRead(BUTTON);  // read the state of the switch into a local variable:
  if (reading != lastButtonState) {   // If the switch changed, due to noise or pressing
    lastDebounceTime = millis();      // reset the debouncing timer
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {     // if the button state has changed:
      buttonState = reading;
      if (buttonState == LOW) {       // only toggle the relay if the new button state is LOW
        relayState = !relayState;
        if (relayState == HIGH) {
          loopflag = true;
          digitalWrite(RELAY, relayState); // set the Relay:
          delay (300);                     // delay to prevent sparks on relay contacts
          startflag = true;                // flag to start motor
        }
        if (relayState == LOW) {
          Setpoint = 200;
          Input = 200;
          runflag = false;
          startflag = false;
          delay (300);                     // delay to prevent sparks on relay contacts
          digitalWrite(RELAY, relayState); // set the Relay:
        }
      }
    }
  }
  lastButtonState = reading;               // save the reading. Next time through the loop, it'll be the lastButtonState:

  //soft start
  if (loopflag == true) {
    myPID.SetTunings(sKp, sKi, sKd);        // Set the PID gain constants and start
    int i = (desiredRPM - tempcounter);
    for (int j = 1; j <= i; j++) {
      Input = RPM;
      Setpoint = tempcounter;
      myPID.Compute();
      dimming = map(Output, minoutputlimit, maxoutputlimit, maxoutputlimit, minoutputlimit); // inverse the output
      dimming = constrain(dimming, mindimminglimit, maxdimminglimit);     // check that dimming is in 20-625 range
      tempcounter++;
      delayMicroseconds (risetime);
    }
    if (tempcounter >= desiredRPM) {
      lastcounttime = millis();
      lastpiddelay = millis();
      loopflag = false;
      runflag = true;
      tempcounter = 100;
    }
  }

  // normal motor running state
  if (relayState == HIGH && loopflag == false) {
    unsigned long piddelay = millis();

    if ((piddelay - lastpiddelay) > 1000) {     // delay to switch PID values. Prevents hard start
      myPID.SetTunings(rKp, rKi, rKd);          // Set the PID gain constants and start
      lastpiddelay = millis();
    }

    Input = RPM;
    Setpoint = desiredRPM;
    myPID.Compute();
    dimming = map(Output, minoutputlimit, maxoutputlimit, maxoutputlimit, minoutputlimit); // reverse the output
    dimming = constrain(dimming, mindimminglimit, maxdimminglimit);     // check that dimming is in 20-625 range
  }

  // diagnose a fault and turn on protection
  unsigned long counttime = millis();
  if (counttime - lastcounttime >= 1000) {
    if (count == 0 && relayState == HIGH && runflag == true) {
      startflag = false;            // flag to turn off triac before relay turns off
      delay (300);                  // delay to prevent sparks on relay contacts
      digitalWrite(RELAY, LOW);
      relayState = LOW;
    }
    lastcount = count;
    count = 0;
    lastcounttime = millis();
  }

  //reset rpm after motor stops
  if (count == 0 && relayState == LOW) {
    RPM = 0;
  }

  // protection against high rpm. i e triac damage
  if (relayState == HIGH && RPM > desiredRPM + protection) {
    startflag = false;            // flag to turn off triac before relay turns off
    delay (300);                  // delay to prevent sparks on relay contacts
    digitalWrite(RELAY, LOW);
    relayState = LOW;
  }


}

results

FreqCount.end
FreqCount.begin
0
FreqCount.end
FreqCount.begin
0
FreqCount.end
FreqCount.begin
0
FreqCount.end
FreqCount.begin

i made test by connecting pin 5 only with sensor and motor circuit not conected

frequency measure uses operational amplifier and it was tested with an example named serial output in the library folder and gives good results .

Did you try it with your sensor providing the input? Are you certain that the sensor is still providing the pulses and they can be read on pin 5?

Why is the frequency reading inside a for() loop with 255 iterations?

Why did you comment the if(readingEnabled)?

your code and its results


/* FreqCount - Example with serial output
  http://www.pjrc.com/teensy/td_libs_FreqCount.html
*/
#include <FreqCount.h>

void setup() {
  Serial.begin(57600);
  //FreqCount.begin(1000);
  pinMode(6, OUTPUT);
  analogWrite(6, 127); //980Hz signal jumper 6 to 5
}

void loop() {

  static boolean readingEnabled = false;
  static unsigned long lastReadingTime;
  if (millis() - lastReadingTime >= 5000 and !readingEnabled)
  {
    Serial.println("FreqCount.begin");
    FreqCount.begin(1000);
    lastReadingTime = millis();
    readingEnabled = true;
  }

  if (readingEnabled)
  {
    if (FreqCount.available()) {
      unsigned long count = FreqCount.read();
      Serial.println(count);
      readingEnabled = false;
      FreqCount.end();
      Serial.println("FreqCount.end");
    }
  }
}
FreqCount.begin
26027
FreqCount.end
FreqCount.begin
24570
FreqCount.end
FreqCount.begin
23485
FreqCount.end
FreqCount.begin
26247
FreqCount.end
FreqCount.begin
26256
FreqCount.end

as you the results as i changed the level of water the freq changed
it works good for the circuit

your code as it is and its results

#include <avr/io.h>
#include <avr/interrupt.h>
#include <PID_v1.h>
#include <FreqCount.h>
#define TACHO 3            // tacho signals input pin
#define DETECT 2           // zero cross detect pin
#define GATE 17            // TRIAC gate pin
#define BUTTON 4           // rottary encoder button pin
#define RELAY 5            // relay pin
#define PULSE 2            // number of triac trigger pulse width counts. One count is 16 microseconds
#define TACHOPULSES 8      // number of pulses per revolution 

unsigned int RPM;                   // real rpm variable
unsigned int count;                 // tacho pulses count variable
unsigned int lastcount = 0;         // additional tacho pulses count variable
unsigned long lastcounttime = 0;
unsigned long lastflash;
unsigned long lastpiddelay = 0;
unsigned long previousMillis = 0;
unsigned long lastDebounceTime = 0;

const int sampleRate = 1;           // Variable that determines how fast our PID loop
const int rpmcorrection = 86;       // sito kazkodel reikia, kad realus rpm atitiktu matuojamus
const int protection = 2000;        // protection will switch on when real rpm exceeds desired by value
const int debounceDelay = 50;       // the debounce time; increase if the output flickers
const int minoutputlimit = 80;      // limit of PID output
const int maxoutputlimit = 540;     // limit of PID output
const int mindimminglimit = 80;     // the shortest delay before triac fires
const int maxdimminglimit = 625;    // for 60Hz will be 520
const int risetime = 100;           // RPM rise time delay in microseconds (risetime x RPM)
const int desiredRPM = 1000;        // ENTER DESIRED RPM HERE

int dimming = 540;                  // this should be the same as maxoutputlimit
int tempcounter = 100;

byte relayState = LOW;              // the current state of the relay pin
byte buttonState;                   // the current reading from the input pin
byte lastButtonState = HIGH;        // the previous reading from the input pin

bool loopflag = false;              // flag for soft start
bool startflag = false;             // flag for motor start delay
bool runflag = false;               // flag for motor running state

double Setpoint, Input, Output;       // define PID variables
double sKp = 0.1, sKi = 0.2, sKd = 0; // PID tuning parameters for starting motor
double rKp = 0.25, rKi = 1, rKd = 0;  // PID tuning parameters for runnig motor

PID myPID(&Input, &Output, &Setpoint, sKp, sKi, sKd, DIRECT); // define PID variables and parameters

void setup() {
  Serial.begin(115200);
  // set up pins
  pinMode(BUTTON, INPUT);             // set the button pin
  pinMode(RELAY, OUTPUT);             // set the relay  pin
  pinMode(DETECT, INPUT);             // set the zero cross detect pin
  pinMode(GATE, OUTPUT);              // set the TRIAC gate control pin
  pinMode(TACHO, INPUT);              // set the tacho pulses detect pin
  digitalWrite(BUTTON, HIGH);         // turn on pullup resistors
  digitalWrite(RELAY, relayState);    // initialize relay output

  Input = 200;                        // asiign initial value for PID
  Setpoint = 200;                     // asiign initial value for PID

  //turn the PID on
  myPID.SetMode(AUTOMATIC);
  myPID.SetOutputLimits(minoutputlimit, maxoutputlimit);
  myPID.SetSampleTime(sampleRate);    // Sets the sample rate

  // set up Timer1
  OCR1A = 100;                        // initialize the comparator
  TIMSK1 = 0x03;                      // enable comparator A and overflow interrupts
  TCCR1A = 0x00;                      // timer control registers set for
  TCCR1B = 0x00;                      // normal operation, timer disabled

  // set up zero crossing interrupt IRQ0 on pin 2.
  // set up tacho sensor interrupt IRQ1 on pin3
  attachInterrupt(0, zeroCrossingInterrupt, RISING);
  attachInterrupt(1, tacho, FALLING);
}

// Interrupt Service Routines
void zeroCrossingInterrupt() { // zero cross detect
  TCCR1B = 0x04;               // start timer with divide by 256 input
  TCNT1 = 0;                   // reset timer - count from zero
  OCR1A = dimming;             // set the compare register brightness desired.
}

ISR(TIMER1_COMPA_vect) {       // comparator match
  if (startflag == true) {     // flag for start up delay
    digitalWrite(GATE, HIGH);  // set TRIAC gate to high
    TCNT1 = 65536 - PULSE;     // trigger pulse width
  }
}

ISR(TIMER1_OVF_vect) {         // timer1 overflow
  digitalWrite(GATE, LOW);     // turn off TRIAC gate
  TCCR1B = 0x00;               // disable timer stops unintended triggers
}

// RPM counting routine
void tacho() {
  count++;
  unsigned long time = micros() - lastflash;
  float time_in_sec  = ((float)time + rpmcorrection) / 1000000;
  float prerpm = 60 / time_in_sec;
  RPM = prerpm / TACHOPULSES;
  lastflash = micros();
}

void loop() {

  //your code as it is
  static boolean readingEnabled = false;
  static unsigned long lastReadingTime;
  if (millis() - lastReadingTime >= 5000 and !readingEnabled)
  {
    Serial.println("FreqCount.begin");
    FreqCount.begin(1000);
    lastReadingTime = millis();
    readingEnabled = true;
  }

  if (readingEnabled)
  {
    if (FreqCount.available()) {
      unsigned long count = FreqCount.read();
      Serial.println(count);
      readingEnabled = false;
      FreqCount.end();
      Serial.println("FreqCount.end");
    }
  }


  // motor code

  // check the start / stop button state
  int reading = digitalRead(BUTTON);  // read the state of the switch into a local variable:
  if (reading != lastButtonState) {   // If the switch changed, due to noise or pressing
    lastDebounceTime = millis();      // reset the debouncing timer
  }
  if ((millis() - lastDebounceTime) > debounceDelay) {
    if (reading != buttonState) {     // if the button state has changed:
      buttonState = reading;
      if (buttonState == LOW) {       // only toggle the relay if the new button state is LOW
        relayState = !relayState;
        if (relayState == HIGH) {
          loopflag = true;
          digitalWrite(RELAY, relayState); // set the Relay:
          delay (300);                     // delay to prevent sparks on relay contacts
          startflag = true;                // flag to start motor
        }
        if (relayState == LOW) {
          Setpoint = 200;
          Input = 200;
          runflag = false;
          startflag = false;
          delay (300);                     // delay to prevent sparks on relay contacts
          digitalWrite(RELAY, relayState); // set the Relay:
        }
      }
    }
  }
  lastButtonState = reading;               // save the reading. Next time through the loop, it'll be the lastButtonState:

  //soft start
  if (loopflag == true) {
    myPID.SetTunings(sKp, sKi, sKd);        // Set the PID gain constants and start
    int i = (desiredRPM - tempcounter);
    for (int j = 1; j <= i; j++) {
      Input = RPM;
      Setpoint = tempcounter;
      myPID.Compute();
      dimming = map(Output, minoutputlimit, maxoutputlimit, maxoutputlimit, minoutputlimit); // inverse the output
      dimming = constrain(dimming, mindimminglimit, maxdimminglimit);     // check that dimming is in 20-625 range
      tempcounter++;
      delayMicroseconds (risetime);
    }
    if (tempcounter >= desiredRPM) {
      lastcounttime = millis();
      lastpiddelay = millis();
      loopflag = false;
      runflag = true;
      tempcounter = 100;
    }
  }

  // normal motor running state
  if (relayState == HIGH && loopflag == false) {
    unsigned long piddelay = millis();

    if ((piddelay - lastpiddelay) > 1000) {     // delay to switch PID values. Prevents hard start
      myPID.SetTunings(rKp, rKi, rKd);          // Set the PID gain constants and start
      lastpiddelay = millis();
    }

    Input = RPM;
    Setpoint = desiredRPM;
    myPID.Compute();
    dimming = map(Output, minoutputlimit, maxoutputlimit, maxoutputlimit, minoutputlimit); // reverse the output
    dimming = constrain(dimming, mindimminglimit, maxdimminglimit);     // check that dimming is in 20-625 range
  }

  // diagnose a fault and turn on protection
  unsigned long counttime = millis();
  if (counttime - lastcounttime >= 1000) {
    if (count == 0 && relayState == HIGH && runflag == true) {
      startflag = false;            // flag to turn off triac before relay turns off
      delay (300);                  // delay to prevent sparks on relay contacts
      digitalWrite(RELAY, LOW);
      relayState = LOW;
    }
    lastcount = count;
    count = 0;
    lastcounttime = millis();
  }

  //reset rpm after motor stops
  if (count == 0 && relayState == LOW) {
    RPM = 0;
  }

  // protection against high rpm. i e triac damage
  if (relayState == HIGH && RPM > desiredRPM + protection) {
    startflag = false;            // flag to turn off triac before relay turns off
    delay (300);                  // delay to prevent sparks on relay contacts
    digitalWrite(RELAY, LOW);
    relayState = LOW;
  }


}


FreqCount.begin
0
FreqCount.end
FreqCount.begin
0
FreqCount.end
FreqCount.begin
0
FreqCount.end
FreqCount.begin
0
FreqCount.end

only pin 5 is connected nothing for the motor

There is a conflict with pin5 being used by the relay.
With this change, I can see nonZero freqCount values with the last code you provided.

//#define RELAY 5            // relay pin
#define RELAY 12

You should follow up on the previous suggestion about making the variables changed inside of ISR's volatile.

1 Like