I am trying to implement a 16-bit timer overflow interrupt on the ATMEGA168. The idea is to write a message to the UART I/O register when the timer overflows.
I've tested the UART separately and it works fine via RealTerm (baudrate of 9600 bits/s).
I created a base project from https://start.atmel.com/#dashboard where I had to set the input clock frequency to 16MHz to be compatible with the debugger (see page 5). So I would expect to see a 0x1 on my serial terminal every (16x106 / 1024)-1 x 216 = 4.194 seconds.
However, I'm not seeing anything on the terminal regardless of the prescaler I select. Can anyone please advise what could be going wrong?
I have attached the ISR and the main() below:
#include <atmel_start.h>
#include <stdio.h>
#include <usart_basic.h>
#include <atomic.h>
#include <avr/interrupt.h>
#include <avr/io.h>
// timer1 overflow
ISR(TIMER1_OVF_vect) {
// Send 0x1 over UART
UDR0 = 0x1;
}
int main(void) {
atmel_start_init();
// enable timer overflow interrupt for Timer1
TIMSK1 = (1<<TOIE1); // also tried |=
// start 16-bit counter with /1024 prescaler
TCCR1B = (1 << CS10) | (1 << CS12); // also tried |=
TCCR1A = 0x0;
// enable interrupts
sei();
while(true) {
// more code here...
}
}
I have tried to isolate the problem by not writing to UART in the ISR, but just incrementing a counter (declared with the volatile qualifier) and then printing its value to the screen via UART in the while(true) loop. But the counter doesn't increment either and remains stuck at 0.
You have no USART initialisation code. Specifically you don't enable the transmitter or set the baud rate. I accept that you have tried it with a counter, but that is not the code shown so we can come to no conclusion about its correctness or otherwise.
Without initialisation, the transmitter will not run, and the baud rate will be 1Mbps. Your need at least:
// Set baud rate 9600
uint16_t brr = (FOSC / 16 / 9600) - 1
UBRR0H = (uint8_t)(ubrr >> 8);
UBRR0L = (uint8_t)ubrr;
// Enable transmitter
UCSR0B = (1<<TXEN0);
// Note reset state frame is N,8,1
I am not convinced that it matters but your timer initialisation order is not idiomatic. You would normally enable the interrupt after setting the prescaler and any other configurations, and to ensure the first period is a complete period, reset the counter to zero immediately before enabling interrupts.
// set up timer with prescaler = 1024
TCCR1B = (1 << CS12) & (1 << CS11);
// initialise counter
TCNT1 = 0;
// enable overflow interrupt
TIMSK = (1 << TOIE1);
// enable global interrupts
sei();
As I said, I am not sure that will fix your problem but the elided part:
while(true) {
// more code here...
}
may well be the code that is breaking it. You would do well to discount that possibility by disabling or removing any code there temporarily.
Every time I enable the timer it instantly activates the Interrupt. No matter how I try to prescale it. only ARR seems to work but 16 bit with 0,5MHz clock gives me ~160ms maneuver.
#define SYSCLK_FREQ 524288
void timer_init(uint16_t detonation_delay_ms);
int main(void){
RCC->APB2ENR = RCC_APB2ENR_TIM22EN;
TIM22->PSC = (SYSCLK_FREQ/1000)-1;
NVIC_EnableIRQ(TIM22_IRQn);
NVIC_SetPriority(TIM22_IRQn,4);
}
/* calling function */
timer_init(65535);
/* calling function */
void timer_init(uint16_t detonation_delay_ms){
TIM22->CR1 &= ~TIM_CR1_CEN;
TIM22->SR=0;
TIM22->ARR = detonation_delay_ms;
TIM22->CR1 |= TIM_CR1_CEN;
TIM22->SR = 0;
}
void TIM22_IRQHandler(void){
TIM22->CR1 &= ~TIM_CR1_CEN;
TIM22->SR=0;
GPIOB->BSRR = GPIO_BSRR_BS_7;
}
I wish that calling function makes the timer tick till the called value in milisec. But no matter how I set it up it ends up with no scaled timer and instant interrupt after calling it.
Correct way to do it?
TIM22->DIER = TIM_DIER_UIE;
TIM22->ARR = 65535-detonation_delay_ms;
TIM22->EGR = TIM_EGR_UG;
TIM22->CR1 |= TIM_CR1_OPM | TIM_CR1_CEN;
TIM22->SR=0;
Do not delay in interrupts
you enable the timer then set the ARR which is wrong - first set ARR and prescaller, then generate the UG event using the EGR register, then enable the timer.
Works like a charm. Just because I got help here will describe for future interested people.
The way to get the interrupt working for the timers is to generate interrupt 'by hand' once. It's okay to do it because you can control what's happening during the interrupt by a single 'if'.
/* TIMER Enable */
RCC->APB2ENR = RCC_APB2ENR_TIM22EN;
I had a problem with the above declaration, dunno why but it wasn't working after declaring some more modules before it. Had to put it on higher on the list. Manual does not say why it happened.
/* Configure TIM22 interrupt */
TIM22->PSC = (SYSCLK_FREQ/1000)-1; /* Prescaler TIMERA 22 */
TIM22->DIER = TIM_DIER_UIE;
TIM22->CNT = 0;
TIM22->EGR = TIM_EGR_UG;
NVIC_EnableIRQ(TIM22_IRQn); /* Zalaczenie przerwania od TIMER'a */
NVIC_SetPriority(TIM22_IRQn,4); /* Ustawienie priorytetu przerwania od TIMER'a */
The prescaler meant to be 1ms so I divided 524288 of my core speed. Then enabling the interrupt, resetting the counter to make sure it starts from 0 and then manually generating the interrupt. And it does the interrupt 'loop' once but with a single 'if' and variable, I can control what it does.
So what I do, I am calling a function that set the clock and enables the count inside another function enable = 1; timer_init(ms);
Then comes the function call
void timer_init(uint16_t ms)
{
TIM22->CNT = 65535-ms;
TIM22->CR1 |= TIM_CR1_CEN;
}
void TIM22_IRQHandler(void)
/* Up-Counter milisec */
{
if(TIM22->CR1 & TIM_CR1_CEN) {TIM22->CR1 &= ~TIM_CR1_CEN;}
if(TIM22->SR & TIM_SR_UIF) {
if(enable == 1){
GPIOB->BSRR = GPIO_BSRR_BS_7;
}
}
TIM22->SR=0;
}
And the interrupt.
Thanks a lot!Have fun with registers!
Afternoon all
I'm looking for some assistance please with something that has been confusing me whilst trying to learn timer interrupts
You'd be best treating me as a novice. I have no specific goal here other than learning something that I think would be useful feather to add to my cap!
I have written the below sketch as a stab at a rigid framework for executing different fcns at different rates. I've done something similar using millis() and whilst that worked I found it inelegant that a) there was no obvious way to check for task overruns and backing-up the execution rate and b) the processor is bunged up by checking millis() every program cycle.*
Essentially what I think should be a 1ms timer interrupt on Timer2 (16MHz/64 prescaler /250 compare register =1000hz) is coming out around 0.5ms. I've been confused for hours on this but I'm prepared to accept it could be something fundamental/basic!
What's also throwing a spanner in the works is that using serial comms to try and debug the faster task rates seems to slow things down considerably, so I'm inferring the problem by counting up 1ms tasks to call 10,100 and 1000ms tasks and debugging at the slower level. I suppose chewing through a few characters at 9600baud probably is quite slow.**
I've pasted the code below. Any pointers highly appreciated. Be as harsh as you like :)
cheers
Al
*Whilst not what I'm confused about - any comments on my logic here also welcome
** Although I don't get how Serial.println manages to slow the program down. It's driven from interrupts so it should surely just drop the comms and perform the next ISR - effectively a task overrun. Any comments here also welcome
//NOTES
//https://www.robotshop.com/letsmakerobots/arduino-101-timers-and-interrupts
//https://sites.google.com/site/qeewiki/books/avr-guide/timers-on-the-atmega328
//http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-42735-8-bit-AVR-Microcontroller-ATmega328-328P_Datasheet.pdf
//
//INITIALISE EVERYTHING
const int ledPin = 13;
volatile int nStepTask1ms = 0; // init 0 - to be used for counting number of 1ms tasks run and hence calling 10ms task
volatile int nStepTask10ms = 0;
volatile int nStepTask100ms = 0;
volatile int nStepTask1000ms = 0;
volatile int LEDFlashState = 0; // init 0 - variable to flip when LED on
volatile int millisNew = 0; // to store up to date time
volatile int millisOld = 0; // to store prev time
volatile int millisDelta = 0; // to store deltas
//
void setup()
{
Serial.begin(9600); //set up serial comms back to PC
pinMode(ledPin,OUTPUT); //to flash the embedded LED
noInterrupts(); //turn off interrupts while we set the registers
//set up TIMER first
TCCR2A = 0; //sets TCCR1A byte to zero, bits to be later individually mod'd
TCCR2B = 0; //sets TCCR1B byte to zero, bits to be later individually mod'd
TCNT2 = 0; //ensures counter value starting from zero
Serial.println("Timer1 vars reset");
TCCR2B |= (1<<WGM12); // bitwise or between itself and WGM12. TCCR2B = TCCR2B | 00001000. Sets WGM12 high. (CTC mode so WGM12=1, WGM 13,11,10 all 0) https://stackoverflow.com/questions/141525/what-are-bitwise-shift-bit-shift-operators-and-how-do-they-work
Serial.println("Mode 4 CTC set");
Serial.println("TCCR2B=");
Serial.println(TCCR2B,BIN);
TCCR2B |= (1<<CS11); // sets CS11 high
TCCR2B |= (1<<CS10); // sets CS10 high (i.e. this and above give /64 prescaler)
Serial.println("Prescaler set to 64");
OCR2A = 250; //compare match register for timer2
Serial.println("Compare Register set");
Serial.println("OCR2A=");
Serial.println(OCR2A);
TIMSK2 |= (1 << OCIE2A); //enables interrupts - https://playground2014.wordpress.com/arduino/basics-timer-interrupts/
Serial.println("Interrupt Mask Register Set");
Serial.println("TIMSK2=");
Serial.println(TIMSK2);
interrupts(); //enable interrupts again - not sure if this is required given OCIE1A being set above?
}
//set up ISR for Timer2 - timer structure called every interrump (1ms) that subsequently calls 1,10,100 and 1000msec task fcns
ISR(TIMER2_COMPA_vect)
{
TASK_1ms();
if (nStepTask1ms>9)
{
TASK_10ms();
if (nStepTask10ms>9)
{
TASK_100ms();
if (nStepTask100ms>9)
{
TASK_1000ms();
}
}
}
}
void TASK_1ms()
{
// 1ms tasks here
nStepTask1ms++;
}
void TASK_10ms()
{
//10ms tasks here
nStepTask1ms=0;
nStepTask10ms++;
}
void TASK_100ms()
{
//100ms tasks here
nStepTask10ms=0;
nStepTask100ms++;
//Serial.println(nStepTask100ms);
}
void TASK_1000ms()
{
//1000ms tasks here
nStepTask100ms=0;
//do something
changeLEDFlashState();
//check timing tick of this task
millisNew=millis();
millisDelta=millisNew-millisOld;
Serial.println(millisDelta);
millisOld=millisNew;
nStepTask1000ms++;
}
void changeLEDFlashState()
{
if(LEDFlashState==0)
{
digitalWrite(ledPin,HIGH);
LEDFlashState=1;
//Serial.println("LED Turned On");
}
else
{
digitalWrite(ledPin,LOW);
LEDFlashState=0;
//Serial.println("LED Turned Off");
}
}
void loop()
{
// empty
}
You have two lines here:
TCCR2B |= (1<<CS11); // sets CS11 high
TCCR2B |= (1<<CS10); // sets CS10 high (i.e. this and above give /64 prescaler)
These two lines set the lower three bits of TCCR2B to 011, which is a /32 prescaler.
Note that for Timer1 and Timer2, the prescaler settings are different than Timer0.
For Timer0, the settings above would give you a /64 prescaler.
Running the code below, when I send any character to the Arduino from the Serial Monitor, the Arduino does not print "a" back. I think it's something wrong with the timer1 code, but it should work because this code was given to me by my teacher in C class.
void setup() {
Serial.begin(115200);
// http://www.instructables.com/id/Arduino-Timer-Interrupts/?ALLSTEPS
noInterrupts();
TCCR1A = 0;// set entire TCCR1A register to 0
TCCR1B = 0;// same for TCCR1B
TCNT1 = 0;//initialize counter value to 0
// set compare match register for 1000000hz increments with 8 bits prescaler
OCR1A = 1;// = (16*10^6) / (1000000*8) - 1 (must be <65536)
// turn on CTC mode
TCCR1B |= (1 << WGM12);
// Set CS11 bit for 8 prescaler. Each timer has a different bit
// code to each prescaler
TCCR1B |= (1 << CS11);
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
interrupts();
}
void loop() {
if (Serial.available()) {
Serial.println("a");
}
}
See also: http://www.instructables.com/id/Arduino-Timer-Interrupts/?ALLSTEPS
Side Note: your code comment about 8 bits prescaler is misleading. It is not an 8-bit prescaler, rather, it is simply a prescaler of 8, meaning the decimal value 8. All that means is the timer's clock tick rate is 8x slower than the main clock, since you divide the main clock frequency by the prescaler to get the timer's clock frequency.
Now for my answer:
The way you set TCCR1A and TCCR1B is all correct.
However, you have 2 major problems, 1 minor problem, and 1 recommendation.
See the 660-pg ATmega328 datasheet pgs. 132~135 for more help & info if you want to know where to look from now on for low-level help.
Update: the new ATmega328 sales page is here: https://www.microchip.com/wwwproducts/en/ATmega328. Its new datasheet is available here: https://ww1.microchip.com/downloads/en/DeviceDoc/ATmega48A-PA-88A-PA-168A-PA-328-P-DS-DS40002061B.pdf. So, the page numbers I mention above and below will likely no longer quite match since I was using an older version of the datasheet when I wrote this.
Here are the 2 major problems which are completely breaking your code:
Since you are enabling the Timer Compare Match 1A interrupt (TIMSK1 |= (1 << OCIE1A);), you MUST also define the Interrupt Service Routine (ISR) which will be called when this happens, or else you will have run-time (but not compile-time) problems. Namely, if you do not define the ISR for Output Compare Match A, once the Output Compare A interrupt occurs, the processor will get stuck in an infinite, empty, dummy ISR created for you by the compiler, and your main loop will not progress (see code below for proof of this).
Add this to the bottom of your code:
ISR(TIMER1_COMPA_vect)
{
// insert your code here that you want to run every time the counter
// reaches OCR1A
}
It takes a couple microseconds to step into an ISR, and a couple microseconds to step out of an ISR, plus whatever time is required to run your code IN the ISR, you need to use an OCR1A value that is large enough that the ISR even has time to execute, rather than being continually called so quickly that you never exit the ISR (this would lock up your code essentially into an infinite loop....which is happening in your case as well).
I recommend you call an ISR no more often than every 10us. Since you are using CTC mode (Clear Timer on Compare match), with a prescaler of 8, I recommend setting OCR1A to nothing less than 20 or so. OCR1A = 20 would call the ISR every 10us. (A prescaler of 8 means that each Timer1 tick take 0.5us, and so OCR1A = 20 would call the ISR every 20*0.5 = 10us).
If you set OCR1A = 20, and add the ISR code as described above, your code will run just fine.
1 Minor problem:
It is good practice to set OCR1A after you configure the rest of the timer, or else under some situations the timer may not start counting. See "Thorsten's" comment here (emphasis added):
Thorsten said...
Thanks for explaining this matter so extensively! I was looking for a way to generate 1 MHz on one of the Arduino-pins. Your post helped me a great deal to accomplish that.
The reason I am writing this comment is the following: It took me almost 6 hours till I found out (mainly in sheer desperation) that the order of setting the timer control registers TCCR2* and the output compare registers OCR2* seems to matter! If you assign an OCR before setting the corresponding TCCR the timer simply doesn't start counting.
February 13, 2011 at 11:47 AM
So, move OCR1A = 20; to after your last TCCR1B line and before your TIMSK1 line.
1 recommendation:
Get rid of your calls to noInterrupts() and interrupts(). They are not needed here.
Functional code:
Now, here is some functional code I wrote which will better demonstrate what you're trying to do, and what I'm talking about:
/*
timer1-arduino-makes-serial-not-work.ino
- a demo to help out this person here:
http://stackoverflow.com/questions/28880226/timer1-arduino-makes-serial-not-work
By Gabriel Staples
http://electricrcaircraftguy.blogspot.com/
5 March 2015
- using Arduino 1.6.0
*/
// Note: ISR stands for Interrupt Service Routine
// Global variables
volatile unsigned long numISRcalls = 0; // number of times the ISR is called
void setup()
{
Serial.begin(115200);
// http://www.instructables.com/id/Arduino-Timer-Interrupts/?ALLSTEPS
// noInterrupts(); // Not necessary
TCCR1A = 0; // set entire TCCR1A register to 0
TCCR1B = 0; // same for TCCR1B
TCNT1 = 0; // initialize counter value to 0
// better to put this line AFTER configuring TCCR1A and TCCR1B below, but in
// Arduino 1.6.0 it appears to be ok here (may crash code in older versions),
// see comment by "Thorsten" here:
// http://www.righto.com/2009/07/secrets-of-arduino-pwm.html?showComment=1297626476152#c2692242728647297320
OCR1A = 20;
// SETTING OCR1A TO 1 OR 2 FOR SURE BREAKS THE CODE, as it calls the interrupt
// too often to even allow the main loop to run at all.
// OCR1A = 1;
// turn on CTC mode [Clear Timer on Compare match---to make timer restart at
// OCR1A; see datasheet pg. 133]
TCCR1B |= (1 << WGM12);
// Set CS11 bit for 8 prescaler [0.5us ticks, datasheet pg. 135]. Each timer
// has a different bit code to each prescaler
TCCR1B |= (1 << CS11);
// enable timer compare match 1A interrupt; NOW YOU *MUST* SET UP THE
// CORRESPONDING ISR OR THIS LINE BREAKS THE CODE
// IT IS RECOMMENDED TO SET OCR1A HERE, *after* first configuring both the
// TCCR1A and TCCR1B registers, INSTEAD OF ABOVE! Like this:
// OCR1A = 20;
TIMSK1 |= (1 << OCIE1A);
// interrupts(); // Not necessary
Serial.println("setup done, input a character");
}
void loop()
{
if (Serial.available())
{
// read and throw away the first byte in the incoming serial buffer (or else
// the next line will get called every loop once you send the Arduino a
// single char)
Serial.read();
Serial.println("a");
// also print out how many times OCR1A has been reached by Timer 1's counter
noInterrupts(); // turn off interrupts while reading non-atomic (> 1 byte)
// volatile variables that could be modified by an ISR at
// any time--incl while reading the variable itself.
unsigned long numISRcalls_copy = numISRcalls;
interrupts();
Serial.print("numISRcalls = "); Serial.println(numISRcalls_copy);
}
// Serial.println("test");
// delay(1000);
}
// SINCE YOU ARE ENABLING THE COMPARE MATCH 1A INTERRUPT ABOVE, YOU *MUST*
// INCLUDE THIS CORRESPONDING INTERRUPT SERVICE ROUTINE CODE
ISR(TIMER1_COMPA_vect)
{
// insert your code here that you want to run every time the counter reaches
// OCR1A
numISRcalls++;
}
Run it and see what you think.
Proof that "Major Problem 1" above is real
(at least as far as I understand it--and based on tests on an Arduino Nano, using IDE 1.6.0):
This code below compiles, but will not continue to print the "a" (it may print it once, however). Note that for simplicity-sake I commented out the portion waiting for serial data, and simply told it to print an "a" every half second:
void setup() {
Serial.begin(115200);
TCCR1A = 0; // set entire TCCR1A register to 0
TCCR1B = 0; // same for TCCR1B
TCNT1 = 0; // initialize counter value to 0
// turn on CTC mode
TCCR1B |= (1 << WGM12);
// Set CS11 bit for 8 prescaler. Each timer has a different bit code to each
// prescaler
TCCR1B |= (1 << CS11);
OCR1A = 20;
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
}
void loop() {
//if (Serial.available()) {
// Serial.println("a");
//}
Serial.println("a");
delay(500);
}
// ISR(TIMER1_COMPA_vect)
// {
// // insert your code here that you want to run every time the counter reaches
// // OCR1A
// }
This code below, on the other hand, works, and the "a" will continue to print out. The only difference between this one and the one just above is that this one has the ISR declaration uncommented at the bottom:
void setup() {
Serial.begin(115200);
TCCR1A = 0; // set entire TCCR1A register to 0
TCCR1B = 0; // same for TCCR1B
TCNT1 = 0; // initialize counter value to 0
// turn on CTC mode
TCCR1B |= (1 << WGM12);
// Set CS11 bit for 8 prescaler. Each timer has a different bit code to each
// prescaler
TCCR1B |= (1 << CS11);
OCR1A = 20;
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
}
void loop() {
//if (Serial.available()) {
// Serial.println("a");
//}
Serial.println("a");
delay(500);
}
ISR(TIMER1_COMPA_vect)
{
// insert your code here that you want to run every time the counter reaches
// OCR1A
}
If this answer solves your problem, please upvote it and accept it as the correct answer. Thanks!
Extra Resources:
I keep a running list of the most helpful Arduino resources I come across at the bottom of an article I wrote here: http://electricrcaircraftguy.blogspot.com/2014/01/the-power-of-arduino.html. Check them out.
Especially look at the first links, under the "Advanced" section, by Ken Shirriff and Nick Gammon. They are excellent!
Nick Gammon's answer here
[my answer] Which Arduinos support ATOMIC_BLOCK? And how can I duplicate this concept in C with __attribute__((__cleanup__(func_to_call_when_x_exits_scope))) and in C++ with class constructors and destructors?
[my own Question and answer] C++ decrementing an element of a single-byte (volatile) array is not atomic! WHY? (Also: how do I force atomicity in Atmel AVR mcus/Arduino)
Gabriel Staples is quite correct, the reason you are not seeing the "a" is because you have not provided an ISR handler for the interrupt. Thus, the compiler-generated code jumps back to address 0x0000 and your sketch restarts.
An alternative to providing the "empty" ISR handler is this:
EMPTY_INTERRUPT (TIMER1_COMPA_vect);
With the EMPTY_INTERRUPT handler there I got a response (the "a") with OCR1A as low as 1:
OCR1A = 1;
Although, one has to wonder why you enable interrupts if you aren't planning to do anything with them.
More information about interrupts on the Arduino.
Depending on what the program needs to do with such a fast interrupt, e.g. generating a high-speed clock on an output pin, one can set it in hardware using COM bits in TCCR1A (out of my memory the 4 most significant bits) to toggle the output on a pin associated with the timer without the need to write any ISR() callback to handle the timer interrupt in software.
You wrote this register 2 times:
TCCR1B |= (1 << WGM12);
TCCR1B |= (1 << CS11);
while I think that it could probably be:
TCCR1A |= (1 << WGM12);
TCCR1B |= (1 << CS11);
Probably the only mistake is there, because you forgot to set TCCR1A and you set the other one 2 times.
TCCR1A |= (1 << WGM12); is a bitwise operation (bitwise OR).
In this particular case is setting only one bit of TCCR1A, the one in position WGM12.
TCCR1B |= (1 << CS11); is setting a different bit in position CS11.
I have an ATMega8515 and I am trying to setup a timer interrupt so that if a process takes too long it will shut off.
I setup the timer with:
void init_software_interupt(double time)
{
OCR1A = time;
TCCR1A = 0;
TCCR1B = 0;
TCCR1B |= (1 << WGM12);
TCCR1B |= (1<<CS10);
TCCR1B |= (1<<CS12);
TIMSK |= (1 << OCIE1A);
sei();
}
This works great. I calculated a clock second to be 7812 for an 8MHz clock and it works exactly as expect printing stuff once every second:
//Timer Interupt
int seconds = 0;
ISR(TIMER1_COMPA_vect){
seconds++;
printf("in timer overflow: %d seconds have passed\r\n",seconds);
in_progress = FALSE;
}
The problem is that I might call the function unlock_door() 750ms into the 1 second overflow count and it would only allow the operation to take 250ms which isn't long enough.
I've tried to just set the output compare register before I call the function but it doesn't seem to have an affect:
OCR1A = 7812;
unlock_door();
But it doesn't change the current overflow.
How can I reset the overflow timer before I call a function to ensure it will take 1 second?
It looks like you're using the compare interrupt, not the overflow interrupt. OCR1A stores the value that the counter is being compared to, and I believe that TCNT1 stores the actual timer value. Try:
TCNT1 = 0;
unlock_door();
Here's a good article on AVR timers, by the way. It's called "The Newbie's Guide to AVR Timers", but it works really well as a reference as well.