Increase multiplexing frequency - Timer1

Hi,

I started coding my new project. Code works as I excpeted, but I decided to use 9 7-segment displays instead of 4 and displays started flickering. I know it happens due to too low refresh frequency. But at this moment I don’t understand timers and interrupts. How to simply increase Timer1 frequency to arodund 2KHz ? Thanks.

/*
 * Matural Exam Countdown Clock
 * By Filip Cichowski
 * CC 2020
 */
 
// counter button definition
#define dayplus    A1
#define dayminus    A0
#define hourplus    A3
#define hourminus    A2
#define grade1    A4
#define grade2    A5
#define grade3    A6
 
// shift register pin definitions
#define clockPin  13   // clock pin
#define dataPin   12   // data pin
 
// common pins of the four digits definitions
#define Dig1    5
#define Dig2    4
#define Dig3    3
#define Dig4    2
#define Dig5    6
#define Dig6    7
#define Dig7    8
#define Dig8    9
#define Dig9    10
 
// variable declarations
byte current_digit;
int  days = 234;
int hours;
void disp(byte number, bool dec_point = 0);

unsigned long startMillis; 
unsigned long currentMillis;
const unsigned long period = 1000;  

void setup()
{
  pinMode(dayplus, INPUT_PULLUP);
  pinMode(dayminus, INPUT_PULLUP);
  pinMode(hourplus, INPUT_PULLUP);
  pinMode(hourminus, INPUT_PULLUP);
  pinMode(Dig1, OUTPUT);
  pinMode(Dig2, OUTPUT);
  pinMode(Dig3, OUTPUT);
  pinMode(Dig4, OUTPUT);
  pinMode(Dig5, OUTPUT);
  pinMode(Dig6, OUTPUT);
  pinMode(Dig7, OUTPUT);
  pinMode(Dig8, OUTPUT);
  pinMode(Dig9, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
 
  disp_off();  // turn off the display
 
  // Timer1 module overflow interrupt configuration
  TCCR1A = 0;
  TCCR1B = 1;  // enable Timer1 with prescaler = 1 ( 16 ticks each 1 µs)
  TCNT1  = 0;  // set Timer1 preload value to 0 (reset)
  TIMSK1 = 1;  // enable Timer1 overflow interrupt
}
 
ISR(TIMER1_OVF_vect)   // Timer1 interrupt service routine (ISR)
{
  disp_off();  // turn off the display
 
  switch (current_digit)
  {
 case 1:
      disp(days / 1000);   // prepare to display digit 1 (most left)
      digitalWrite(Dig1, LOW);  // turn on digit 1
       delay(1);
      break;
 
    case 2:
      disp( (days / 100) % 10 );   // prepare to display digit 2
      digitalWrite(Dig2, LOW);     // turn on digit 2
       delay(1);
      break;
 
    case 3:
      disp( (days / 10) % 10 );   // prepare to display digit 3
      digitalWrite(Dig3, LOW);    // turn on digit 3
       delay(1);
      break;
 
    case 4:
      disp(days % 10);   // prepare to display digit 4 
      digitalWrite(Dig4, LOW);  // turn on digit 4
       delay(1);
      break;

      case 5:
      disp(hours / 10000);  // prepare to display digit 5
      digitalWrite(Dig5, LOW);  // turn on digit 5
       delay(1);
      break;
      

      case 6:
      disp((hours / 1000) % 10);   // prepare to display digit 6
      digitalWrite(Dig6,LOW);  // turn on digit 6
       delay(1);
      break;
      
 
    case 7:
      disp( (hours / 100) % 10 );   // prepare to display digit 7
      digitalWrite(Dig7,LOW);     // turn on digit 7
       delay(1);
      break;
 
    case 8:
      disp( (hours / 10) % 10 );   // prepare to display digit 8
      digitalWrite(Dig8,LOW);    // turn on digit 8
       delay(1);
      break;
 
    case 9:
      disp(hours % 10);   // prepare to display digit 9 (most right)
      digitalWrite(Dig9,LOW);  // turn on digit 9
      delay(1);
  }
 
  current_digit = (current_digit % 9) + 1;
}

void loop()
{
  currentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
  if (currentMillis - startMillis >= period)  //test whether the period has elapsed
  {
    days--;
    hours = days * 24;
    startMillis = currentMillis; 
  }

  if(digitalRead(dayplus) == 0)
  {
    days++;  
    if(days > 9999)
      days = 0;
    delay(150); 
  }
  if(digitalRead(dayminus) == 0)
  {
    days--; 
    if(days < 0)
      days = 0;
    delay(150);
  }

  /*if(digitalRead(hourplus) == 0)
  {
    hours++;  // increment 'count' by 1
    if(hours > 99999)
      hours = 0;
    delay(150);  // wait 200 milliseconds
  }
  if(digitalRead(hourminus) == 0)
  {
    hours--;  // decrement 'count' by 1
    if(hours < 0)
      hours = 0;
    delay(150);  // wait 200 milliseconds
  }*/
  
}
 
void disp(byte number, bool dec_point)
{
  switch (number)
  {
    case 0:  // print 0
      shiftOut(dataPin, clockPin, MSBFIRST, 0x02 | !dec_point);
      digitalWrite(clockPin, HIGH);
      digitalWrite(clockPin, LOW);
      break;
 
    case 1:  // print 1
      shiftOut(dataPin, clockPin, MSBFIRST, 0x9E | !dec_point);
      digitalWrite(clockPin, HIGH);
      digitalWrite(clockPin, LOW);
      break;
 
    case 2:  // print 2
      shiftOut(dataPin, clockPin, MSBFIRST, 0x24 | !dec_point);
      digitalWrite(clockPin, HIGH);
      digitalWrite(clockPin, LOW);
      break;
 
    case 3:  // print 3
      shiftOut(dataPin, clockPin, MSBFIRST, 0x0C | !dec_point);
      digitalWrite(clockPin, HIGH);
      digitalWrite(clockPin, LOW);
      break;
 
    case 4:  // print 4
      shiftOut(dataPin, clockPin, MSBFIRST, 0x98 | !dec_point);
      digitalWrite(clockPin, HIGH);
      digitalWrite(clockPin, LOW);
      break;
 
    case 5:  // print 5
      shiftOut(dataPin, clockPin, MSBFIRST, 0x48 | !dec_point);
      digitalWrite(clockPin, HIGH);
      digitalWrite(clockPin, LOW);
      break;
 
    case 6:  // print 6
      shiftOut(dataPin, clockPin, MSBFIRST, 0x40 | !dec_point);
      digitalWrite(clockPin, HIGH);
      digitalWrite(clockPin, LOW);
      break;
    
    case 7:  // print 7
      shiftOut(dataPin, clockPin, MSBFIRST, 0x1E | !dec_point);
      digitalWrite(clockPin, HIGH);
      digitalWrite(clockPin, LOW);
      break;
 
    case 8:  // print 8
      shiftOut(dataPin, clockPin, MSBFIRST, !dec_point);
      digitalWrite(clockPin, HIGH);
      digitalWrite(clockPin, LOW);
      break;
 
    case 9:  // print 9
      shiftOut(dataPin, clockPin, MSBFIRST, 0x08 | !dec_point);
      digitalWrite(clockPin, HIGH);
      digitalWrite(clockPin, LOW);
  }
}
 
void disp_off()
{
   digitalWrite(Dig1, HIGH);
   digitalWrite(Dig2, HIGH);
   digitalWrite(Dig3, HIGH);
   digitalWrite(Dig4, HIGH);
   digitalWrite(Dig5, HIGH);
   digitalWrite(Dig6, HIGH);
   digitalWrite(Dig7, HIGH);
   digitalWrite(Dig8, HIGH);
   digitalWrite(Dig9, HIGH);

}
 
// end of code.

filip_cichowski:
But at this moment I don't understand timers and interrupts.

Clearly not! :cold_sweat:

filip_cichowski:
How to simply increase Timer1 frequency to around 2KHz ?

If you do not know how to write the code, then you most certainly should not be dreaming of using timers, let alone interrupts!

Read this thread and/ or this.

I started coding my new project.

Delay will not work inside an ISR.

filip_cichowski:
How to simply increase Timer1 frequency to arodund 2KHz ?

  TCNT1  = 57500;  // set Timer1 preload value to interrupt in ~500us

You will need to add this line into the timer interrupt code also, or it will revert back to ~0.25KHz after the first interrupt.

However, I agree completely with the comments from Paul__B and Mike. The way your interrupt routine is coded is an almost perfect example of all the errors that beginners make with interrupt routines. (The only thing that is missing is some Serial.print() to make it the perfect example!).

Timers and interrupts are not for beginners. Until you can write efficient code that does not use timers and interrupts, it would be better to spend your time improving those skills. What you want to do can be done using standard functions such as millis() or micros(), which will work on any type of Arduino. Using timers and interrupts will only work on one type of Arduino and will not transfer to other types of Arduino because they have different chips with different timers and registers.

So I would recommend starting over, using the opportunity to learn to write efficient code, avoid long repetitive code, use arrays, avoid re-computing values unnecessarily and so on.

Hi,

I send you wrong part of code. Not sure why but I merged not working delay code with working interrupts code. Kinda shorthand. The version uploaded to Arduino does not contain delay in case ... break.

OK, so I decided to expand my knowledge about Arduino. Could you recommend a good tutorial on interrupts and timers for 328-based boards? Arduino Nano and Micro are very handy, for more advanced project I will probably use STM32F103C8T6 board but it's completly different architecture. Thanks.

filip_cichowski:
would you recommend a good tutorial on interrupts and timers for 328-based boards? Arduino Nano and Micro are very handy, for more advanced project I will probably use STM32F103C8T6 board

Exactly the point I was making. What you learn about timers and interrupts about atmega328 won't really help you with STM32. Better to learn about writing efficient code that does not rely on any particular hardware. That will help you no matter what platform you use.

We are trying to make the point that interrupts and timers are totally irrelevant for your project.

Your displays were flickering because you coded it wrongly. It has nothing whatsoever to do with "too low refresh frequency". :cold_sweat:

Nine display digits can be multiplexed at 1 ms steps giving a refresh frequency of 111 Hz- no flicker. At 2 ms steps it will be 55.5 Hz, no visible flicker unless the display (or your eye) is physically moving.