controlling a dc motor using an H-Brige, potentiometer, and and direction button

hi all. im new to Arduino. i need a little help from the community.
i would like to know if this small program would work before i order the parts.

what im trying to achieve is controlling a dc motor using an H-Brige. A potentiometer will be used to control the speed, and a photoresistor for reading the speed. there is a pushbutton that controls the direction of the motor. eventually i will get a screen to display the speed but i first want to make sure this works.

here is my code so far.

const int potentiometerPin = 0; // potentiometerPin Pin (analog)
const int phototransistorPin = 0; // Phototransistor Pin (analog)
const int hbrigePin = 0; // the H-Brige pin (PWM)
const int directionPin = 0; // the pushbutton pin
const int cwPin = 0;
const int ccwPin = 0;
volatile int buttonState = 0; // interupt pin
int motorSpeed = 0;
bool clockwise = true;

void setup() {
Serial.begin(9600);
pinMode(directionPin, INPUT);
pinMode(potentiometerPin, INPUT);
pinMode(phototransistorPin, INPUT);
pinMode(hbrigePin, OUTPUT);
attachInterrupt(0, directionChange, CHANGE);
}

void loop() {
//set the direction of the h-brige
if(clockwise == true){
digitalWrite(cwPin, HIGH);
digitalWrite(ccwPin, LOW);
}
else if(clockwise == false){
digitalWrite(cwPin, LOW);
digitalWrite(ccwPin, HIGH);
}

int pot = analogRead(potentiometerPin);
// print the potentiometer values.
Serial.print("Potentiometer Value = ");
Serial.println(potentiometerPin);

motorSpeed = map(potentiometerPin, 0,1203, 0, 255);
// print the maped pwm motor values.
Serial.print("Motor PWM Value = ");
Serial.println(motorSpeed);
// write the values to the motor
analogWrite(hbrigePin, motorSpeed); // send PWM to H-brige
delay(1000);

analogRead(phototransistorPin);
// print the speed of the motor
Serial.println(phototransistorPin); // value 0-1023
delay(1000);
}

void directionChange() {
for (int i = motorSpeed; i <= 0; i = i - 10){
analogWrite(hbrigePin, i);
delay(10);
}
if(clockwise == true){
clockwise = false;
}
else if(clockwise == false){
clockwise = true;
}
}

Hi,
Welcome to the forum.

Please read the first post in any forum entitled how to use this forum.
http://forum.arduino.cc/index.php/topic,148850.0.html then look down to item #7 about how to post your code.
It will be formatted in a scrolling window that makes it easier to read.

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

const int potentiometerPin = 0; // potentiometerPin Pin (analog)
const int phototransistorPin = 0; // Phototransistor Pin (analog) 
const int hbrigePin = 0;  // the H-Brige pin (PWM)
const int directionPin = 0; // the pushbutton pin
const int cwPin = 0;
const int ccwPin = 0;

Giving pins no number will not help.
Have you tried "verify" in the IDE, to see if it is constructed correctly?

Do you have the hardware connected?

Thanks.. Tom.. :slight_smile:

Hmm...

The first place to start is your pin assignments:-

const int potentiometerPin = 0; // potentiometerPin Pin (analog)
const int phototransistorPin = 0; // Phototransistor Pin (analog)
const int hbrigePin = 0;  // the H-Brige pin (PWM)
const int directionPin = 0; // the pushbutton pin
const int cwPin = 0;
const int ccwPin = 0;

You have assigned them all to the same pin 0! Try the following

   // Analog inputs
const int potentiometerPin = A0; // First analog input
const int phototransistorPin = A1; // Second analog input

   // Motor control pins
const int hbrigePin = 9;  // A PWM pin
const int cwPin = 8;      // A digital pin
const int ccwPin = 7;    // A digital pin

   // The push button
const int directionPin = 2; // the pushbutton pin connected to INT0

This will assign the correct type of pin for your requirements.

