Rpm controlled relays

Hi everyone.

Im new on this forum and im looking for some help.
I am doing a project where a arduino 2560 mega is supposed to control relays depending on rpm( phototransistor), temperature(pt100) and 1/0 inputs.
I resently started with the programming and got stuck pretty fast.
Do someone have a code example for only rpm count with a output high and low at a given rpm? No display is needed only the in and output.
Thanks for any help!

Can you at least make a start by writing some code which, in the loop(), does a digitalRead() of the pin that the phototransistor is connected to and writes the value to the serial monitor ? Deriving rpm is simply a matter of counting the pulses in a time period. Deriving a high or low depending on rpm is also a simple addition.

Thank you yes this is what i have so far and i think it needs some adjustments.

void setup() {

pinMode(2, INPUT);
pinMode(3, INPUT);
pinMode(A0, OUTPUT);
pinMode(A1, OUTPUT);
pinMode(A2, OUTPUT);
pinMode(A3, OUTPUT);
pinMode(A4, OUTPUT);

}

int rpm = 2;
int level = 3;
int rel1 = A0;
int rel2 = A1;
int rel3 = A2;
int rel4 = A3;
int rel5 = A4;

volatile byte half_revolutions;
unsigned int rpm;
unsigned long timeold;
void setup()
{
Serial.begin(9600);
attachInterrupt(0, rpm_fun, RISING); half_revolutions = 0;
rpm = 0;
timeold = 0;
}
void loop()
{
if (half_revolutions >= 20) {
//Update RPM every 20 counts, increase this for better RPM resolution, //decrease for faster update
rpm = 30*1000/(millis() -
timeold)*half_revolutions;
timeold = millis();
half_revolutions = 0;
Serial.println(rpm,DEC);

while(rpm > 995){
analogWrite(rel1, HIGH);
analogWrite(rel2, HIGH);
}

while(rpm, < 1005){
analogWrite(rel3, HIGH);
analogWrite(rel4, HIGH);
}
while(level, 1){
analogWrite(rel4, HIGH);
}

}
}
void rpm_fun()
{
half_revolutions++;
//Each rotation, this interrupt function is run twice
}

I guess you have got as far as installing the Arduino IDE on your PC.

You should use the Tools > Autoformat option on code before posting code here.
You should also compile it and get rid of compilation errors first.

Some comments:

You are using the variable rpm both as a pin number and as value of the rpm currently measured.

suggestion: use rpmPin as the name of pin.

which means this:

attachInterrupt(0, rpm_fun, RISING); half_revolutions = 0;

should be this:

attachInterrupt(digitalPinToInterrupt(rpmPin), rpm_fun, RISING); half_revolutions = 0;

In the loop() you have constructs like this:

    while (level, 1) {
      analogWrite(rel4, HIGH);
    }
  1. A 'while' statement like this will block the loop. An 'if' statement might be nearer to what you want to do.
  2. Use digitalWrite instead of analogWrite if you are going to power a relay (module).

To make it easy for people to help you please modify your post and use the code button </>
codeButton.png

so your code looks like this

and is easy to copy to a text editor. See How to use the Forum

The code in this link is derived from a program I use to control the speed of a small DC motor.

...R

Okay thaks for all help! :slight_smile:
Now it looks like this so ill try it later and se how it works.

void setup() {

pinMode(2, INPUT);
pinMode(3, INPUT);
pinMode(A0, OUTPUT);
pinMode(A1, OUTPUT);
pinMode(A2, OUTPUT);
pinMode(A3, OUTPUT);
pinMode(A4, OUTPUT);

}

int rpmPin = 2;
int level = 3;
int rel1 = A0;
int rel2 = A1;
int rel3 = A2;
int rel4 = A3;
int rel5 = A4;

volatile byte half_revolutions; 
unsigned int rpm;
unsigned long timeold;
void setup()
{ 
Serial.begin(9600); 
attachInterrupt(digitalPinToInterrupt(rpmPin), rpm_fun, RISING); half_revolutions = 0; 
rpm = 0;
timeold = 0; 
} 
void loop()
{
if (half_revolutions >= 20) { 
//Update RPM every 20 counts, increase this for better RPM resolution, //decrease for faster update
rpm = 30*1000/(millis() -
timeold)*half_revolutions;
timeold = millis();
half_revolutions = 0; 
Serial.println(rpm,DEC);

if(rpmPin > 995){
analogWrite(rel1, HIGH);
analogWrite(rel2, HIGH);
}

if(rpmPin, < 1005){
analogWrite(rel3, HIGH);
analogWrite(rel4, HIGH);
}
if(level, 1){
analogWrite(rel5, HIGH);
}

}
} 
void rpm_fun()
{ 
half_revolutions++; 
//Each rotation, this interrupt function is run twice
}

