DC motor + Hall Sensor, Spin once on a push of a button

Hi there,
I need help with coding.
I am trying to control the DC motor with a push of a button to spin once and then stop at a specific position. I have an Arduino board (Wemos D1 Pro is one that I have at the moment), three magnetic hall sensors, and MOSFET to drive the motor.
H1 acts like a trigger.
H2 acts like MODE SELECTOR, On state (D3 HIGH) is SPIN ONCE mode, and
the OFF state (D3 LOW) is SPIN INFINITE mode, keep the motor running as long as the trigger is pressed.
Here is what I want:
CASE 1: SPIN ONCE MODE
In a stationary position, the gear which has a small neodymium magnet on it always rests at the position like in my image, and Hall Sensor H3 on the D2 pin is at a LOW state when the magnet is close to it. ( I am using Pulldown resistors 10K)
MODE SWITCH is at an ON state, and the D3 input is at a HIGH state, which means it is in SPIN ONCE MODE, if the H1 button is pressed either once or held pressed and D5 is at LOW, the motor will start spinning, and as it starts spinning it will change the state of a H3 to HIGH as the magnet goes far from the sensor, and keep running until the magnet on the gear reaches HALL SENSOR again, and when it does, HALL Sensor will go to LOW again and stop the motor. I repeat, no matter if the H1 is pressed once or held pressed, the motor has to stop after one rotation.

CASE 2 - SPIN INFINITE MODE
H2 is at an OFF state, and the D3 input is at a LOW state. When I press and hold the H1, the motor starts spinning and it spins as long as the button is pressed, ignoring the H3. When I release button H1, the motor should stop.
H1, H2, and H3 are the same hall sensors marked as 49E. I changed the design from switches and push buttons to hall sensors to prevent "wear off" the micro contacts.

What I have now is the code that works fine but with only 2 hall sensors, H1 for TRIGGER and H2 as MODE SELECTOR, and that runs for 700ms to spin once, but it is hard to get the motor in the exact position every time. Now I added one more sensor H3 to detect the exact position of the gear to turn off the motor, but I am stuck on the code.

I would appreciate it if someone could help with the code.

Here is my code for time-based design, but I would like to change it to work with 3 sensors and turn off the motor at the H3 position instead of time-based rotation:

//////// WIRE PIN AN COMPONENT LAYOUT /////////
#define LED_BUILTINN D4
#define MOSFET_PIN D7         // The Digital pin that attaches to the MOSFET gate, to turn it on and off.
#define TRIGGER_PIN D5       // The digital pin that attaches to the trigger pin
#define MODE_PIN D3         // The Digital pin that attaches to the SWITCH, to switch between Full auto and burst mode.



//////// CONFIG VALUES /////////
int Max_ON_Time = 700;      // The time in MS for one rotation...

//////// INTERNAL VALUES /////////
int TriggerStatus = LOW;     // The state of the trigger LOW => pressed, HIGH => Not Pressed
int TriggerReadValue = LOW;   // The value read from the digital trigger pin.
int CurrentSleepTime = 0;   // The ammount of time the mosfet has been on.

// The setup routine runs once when you press reset.
void setup() {                
  // Initialize the digital pin as an output.
  pinMode(LED_BUILTIN, OUTPUT);              // LED pin
  pinMode(MOSFET_PIN, OUTPUT);      // Set the MOSFET pin as an output so that we can send power to the MOSFET.
  pinMode(MODE_PIN, INPUT);     // The MODE SELECTOR pin
  digitalWrite(MOSFET_PIN, LOW);    // Make sure we start with power OFF!
  digitalWrite(LED_BUILTIN, LOW);    // Make sure we start with power OFF!
}

