How can I use millis() rather than dalay() in the code below?

#include <Wire.h>
#include <IRremote.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);

int RECV_PIN = 6;

IRrecv irrecv(RECV_PIN);

decode_results results;
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
byte heart[8] = {
  0b00000,
  0b01010,
  0b11111,
  0b11111,
  0b11111,
  0b01110,
  0b00100,
  0b00000
};
byte frownie[8] = {
  0b00000,
  0b00000,
  0b01010,
  0b00000,
  0b00000,
  0b00000,
  0b01110,
  0b10001
};

byte armsDown[8] = {
  0b00100,
  0b01010,
  0b00100,
  0b00100,
  0b01110,
  0b10101,
  0b00100,
  0b01010
};

byte armsUp[8] = {
  0b00100,
  0b01010,
  0b00100,
  0b10101,
  0b01110,
  0b00100,
  0b00100,
  0b01010
};
void setup() {

  irrecv.enableIRIn();
  Serial.begin(9600);
  // set up the LCD's number of columns and rows:
  lcd.begin();
  lcd.createChar(0, heart);
  lcd.createChar(2, frownie);
  // create a new character
  lcd.createChar(3, armsDown);
  // create a new character
  lcd.createChar(4, armsUp);


}

void loop() {

  if (irrecv.decode(&results)) {
    Serial.println(results.value, HEX);
    if (results.value == 0x80C) //<--Replace the new decimal value here
    {
      lcd.backlight();
    }
    else if (results.value == 0xC) {
      lcd.clear();
      lcd.noBacklight();
    }
    else if ( results.value == 0x1 || results.value == 0x801) {
      sam();
    }
    else {
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("WRONG INPUT");
    }
    irrecv.resume();
  }
}
void sam() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("some text here");
  lcd.setCursor(0, 1);
  lcd.print("some text here");
  lcd.write(byte(0));
  lcd.setCursor(14, 1);
  lcd.write(byte(0));


  int sensorReading = analogRead(A5);
  // map the result to 200 - 1000:
  int delayTime = map(sensorReading, 0, 1023, 200, 1000);
  // set the cursor to the bottom row, 5th position:
  while (results.value == 0x1 || results.value == 0x801) {
    lcd.setCursor(13, 1);
    // draw the little man, arms down:
    lcd.write(3);
    delay(delayTime);
    lcd.setCursor(13, 1);
    // draw him arms up:
    lcd.write(4);
    delay(delayTime);

  }
}
void woow() {
  lcd.clear();
  lcd.print("some text here");
}

Welcome to the forum

Thank you for using code tags but please post your complete sketch and see Using millis() for timing. A beginners guide, Several things at the same time and the BlinkWithoutDelay example in the IDE

You will need to restructure your sketch but for more advice we need to see it all

Instead of using a while loop you need to take advantage of the fact that the loop() function does what its name suggests, ie it loops

Look at the examples in the links I posted. You will see that they work by saving the value of millis() as the start time of a period. Then, each time around loop() they test whether the required period has elapsed by subtracting the current value of millis() from the saved start time and if so, the appropriate code is executed. In your case this would be to change which user defined character is printed on the LCD

This is my code after editing
the function "one" loop just one time then stop
Did I do it right?

#include <Wire.h>
#include <IRremote.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);

int RECV_PIN = 6;
unsigned long startMillis;  //some global variables available anywhere in the program
unsigned long currentMillis;
const unsigned long period = 1000;
IRrecv irrecv(RECV_PIN);

decode_results results;
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
byte heart[8] = {
  0b00000,
  0b01010,
  0b11111,
  0b11111,
  0b11111,
  0b01110,
  0b00100,
  0b00000
};
byte frownie[8] = {
  0b00000,
  0b00000,
  0b01010,
  0b00000,
  0b00000,
  0b00000,
  0b01110,
  0b10001
};

byte armsDown[8] = {
  0b00100,
  0b01010,
  0b00100,
  0b00100,
  0b01110,
  0b10101,
  0b00100,
  0b01010
};

byte armsUp[8] = {
  0b00100,
  0b01010,
  0b00100,
  0b10101,
  0b01110,
  0b00100,
  0b00100,
  0b01010
};
void setup() {

  irrecv.enableIRIn();
  Serial.begin(9600);
  // set up the LCD's number of columns and rows:
  lcd.begin();
  lcd.createChar(0, heart);
  lcd.createChar(2, frownie);
  // create a new character
  lcd.createChar(3, armsDown);
  // create a new character
  lcd.createChar(4, armsUp);
  startMillis = millis();

}

void loop() {
  currentMillis = millis();

  if (irrecv.decode(&results)) {
    Serial.println(results.value, HEX);
    if (results.value == 0x80C) //<--Replace the new decimal value here
    {
      lcd.backlight();
    }
    else if (results.value == 0xC) {
      lcd.clear();
      lcd.noBacklight();
    }
    else if ( results.value == 0x1 || results.value == 0x801) {
      if (currentMillis - startMillis >= period)  //test whether the period has elapsed
      {
        one();
        startMillis = currentMillis;
      }
    }
    else if ( results.value == 0x2 || results.value == 0x802) {
      two();
    }
    else {
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("WRONG INPUT");
    }
    irrecv.resume();
  }
}
void one() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("11111");
  lcd.setCursor(0, 1);
  lcd.print("22222");
  lcd.setCursor(12, 1);
  lcd.write(byte(0));
  lcd.setCursor(14, 1);
  lcd.write(byte(0));


  int sensorReading = analogRead(A5);
  // map the result to 200 - 1000:
  int delayTime = map(sensorReading, 0, 1023, 200, 1000);
  // set the cursor to the bottom row, 5th position:
  lcd.setCursor(13, 1);
  // draw the little man, arms down:
  lcd.write(3);
  delay(delayTime);
  lcd.setCursor(13, 1);
  // draw him arms up:
  lcd.write(4);
  delay(delayTime);
}
void two() {
  lcd.clear();
  lcd.print("333333");
}

You are moving in the right direction but still have delay()s in the one() function which will mess up any millis() timing elsewhere in the code

When you receive the command to run the one() function set a boolean to true rather than calling the function immediately

Later in loop(), outside of the switch/case, if the boolean is true then call the one() function but change it to use millis() for timing using the principles of the BlinkWithoutDelay example. Each time the period ends change the character that is displayed and save the start time. The period can be derived from the pot position

Once the signal to do something else is received then set the boolean to false to stop the one() function being called

Cut and dry un-delay

// add-a-sketch_un-delay 2018 by GoForSmoke @ Arduino.cc Forum
// Free for use, Apr 30/18 by GFS. Compiled on Arduino IDE 1.6.9.
// This sketch shows a general method to get rid of delays in code.
// You could upgrade code with delays to work with add-a-sketch.

#include <avr/io.h>
#include "Arduino.h"

const byte ledPin = 13;
unsigned long delayStart, delayWait;

void setup()
{
  Serial.begin( 115200 );
  Serial.println( F( "\n\n\n  Un-Delay Example, free by GoForSmoke\n" ));
  Serial.println( F( "This sketch shows how to get rid of delays in code.\n" ));

  pinMode( ledPin, OUTPUT );
};


/* The section of the original sketch with delays:
 * 
 * digitalWrite( ledPin, HIGH );   --  0
 * delay( 500 );
 * digitalWrite( ledPin, LOW );    --  1
 * delay( 250 );
 * digitalWrite( ledPin, HIGH );   --  2
 * delay( 250 );
 * digitalWrite( ledPin, LOW );    --  3
 * delay( 250 );
 * digitalWrite( ledPin, HIGH );   --  4
 * delay( 1000 );
 * digitalWrite( ledPin, LOW );    --  5
 * delay( 1000 );
 */

byte blinkStep; // state tracking for BlinkPattern() below

void BlinkPattern()
{
  // This one-shot timer replaces every delay() removed in one spot.  
  // start of one-shot timer
  if ( delayWait > 0 ) // one-shot timer only runs when set
  {
    if ( millis() - delayStart < delayWait )
    {
      return; // instead of blocking, the undelayed function returns
    }
    else
    {
      delayWait = 0; // time's up! turn off the timer and run the blinkStep case
    }
  }
  // end of one-shot timer

  // here each case has a timed wait but cases could change Step on pin or serial events.
  switch( blinkStep )  // runs the case numbered in blinkStep
  {
    case 0 :
    digitalWrite( ledPin, HIGH );
    Serial.println( F( "Case 0 doing something unspecified here at " ));
    Serial.println( delayStart = millis()); // able to set a var to a value I pass to function
    delayWait = 500; // for the next half second, this function will return on entry.
    blinkStep = 1;   // when the switch-case runs again it will be case 1 that runs
    break; // exit switch-case

    case 1 :
    digitalWrite( ledPin, LOW );
    Serial.println( F( "Case 1 doing something unspecified here at " ));
    Serial.println( delayStart = millis());
    delayWait = 250;
    blinkStep = 2;
    break;

    case 2 :
    digitalWrite( ledPin, HIGH );
    Serial.println( F( "Case 2 doing something unspecified here at " ));
    Serial.println( delayStart = millis());
    delayWait = 250;
    blinkStep = 3;
    break;

    case 3 :
    digitalWrite( ledPin, LOW );
    Serial.println( F( "Case 3 doing something unspecified here at " ));
    Serial.println( delayStart = millis());
    delayWait = 250;
    blinkStep = 4;
    break;

    case 4 :
    digitalWrite( ledPin, HIGH );
    Serial.println( F( "Case 4 doing something unspecified here at " ));
    Serial.println( delayStart = millis());
    delayWait = 1000;
    blinkStep = 5;
    break;

    case 5 :
    digitalWrite( ledPin, LOW );
    Serial.print( F( "Case 5 doing something unspecified here at " ));
    Serial.println( delayStart = millis());
    delayWait = 1000;
    blinkStep = 0;
    break;
  }
}


void loop()  // runs over and over, see how often
{            
  BlinkPattern();
}

1 Like

Oops! :astonished:

That is because you wait for a new IR value before doing anything. You should record the last IR value you received and repeat that until the next command comes in.

I think this will get you closer to what you want to do:

void loop()
{
  currentMillis = millis();
  static unsigned long currentCommand = 0;

  int sensorReading = analogRead(A5);
  // map the result to 200 - 1000:
  unsigned delayTime = map(sensorReading, 0, 1023, 200, 1000);

  if (irrecv.decode(&results))
  {
    Serial.println(results.value, HEX);
    currentCommand = results.value;
  }
  irrecv.resume();

  switch (currentCommand)
  {
    case 0x80C: //<--Replace the new decimal value here
      lcd.backlight();
      break;

    case 0xC:
      lcd.clear();
      lcd.noBacklight();
      break;

    case 0x1:
    case 0x801:
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("11111");
      lcd.setCursor(0, 1);
      lcd.print("22222");
      lcd.setCursor(12, 1);
      lcd.write(byte(0));
      lcd.setCursor(14, 1);
      lcd.write(byte(0));

      startMillis = currentMillis;
      currentCommand = 999;
      break;

    case 999:
      if (currentMillis - startMillis >= delayTime)  //test whether the period has elapsed
      {
        startMillis = currentMillis;
        one();
      }
      break;

    case 0x2:
    case 0x802:
      two();
      break;

    case 0: break;

    default:
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("WRONG INPUT: 0x");
      lcd.print(currentCommand, HEX)
      currentCommand = 0;
      break;
  }

}


void one()
{
  static bool armsUp = true;
  // set the cursor to the bottom row, 5th position:
  lcd.setCursor(13, 1);

  if (armsUp)
  {
    // draw the little man, arms down:
    lcd.write(3);
  }
  else
  {
    // draw him arms up:
    lcd.write(4);
  }
  armsUp = !armsUp;
}

void two()
{
  lcd.clear();
  lcd.print("333333");
}

Whoops, wrong way round, of course

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.