PWM and millis() for delay

Gentlemen,

I am a complete novice--actually I just began a few weeks ago, so please have mercy if I stumble. I have been reading pdfs on Arduino programming and acquired a Leonardo.

The problem I'm having with this sketch is as follows. Originally I had written a simple delay to offset analogWrite to pins 9 or 12, but then I discovered the benefits of using the millis() function. I changed the sketch accordingly, or so I thought. For testing purposes I have LEDs on pins 2, 6 and motors on pins 9, 12. Output of all pins are individually routed to it's own TIP120 transistor.

When it runs it alters the speed of the motor on pin 9 as expected, but I get a write delay when I change the value of pot1 that is equal to the value of pot2--precisely what I was trying to avoid by using millis() instead of delay{}.

Strange also is when pin 4 is HIGH, pot1 does not alter the speed of the motor attached to pin 12, except that when I dial it down about 1/4 the motor completely stops.

Apparently, I am not completely understanding the program flow. Can someone please provide some insight as to what is going on here?

const int kPinMotor1 = 2;

const int kPinMotor2 = 6;

const int kPinSpring1PWM = 9;

const int kPinSpring2PWM = 12;

const int kPinSwitch = 4;

void setup()

{

pinMode(kPinMotor1, OUTPUT);

pinMode(kPinMotor2, OUTPUT);

pinMode(kPinSpring1PWM, OUTPUT);

pinMode(kPinSpring2PWM, OUTPUT);

pinMode(A0, INPUT);

pinMode(kPinSwitch, INPUT_PULLUP);

}

void loop()

{

int potentioValue1 = analogRead(A0) / 4; // PWM value from 0 to 255

int potentioValue2 = analogRead(A5); // delay before writing to PWM value to pin

long currentTime = 0;

long startTime = 0;

int delay = potentioValue2;

if(digitalRead(kPinSwitch) == LOW){

currentTime = millis(); // start of button press

analogWrite(kPinSpring2PWM, 0);

digitalWrite(kPinMotor2, HIGH);

digitalWrite(kPinMotor1, LOW);

startTime = currentTime + delay; // beginning of writing to PWM pin

while (startTime > millis()){

analogRead(A0);

}

analogRead(A0);

analogWrite(kPinSpring1PWM, potentioValue1);

}

if (digitalRead(kPinSwitch) == HIGH){

currentTime = millis();

startTime = currentTime + delay;

analogWrite(kPinSpring1PWM, 0);

digitalWrite(kPinMotor1, HIGH);

digitalWrite(kPinMotor2, LOW);

while (startTime > millis()) {

analogRead(A0);

}

analogRead(A0);

analogWrite(kPinSpring2PWM, potentioValue1);

}

}

This is the same as a delay()

while (startTime > millis()){

analogRead(A0);

}


Make these unsigned long

long currentTime = 0; long startTime = 0; int delay = potentioValue2;

please have mercy if I stumble

You need a thinker (thicker, lol) skin ;)

You're doing the blink w/out delay bit wrong. What you want to do is test each time loop runs, whether it's waited long enough, and if so, then do that, and set the variables in a way that makes it clear that it doesn't need to be run again (like, you might set startTime to 0, and have your condition be (startTime>0 && millis()>startTime))

What you're doing is something that's effectively delay() - this will block until the condition is met, just like delay, and has all of the same problems:

while (startTime > millis()){

analogRead(A0);

}

Have a look at how millis() is used in the demo several things at a time

...R

LarryD: You need a thinker (thicker, lol) skin ;)

Probably, but I a veteran of ImageLine's FLStudio user's forum, and I know how litlle patience can be shown to newbies. Those guys are sometttme brutal, but overall very helpful.

LarryD: This is the same as a delay()

while (startTime > millis()){

analogRead(A0);

}


Make these unsigned long

long currentTime = 0; long startTime = 0; int delay = potentioValue2;

Why unsigned long? The values are always going to be positive from the millis(), correct? Potentiovalue2 is only 1023 ms or less also, as this is the maximum amount of time I foresee writing to the PWM pin.

So would an If() statement work to delay writing to the PWM pin? I want to be able to adjust the PWM via pot1 without having to wait another time thru the loop. When the switch first changes I need a write delay, but not all the while the switch is in that state.

lexx7887: So would an If() statement work to delay writing to the PWM pin?

See Reply #4 If there is something about the code in the link that you don't understand, tell me and I will try to explain. Much easier than re-inventing the wheel.

...R

Okay,

I’ve changed the variable type from long to unsigned long (Isee) and replaced the while( ) with if ( ), I see why the while( ) was efeectively just a delay. But now I am even more confused as to why my code doesn.t work with my new changes. The entire sketch is attached along with a rough schematic. I just want a variable delay via a potentiometer of 0-1023 ms without delaying the potentimeter for PWM. If I have the delay pot to zero, all works as intended, but if I try to dial in a delay, when the switch state changes neither motor will run. If I turn the pot back to zero the motor starts.
Here is a snippet:

unsigned long startTime = 0;

unsigned long interval = potentioValue2;

potentioValue1 = map(potentioValue1, 0, 1023, 0, 255);

if(digitalRead(kPinSwitch) == LOW){

startTime = millis();

analogWrite(kPinSpring2PWM, 0);

digitalWrite(kPinMotor2, HIGH);

digitalWrite(kPinMotor1, LOW);

if (millis() >= startTime + interval){

analogRead(A0);

analogWrite(kPinSpring1PWM, potentioValue1);

}

The project will be more complex, but I’ll have major problems if I can’t get over this simple hurdle. A litlle help?

Revision_1.ino (1.55 KB)

lexx7887: ```         if(digitalRead(kPinSwitch) == LOW){

    startTime = millis();             analogWrite(kPinSpring2PWM, 0);

    digitalWrite(kPinMotor2, HIGH);

    digitalWrite(kPinMotor1, LOW);                      if (millis() >= startTime + interval){

How many times is it necessary to suggest you study the example that does work

I am not going to re-write the working example specially for you.

In the snippet above you are saving the value of millis() and a few microseconds later you expect it to be different.

...R

Hi lex

I'm new to Arduino too however I do a lot of programming in lots of different languages, no expert but what is needed.

All languages follow the same principles with their conditional statements.

A while is basically loop while there is a certain conspdition, so you could say keep doing the next few commands if some condition is met, notice the if part so it is an if in a loop.

Your main problem seems to be nesting your if statements within each other and therefore you are not dealing with the else parts.

When you have something complex to work out this way or even before you start a project its best to get it down on paper or equivalent. I'm a computer person so prefer my documentation on the computer rather than pen and paper. A flow chart is the best method as it is full of conditional statements. There is a free piece of flow chart software that I have just started using called yed, I guess there are many others out there too. The good thing about a flowchart is that when ever you ask a question like if a is greater than b you have to take a yes or no branch which is exactly how your computer works.

If you lay out your procedures this way when you write the code it will be far easier as you will then know exactly what to put in the true part of the conditional statement and what to put in the false part.

Beware of using things like delay when you have more complex code as this will the delay the whole code. They work well when you have a simple piece of code like flashing an led as the code doesn't need to do anything else. When you need two separate delays for two different LEDs the it doesn't work so you need to somehow have a start time in a variable or equivalent and when the start time plus the time since when checking reaches the required delay you can then trigger the action.

Hope that helps.

From experience if you can work it out yourself and get help where things are wrong rather than someone do it for you , you will learn quicker. I'm the same on that side with the electronics. If someone supplies me with an answer I want to know how that answer works not just the end result.

Good luck!

Okay, I understand now, Robin, how I expected the millis() to be different a few microseconds later. Thanks for pointing that out. Somehow I thought that if miilis() was unassigned to a variable that it would maintain a running count, which it doesn’t.

I did, in fact, study your “Several Things…” sketch, but I must say that using all those callbacks doesn’t make it easy to follow. I still do not see clearly how I can translate the way you coded that to accomplish my purpose, But I did come across another of your replies to a post about resetting alarm sensors, and saw you made mention of timing libraries. It seems that others have already laid the groundwork for intricate and accurate timing of events. One in particular – elapsedMillis – seems most logical to understand and put into effect, so I think integrating that library is the direction I’ll be taking.

lexx7887: Somehow I thought that if miilis() was unassigned to a variable that it would maintain a running count, which it doesn't.

Yes it DOES - that is exactly what it is for.

The problem with your code is that you have two references to the value of millis() a few lines apart. It will only take the Arduino a number microseconds to do those few lines so there will not have been time for millis() to change - it only changes after 1000 microsecs.

All I can suggest is reading through several things at a time several more times. If you have a specific question about how it works I will be try to answer.

Think of the process like this pseudo code

void loop() {

   if (toastStart == true && toasterRunning == false) {
      toasterStartedMillis = millis()
      switchToasterOn();
      toasterRunning = true
   }

   if (currentMillis - toasterStartedMillis >= toastCookTimeMillis) {
     switchToasterOff();
     toasterRunning = false;
   }
}

...R

Note also that Robin2 is using subtraction in the test.

if (millis() >= startTime + interval){

This will cause errors if/when millis() rolls over. It is also bad practice to use the live value of millis() in your tests, because it will change during the program. If you only do one test, it is OK, but as soon as more than one program function depends on this, you can run into problems.

Better to start by storing millis() into a variable at the top of that section of program, then use that variable in all of your if statements.

Here I've incorporated several improvements: 1. Using currentMillisn += intervaln as suggested to avoid accumulation of timing errors. 2. Unsigned Long variables to match millis() and micros() datatypes. 3. Storing the value of millis() in a variable to prevent problems caused by it changing during the program run. 4. Using subtraction in logical tests to avoid problems with rollover of millis().

/* Blink Four LEDs Without Delay
  Adapted from Blink Without Delay
  by Steven J Greenfield, aka Polymorph
  Use however you like.
  
  LEDs can blink asynchronously without worrying about what rate any other LEDs
  or events are happening. In addition, any errors in timing due to other code
  and events is noncumulative, unlike using delay().
  ledPinn is a byte because it doesn't need more than what a byte will hold.
  ledStaten is a boolean because it will only be HIGH or LOW, although each variable still
  takes up a byte.
  previousMillisn and currentMillis must be unsigned long to prevent rollover errors,
  as millis() is an unsigned long.
  intervaln could be a smaller datatype, depending on the maximum length of time
  in milliseconds between events. An unsigned int, for example, uses only two bytes
  but can be used for a delay up to 65,535 milliseconds.
  This can undoubtedly be improved by using arrays for storing ledPin, ledState,
  interval, and previousMillis.
  
  Rather than using previousMillisn = currentMillis, which can cause the accumulation of
  timing errors, I'm using previousMillisn += intervaln (where n is the number of the 
  output)
*/


// constants won't change. Used here to 
// set pin numbers:
const byte ledPin0 =  2;      // the number of the LED0 pin
const byte ledPin1 =  3;      // the number of the LED1 pin
const byte ledPin2 =  4;      // the number of the LED2 pin
const byte ledPin3 =  5;      // the number of the LED3 pin

// Variables will change:
boolean ledState0 = LOW;             // ledState used to set the LED0
boolean ledState1 = LOW;             // ledState used to set the LED1
boolean ledState2 = LOW;             // ledState used to set the LED2
boolean ledState3 = LOW;             // ledState used to set the LED3

unsigned long previousMillis0 = 0;        // will store last time LED0 was updated
unsigned long previousMillis1 = 0;        // will store last time LED1 was updated
unsigned long previousMillis2 = 0;        // will store last time LED2 was updated
unsigned long previousMillis3 = 0;        // will store last time LED3 was updated

// the follow variables is a long because the time, measured in milliseconds,
// will quickly become a bigger number than can be stored in an int.
unsigned long interval0 = 1000;           // interval at which to blink LED0 (milliseconds)
unsigned long interval1 = 457;           // interval at which to blink LED1 (milliseconds)
unsigned long interval2 = 1020;           // interval at which to blink LED2 (milliseconds)
unsigned long interval3 = 742;           // interval at which to blink LED3 (milliseconds)

void setup() {
  // set the digital pin as output:
  pinMode(ledPin0, OUTPUT);    
  pinMode(ledPin1, OUTPUT); 
  pinMode(ledPin2, OUTPUT); 
  pinMode(ledPin3, OUTPUT);   
}

void loop()
{
  // here is where you'd put code that needs to be running all the time.

  // check to see if it's time to blink the LED; that is, if the 
  // difference between the current time and last time you blinked 
  // the LED is bigger than the interval at which you want to 
  // blink the LED.

  // save the current time so it doesn't change during an operation
  unsigned long currentMillis = millis();

  // LED0 
  if(currentMillis - previousMillis0 > interval0) {
    // save the last time you blinked the LED0 
    previousMillis0 += interval0;      // Timing errors no longer accumulate as compared
                              // to using  previousMillis0 = currentMillis

    // if the LED is off turn it on and vice-versa:
    if (ledState0 == LOW)
      ledState0 = HIGH;
    else
      ledState0 = LOW;
  }

  //LED1
  if(currentMillis - previousMillis1 > interval1) {
    // save the last time you blinked the LED1 
    previousMillis1 += interval1;   

    // if the LED is off turn it on and vice-versa:
    if (ledState1 == LOW)
      ledState1 = HIGH;
    else
      ledState1 = LOW;
  }

  //LED2
  if(currentMillis - previousMillis2 > interval2) {
    // save the last time you blinked the LED2 
    previousMillis2 += interval2;   

    // if the LED is off turn it on and vice-versa:
    if (ledState2 == LOW)
      ledState2 = HIGH;
    else
      ledState2 = LOW;
  }

  //LED3
  if(currentMillis - previousMillis3 > interval3) {
    // save the last time you blinked the LED3 
    previousMillis3 += interval3;   

    // if the LED is off turn it on and vice-versa:
    if (ledState3 == LOW)
      ledState3 = HIGH;
    else
      ledState3 = LOW;
  }
    // set the LEDs with the ledStates of the variable:
    digitalWrite(ledPin0, ledState0);
    digitalWrite(ledPin1, ledState1);
    digitalWrite(ledPin2, ledState2);
    digitalWrite(ledPin3, ledState3);

  
}

I rediscovered my original post by happenstance after losing my bookmark and almost cross-posting in the Programming section. Actually, I probably should have posted this there instead, come to think of it.

I think using timing libraries like elapsedMillis is the way to go for newbies (real ones), because it eliminates or replaces extraneous variables and arithmetic. That being said, my efforts to use it have still not come to fruition.

Problem is, Robin et. al., is that I am not toggling LEDs or I suppose more specifically, delaying a digitalWrite. My project will not even use an LED except to indicate ‘power-on’, and I have not problem with that. The "LED"s are there in lieu of 5V fans which I will turn either on or off with no speed control necessary, and the “motors” are there in lieu of nitinol springs which I will vary the PWM during their activation. I can just switch out components out later once I have the sketch running properly. The reason I need a delay, possibly, before writing to a PWM pin is to allow the spring to adequately cool before it is stretched by the opposing one.

All that being said, I think there is something inherent with using millis() or even elapsedMillis() when dealing with PWM, because every configuration I tried ends up with the same unsatisfactory result. Any millis() or elapsedMillis() delay I used, if greater than zero, resulted in no output to my PWM pins. I cannot find a single example via timer delaying of writing to a PWM pin. Excuse me if I’m wrong–I’ve
tried everything I can think of but nothing works. I can vary the delay to digitalWrite , no problem.

I revised the original sketch, but it functions the same as before. After days of banging my head on the wall with this, today I decided to try two separate timers initialized locally to each switch state. So why can’t I dial in a delay?

Revision_4.ino (1.42 KB)

I'm really struggling to understand what you're trying to achieve. I wonder why you are using PWM at all if you're also inserting a delay in there?

You do realise that if you write PWM then the PWM signal continues to flow from that point on until you do something to change it?

lexx7887: Problem is, Robin et. al., is that I am not toggling LEDs or I suppose more specifically, delaying a digitalWrite. My project will not even use an LED except to indicate 'power-on', and I have not problem with that. The "LED"s are there in lieu of 5V fans which I will turn either on or off with no speed control necessary, and the "motors" are there in lieu of nitinol springs which I will vary the PWM during their activation. I can just switch out components out later once I have the sketch running properly. The reason I need a delay, possibly, before writing to a PWM pin is to allow the spring to adequately cool before it is stretched by the opposing one.

All that being said, I think there is something inherent with using millis() or even elapsedMillis() when dealing with PWM, because every configuration I tried ends up with the same unsatisfactory result. Any millis() or elapsedMillis() delay I used, if greater than zero, resulted in no output to my PWM pins. I cannot find a single example via timer delaying of writing to a PWM pin. Excuse me if I'm wrong--I've tried everything I can think of but nothing works. I can vary the delay to digitalWrite , no problem.

I revised the original sketch, but it functions the same as before. After days of banging my head on the wall with this, today I decided to try two separate timers initialized locally to each switch state. So why can't I dial in a delay?

We seem to be making no progress here.

Why don't you forget about code for a few minutes and just describe what your project is intended to do and describe it using the external devices that you intend to use, not substitutes such as LEDs.

...R

Robin2:
We seem to be making no progress here.

Why don’t you forget about code for a few minutes and just describe what your project is intended to do and describe it using the external devices that you intend to use, not substitutes such as LEDs.

…R

\

I thought I already did just that. I am using the LED instead of the 5V fans, because all I need to know is if they are on of off. I am using 12V motors instead of the nitinol springs, because I don’t want to stress the springs unnecessarily until I know the code is correct. The circuit will operate the same, so this is the best setup for testing.

I want to digitalWrite to two pins alternately and analog write to two pins alternately with a variable delay between the digital and analogWrite. I want a variable delay before analogWrite --that gives extra time for a 5V fan to cool the spring that was just activated in the previous cycle and contracted by PWM. The opposing spring that will be activated after the delayt will stretch the former spring. If the spring is not cool enough, it won’t relax–it’s made of nitinol(nickel titanium) a shape-memory alloy.

Basically, I just need a delay between the fan activation and the spring activation that will vary dependent upon other sensor input which will be used in a calculation to determine an adequate delay before an analogWrite to the opposing spring. I am just using a potentiometer on A5 in the meantime to simulate whatever delay other variables will determine.

The opposing spring must be cool enough and the activating spring must not be overly heated. For example, once the spring starts moving, it has reached transformation temp and heating it further will not speed up the process of contraction, so I plan to substitute the control pot on A0 with an algorithm that drops the PWM duty cycle sharply to a level that maintains a temp just above it’s transformation temp. That will conserve energy and also allow for faster cooling and recovery, the cycle can be repeated faster.

If I can get the code to work as depicted, it will work as I intend with slight modification. I atttached the schematic before–here it is again. I want a variable delay before analogWrite that does not affect varying the duty cycle of the PWM subsequently. The schematic is as close of a representation as I can provide given the limitations of the app it was done on.

By the way, I’m doing all of this, coding the sketches and uploading with only an Android phone and/or MK809IV Android stick, so everything is limited. I would like to write feedback via a serial monitor into my sketches so I could see what was going on, but integrating serial monitor capability with ArduinoDroid correctly is a whole other issue.

So here's my problem. Your potentiometer is giving you the value for your DELAY before you make an analog write. but WHAT value do you use in your analog write? If it's the same value as you used the last time around you are effectively not doing anything because, that analog output is already PWMing away to the tune you last gave it.

Am I correct to think that the structure of the program should be like this

make digital pin X high delay(M) make digitaal pin Y high delay(N) start pwm on pin K delay(P) stop pwm on pin K delay(R) start pwm on pin L delay(S) stop pwm on pin L delay(T)

repeat indefinitely.

...R