// The loop routine runs over and over again forever.
void loop() {
  ReadTrigger();                                   // Update the trigger state
  if(TriggerStatus == LOW)                         // If the trigger is pushed.
  {
    SetMosfet(HIGH);                               // First turn the Mosfet On
    while (TriggerStatus == LOW) 
    {
      int spinOnceMode = digitalRead(MODE_PIN);
      if(spinOnceMode == HIGH)                        // If the H2 has power on it it's in Spin Once mode.
      {         
        if(CurrentSleepTime < Max_ON_Time){          // If we have not completed a cycle
          CurrentSleepTime = CurrentSleepTime + 1;   // Leave the mosfet on, and increase time counter.
        } else {
          SetMosfet(LOW);                            // If a full cycle has gone, turn the Monfet Off.
        }
        delay(1);                                    // Sleep for one milisecond
      }
      ReadTrigger();                               // Update the trigger status (We stay in the loop untill the trigger is released)
    }
    SetMosfet(LOW);                                // Make sure the Mosfet is off when the trigger is released
    CurrentSleepTime = 0;                          // Reset time counter when the trigger is released.
  }
}

// This function updates the trigger status when it's called.
void ReadTrigger()
{
  int TriggerReadValue = digitalRead(TRIGGER_PIN);
    
  TriggerStatus = LOW;
  if(TriggerReadValue == HIGH) {
      TriggerStatus = HIGH;
  }
}

// This function set the Mosfet state 
void SetMosfet(int val)
{
  digitalWrite(LED_BUILTIN, val);            // turn the LED on / off to indicate what the mosfet should be dooing
  digitalWrite(MOSFET_PIN, val);    // turn the Mosfet on / off
}

Odd that on your diagram you use red for ground and black for VCC.

One obvious issue is that your inputs should all be INPUT_PULLUP in order to utilize the internal pullup resistor. This is assuming your hall effect sensor is open collector since you didn't specify a part number.

The way you have it wired when MODE SWITCH is at an ON state, the D3 input is at a LOW state.

Which Arduino are you using?

Is it just me or is some code missing?

1 Like

Yes. Code is missing.

I would recommend processing the switch and the button using StateChangeDetection and then use a State Machine to manage the motor wrt the mode.

The diagram is fixed now and the design is changed a lot, thanks for noticing it. I hope I'll get some help now :wink:

It was missing as the Anti Spam system hid my post for some time to be checked and I couldn't edit it. Now the post is edited right, there is a new diagram with 3 sensors and the changed descriptions of cases. Also, code is included but for my time-based design which I want to change.

There is code now, but also a new diagram and a new description of it. I hope this is better now.

I added a new diagram but also there are a few design changes, also complete description is changed, and now I use hall sensors as switches and there is my code for time-based design, but I want to change it to use 3 sensors instead of 2 without time base for rotation.

There is a whole new diagram now, and the design is changed. Take a look now and read the post again, I tried to explain as well as I can. Thx

Have you tested the code you have and does it work?

I have tested the code, this code does work. When I press and hold the trigger, H1 goes to LOW state, the motor rotates for 700ms, and stops. When the MODE SWITCH is in a LOW state, the motor rotates as long as I hold the trigger.

OK good. So it sounds like the hardware is working. I can help you but I'm a little pressed for time. I will post again with some suggestions.

No problem, it's not a big rush, it's just some small project for one toy that I want to make for my son. Thanks in advance.

Let's start with optimizing what you have. Look at the changes I made and make sure you understand them. Also I could have made more constants to make the code more readable but I think it is pretty readable compared to other code I have seen.

//////// WIRE PIN AN COMPONENT LAYOUT /////////
#define LED_BUILTIN D4
#define MOSFET_PIN D7         // The Digital pin that attaches to the MOSFET gate, to turn it on and off.
#define TRIGGER_PIN D5       // The digital pin that attaches to the trigger pin
#define MODE_PIN D3         // The Digital pin that attaches to the SWITCH, to switch between Full auto and burst mode.

//////// CONFIG VALUES /////////
const int Max_ON_Time = 700;      // The time in MS for one rotation...

//////// INTERNAL VALUES /////////
int CurrentSleepTime = 0;   // The ammount of time the mosfet has been on.

// The setup routine runs once when you press reset.
void setup() 
{                
  // Initialize the digital pin as an output.
  pinMode(LED_BUILTIN, OUTPUT);       // LED pin
  pinMode(MOSFET_PIN, OUTPUT);        // Set the MOSFET pin as an output so that we can send power to the MOSFET.
  pinMode(MODE_PIN, INPUT);           // The MODE SELECTOR pin
  digitalWrite(MOSFET_PIN, LOW);      // Make sure we start with power OFF!
  digitalWrite(LED_BUILTIN, LOW);     // Make sure we start with power OFF!
}

// The loop routine runs over and over again forever.
void loop() 
{
  int TriggerStatus = digitalRead(TRIGGER_PIN);    // Update the trigger state
  if(TriggerStatus == LOW)                         // If the trigger is pushed.
  {
    SetMosfet(HIGH);                               // First turn the Mosfet On
    int spinOnceMode = digitalRead(MODE_PIN);
    while (TriggerStatus == LOW) 
    {
      if(spinOnceMode == HIGH)                        // If the H2 has power on it it's in Spin Once mode.
      {         
        if(CurrentSleepTime < Max_ON_Time)
        {          // If we have not completed a cycle
          CurrentSleepTime = CurrentSleepTime + 1;   // Leave the mosfet on, and increase time counter.
        } 
        else 
        {
          SetMosfet(LOW);                            // If a full cycle has gone, turn the Monfet Off.
        }
        delay(1);                                    // Sleep for one milisecond
      }
      TriggerStatus = digitalRead(TRIGGER_PIN);        // Update the trigger state
    }
    SetMosfet(LOW);                                // Make sure the Mosfet is off when the trigger is released
    CurrentSleepTime = 0;                          // Reset time counter when the trigger is released.
  }
}

// This function set the Mosfet state 
void SetMosfet(int val)
{
  digitalWrite(LED_BUILTIN, val);            // turn the LED on / off to indicate what the mosfet should be dooing
  digitalWrite(MOSFET_PIN, val);    // turn the Mosfet on / off
}

So here is a version that works. I normally don't like to use while loops waiting for input but since it is for for a toy I can't see jumping through hoops to avoid wait loops. The risk you have with this implementation is that if you have a hardware issue the program can get "stuck". For example, a failure scenario could be that if the H3 hall effect fails to detect the magnet the motor will spin until you correct the condition or the Arduino is reset.

You can enhance the code by implementing timeouts in the wait loops using a counter or the millis() function to determine how much time has passed.

#define LED_BUILTINN D4
#define MOSFET_PIN   D7        // The Digital pin that attaches to the MOSFET gate, to turn it on and off.
#define TRIGGER_PIN  D5        // The digital pin that attaches to the trigger pin
#define MODE_PIN     D3        // The Digital pin that attaches to the SWITCH, to switch between Full auto and burst mode.
#define H3_PIN       D2        // The Digital pin that attaches to the motor Hall Effect Sensor

const int ON = HIGH;
const int OFF = LOW;

void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);     
  pinMode(MOSFET_PIN, OUTPUT);      
  pinMode(MODE_PIN, INPUT);         
  pinMode(TRIGGER_PIN, INPUT);      
  pinMode(H3_PIN, INPUT);           
  SetMosfet(OFF); // Start with motor off
}

void loop()
{
  if (digitalRead(TRIGGER_PIN) == LOW)
  {
    // Trigger pushed
    SetMosfet(ON); // Turn motor ON no matter which mode we are in 
    
    if (digitalRead(MODE_PIN) == HIGH)   // Determine the mode
    {
      // SPIN ONCE MODE
      while (digitalRead(H3_PIN) == LOW) delay(1);      // wait for spin to begin
      while (digitalRead(H3_PIN) == HIGH) delay(1);     // wait for spin to end
      SetMosfet(OFF);                                   // Turn motor OFF
      while (digitalRead(TRIGGER_PIN) == LOW) delay(1); // Wait for trigger to be released
    }
    else
    {
      // SPIN INFINITE MODE
      while (digitalRead(TRIGGER_PIN) == LOW) delay(1); // Wait for trigger to be released
      SetMosfet(OFF);                                // Turn motor OFF
    }
  }
}

// This function set the Mosfet state
void SetMosfet(int val)
{
  digitalWrite(LED_BUILTIN, val);            // turn the LED on / off to indicate what the mosfet should be dooing
  digitalWrite(MOSFET_PIN, val);    // turn the Mosfet on / off
}

Yes, this works like charm. Thank you to the moon and back. :+1:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.