OK. Come back when you have got this to compile and can format the code as suggested above.

Why are you using analogWrite() to turn a pin on or off?

Why are you using analogWrite() on pins that do not support PWM?

rpm = 30*1000/(millis() -
timeold)*half_revolutions;

You

need

to

get

your

enter

key

fixed!

if(rpmPin, < 1005){
if(level, 1){

What have you been smoking?

Thanks for help I got a few errors i think i fixed or made wors but now it says ‘rpmpin’ was not declared in this scope.

attachInterrupt(digitalPinToInterrupt(rpmpin); rpm_fun, RISING);

This it the program now

void setup() {

pinMode(2, INPUT);
pinMode(3, INPUT);
pinMode(A0, OUTPUT);
pinMode(A1, OUTPUT);
pinMode(A2, OUTPUT);
pinMode(A3, OUTPUT);
pinMode(A4, OUTPUT);



int rpmpin = 2;
int level = 3;
int rel1 = A0;
int rel2 = A1;
int rel3 = A2;
int rel4 = A3;
int rel5 = A4;

volatile byte half_revolutions; 
unsigned int rpm;
unsigned long timeold;

void loop(){

Serial.begin(9600); 
attachInterrupt(digitalPinToInterrupt(rpmpin); rpm_fun, RISING); half_revolutions = 0; 
rpm = 0;
timeold = 0; 

} 


if (half_revolutions >= 20) { 
//Update rpm every 20 counts, increase this for better rpm resolution, //decrease for faster update
rpm = 30*1000/(millis() -
timeold)*half_revolutions;
timeold = millis();
half_revolutions = 0; 
Serial.printIn(rpm,DEC);

if(rpmpin > 995){
analogWrite(rel1, HIGH);
analogWrite(rel2, HIGH);
}

if(rpmpin, < 1005){
analogWrite(rel3, HIGH);
analogWrite(rel4, HIGH);
}
if(level, 1){
analogWrite(rel5, HIGH);
}

} 
void rpm_fun() { 
half_revolutions++; 
//Each rotation, this interrupt function is run twice//
}

Vicke:
Thanks for help I got a few errors i think i fixed or made wors but now it says 'rpmpin' was not declared in this scope.

That's because you are defining your variables inside the setup() function. You should define them outside any function if you want them to be visible everywhere.

...R

I’ve made just enough changes so it compiles, but it certainly will not produce any valid results.
You have to address the points made above including using digitalWrite() etc. then you have to add some Serial.print() statements to see what values you are getting for the main variables with the photo transistor correctly wired up to pin 2.

int rpmpin = 2;
int level = 3;
int rel1 = A0;
int rel2 = A1;
int rel3 = A2;
int rel4 = A3;
int rel5 = A4;
volatile byte half_revolutions;
unsigned int rpm;
unsigned long timeold;


void setup() {

  pinMode(rpmpin, INPUT);
  pinMode(3, INPUT);
  pinMode(A0, OUTPUT);
  pinMode(A1, OUTPUT);
  pinMode(A2, OUTPUT);
  pinMode(A3, OUTPUT);
  pinMode(A4, OUTPUT);

  Serial.begin(9600);
  attachInterrupt(digitalPinToInterrupt(rpmpin), rpm_fun, RISING); 
  half_revolutions = 0;
  rpm = 0;
  timeold = 0;
}


void loop() {

  if (half_revolutions >= 20) {
    //Update rpm every 20 counts, increase this for better rpm resolution, //decrease for faster update
    rpm = 30 * 1000 / (millis() - timeold) * half_revolutions;
    timeold = millis();
    half_revolutions = 0;
    Serial.println(rpm, DEC);

    if (rpm > 995) {
      analogWrite(rel1, HIGH); 
      analogWrite(rel2, HIGH);
    }

    if (rpm < 1005) {
      analogWrite(rel3, HIGH);
      analogWrite(rel4, HIGH);
    }
    if (level, 1) {  
      analogWrite(rel5, HIGH);
    }
  }
}

void rpm_fun() {
  half_revolutions++;
  //Each rotation, this interrupt function is run twice//
}

Vicke, can you clarify what your relays are supposed to do?

The way your pseudocode is written relays 3 & 4 will turn on immediately (unless the RPM of whatever is being measured is >= 1005 when the Arduino boots) and will never be turned off.

Similarly, if the RPM exceeds 995 relays 1 and 2 will turn on and never turn off.

What is this supposed to be doing?

Thanks ill try it when i get of work.
They should all be off while rpm is 995-1005 i got the <> wrong.
It is a dc motor that shuld adjust a nozzle when the rpm gets eighter to low or to high then the nozzle should just rest in that possition until the rpm is outside given values again.

Hi,
Can I suggest you forget all about relay control in your code for the time being and just write code that has ONLY basic TACHO code working?

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

Thanks.. Tom.. :slight_smile:

Compiles but not tested. Uses a different method to compute RPM.

#define R12_SETPOINT    995.0
#define R12_LOWHYST     1.5
#define R12_HIGHHYST    1.5

#define R34_SETPOINT    1005.0
#define R34_LOWHYST     1.5
#define R34_HIGHHYST    1.5

const byte pinRPM = 2;
const byte pinLevel = 3;
const byte pinRelay1 = A0;
const byte pinRelay2 = A1;
const byte pinRelay3 = A2;
const byte pinRelay4 = A3;
const byte pinRelay5 = A4;

unsigned long 
    timerEdgeTimeout;
    
//volatile unsigned long
//    periodRPM;
volatile bool
    bFirstFlag;
//    bNewPeriodAvailable;
float
    lastRPM,
    rpm;
    
void setup() 
{
    pinMode(pinRPM, INPUT);
    pinMode(pinLevel, INPUT);
    pinMode(pinRelay1, OUTPUT);
    pinMode(pinRelay2, OUTPUT);
    pinMode(pinRelay3, OUTPUT);
    pinMode(pinRelay4, OUTPUT);
    pinMode(pinRelay5, OUTPUT);

    Serial.begin(9600); 
    attachInterrupt( digitalPinToInterrupt(pinRPM), rpm_fun, RISING ); 

    bFirstFlag = true;
    rpm = 0.0;
    lastRPM = -1.0;   
    
}//setup 

void loop()
{
    if( !CheckRPMTimeout() )
        rpm = 0.0;

    if( rpm != lastRPM )
    {
        Serial.print( "RPM: " ); Serial.println( rpm,2 );
        lastRPM = rpm;
        updateRelays( rpm );
    
    }//if
    
}//loop 

//////////////////////////////////////////////////////////////////////////////////////
// CheckRPMTimeout
//////////////////////////////////////////////////////////////////////////////////////
bool CheckRPMTimeout( void )
{
    //at just two pulses per revolution, sensing super-slow angular velocity
    //is tricky
    //  - 10rpm     --> 6-secs/rev; 3 seconds per pulse     *** use this limit
    //  - 1rpm      --> 60-secs/rev; 30-seconds per pulse
    //  - 0.1rpm    --> 600-secs/rev; 300-seconds per pulse
    //  - if time between pulses indicates <10rpm set first flag
    if( (millis() - timerEdgeTimeout) >= 3000 )
    {
        noInterrupts();
        bFirstFlag = true;
        interrupts();

        return false;
        
    }//if
    
    return true;
    
}//CheckRPMTimeout

//////////////////////////////////////////////////////////////////////////////////////
// updateRelays
//////////////////////////////////////////////////////////////////////////////////////
void updateRelays( float w )
{
    byte
        lvl;
    static byte
        last_level = -1;
    static bool
        stateR12 = false,
        stateR34 = false;

    //relay5 does ???? Let it follow the "level" input
    lvl = digitalRead( pinLevel );
    if( lvl != last_level )
    {
        Serial.print( "Relay 5 " );
        last_level = lvl;
        if( lvl )
        {
            digitalWrite( pinRelay5, HIGH );
            Serial.println( "on." );
            
        }//if
        else
        {
            digitalWrite( pinRelay5, LOW );
            Serial.println( "off." );
                        
        }//else
        
    }//if
    
    if( w <= 10 )
    {
        Serial.println( "All relays off." );
        digitalWrite( pinRelay1, HIGH );
        digitalWrite( pinRelay2, HIGH );
        digitalWrite( pinRelay3, HIGH );
        digitalWrite( pinRelay4, HIGH );

        return;
        
    }//if

    switch( stateR12 )
    {
        case    false:
            if (w <= (R12_SETPOINT - R12_LOWHYST) )
            {
                Serial.println( "Relays 1/2 on." );
                digitalWrite( pinRelay1, HIGH );
                digitalWrite( pinRelay2, HIGH );
                stateR12 = true;
                
            }//if
                        
        break;
        case    true:
            if (w >= (R12_SETPOINT + R12_HIGHHYST) )
            {
                Serial.println( "Relays 1/2 off." );
                digitalWrite( pinRelay1, LOW );
                digitalWrite( pinRelay2, LOW );
                stateR12 = false;
                
            }//if
        break;
                                
    }//switch R12

    switch( stateR34 )
    {
        case    false:
            if (w >= (R34_SETPOINT - R34_HIGHHYST) )
            {
                Serial.println( "Relays 3/4 on." );
                digitalWrite( pinRelay3, HIGH );
                digitalWrite( pinRelay4, HIGH );
                stateR34 = true;
                
            }//if
                        
        break;
        case    true:
            if (w <= (R34_SETPOINT + R34_LOWHYST) )
            {
                Serial.println( "Relays 3/4 off." );
                digitalWrite( pinRelay3, LOW );
                digitalWrite( pinRelay4, LOW );
                stateR34 = false;
                
            }//if
        break;
                                
    }//switch R34
    
}//updateRelays

//////////////////////////////////////////////////////////////////////////////////////
// rpm_fun
//////////////////////////////////////////////////////////////////////////////////////
void rpm_fun()
{
    unsigned long
        periodRPM;
    static unsigned long
        timelastRising = 0;
    unsigned long
        timeNow;
        
    timerEdgeTimeout = millis();
    timeNow = micros();
    if( bFirstFlag )
    {
        timelastRising = timeNow;
        bFirstFlag = false; 
        
    }//if
    else
    {
        periodRPM = timeNow - timelastRising;
        rpm = 60.0 * 1000000.0 / (2.0 * (float)periodRPM );
        timelastRising = timeNow;
    
    }//else
    
}//rpm_fun

Yes Tom i can try to do that later after work.
Black thanks i will try that also later today.
:slight_smile:

Blackfin.
Thanks for the code, i just tested it and it almost works :slight_smile:
The relay pairs (1-2 and 3-4) does not make much sens when they turn on and off.
At realy low rpm relay 1 and 2 turn on wich is good but relay 3 and 4 turn on every time something passes the phototransistor.
At little higher rpm everything is eighter on or off or blinking.
Not sure whats causing this but maby its not reading constantly and the object is passing when bot reading and it estimates some rpm or my brushless motor i use when testing is disturbing the signal.

Also the level relay5 is on all the time.

Maby i should try to find somethin else to test rpm with before searching in the code?

I am very thankful for all help i get here and it feels like we soon have this code working!
:slight_smile: :slight_smile: :slight_smile:

Rpm 0.00
Relay 5 on
All relays off
Rpm 3114.64
Relays 3/4 on
Rpm 49.99
Relays 1/2 on
Relays 3/4 off
Rpm 2937.72
Relays 1/2off
Relays 3/4on
Rpm 3046.3
Rpm 46.13
Relays 1/2 on
Relays 3/4 off
Rpm 3117.21
Relay 1/2 off
Relay 3/4 on
Rpm 0.00
All relays off
Rpm 78.96
Relays 1/2 on
Relays 3/4 off
Rpm 103
Rpm 176
Rpm214
Rpm98
Rpm352
Rpm372
Rpm141

This is what it says when slowly rising the rpm so is sems to do the right thing with wrong signal i will try something else tomorrow and hopefully it works fine :slight_smile:

Interesting.

It looks a little like the rpm input is floating or noisy. What’s driving it? Do you have the opportunity to put an oscilloscope on it?

Are you certain the sensor output is correct? That the wiring is correct?

Or have you had other code working suggesting it’s a software problem?

Hi,

Can you please post a copy of your circuit, in CAD or a picture of a hand drawn circuit in jpg, png?

How have you got the photo-transistor sensing engine rotation?

Thanks.. Tom... :slight_smile: