Trying to fully understand timer code

Hello all,

I have been reading up and following some examples on using the built in timers. I created what I thought would be a very simple code; but I am clearly missing something pretty fundamental.
My goal was to use timer1
Count to the max number in timer1 and toggle the overflow interrupt
The interrupt simply displays the length of time the program as been running.
This code should output every 4 milliseconds, which it does, but then it maxes out at 340 and continues to output 340 indefinitely. Why is the outputted time stopping and maxing out?

void setup() {
  Serial.begin(9600);
  TCCR1A = 0;
  TCCR1B = 0;
  TCCR1B |= (1<<CS10); //prescalar set to 1
  TIMSK1 |= (1<<TOIE1); //enable timer overflow

}

ISR(TIMER1_OVF_vect){
  Serial.println(millis());
}
void loop() {

}

You can’t use Serial in interrupts. It gives you weird results (because it is itself based on interrupts). You should set a flag in interrupt and then in your main loop do your print based on whether that flag is set or not.

boolean doPrint = false;
void setup() {
  Serial.begin(9600);
  TCCR1A = 0;
  TCCR1B = 0;
  TCCR1B |= (1<<CS10); //prescalar set to 1
  TIMSK1 |= (1<<TOIE1); //enable timer overflow

}

ISR(TIMER1_OVF_vect){
  doPrint = true;
}
void loop() {
  if(doPrint){
    Serial.println(millis());
    doPrint = false;
  }
}

Edit: I’d also choose a higher baudrate, 115200 for example, because the print itself can take some time and you are interrupting every 4ms.

This code should output every 4 milliseconds,

Serial.begin(9600);

Problem.
Right there.

Within an ISR you will find the processor automatically disables interrupts.

Serial write/print calls will wait for interrupts once the buffer is full, and if
interrupts are disabled they wait forever. I'm not even sure if the HardwareSerial
code is written to be safe for use in an ISR w.r.t. disabling/reenabling around
critical sections - would need to delve around in the sources.

Basically resist the urge to use Serial (and delay) inside an ISR unless you
prematurely re-enable interrupts inside the ISR (which can have problems
itself if your ISR isn't re-entrant.)

Google will explain "critical section", "ISR", "re-entrant code" if you don't
know these terms, they are often encountered with interrupt-driven systems.

MarkT:
Serial write/print calls will wait for interrupts once the buffer is full, and if
interrupts are disabled they wait forever. I'm not even sure if the HardwareSerial
code is written to be safe for use in an ISR w.r.t. disabling/reenabling around
critical sections - would need to delve around in the sources.

The HardwareSerial.write() will notice that interrupts are disabled and will poll the serial output interrupt flag. This will GREATLY slow down interrupt handling. About a millisecond per character at 9600.
By the time the timer overflow interrupt handler returns it will immediately be signaled again. This is also keeping most of the millisecond interrupts from being handled so time slows way down.
The OP should try a much larger prescale that has enough time to print the message before overflowing again.