In your setup you have left out the configuration for the cwPin and ccwPin. It is best not to use pinmode on analog pins. Also the recommended syntax for attachInterrupt() is to use the digitalPinToInterrupt() function so your setup() should change from this:-

  Serial.begin(9600);
  pinMode(directionPin, INPUT);
  pinMode(potentiometerPin, INPUT);
  pinMode(phototransistorPin, INPUT);
  pinMode(hbrigePin, OUTPUT);
  attachInterrupt(0, directionChange, CHANGE);

to this:-

  Serial.begin(9600);
  pinMode(directionPin, INPUT);
  pinMode(cwPin, OUTPUT);
  pinMode(ccwPin, OUTPUT);
  pinMode(hbrigePin, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(directionPin), directionChange, CHANGE);

The information page on attchInterrupt() contains the following warning:-

Note
Inside the attached function, delay() won’t work and the value returned by millis() will not increment. Serial data received while in the function may be lost. You should declare as volatile any variables that you modify within the attached function. See the section on ISRs below for more information.

Therefore you want to rethink your ISR. Your best bet is to just flip the state of clockwise in the ISR and handle changes in direction in the main loop.

Ian

thank you very much for your input. the reason i did not declare the pins is im not sure what Arduino board i will be using. would the nano work? or do i need the uno.

i also fixed the interrupt function is that what you meant by putting it all in the main?
also is there a way for the main loop to restart every time the interrupt is called?

here is the new code.

// Analog inputs
const int potentiometerPin = A0; // First analog input
const int phototransistorPin = A1; // Second analog input

  // Motor control pins
const int hbrigePin = 9;  // A PWM pin
const int cwPin = 8;      // A digital pin
const int ccwPin = 7;    // A digital pin

   // The push button
const int directionPin = 2; // the pushbutton pin connected to INT0

  // golbal variables
bool cw_rotation = true;

void setup() {
  Serial.begin(9600);
  pinMode(directionPin, INPUT);
  pinMode(cwPin, OUTPUT);
  pinMode(ccwPin, OUTPUT);
  pinMode(hbrigePin, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(directionPin), directionChange, CHANGE);
}
/* 
  button interupt. the function will change the value of cw_rotation 
  and thus change the rotation from clockwise to counter clockwise
*/
void directionChange() {
   if(cw_rotation == true){
    cw_rotation = false;
   }
   else if(cw_rotation == false){
    cw_rotation = true;
   }
}

void loop() {
  
    //set the direction of the h-brige 
   if(cw_rotation == true){
    digitalWrite(cwPin, HIGH);
    digitalWrite(ccwPin, LOW);
   }
   else if(cw_rotation == false){
    digitalWrite(cwPin, LOW);
    digitalWrite(ccwPin, HIGH);
   }

    // read the potentiometr value
  int pot = analogRead(potentiometerPin);
  Serial.print("Potentiometer Value = ");
  Serial.println(potentiometerPin);

    // map and send the motor value
  int motorSpeed = map(potentiometerPin, 0,1203, 0, 255);
  Serial.print("Motor PWM Value = ");
  Serial.println(motorSpeed);
  analogWrite(hbrigePin, motorSpeed); 
  delay(1000);
  
    // read the photoresistor value  
  float phototransistor = analogRead(phototransistorPin);
  float rpm = phototransistor;    // this value will be found experimentaly.
  Serial.println(rpm); // 0-1300 RPM
}

sketch_feb02a.ino (1.72 KB)

brcollege:
thank you very much for your input. the reason i did not declare the pins is im not sure what Arduino board i will be using. would the nano work? or do i need the uno.

i also fixed the interrupt function is that what you meant by putting it all in the main?
also is there a way for the main loop to restart every time the interrupt is called?

here is the new code.

// Analog inputs

const int potentiometerPin = A0; // First analog input
const int phototransistorPin = A1; // Second analog input

// Motor control pins
const int hbrigePin = 9;  // A PWM pin
const int cwPin = 8;      // A digital pin
const int ccwPin = 7;    // A digital pin

