1

I have been using delay() as the function for my motor spinning time. However, at the same time, I need to calculate the rpm of my motor. Delay() function have to make it impossible for me to get the rpm whilst the motor spin. I have learned that I needed to use Elapsed millis as a replacement for delay() for my timing.

I have tried it and to no avail, I did not get the result in wanted. Yes, the motor spin according to the speed that I desired, however, it does not spin according to the time I wanted. It kept on spinning non-stop till I have to disconnect the power supply.

So, my question is, how do I implement the elapsed millis as my timer for my spinning motor? please, guys, help me with this... Just guide me through and give me guidance.

This is my code that I have tried using elapsed millis. Any suggestion is welcome.

#include <elapsedMillis.h>
#include <Keypad.h>
#include <Wire.h>  // Comes with Arduino IDE
#include <LiquidCrystal_I2C.h>
#include <Servo.h>
Servo myservo;
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address
elapsedMillis timeElapsed;

const byte ROWS = 4; //four rows
const byte COLS = 3; //three columns
char keys[ROWS][COLS] =
{
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};

byte rowPins[ROWS] = {9,8,7,6}; //row pinouts of the keypad (L1, L2, L3, L4)
byte colPins[COLS] = {5,4,3}; //column pinouts of the keypad (R1, R2, R3)
Keypad keypad = Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS );


void setup()
{ 

  Serial.begin(9600);
  lcd.begin(20,4);
  myservo.attach(11);

   lcd.setCursor(0,0);
  lcd.print("S=");
  lcd.setCursor(0,1);
  lcd.print("T=");
  lcd.setCursor(0,2);
  lcd.print("S=");
  lcd.setCursor(0,3);
  lcd.print("T=");
  lcd.setCursor(10,0);
  lcd.print("S=");
  lcd.setCursor(10,1);
  lcd.print("T=");
  lcd.setCursor(10,2);
  lcd.print("RPM");

}


 void loop()

{ 

  int stage1speed = getTheNumber();
  lcd.setCursor(2,0);
  lcd.print(stage1speed);
  lcd.print("sv");
  int stage1time = getTheNumber();
  lcd.setCursor(2,1);
  lcd.print(stage1time);
  lcd.print("sec");

  int stage2speed = getTheNumber();
  lcd.setCursor(2,2);
  lcd.print(stage2speed);
  lcd.print("sv");
  int stage2time = getTheNumber();
  lcd.setCursor(2,3);
  lcd.print(stage2time);
   lcd.print("sec");


  int stage3speed = getTheNumber();
  lcd.setCursor(12,0);
  lcd.print(stage3speed);
  lcd.print("sv");
  int stage3time = getTheNumber();
  lcd.setCursor(12,1);
  lcd.print(stage3time);
  lcd.print("sec");





   if ( stage1speed > 0 && stage1time > 0 && stage2speed > 0 && stage2time > 0 && stage3speed > 0 
        && stage3time > 0 )

   {

    if(timeElapsed <= 1000*stage1time)

    {

     myservo.write(stage1speed);

     }

    if(timeElapsed <= 1000*stage2time)

    {

     myservo.write(stage2speed);

     }

    if(timeElapsed <= 1000*stage3time)

    {

     myservo.write(stage3speed);

     }
  }

}



int getTheNumber()
{
    char buffer[4];
    // Input up to 3 numbers until we find a * or #
    int i=0;
    while (1)
    {
        char key = keypad.getKey();

        // If it's a number AND we have space left, add to our string
        if ('0' <= key && key <= '9' && i < 3)
        {
            buffer[i] = key;
            i++;        
        }
        // If it's a * or #, end
        else if ('#' == key && i > 0)
        {
            // Null terminate
            buffer[i] =0; 
           int value = atoi(buffer);  // Convert to an integer
            break;
        } 

    }
    return atoi(buffer);
    }
2

delay() is only the tip of the iceberg. The problem with delay() is that it is a blocking function: nothing else can be done during the delay. If you want to control your motor and at the same time be responsive to the user, you must avoid blocking your program. This means not only getting rid of delay(), but also getting rid of any blocking function.

Here your problem is on getTheNumber(). This function blocks until the user is done typing the number. Try to rewrite it in a non-blocking fashion. For example, it could return -1 on every call as long as the user is not done typing the number. On the first call after the user is done it would return the valid value. If you manage to write everything non-blocking, then you loop() will restart very often, and the program will work with no significant latency.

As for managing the servo stages, simplest thing would be to write a finite state machine. I would write it with four states: IDLE, STAGE1, STAGE2 and STAGE3. The transitions STAGE1 → STAGE2 → STAGE3 → IDLE would be time-based, using the elapsedMillis object to track the time spent in each state. The transition IDLE → STAGE1 would be triggered by the user input.

static enum { IDLE, STAGE1, STAGE2, STAGE3 } state;
switch (state) {
    case IDLE:
        if (userRequestedToStartAgain()) {
            myservo.write(stage1speed);
            state = STAGE1;
            timeElapsed = 0;
        }
        break;
    case STAGE1:
        if (timeElapsed >= stage1time) {
            myservo.write(stage2speed);
            state = STAGE2;
            timeElapsed = 0;
        }
        break;
    case STAGE2:
        if (timeElapsed >= stage2time) {
            myservo.write(stage3speed);
            state = STAGE3;
            timeElapsed = 0;
        }
        break;
    case STAGE3:
        if (timeElapsed >= stage3time) {
            myservo.write(idleValue);
            state = IDLE;
        }
        break;
}
  • Thank you sir for your suggestions... I really appreciate it. I 'll give it a try based on your suggestions.thanks so much .. – rjadkins Apr 9 '17 at 2:06
  • Sir, I have to build userRequestedToStartAgain() function?? I don't understand that..care to elaborate it for me.. – rjadkins Apr 9 '17 at 5:00
  • @rjadkins: You may consider that call to userRequestedToStartAgain() as pseudo-code. It means you have to decide when the cycle is supposed to start, presumably on the basis of some user input. Then you write the if (...) condition for the IDLE → STAGE1 transition. – Edgar Bonet Apr 9 '17 at 7:05
  • how do I do that?? I'm very confused right now. Forgive me, sir, I'm new to Arduino programming and this finite state machine is new to me. I am trying to understand the state machine. The transition from state to state really confuses me. In a typical switch statement, I understand that we can choose the cases in the switch statement, however, trying to move case to case or state to state in the switch statement is really new to me. So the transition part is a bit hard for me. Please help me, sir, trying to understand this transition. – rjadkins Apr 9 '17 at 8:01
  • @rjadkins: Then you should probably take some time to study the subject. See this Wikipedia article for a general background on the concept of FSM, and Majenko's tutorial for an introduction of the FSM as an Arduino programming technique. – Edgar Bonet Apr 9 '17 at 8:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.