Newbie Coding Help For Potentiometer and DC Motor

Hi, would anyone be so kind as to help me out with the coding portion of this circuit I have made? I'm trying to get the motor to spin proportional to the value of the potentiometer. Once the potentiometer is above the value 3, I'd like volts to start kicking in and slightly powering the motor, depending on how far the potentiometer value goes. I think I started off fairly well, but then my brain crashed and I can't seem to get past this part of the code. Here is the code I have so far:

const int potPin = A0;
const int motorPin = 9;
int motorSpeed = 0;

void setup() {
  Serial.begin(9600);
  pinMode(potPin, INPUT);
  pinMode(motorPin, OUTPUT);
}

void loop() {
  int potValue = analogRead(potPin)/4;
  if (potValue > 3) {
    digitalWrite(motorSpeed);
  }
  delay(5);
  
}

My circuit:

  if (potValue > 3) {
    digitalWrite(motorSpeed);
  }

Did you mean an analogWrite to the motorPin?
But what "analogue" value to write?

@AWOL I think I'm trying to convert the values that A0 gives to Digital 9, which is supposed to gradually supply current to the motor, right? I'm not sure if my code depicts that or not, but that is how I thought it would work.

If I remember right:

When you do Analog Read function - you get a value between 0 and 1024.

So to read it as volts, you need to use the map function:

MAP

map(potValue, 1, 1024, 0, 5)

Second,

if you write digitalWrite(motorSpeed) you can be sure that it will instantly run the motor.

To run the motor smooth you must use analogWrite and a delayed for loop:

ANALOGWRITE

For example:

for( int acc = 0 ; acc < 255 ; acc = acc + 20 )
{
analogWrite(motorPin,acc);
delay(50);
}

To further simulate a good acceleration, you will have to apply a sine curve, then you would need to add math function :slight_smile: - but for beginning it should be enough.

toxicxarrow:
@AWOL I think I'm trying to convert the values that A0 gives to Digital 9, which is supposed to gradually supply current to the motor, right? I'm not sure if my code depicts that or not, but that is how I thought it would work.

Nope, voltage is not running gradually - it runs instantly. In the world of electronics that is micro seconds or even nano seconds.

Corrected bottom text

thx J-M-L :slight_smile:

Hum... @BugDee2,

you write digitalWrite(motorSpeed) you can be sure that it will instantly run the motor

No because motorSpeed is not (most of the time unless you are lucky) the PIN number connected to the mosfet

guess you meant acc not i...

for( int acc = 0 ; acc < 255 ; acc = acc + 20 )

{
  analogWrite(motorPin,i); // <== HERE
  delay(50);
}

(and obviously you would need to start from the previous value and end at the new one no 0 to 255)

Also

Also, I strongly guess that Arduino cannot fully power up the motor, because it uses a max. output of 50mA.

You would need (if your motor can draw more than 50mA) an external battery and a transistor.

==> have a look at the circuit, that’s the case. the motor is powered separately, there is a mosfet (hopefully with the right spec) controled by the arduino. There is even the freewheel/snubber diode - nice!

J-M-L:
Hum... @BugDee2,
No because motorSpeed is not (most of the time unless you are lucky) the PIN number connected to the mosfet

Yes, I should have looked the curcuit more carefully.

If I remember correct by using an analog value for a transistor can still control the voltage on the motor and this way gradually accelerating the motor.

I meant the digitalWrite was not done with a PIN number. Yes you can use PWM and a mosfet to drive your motor at various speed

@J-M-L Sorry, I'm really new to Arduino circuits and coding, and didn't exactly understand what you meant. What should I put instead of "i" in your code?

const int potPin = A0;
const int motorPin = 9;
int motorSpeed = 0;

void setup() {
  Serial.begin(9600);
  pinMode(potPin, INPUT);
  pinMode(motorPin, OUTPUT);
}

void loop() {
  int potValue = analogRead(potPin)/4;
  for( int acc = 0 ; acc < 255 ; acc = acc + 20 )
{
   analogWrite(motorPin, ???); // <== HERE
   delay(50);
}
}

I got the result I wanted by using this code with the schematic posted in my original post. Thanks for all reply's and help.

int analogInPin = A0;

int sensorValue = 0;

int outputValue = 0;

int transistorPin = 9;

void setup()  {

Serial.begin(9600);

pinMode(transistorPin, OUTPUT);

}

void loop() {

sensorValue = analogRead(analogInPin)/4;

outputValue = map(sensorValue, 0, 1023, 0, 255);

analogWrite(transistorPin, sensorValue);

delay(2);
}

If you want to gradually increase the speed, you can base your for-loop on potValue.

  for (int value = 0; value < potValue; value++)
  {
    analogWrite(motorPin, value);
    delay(50);
  }