// The push button
const int directionPin = 2; // the pushbutton pin connected to INT0

// golbal variables
bool cw_rotation = true;

void setup() {
  Serial.begin(9600);
  pinMode(directionPin, INPUT);
  pinMode(cwPin, OUTPUT);
  pinMode(ccwPin, OUTPUT);
  pinMode(hbrigePin, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(directionPin), directionChange, CHANGE);
}
/*
  button interupt. the function will change the value of cw_rotation
  and thus change the rotation from clockwise to counter clockwise
*/
void directionChange() {
  if(cw_rotation == true){
    cw_rotation = false;
  }
  else if(cw_rotation == false){
    cw_rotation = true;
  }
}

void loop() {
 
    //set the direction of the h-brige
  if(cw_rotation == true){
    digitalWrite(cwPin, HIGH);
    digitalWrite(ccwPin, LOW);
  }
  else if(cw_rotation == false){
    digitalWrite(cwPin, LOW);
    digitalWrite(ccwPin, HIGH);
  }

// read the potentiometr value
  int pot = analogRead(potentiometerPin);
  Serial.print("Potentiometer Value = ");
  Serial.println(potentiometerPin);

// map and send the motor value
  int motorSpeed = map(potentiometerPin, 0,1203, 0, 255);
  Serial.print("Motor PWM Value = ");
  Serial.println(motorSpeed);
  analogWrite(hbrigePin, motorSpeed);
  delay(1000);
 
    // read the photoresistor value 
  float phototransistor = analogRead(phototransistorPin);
  float rpm = phototransistor;    // this value will be found experimentaly.
  Serial.println(rpm); // 0-1300 RPM
}

To answer your questions in order:-

The Uno and Nano are logically identical other than the Nano has two extra analogue inputs (A6 and A7) and the bootloader is bigger so there is about 512 bytes less of available program memory. Almost all but the very largest Uno sketches will run on a Nano.

The whole point of an interrupt is that it breaks into the main program, does what it is supposed to and then returns to main program exactly where it left off.

What you need to do is get rid of your delay(1000) statement. Your code effectively halts at this point until the delay has finished.

Your best bet is to group together all the things you only want to do once a second (that basically looks like all the Serial.print statements) and use the millis() function and a variable that records the value of millis the previous time you did an output something like this:-

     // N.B. This is psudocode i.e. just an example
     if (millis() >= oldMillis + 1000) {  // If the latest count of milliseconds is greater than the last time we printed output by more than 1000ms (i.e. 1s) print again
         Serial.print("This stuff");
         Serial.print(" that stuff ");
         Serial.println("the other stuff");
         oldMillis = millis();          // record the millisecond count when we did our latest printout
     }

This way the Uno/Nano will zip round the code rapidly only printing the output every second. Any change in state of cw_rotation will be picked up within a few hundred microseconds of the interrupt.

By the way you can replace this code in the ISR:-

   if(cw_rotation == true){
    cw_rotation = false;
   }
   else if(cw_rotation == false){
    cw_rotation = true;
   }

With this:-

   cw_rotation = !cw_rotation; // cw_rotation is assigned the inverse of cw_rotation.

Ian

Hi,
Have you been able to verify the code?

It looks like you are trying to do all your coding before trying it in the controller.
PLEASE STOP!!!

Get you hardware together and start with simple code.
First write some code to prove you can read from a potentiometer.
Then add the button and get that part working.

Second start a new fresh code to connect and test the motor driver, get it working before adding the first code.

I know it sounds long and laborious, but by taking the time to prove the various parts of your code first means that when you start to combine, you will have fewer bugs.

Also the process of writing code in stages will help you to understand the code.

We can help you write the code, but just presenting us with a mass of untried code, we still do not know what model Arduino controller you have, will only make the correcting process harder.

So connect your hardware and show us a circuit, and write a bit of code to read your potentiometer.

Sorry, but doing your build and coding in stages will help us all.

Tom… :slight_smile: