Controlling a DC motor using PWM and a potentiometer

I am using a potentiometer and a PWM signal to make a variable speed DC motor. As our code works now, we have full speed forward, and variable speed backwards. The variable speed is VERY slow. We only want the motor to go forward, and a range of variable speed.

Our current code is:

int pot = 0;
int relay = 3;
int motorPin = 11;  
int val = 0;

void setup()                    // run once, when the sketch starts
{
  Serial.begin(9600);           // set up Serial library at 9600 bps
  pinMode(pot, INPUT); 
  pinMode(relay, OUTPUT);
  pinMode(motorPin, OUTPUT);
}

int getPot() {
  int v;
  v = analogRead(pot);
  v /=   4;
  v = max(v, 90);
  v = min(v, 255);
  return v;
}

int motorFoward() {
  analogWrite(motorPin, getPot());
  delayMicroseconds(250000);
  digitalWrite(motorPin, LOW);
  delayMicroseconds(250000);
  digitalWrite(relay, HIGH);
  delayMicroseconds(250000);
}

int motorBackward() {
  analogWrite(motorPin, getPot());
  delayMicroseconds(250000);
  digitalWrite(motorPin, LOW);
  delayMicroseconds(250000);
  digitalWrite(relay, HIGH);
  delayMicroseconds(250000);
}
 int value() {
  val = analogRead(pot);
  val = map(val, 90, 255, 100, 140);
  analogWrite(0, val);
  if (val = map(val, 90, 255, 100, 140))
    {
    analogWrite(motorPin, 0);
  }
  else 
  {}
  
}

void loop()                     // run over and over again
{
  value();
  motorFoward();
  motorBackward();
}

Is there anything we are doing wrong; that can be improved?

Thanks!

You should connect the pot to analog port 0; did some code tweaks

int pot = A0;            // analog ports are named An
int relay = 3;
int motorPin = 11;  

void setup()                    // run once, when the sketch starts
{
  Serial.begin(9600);           // set up Serial library at 9600 bps

  pinMode(relay, OUTPUT);
  pinMode(motorPin, OUTPUT);
}

// simplified a bit
int getPot() 
{
  int v = analogRead(pot) /4;  // makes v between 0..255
  if (v < 90) v = 90;  // 90..255
  return v;
}

// used a parameter iso internal call to potmeter
int motorFoward(int value)
{
  analogWrite(motorPin, value);  // PWM OUTPUT
  delay(250);
  digitalWrite(motorPin, LOW);
  delay(250);
  digitalWrite(relay, HIGH);
  delay(250);  // better than micros for such a long delay
}


void loop()                     // run over and over again
{
  int value = getPot();
  motorFoward(value);
}

give it a try

I tried the code but it didn't work.
When I changed the delay back to microseconds it worked the same way it did before, (full speed forward and variable speed backward). The code is much more simple, but there is still a problem with everything not going in the same direction.

Some remarks on the original code:

  • In the code of your first post the code for forwards and backwards is 100% identical except for the name. (see below)
  • 2nd I would expect somewhere in the code that the relay is set to LOW. Where/when is this done?
    Can you post the schematics wrt the relay?
int motorFoward() {
  analogWrite(motorPin, getPot());
  delayMicroseconds(250000);
  digitalWrite(motorPin, LOW);
  delayMicroseconds(250000);
  digitalWrite(relay, HIGH);  // <<<<<<<<<
  delayMicroseconds(250000);
}

int motorBackward() {
  analogWrite(motorPin, getPot());
  delayMicroseconds(250000);
  digitalWrite(motorPin, LOW);
  delayMicroseconds(250000);
  digitalWrite(relay, HIGH);  // <<<<<<<<<<<
  delayMicroseconds(250000);
}
  • I do not understand the function of this code, can you explain what it should do?
 int value() {
  val = analogRead(pot);
  val = map(val, 90, 255, 100, 140);
  analogWrite(0, val);                                  // what is on pin 0

  if (val = map(val, 90, 255, 100, 140))  // <<< Assignment not a comparison so evaluates almost always to true
    {
    analogWrite(motorPin, 0);    // stops the motor.
  }
  else // not needed ?
  {}
  
}

Finally in the loop() you alternate between forward and backwards in a very high frequency, is that what you meant to do?
or did you want something like this?

void loop()                     // run over and over again
{
  int val = analogRead(pot);
  if (val > SOMEVALUE) motorFoward();
  else motorBackward();
}

