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++.
Hi, @sakr199
Thanks.. Tom..
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.
Hi,
To add code please click this link;
Thanks... Tom...
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.