Multiple PWM values based on digital inputs

Hi,

I hope somebody may be able to give me a push in the right direction. It's my first go at programming (bar a little html and BBC Basic back when I was 10!)

I am trying to get a couple of PWM outputs to vary their output based on which inputs are high. By default I need a 50% duty cycle varying to 25%, 37/38%, 50%, 62/63% and 75% depending on which input is high ( Slow or Fast ) and which input direction is selected (up or down).
Below is the first code I was trying which I can get one change out of, the second code doesn't change the value at all.
I'm sure this is a very long winded way of coding it but I thought it should have worked none the less, unfortunately it doesn't! :frowning:

First attempt:

// Constants - used to set inputs or output pin numbers

const int propleft = 11;   //output variable
const int propright = 12;  //output variable
const int fast = 2;        //Input
const int slow = 3;
const int leftup = 4;
const int leftdown = 5;
const int rightup = 6;
const int rightdown = 7;
const int HeaderBack = 22;
const int HeaderForwards = 23;
const int HeaderLeft = 24;
const int HeaderRight = 25;
const int TransLeftForwards = 26;
const int TransLeftBackwards = 27;
const int TransRightForwards = 28;
const int TransRightBackwards = 29;
const int EStop = 30;

// Variables - can be changed.

// Button presses

int buttonFast = 0;
int buttonSlow = 0;
int buttonLeftUp = 0;
int buttonLeftDown = 0;
int buttonRightUp = 0;
int buttonRightDown = 0;
int buttonHeaderBack = 0;
int buttonHeaderForward = 0;
int buttonHeaderLeft = 0;
int buttonHeaderRight = 0;
int buttonTransLeftForwards = 0;
int buttonTransLeftBackwards = 0;
int buttonTransRightForwards = 0;
int buttonTransRightBackwards = 0;
int buttonEStop = 0;

int propleftamount = 127;   // mid position of valve from 0-255.
int proprightamount = 127;
int fastup = 64;
int fastdown = -64;
int slowup = 96;
int slowdown = -32;

void setup() {
 // put your setup code here, to run once:
 
// initialize serial communication at 9600 bits per second:
 Serial.begin(9600);
 
pinMode(propleft, OUTPUT);
pinMode(propright, OUTPUT);
pinMode(fast, INPUT);
pinMode(slow, INPUT);
pinMode(leftup, INPUT);
pinMode(leftdown, INPUT);
pinMode(rightup, INPUT);
pinMode(rightdown, INPUT);
pinMode(HeaderBack, INPUT);
pinMode(HeaderForwards, INPUT);
pinMode(HeaderLeft, INPUT);
pinMode(HeaderRight, INPUT);
pinMode(TransLeftForwards, INPUT);
pinMode(TransLeftBackwards, INPUT);
pinMode(TransRightForwards, INPUT);
pinMode(TransRightBackwards, INPUT);
pinMode(EStop, INPUT);

}

void loop() {
 // put your main code here, to run repeatedly:
 
buttonFast = digitalRead(fast);
buttonSlow = digitalRead(slow);
buttonLeftUp = digitalRead(leftup);
buttonLeftDown = digitalRead(leftdown);
buttonRightUp = digitalRead(rightup);
buttonRightUp = digitalRead(rightdown);
 
analogWrite(propleft, propleftamount);
analogWrite(propright, proprightamount);

if(digitalRead(fast) == HIGH && digitalRead(leftup) == HIGH) {
 propleftamount = 191 ;
}
else
{ propleftamount = 127 ; }
if ((fast == 1) && (leftdown == 1)) {
 propleftamount = 63 ;
}
//if ((slow == HIGH) && (leftup == HIGH)); {
//  propleftamount = +31 ;
//}
//if ((slow == HIGH) && (leftdown == HIGH)); {
//  propleftamount = -31 ;
//}

// print out the state of the button:
 Serial.println(buttonFast);
 Serial.println(buttonSlow);
 Serial.println(buttonLeftUp);
 Serial.println(buttonLeftDown);
 Serial.println(propleftamount);
 delay(1);        // delay in between reads for stability
}

Second Attempt:

// Constants - used to set inputs or output pin numbers

const int propleft = 11;   //output variable
const int propright = 12;  //output variable
const int fast = 2;        //Input
const int slow = 3;
const int leftup = 4;
const int leftdown = 5;
const int rightup = 6;
const int rightdown = 7;
const int HeaderBack = 22;
const int HeaderForwards = 23;
const int HeaderLeft = 24;
const int HeaderRight = 25;
const int TransLeftForwards = 26;
const int TransLeftBackwards = 27;
const int TransRightForwards = 28;
const int TransRightBackwards = 29;
const int EStop = 30;

// Variables - can be changed.

// Button presses

int buttonFast = 0;
int buttonSlow = 0;
int buttonLeftUp = 0;
int buttonLeftDown = 0;
int buttonRightUp = 0;
int buttonRightDown = 0;
int buttonHeaderBack = 0;
int buttonHeaderForward = 0;
int buttonHeaderLeft = 0;
int buttonHeaderRight = 0;
int buttonTransLeftForwards = 0;
int buttonTransLeftBackwards = 0;
int buttonTransRightForwards = 0;
int buttonTransRightBackwards = 0;
int buttonEStop = 0;

int propleftamount = 127;   // mid position of valve from 0-255.
int proprightamount = 127;
int fastup = 64;
int fastdown = -64;
int slowup = 96;
int slowdown = -32;

void setup() {
 // put your setup code here, to run once:
 
// initialize serial communication at 9600 bits per second:
 Serial.begin(9600);
 
pinMode(propleft, OUTPUT);
pinMode(propright, OUTPUT);
pinMode(fast, INPUT);
pinMode(slow, INPUT);
pinMode(leftup, INPUT);
pinMode(leftdown, INPUT);
pinMode(rightup, INPUT);
pinMode(rightdown, INPUT);
pinMode(HeaderBack, INPUT);
pinMode(HeaderForwards, INPUT);
pinMode(HeaderLeft, INPUT);
pinMode(HeaderRight, INPUT);
pinMode(TransLeftForwards, INPUT);
pinMode(TransLeftBackwards, INPUT);
pinMode(TransRightForwards, INPUT);
pinMode(TransRightBackwards, INPUT);
pinMode(EStop, INPUT);

}

void loop() {
 // put your main code here, to run repeatedly:
 
buttonFast = digitalRead(fast);
buttonSlow = digitalRead(slow);
buttonLeftUp = digitalRead(leftup);
buttonLeftDown = digitalRead(leftdown);
buttonRightUp = digitalRead(rightup);
buttonRightUp = digitalRead(rightdown);
 
analogWrite(propleft, propleftamount);
analogWrite(propright, proprightamount);

// Proportional LEFT

if(digitalRead(fast) == HIGH && digitalRead(leftup) == HIGH)
{ propleftamount = 191 ; }
else
{ propleftamount = 127 ; }

if(digitalRead(fast) == HIGH && digitalRead(leftdown) == HIGH)
{ propleftamount = 63 ; }
else
{ propleftamount = 127 ; }

if(digitalRead(slow) == HIGH && digitalRead(leftup) == HIGH)
{ propleftamount = 159 ; }
else
{ propleftamount = 127 ; }

if(digitalRead(slow) == HIGH && digitalRead(leftup) == HIGH)
{ propleftamount = 95 ; }
else
{ propleftamount = 127 ; }

// Proportional RIGHT

if(digitalRead(fast) == HIGH && digitalRead(rightup) == HIGH)
{ proprightamount = 191 ; }
else
{ proprightamount = 127 ; }

if(digitalRead(fast) == HIGH && digitalRead(rightdown) == HIGH)
{ proprightamount = 63 ; }
else
{ proprightamount = 127 ; }

if(digitalRead(slow) == HIGH && digitalRead(rightup) == HIGH)
{ proprightamount = 159 ; }
else
{ proprightamount = 127 ; }

if(digitalRead(slow) == HIGH && digitalRead(rightup) == HIGH)
{ proprightamount = 95 ; }
else
{ proprightamount = 127 ; }


// print out the state of the button:
 Serial.println(buttonFast);
 Serial.println(buttonSlow);
 Serial.println(buttonLeftUp);
 Serial.println(buttonLeftDown);
 Serial.println(propleftamount);
 Serial.println(proprightamount);
 delay(1000);        // delay in between reads 
}

The first attempt that did sort of work also seemed to take a long time to return to 127 when all input go back LOW even with the delay set to 1ms. Is the cycle time quite slow on Arduino's?

Many thanks in advance,

Richard

When you are not sure what you are doing keep your program as short as possible. Just have one button to start with.

That way you can more easily see where the problem is.

...R

Sorry, I can't take the time to analyze your code...

But, it looks like your basic problem is trying to write (and debug) the whole program at once. That's the most common mistake beginning programmers make. You might have multiple bugs/errors and you don't know where to look.

Start with the code for one or two buttons, and maybe just one output. When you get that working, add the code for another button, etc.

You are doing the right thing by "peeking" at your variables with Serial.print(). Sometimes it's also helpful to add little messages like "Slowing down", or "Up direction", or something to let you know if the correct part of the code is being executed, or to check if your if-statements are behaving as expected, etc.

You aren't writing any functions, but when I create a function I'll usually start with do-nothing function that sends-out a message, such as "Running Motor Left" (or whatever the function is supposed to do) and then I know my code is "getting to" to the correct function at the correct time before the function actually does anything. And, I'll leave that message in the function as I'm developing until I'm sure everything's working, then I'll "comment it out". But, it will still be there in case I want to remove the comment marks for later debugging.*

If you write one or two lines of code at a time, you'll know where to look when a problem crops-up. Of course, professional programmers write more than one or two lines of code at a time, but NOBODY writes the whole program before testing & debugging. I've been programming on & off for many years, but I'm not an expert and I only write a few lines of code at a time. (I suppose I am an expert on which lines of code to add next, and that's not always an easy thing!)

  • There are ways of making a "debug version" so you can change one debug variable/flag to turn on or turn-off the "extra" printing. I think I've done that before... I've seen that done, but I've never done it with the Arduino and I've forgotten exactly how it's done (but it shouldn't be too hard to figure out).

I did try using just the variables in the IF statements however it didn't seem to read the inputs at all then?!
Also when not debugging I set the delay to 1 which I assume should be just 1 millisecond but measuring the physical signal I found there was a delay, not changing with from LOW to HIGH inputs but after the input went LOW again.

I'll try stripping back the code and see if I can get the AnalogWrite value to change properly.
I'll also have a look at trying to get messages to display in the serial monitor, that should help make it clearer - good tip.

I take it using multiple IF statements one after the other is an ok way to do it then and won't slow the program down too much?

Thanks for your replies,

Richard

I think, it was a few days ago now, that I couldn't see the input change in the serial monitor or when physically checking the output.

I think it was this is was using:

if ((fast == 1) && (leftdown == 1)) {
  propleftamount = 63 ;
[\code]

Doh, my mistake. I actually had HIGH instead of 1 which still didn't work. I'll try again with a stripped out code and see how it goes. Thanks for your help.

Hi,
Have you got pullup or pulldown resistors on your button input pins?

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

Tom.... :slight_smile:

richardneilson:
I am trying to get a couple of PWM outputs to vary their output based on which inputs are high. By default I need a 50% duty cycle varying to 25%, 37/38%, 50%, 62/63% and 75% depending on which input is high ( Slow or Fast ) and which input direction is selected (up or down).

I would start by removing all those other pins and separating speed and directions.

// Constants - used to set inputs or output pin numbers
// Outputs
const int PropLeftPWMPin = 11;
const int PropRightPWMPin = 12;
// Inputs
const int FastButtonPin = 2;
const int SlowButtonPin = 3;
const int LeftUpPin = 4;
const int LeftDownPin = 5;
const int RightUpPin = 6;
const int RightDownPin = 7;

void setup() {
  // initialize serial communication at 9600 bits per second:
  Serial.begin(9600);

  // Outputs
  pinMode(PropLeftPWMPin, OUTPUT);
  pinMode(PropRightPWMPin, OUTPUT);
  // Inputs.
  // These buttons have extenal pull-down resistors
  pinMode(FastButtonPin, INPUT);
  pinMode(SlowButtonPin, INPUT);
  pinMode(LeftUpPin, INPUT);
  pinMode(LeftDownPin, INPUT);
  pinMode(RightUpPin, INPUT);
  pinMode(RightDownPin, INPUT);
}

void loop() {
  // Read the inputs into boolean variables
  boolean Fast = digitalRead(FastButtonPin);
  boolean Slow = digitalRead(SlowButtonPin);
  boolean LeftUp = digitalRead(LeftUpPin);
  boolean LeftDown = digitalRead(LeftDownPin);
  boolean RightUp = digitalRead(RightUpPin);
  boolean RightDown = digitalRead(RightDownPin);

  int Speed = 0;
  if (Fast)
    Speed = 64;
  else if (Slow)
    Speed = 31;

  int LeftSpeed = 127;
  if (LeftUp)
    LeftSpeed += Speed;
  else if (LeftDown)
    LeftSpeed -= Speed;

  int RightSpeed = 127;
  if (RightUp)
    RightSpeed += Speed;
  else if (RightDown)
    RightSpeed -= Speed;

  analogWrite(PropLeftPWMPin, LeftSpeed);
  analogWrite(PropRightPWMPin, RightSpeed);

  // DEBUG: Show the speeds if either changes
  static int oldLeftSpeed, oldRightSpeed;
  if (LeftSpeed != oldLeftSpeed || RightSpeed != oldRightSpeed) {
    Serial.print(LeftSpeed);
    Serial.println(RightSpeed);
    oldLeftSpeed = LeftSpeed;
    oldRightSpeed = RightSpeed;
  }
}

Thanks Tom, Pull down resisters, or lack of, were the reason behind the delay switching back.

Thanks John, that was a great help and a good introduction to using compound operators.

Delta_G, I thought (was trying) to compare the pin state from an earlier digitalRead that I assumed had been stored as a variable. I think I was have confused fast with buttonFast, or just got totally confused in general! :confused:

Thanks to everyone else for their help and hints too, much appreciated.

Richard