0

I'm trying to run a 3-digit 7-segment using single 74HC595 based on Arduino. But I have a serious problem with delay() function. When I want to count from 000 to 999 with delay(1000), this delay function causes all digits to be off! My code is as below and I uploaded a video Click Here to understand my purpose. This problem can affect some applications like reading the temperature of DS12b20 which requires a delay itself.

//                 2        1         0       
//               ----      ----      ----    
//              |    |    |    |    |    |
//               ----      ----      ----
//              |    |    |    |    |    |
//               ----      ----      ----

int latch = 8; //74HC595  pin STCP
int clock = 9; //74HC595  pin SHCP
int data = 10; //74HC595  pin DS

// Each annode pin (for those that don't know think of it as an on switch when it's assigned HIGH)
int dig1 = 2; // digit0
int dig2 = 3; // digit1
int dig3 = 4; // digit2
int digit[4]={dig1, dig2, dig3};

int timer=3;
// these are bits to make the 8 bit byte accepted by the segment display the 9th is the demical point
// 0-9 then invald numbers
byte table[] = {
  B00111111, B00000110, B01011011, B01001111, B01100110,
  B01101101, B01111101, B00000111, B01111111, B01101111, B01111111
};

void setup(){
  pinMode(latch, OUTPUT);
  pinMode(clock, OUTPUT);
  pinMode(data, OUTPUT);
  pinMode(dig1, OUTPUT);
  pinMode(dig2, OUTPUT);
  pinMode(dig3, OUTPUT);
}

//this sends the data to the digit
void RunNum(int num, int SelectDigit){
  digitalWrite(latch, LOW);
  shiftOut(data, clock, MSBFIRST, table[num]);
  digitalWrite(latch, HIGH);
  digitalWrite(digit[SelectDigit], LOW);
  delay(timer);
  digitalWrite(digit[SelectDigit], HIGH);
  
}


//main program
void loop() {
  for (int i=0; i<10; i++){
    for (int j=0; j<10; j++){
      for (int k=0; k<10; k++){
        RunNum(k, 0);
        RunNum(j, 1);
        RunNum(i, 2);
        delay(1000);  //  <====    This line affects the project
      }
    }
  }
}

I updated my code (only void loop()) as below using millis(). You can watch the results (Click Here). But, the delay problem has not been solved so far!

const long interval = 1000;   //  1000 ms = 1 s
long previousMillis = 0; 
unsigned long currentMillis=0;

//main program
void loop() {
  for (int i=0; i<10; i++){
    for (int j=0; j<10; j++){
      for (int k=0; k<10; k++){
        while (currentMillis - previousMillis < interval){
          currentMillis=millis();
          RunNum(k, 0);
          RunNum(j, 1);
          RunNum(i, 2);
        }
        previousMillis = currentMillis;
      }
    }
  }
}
  • 2
    So then don't use delay(). To do timed things, you need to learn a non-blocking coding style, like in the BlinkWithoutDelay example via the millis(). Look a the example and at tutorials about millis(). When you fully understand them, you will be able to replace the delay with non-blocking code – chrisl Jun 17 at 17:28
  • Thanks @chrisl. I already used of millis function. But it's useful for digital counting only like for making a digital clock. It's too bad for other applications like for DS18b20 temperature. – soheil Jun 17 at 17:46
  • @soheil What are you talking about? I don't see, why millis()should be too bad to use here. delay() also just uses millis()in the background. And I also don't see how it should affect the temperature measurement. It is absolutely the way to go for handling the 1s delay there. – chrisl Jun 17 at 18:33
  • @chrisl This is a good question. Suppose that you have a DS18B20 temperature sensor. The sensor response time is about 0.5 sec (may be up to 0.75 sec). If you want to display it using 74HC595, during this time (exactly like a delay) the 7-segments are turned off! and after that they are turned on to display temperature. This appears like a flash (carefully watch the uploaded video). Some chips like MAX7219 doesn't interrupt the output when they don't have input (they run previous commands) while it seems that 74HC595 continuously needs the commands to keep the its output active. – soheil Jun 17 at 21:01
  • 1
    @soheil So your problem is with the temperature sensor. Then you need to show a code, that really uses your temperature sensor. Currently you are asking about the 1s delay, for which Juraj provided a fitting answer. We can only understand how that might collude with the temp sensor, when we see the temp sensor code. – chrisl Jun 17 at 21:49
2

Whit the displays which use shift register to light multiple seven segment digit blocks, the register lights up only one digit at a time. The illusion of multiple digits lit is created by fast switching the digits in round. Small delays in this cause the number to look dim, larger delays create flickering and long delays show only one digit lit. So a sketch handling this type of display must run without delays.

In this type of sketch, everything must be handled without delays, so if some sensor requires a delay, start the reading and a millis timer and after the elapsed time read the result.

There are displays using specialized chips, for example TM1637D, which handle the seven segments even if your sketch stops in delay.


adoption of the BlinkWithoutDelay basic example for your algorithm:

unsigned long previousMillis = 0;
const long interval = 1000;
int i, j, k;

void setup() {
  Serial.begin(115200);
}

void loop() {
  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    previousMillis = currentMillis;
    k++;
    if ( k == 10) {
      k = 0;
      j++;
      if (j == 10) {
        j = 0;
        i++;
        if (i == 10) {
          i = 0;
        }
      }
    }
    Serial.print(i);
    Serial.print(j);
    Serial.println(k);
  }
}
| improve this answer | |
  • Thank you so much. But this isn't the correct answer! I already tried it. Please, carefully read the question. – soheil Jun 17 at 20:45
  • Just a note, there is no temperature sensor or library included for one in the code presented. For the question as presented this is the correct answer. If there is some problem where your temperature sensor takes too long to read then that is a separate issue. That's not the same as having a delay in your code. Instead of trying to code around that time, fix the library for the sensor so it doesn't take so long. – Delta_G Jun 18 at 1:23
  • delay() just simulates the required delay of such sensors. In real applications, this delay causes the flashing in display. – soheil Jun 18 at 3:00
  • @soheil, I enhanced the answer – Juraj Jun 18 at 5:32
  • Thank you. I think changing chip is the best idea. I even used of two 74HC595 combined with ULN2803. But its result became worst. In fact, some segments of an inactive digit were a little bright!!!!!! 74HC595 can't handle the delay(). – soheil Jun 18 at 5:56
1

In loop() as you've shown it in your code, you can move RunNum(i,2); down to outside of the 'j' and 'k' loops. Likewise you can move RunNum(j,1); down to outside of the 'k' loop. This won't fix your problem but it will speed up each update of the display.

Then, know that you can tell one (or all) of your DS18B20 sensors to start a temperature conversion without waiting for the conversion to finish. Then you use millis() to tell you when the conversion is done, and you can get the result very quickly. Some libraries provide the amount of time you need to wait for the conversion; some provide some kind of an "is it done yet?" boolean function. Either one of those will let you remove the 'wait til done' delay.

Update:

This strategy doesn't work properly!...

Sorry if I missed something - it looked like there were opportunities to optimize there.

About temperature sensor, I should say that reading the temperature takes about 750 ms itself. In other words, it acts as a delay and causes turning off the display for 750 ms.

It is temperature measurement and conversion to a 12-bit result - which takes place entirely within the DS18B20 sensor itself - that takes 750ms. The Arduino is not involved in that process and could be doing other tasks such as maintaining your display during that time.

Reading the temperatures, once the conversion is done, is much quicker. If your library doesn't provide the ability to start a conversion and return, without waiting for the results, and separate entry to read the results, look for a library that does.

Update: Miles Burton's Arduino-Temperature-Control-Library provides a 'wait for conversion' flag that you can set false so ::requestsTemperatures() will return immediately, and an ::isConversionComplete() call to check whether the data is ready. (Of course, knowing that the device takes 750ms for a 12-bit conversion, you could just as well use millis() to decide that.)

| improve this answer | |
  • Thank you. This strategy doesn't work properly! because if you do that, digits 1 and 2 are turned off until digit 0 counts from 0 to 9. Then digit 1 quickly displays number 1 and is turned off and again digit 0 counts from 0 to 9 and so on. – soheil Jun 19 at 5:22
  • About temperature sensor, I should say that reading the temperature takes about 750 ms itself. In other words, it acts as a delay and causes turning off the display for 750 ms. As another example, suppose that you need to call a php script using ESP8266 D1 Mini (it can similarly be programmed using Arduino IDE) and then display some returned numbers using 74HC595. Calling a php script may take over 15 s and during this time all digits are turned off. – soheil Jun 19 at 5:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.