This will slowly increase the PWM value from 0 to potValue. Next time loop() is executed, it will start again from 0 to potValue. This might not be what you want.

You can remember the previous value and only loop if it changed

void loop()
{
  // variable to remember previous potValue
  static int oldPotValue;
  // read potValue
  int potValue = analogRead(potPin) / 4;

  Serial.print("potValue = "); Serial.println(potValue);
  Serial.print("oldPotValue = "); Serial.println(oldPotValue);
  delay(2000);

  if (oldPotValue > potValue)
  {
    // slower
    ...
    ...
  }
  else if (oldPotValue < potValue)
  {
    // faster
    ...
    ...
  }
  else
  {
    // no change
  }


  oldPotValue = potValue;
  delay(5000);
}

Now you can fill in the dots. When slowing down, you start a loop starting at oldPotValue and decrementing till you reach potValue. When speeding up, you start a loop starting at oldPotValue and incrementing till you reach potValue.

The longer delays were added so you can observe the the serial output.

Full code

const int potPin = A0;
const int motorPin = 9;
int motorSpeed = 0;

void setup() {
  Serial.begin(57600);
  pinMode(potPin, INPUT);
  pinMode(motorPin, OUTPUT);
}

void loop()
{
  // variable to remember previous potValue
  static int oldPotValue;
  // read potValue
  int potValue = analogRead(potPin) / 4;

  Serial.print("potValue = "); Serial.println(potValue);
  Serial.print("oldPotValue = "); Serial.println(oldPotValue);
  delay(2000);

  if (oldPotValue > potValue)
  {
    for (int value = oldPotValue; value > potValue; value--)
    {
      Serial.println(value);
      analogWrite(motorPin, value);
      delay(50);
    }
  }
  else if (oldPotValue < potValue)
  {
    for (int value = oldPotValue; value < potValue; value++)
    {
      Serial.println(value);
      analogWrite(motorPin, value);
      delay(50);
    }
  }
  else
  {
    // nothing to do
  }

  oldPotValue = potValue;

  delay(5000);

}

Needs a bit of fine-tuning (does not reach 0, I think). Can be optimised depending on needs.

Hi

Your initial code came pretty close to working:-

Change this

void loop() {
  int potValue = analogRead(potPin)/4;
  if (potValue > 3) {
    digitalWrite(motorSpeed);
  }
  delay(5);

To

void loop() {
  int potValue = analogRead(potPin)/4;
  if (potValue > 3) {
    analogWrite(motorpin, potValue);
  }
  delay(5);

This will work, however due to the fact you are using a P-MOSFET you will find the effect will be reversed. I.E. When the potValue is low the motor will spin fast and vice versa. This is because the mosfet turns on when the voltage on the gate is low compared to the source. You would do better replacing the device with a N-MOSFET which turns on when the gate voltage is high compared to the source.

The analogWrite(outputPin, value) function produces a 980Hz square wave on the output pin where the proportion of the time the output is high varies controlled by the value you send it. A value of 0 will give you 0/255ths of the output high or always low. A value of 128 will give you 128/255ths or 50% high 50% low. A value of 255 will give 255/255ths or always high.

Your integer division of the reading from the pot wiper (range 0-1023) will give you potValue ranging between 0 and 255.

With the pot set at its lowest to start the moter (potValue = 3) that will give you 3/255ths high and 252/255ths low, meaning the the mosfet will be turned almost all the time thus applying maximum power to the motor. Change the pot to it's maximum and you get potValue = 255 and motorPin will be high 255/255ths of the time and the mosfet will be turned off all the time.

You can fix this by either switching to a N-MOSFET or changing the analogWrite line from

analogWrite(motorPin, potValue);

to

analogWrite(motorPin, (255-potValue));

By the way it is not a good idea to power the arduino from the same supply as the the motor. Motors can produce a large amount of electrical noise which can upset the arduino. Keeping the two supplies separate with a common ground keeps a lot of the noise out. Remove the link between the battery positive and +5V on the arduino and power the arduino either from the power jack or the USB port.

Hope this helps

Ian

@sterretje Very interesting, thank you for your input. It's amazing how many different ways there are to accomplish a certain task using different methods. What was the purpose of changing Serial.read to 57600?

@IanCrowe Thanks for that. I think what I really wanted is to see how the original code could be made to work, even if it's not the most "correct" way to do it; which you provided. Even then, just adding the "255-" to pot value makes it work properly!? Once I build the circuit again, I'll give it a try. Thanks for the lesson.

Sending a pulse-width-modulated signal to an inductive load like a motor is not going to work well, even with that mosfet there. Even if the programming is right, the electronics are not likely to work well.

toxicxarrow:
What was the purpose of changing Serial.read to 57600?

It's the default baudrate for realterm (one of the alternatives to serial monitor); so I have basically standardised on that.