Blink with millis: processor time shift?

Hello guys,

currently im working on a blink without delay sketch in combination with an LCD touchscreen.
The goal is to blinck 4 leds consecutive for the same period of time, if page 1 is the current page displayed at the screen.. Means i want to switch on the first LED at time period 0-200ms, second LED 201-400ms and so on.

The challenge is the following: If i test the sketch without Touchscreen, it works well!
Im using this one:

unsigned long previousMillis1 = 0;
unsigned long previousMillis2 = 0;
unsigned long previousMillis3 = 0;
unsigned long previousMillis4 = 0;// speichert den Zeitpunkt an dem zuletzt geschalten wurde

const long intervalon1 = 400;
const long intervaloff1 = 1200;
const long intervalon2 = 400;
const long intervaloff2 = 1200;
const long intervalon3 = 400;
const long intervaloff3 = 1200;
const long intervalon4 = 400;
const long intervaloff4 = 1200;

void setup() {
  pinMode(A1, OUTPUT); // LED 1 
  pinMode(A2, OUTPUT); // LED 1 
  pinMode(A3, OUTPUT); // LED 1 
  pinMode(A4, OUTPUT); // LED 1 
 
}

void loop(){

startventilate(); 

}
void startventilate()
{
    unsigned long currentMillis = millis();

  if(digitalRead(A1) == HIGH && currentMillis - previousMillis1 > intervalon1 ) {
     previousMillis1 = currentMillis;  
     digitalWrite(A1,LOW);
     digitalWrite(A1, digitalRead(A1));
  }
   if(digitalRead(A1) == LOW && currentMillis - previousMillis1 > intervaloff1) {
     previousMillis1 = currentMillis;  
     digitalWrite(A1,HIGH);
     digitalWrite(A1, digitalRead(A1));
  }

if(digitalRead(A2) == HIGH && currentMillis+400 - previousMillis2 > intervalon2) {
     previousMillis2 = currentMillis+400;  
     digitalWrite(A2,LOW);
     digitalWrite(A2, digitalRead(A2));
  }
   if(digitalRead(A2) == LOW && currentMillis+400 - previousMillis2 > intervaloff2) {
     previousMillis2 = currentMillis+400;  
     digitalWrite(A2,HIGH);
     digitalWrite(A2, digitalRead(A2));
  }

if(digitalRead(A3) == HIGH && currentMillis+800 - previousMillis3 > intervalon3) {
     previousMillis3 = currentMillis+800;  
     digitalWrite(A3,LOW);
     digitalWrite(A3, digitalRead(A3));
  }
   if(digitalRead(3) == LOW && currentMillis+800 - previousMillis3 > intervaloff3) {
     previousMillis3 = currentMillis+800;  
     digitalWrite(A3,HIGH);
     digitalWrite(A3, digitalRead(A3));
  }

if(digitalRead(A4) == HIGH && currentMillis+1200 - previousMillis4 > intervalon4) {
     previousMillis4 = currentMillis+1200;  
     digitalWrite(A4,LOW);
     digitalWrite(A4, digitalRead(A4));
  }
   if(digitalRead(4) == LOW && currentMillis+1200 - previousMillis4 > intervaloff4) {
     previousMillis4 = currentMillis+1200;  
     digitalWrite(A4,HIGH);
     digitalWrite(A4, digitalRead(A4));
  }
}

If we┬┤re using the same code with the TFT touchscreen and all the librarys, it does not work. What happens is, that LED1, LED2, LED3 are blinking for about 400ms and then switching for about an second off.

Do you have any idea, why this error occurs? Could it be a timing problem caused by the processor, or is there a fault in the code?

Im really looking forward to your answers mates!
best regards
Gustav

Code:

#include "Adafruit_GFX.h"     
#include "Adafruit_ILI9341.h" 
#include "URTouch.h"

#define TFT_DC 2            
#define TFT_CS 10            
#define TFT_RST 8
#define TFT_MISO 12         
#define TFT_MOSI 11           
#define TFT_CLK 13            

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);

#define t_SCK 3              
#define t_CS 4                
#define t_MOSI 5              
#define t_MISO 6             
#define t_IRQ 7    

#define BLUE 0x001F
#define GREEN 0x07E0
#define WHITE 0xFFFF
#define BLACK 0x0000
#define YELLOW 0xFFF0
#define RED 0xF800

char currentpage;
URTouch ts(t_SCK, t_CS, t_MOSI, t_MISO, t_IRQ);
int x, y;

// definition Parameter for: void startventilate
unsigned long previousMillis1 = 0;
unsigned long previousMillis2 = 0;
unsigned long previousMillis3 = 0;
unsigned long previousMillis4 = 0;
const long intervalon1 = 400;
const long intervaloff1 = 1200;
const long intervalon2 = 400;
const long intervaloff2 = 1200;
const long intervalon3 = 400;
const long intervaloff3 = 1200;
const long intervalon4 = 400;
const long intervaloff4 = 1200;

//////////////////////////////
void setup(){
  pinMode(A1, OUTPUT);
  pinMode(A2, OUTPUT);
  pinMode(A3, OUTPUT);
  pinMode(A4, OUTPUT);
  
  Serial.begin(9600);   
  tft.begin();                     
  tft.setRotation(3);           
  tft.fillScreen(ILI9341_WHITE);
  ts.InitTouch();                   
  ts.setPrecision(PREC_EXTREME);
  
currentpage = '0'; // standard starting page after booting is home screen
drawhomescreen();

}
 
void loop(){
// home screen setup 
if (currentpage == '0'){
    if(ts.dataAvailable()){       
    ts.read();                      
    x = ts.getX();                 
    y = ts.getY();                  
    
   if((x>=50) && (x<=125) && (y>=20) && (y<=60)){     // check, if click is within coordinates
    
    ventilate();
    currentpage = '1';
    }      
  }  
  }
                           
// snippet zur entl├╝ftung

if (currentpage == '1'){
  if(ts.dataAvailable()){ 
  ts.read(); 
  x = ts.getX();                 
  y = ts.getY(); 
     
         if ((x>=0) && (x<=320) && (y>=0) && (y<=240)){
         digitalWrite(A1, LOW); 
         digitalWrite(A2, LOW); 
         digitalWrite(A3, LOW); 
         digitalWrite(A4, LOW);
         
         currentpage = '2';     
     }
     }

  startventilate(); // entl├╝ftung der d├╝sen 
 
}
}

void ventilate(){
             
        tft.fillScreen(ILI9341_WHITE);
        tft.setTextColor(BLACK);
        tft.setCursor(50,20);
        tft.setTextSize(3); 
        tft.print("Einstellen");
        tft.setCursor(50,50);
        tft.setTextSize(2);
        tft.print("3,0 Bar Druck ");
        //fertig button        
        tft.fillRect (90,160,140,40, BLUE);
        tft.drawRect (90,160,140,40, WHITE);
        tft.setCursor(100,170);
        tft.setTextColor(WHITE);
        tft.setTextSize(3);
        tft.print("FERTIG"); 
}

void drawhomescreen(){
  // creating home screen
  tft.fillScreen(ILI9341_WHITE);
  tft.setTextColor(ILI9341_RED);  
  tft.setTextSize(1);               
  tft.setCursor(80,5);              
  tft.print("Duesengroesse waehlen"); 
  tft.fillRect (50,20,75,40, BLUE);
  tft.drawRect (50,20,75,40, BLACK);
  tft.setCursor(65,30);
  tft.setTextColor(WHITE);
  tft.setTextSize(3);
  tft.print("400");
  
  tft.fillRect (200,20,75,40, BLUE);
  tft.drawRect (200,20,75,40, BLACK);
  tft.setCursor(215,30);
  tft.setTextColor(WHITE);
  tft.setTextSize(3);
  tft.print("470");
  
  tft.fillRect (50,90,75,40, BLUE);
  tft.drawRect (50,90,75,40, BLACK);
  tft.setCursor(65,100);
  tft.setTextColor(WHITE);
  tft.setTextSize(3);
  tft.print("600");
  
  tft.fillRect (50,160,75,40, BLUE);
  tft.drawRect (50,160,75,40, BLACK);
  tft.setCursor(65,170);
  tft.setTextColor(WHITE);
  tft.setTextSize(3);
  tft.print("900");
  }


void startventilate(){

    unsigned long currentMillis = millis();

  if(digitalRead(A1) == HIGH && currentMillis - previousMillis1 > intervalon1 ) {
     previousMillis1 = currentMillis;  
     digitalWrite(A1,LOW);
     digitalWrite(A1, digitalRead(A1));
  }
   if(digitalRead(A1) == LOW && currentMillis - previousMillis1 > intervaloff1) {
     previousMillis1 = currentMillis;  
     digitalWrite(A1,HIGH);
     digitalWrite(A1, digitalRead(A1));
  }

if(digitalRead(A2) == HIGH && currentMillis+400 - previousMillis2 > intervalon2) {
     previousMillis2 = currentMillis+400;  
     digitalWrite(A2,LOW);
     digitalWrite(A2, digitalRead(A2));
  }
   if(digitalRead(A2) == LOW && currentMillis+400 - previousMillis2 > intervaloff2) {
     previousMillis2 = currentMillis+400;  
     digitalWrite(A2,HIGH);
     digitalWrite(A2, digitalRead(A2));
  }

if(digitalRead(A3) == HIGH && currentMillis+800 - previousMillis3 > intervalon3) {
     previousMillis3 = currentMillis+800;  
     digitalWrite(A3,LOW);
     digitalWrite(A3, digitalRead(A3));
  }
   if(digitalRead(3) == LOW && currentMillis+800 - previousMillis3 > intervaloff3) {
     previousMillis3 = currentMillis+800;  
     digitalWrite(A3,HIGH);
     digitalWrite(A3, digitalRead(A3));
  }


if(digitalRead(A4) == HIGH && currentMillis+1200 - previousMillis4 > intervalon4) {
     previousMillis4 = currentMillis+1200;  
     digitalWrite(A4,LOW);
     digitalWrite(A4, digitalRead(A4));
  }
   if(digitalRead(4) == LOW && currentMillis+1200 - previousMillis4 > intervaloff4) {
     previousMillis4 = currentMillis+1200;  
     digitalWrite(A4,HIGH);
     digitalWrite(A4, digitalRead(A4));
  }
}

Well,I thing that the used libaries are using an interrupt handling that can influence the millis() timing.

I think this statement

should be on the top level of loop, and not be controlled by

You should also use ctrl-T in the IDE to format the code,
it would make the indentation match the real nesting level.

Are you sure your original code actually does what you think it does?

if(digitalRead(A3) == HIGH && currentMillis+800 - previousMillis3 > intervalon3) {
     previousMillis3 = currentMillis+800;  
     digitalWrite(A3,LOW);
     digitalWrite(A3, digitalRead(A3));
  }
   if(digitalRead(3) == LOW && currentMillis+800 - previousMillis3 > intervaloff3) {
     previousMillis3 = currentMillis+800;  
     digitalWrite(A3,HIGH);
     digitalWrite(A3, digitalRead(A3));
  }

These are looking at different pins A3 & 3 ?

I ran your code with a couple of tweaks to see what it was actually doing..

unsigned long previousMillis1 = 0;
unsigned long previousMillis2 = 0;
unsigned long previousMillis3 = 0;
unsigned long previousMillis4 = 0;// speichert den Zeitpunkt an dem zuletzt geschalten wurde

const long intervalon1 = 400;
const long intervaloff1 = 1200;
const long intervalon2 = 400;
const long intervaloff2 = 1200;
const long intervalon3 = 400;
const long intervaloff3 = 1200;
const long intervalon4 = 400;
const long intervaloff4 = 1200;

void setup() {
  pinMode(A1, OUTPUT); // LED 1 
  pinMode(A2, OUTPUT); // LED 1 
  pinMode(A3, OUTPUT); // LED 1 
  pinMode(A4, OUTPUT); // LED 1 

  Serial.begin(9600);
}

void loop(){
delay(100);
startventilate(); 

}
void startventilate()
{
    unsigned long currentMillis = millis();
    Serial.print("Current millis: ");
    Serial.println(currentMillis);

  if(digitalRead(A1) == HIGH && currentMillis - previousMillis1 > intervalon1 ) {
     previousMillis1 = currentMillis;  
     digitalWrite(A1,LOW);
     digitalWrite(A1, digitalRead(A1));
     Serial.println("1 off");
  }
   if(digitalRead(A1) == LOW && currentMillis - previousMillis1 > intervaloff1) {
     previousMillis1 = currentMillis;  
     digitalWrite(A1,HIGH);
     digitalWrite(A1, digitalRead(A1));
      Serial.println("1 on");
  }

if(digitalRead(A2) == HIGH && currentMillis+400 - previousMillis2 > intervalon2) {
     previousMillis2 = currentMillis+400;  
     digitalWrite(A2,LOW);
     digitalWrite(A2, digitalRead(A2));
          Serial.println("2 off");
  }
   if(digitalRead(A2) == LOW && currentMillis+400 - previousMillis2 > intervaloff2) {
     previousMillis2 = currentMillis+400;  
     digitalWrite(A2,HIGH);
     digitalWrite(A2, digitalRead(A2));
          Serial.println("2 on");
  }

if(digitalRead(A3) == HIGH && currentMillis+800 - previousMillis3 > intervalon3) {
     previousMillis3 = currentMillis+800;  
     digitalWrite(A3,LOW);
     digitalWrite(A3, digitalRead(A3));
          Serial.println("3 off");
  }
   if(digitalRead(3) == LOW && currentMillis+800 - previousMillis3 > intervaloff3) {
     previousMillis3 = currentMillis+800;  
     digitalWrite(A3,HIGH);
     digitalWrite(A3, digitalRead(A3));
          Serial.println("3 on");
  }

if(digitalRead(A4) == HIGH && currentMillis+1200 - previousMillis4 > intervalon4) {
     previousMillis4 = currentMillis+1200;  
     digitalWrite(A4,LOW);
     digitalWrite(A4, digitalRead(A4));
          Serial.println("4 off");
  }
   if(digitalRead(4) == LOW && currentMillis+1200 - previousMillis4 > intervaloff4) {
     previousMillis4 = currentMillis+1200;  
     digitalWrite(A4,HIGH);
     digitalWrite(A4, digitalRead(A4));
     Serial.println("4 on");
  }
}

Here's the output...

22:26:01.615 -> Current millis: 4215
22:26:01.717 -> Current millis: 4316
22:26:01.818 -> Current millis: 4416
22:26:01.818 -> 1 on
22:26:01.818 -> 2 off
22:26:01.920 -> Current millis: 4516
22:26:01.991 -> Current millis: 4617
22:26:02.093 -> Current millis: 4717
22:26:02.229 -> Current millis: 4817
22:26:02.229 -> 1 off
22:26:02.330 -> Current millis: 4918
22:26:02.330 -> 4 on
22:26:02.398 -> Current millis: 5018
22:26:02.503 -> Current millis: 5118
22:26:02.606 -> Current millis: 5219
22:26:02.707 -> Current millis: 5319
22:26:02.707 -> 3 on
22:26:02.707 -> 4 off
22:26:02.811 -> Current millis: 5420
22:26:02.913 -> Current millis: 5520
22:26:03.015 -> Current millis: 5620
22:26:03.015 -> 2 on
22:26:03.117 -> Current millis: 5721
22:26:03.117 -> 3 off
22:26:03.218 -> Current millis: 5821
22:26:03.324 -> Current millis: 5921
22:26:03.426 -> Current millis: 6022
22:26:03.426 -> 1 on
22:26:03.426 -> 2 off
22:26:03.501 -> Current millis: 6123
22:26:03.604 -> Current millis: 6223
22:26:03.714 -> Current millis: 6424

Dear guys,

thanks for the hint with ctrl-T!

Ive tried to put the startventilate(); to the start of the loop- nothin changed.

Unfortunately startventilate(); should only run, if currentpage == '1', so i think we need the if- statement.

Ive checked the librarys and searched for delay / interrupts, but cant find anything, which could be the reason for the fault.

Do you have any other ideas?

your description above doesn't seem to match what the code does.

consider the following which simplifies the original code, avoiding redundant code.

it sequentially turns each LED on for 200 msec. but i'm not sure it does what you want either

#define MyHW
#ifdef MyHW
const byte Led1 = 10;
const byte Led2 = 11;
const byte Led3 = 12;
const byte Led4 = 13;
const byte Leds [] = { Led1, Led2, Led3, Led4 };

#else
#endif

enum { Off = HIGH, On = LOW };

const long Interval  = 200;

const byte N_LED = sizeof(Leds);
int ledIdx;

unsigned long msecLst;
unsigned long msec;

// -----------------------------------------------------------------------------
void ventilate ()
{
    if ( (msec - msecLst) > Interval)  {
        msecLst = msec;

        digitalWrite (Leds [ledIdx], Off);

        ledIdx++;
        if (N_LED <= ledIdx)
            ledIdx = 0;

        digitalWrite (Leds [ledIdx], On);
    }
}

// -----------------------------------------------------------------------------
void loop ()
{
    msec = millis ();

    ventilate ();
}

// -----------------------------------------------------------------------------
void setup ()
{
    for (unsigned n = 0; n < N_LED; n++)  {
        pinMode      (Leds [n], OUTPUT);
        digitalWrite (Leds [n], Off);
    }
}
1 Like

My implementation of the blinking would be

const uint8_t ledPins[4] = { A1, A2, A3, A4 };
const uint8_t lastIndex = sizeof(ledPins) - 1;
const uint16_t blinkDuration = 200;
uint32_t lastBlink;
uint8_t currLed = lastIndex;

void setup() {
  for (auto pin : ledPins) {
    pinMode(pin, OUTPUT);
  }
}

void loop() {
  uint32_t topLoop = millis();
  if (topLoop - lastBlink >= blinkDuration) {
    lastBlink = topLoop;
    digitalWrite(ledPins[currLed], LOW);  // switch off last lit
    if (++currLed > lastIndex) {
      currLed = 0;
    }
    digitalWrite(ledPins[currLed], HIGH); // lite new
  }
}
1 Like

Thank you guys! Both codes are working like a charme.

Honestly I didnt understand, why my "expanded" (:D) code version is not working with the tft.

Nethertheless its good to have a more efficient code, so thanks a lot for your help guys!