I concur, the code doesn't really make any sense.

The value function just looks like a leftover from the getpot() function. OP, appears to be trying to constrain the ADC values (normally 0-1023) to 90->255. Arduino actually has a constrain function which does this, btw.

Your motor forward and backward are doing exactly the same thing. There is no way you are getting a different action, other than a slower FORWARD speed and only because you are turning the pot to a lower value.

So, let's start at the beginning...

You are trying to control the speed of the motor using a pot in only one direction. Then why do you have motorForward and motorBackward routines?

What does the relay do?

The code is a mess and the only reason it is doing anything at all is because you are writing an uncontrolled 'something' to the motor line. It kind of looks like you were copying code from some other project and not understanding how to use it.

What you are trying to do is extremely simple (and the code you posted far too complex for that), so let us know what the relay is for and we can help.

1 Like

Here. This is just about as useless as the original code, but will actually sort of do what you want. Because we don't know what the delays and the relays are for, it makes no sense. But this code will basically read the pot value, constrain it to between 90 and 255 (which will NEVER turn off the motor, btw.) Then the motor will run at the set speed for 250 milliseconds, stop running, do nothing for 250 milliseconds, then set a relay high, do nothing for another 250 milliseconds, and then repeat. The motor will never stop running except during those delays (500 milliseconds). You will not be able to shut this off unless you unplug it.

int pot = 0;
int relay = 3;
int motorPin = 11;  
int val = 0;

void setup()                    // run once, when the sketch starts
{
  //Serial.begin(9600);           // set up Serial library at 9600 bps
//  pinMode(pot, INPUT); //don't need this
  pinMode(relay, OUTPUT);
  pinMode(motorPin, OUTPUT);
}

void getPot() {
  val = analogRead(pot);
  constrain(val,90,255); //this restricts the analog value to between 90 and 255
}

void run() {

  analogWrite(motorPin, val); //this will run the motor at the speed set by the pot value
  delay(250); //no idea why you have a delay
  digitalWrite(motorPin, LOW); //but because you pull the motor pin low, it stops after 250 milliseconds here
  delay(250); //then you delay again ??
  digitalWrite(relay, HIGH); //then you set a relay (for what purpose?)
  delay(250); //then you delay again... no idea why
}


void loop()                     // run over and over again
{
  getpot(); //get the analog value
  run(); //run the motor

}

the purpose of this code is to generate a pwm signal and use a potentiometer that changes speed of the motor in one direction smoothly. the reason that the value is set between 90 and 255 is because 0 and 255 was very choppy.

what is the syntax for constraining a pwm signal reading? analogWrite(pot) I'm not sure this is correct.

int getpot()
{
  analogRead(pot) = constrain(pot, 90, 255)
}

the value string was supposed to set the motor to stop when the signal was between 100 and 140.

the code I used was modified off of an example found on the arduino playground under DC motor control, which is why there is both forward an backward motor control, although i am not sure what it's original purpose was. The case is the same with the relay and as I am still pretty inexperienced I don't even know what it does. the code we first tried was

int motorFoward() {
  analogWrite(motorPin, getPot());
  delayMicroseconds(35000);
  digitalWrite(motorPin, LOW);
  delayMicroseconds(35000);
  digitalWrite(relay, HIGH);
  delayMicroseconds(35000);
}

int motorBackward() {
  analogWrite(motorPin, getPot());
  delayMicroseconds(35000);
  digitalWrite(motorPin, HIGH);
  delayMicroseconds(35000);
  digitalWrite(relay, LOW);
  delayMicroseconds(35000);
}

I remember that the highs and lows were inverse of each other but as far as I could see, switching them didn't make a difference in how the motor ran.
It'd be great if you could point me to a solution. thanks.

matt9522:
what is the syntax for constraining a pwm signal reading? analogWrite(pot) I'm not sure this is correct.

int getpot()

{
  analogRead(pot) = constrain(pot, 90, 255)
}

No, that's not right. analogRead returns a value equal to the sensor reading, which means you have to assign it to a variable or use it as a variable directly. The point of the constrain function is to limit what values a variable can be. Anything above 255 will be 255, and anything below 90 will be 90. The actual analogRead function will return a value of 0 to 1023, and the PWM can only take a value between 0 and 255. So, you constrain it. There is also the map() function which you could use. How these are used is detailed in the "reference" section of this website.

So:

int val = analogRead(pot);
constrain(val,90,255);

would work, or:

constrain(analogRead(pot),90,255);

But doing it the first way is best.

matt9522:
the value string was supposed to set the motor to stop when the signal was between 100 and 140.

Then in your getpot() routine, check if the val is between 100 and 140 (but this would mean the motor would run at values from 90 to 99, and 141 to 255 and only stop while it is in between 100 and 140. I think the original code was supposed to run forward for values above 140 and backwards for values below 100. So centering the pot is what stopped it. Since you are going in only one direction, change the getpot routine in my code to this:

void getPot() {
  val = analogRead(pot);
  constrain(val,90,255); //this restricts the analog value to between 90 and 255
  if(val=<90){
    val = 0
  }

}

That will stop the motor for values of 90 (or below). Since we constrained the value, 0 (potentiometer all the way to one side) becomes 90. So, your actual variable speed is now 91-255. And the motor will completely stop when you move the pot completely to one side.

Since you are not using the relay, change the run() routine to this:

void run() {

  analogWrite(motorPin, val); //this will run the motor at the speed set by the pot value

}

Or just put that one line in your loop in place of run();

Hi, i'm.sorry if i.have so many typ, i typing using a phone.
I would recommend you to use the map function

 int speedread=analogRead(pot1);
 Int speed=map(speedread,0,1023,90,255);
 AnalogWrite(motor1,speed);

This way you could use the full renge of the pot and have the motor start moving as your intended speed....
This is not a complete code so add the thing

stopping the motor isn't really a priority, the code you wrote for getpot had an error saying void was not ignored how it should be and motorForward has an error about too many arguments. As the code stands, all i want is to make everything go in one direction.

by the way, 100 and 140 are arbitrary numbers, I modified the program when I thought i needed to turn the motor off.

@retroplayer what do you mean by void run()?

matt9522:
@retroplayer what do you mean by void run()?

void run(){

}

is a function named "run" that "returns" nothing (void). A function is a collection of code wrapped together that does something. Since your code has to make decisions and branch around and do different things, you use functions to separate stuff.

int run(){

}

would also work fine, but the int means that you expected to return an int FROM the function.

Here's an example:

int getPot() 
{

  val = analogRead(pot);
  constrain(val,90,255); //this restricts the analog value to between 90 and 255
  if(val=<90){
    val = 0;
  }
  
  return val;

}

void loop(){
int newval;

newval=getpot(); //newval will now call getpot, which returns val, and assign it to newval. So newval = val

analogWrite(motorpin, newval);

}

see the difference in how I called getpot from this code and my original? This time it calls getpot() and getpot() actually is the value. I didn't do it this way before because it is not as clear for a beginner what is happening.

btw, here is the complete code with the changes I suggested you make:

int pot = 0;
int relay = 3;
int motorPin = 11;  
int val = 0;

void setup()                    // run once, when the sketch starts
{
  //Serial.begin(9600);           // set up Serial library at 9600 bps
//  pinMode(pot, INPUT); //don't need this
  pinMode(relay, OUTPUT);
  pinMode(motorPin, OUTPUT);
}

void getPot() 
{

  val = analogRead(pot);
  constrain(val,90,255); //this restricts the analog value to between 90 and 255
  if(val=<90){
    val = 0;
  }


}

void run() 
{

  analogWrite(motorPin, val); //this will run the motor at the speed set by the pot value

}


void loop()                     // run over and over again
{
  getpot(); //THIS CALLS THE FUNCTION NAMED getpot ABOVE WHICH SETS val BASED ON THE ANALOG INPUT
  run(); //THIS CALLS THE FUNCTION NAMED run ABOVE

}

The flow is controlled by "loop()." In that function, I am calling the "getpot" function. That reads the value of the potentiometer and stores it in the variable "val" after it adjusts it to 90 to 255. Then control returns back to loop where it next calls "run" which sends "val" to the analog output which runs the motor at the desired speed. Loop is called automatically over and over again, so whenever a function that is called completes, control returns to loop. and when loop runs out of stuff, it just starts over and runs it all again. It is the only function that does this. Any other functions will not do anything unless you call them.

constrain(val,90,255); //this restricts the analog value to between 90 and 255

no it does not, however

val = constrain(val,90,255); //this restricts the analog value to between 90 and 255

does work

robtillaart:

constrain(val,90,255); //this restricts the analog value to between 90 and 255

no it does not, however

val = constrain(val,90,255); //this restricts the analog value to between 90 and 255

does work

Of course... my mistake