I am trying to implement a high precision timer using AT89S8252 using the following code: void configureTimer0(void) { EA = 0; TMOD &= 0xf0; TMOD |= 0x01; ET0 =1; TH0 = TH_VAL TL0 = TL_VAL TR0= 1; EA = 1; } // timer 0 interrupt handle void timer0 (void) interrupt 1 { TH0 = TH_VAL; TL0 = TL_VAL; P2_1 = !P2_1; switch(val) { case 1: // code break; case 2: // code break; } } void main(void) { configureTimer0(); while(1); } The problem occurs when I try to insert any code inside the Timer 0 interrupt handle, such as a blinking LED ar a simple switch statement. The code inside interrupt handle was as simple as possible. In order to keep a constant rate, I have to use a digital osciloscope to adjust TH_VAL and TL_VAL. Is there any other way to implement this ? Do I have to constantly calibrate TH_VAL and TL_VAL after inserting any piece of code inside the timer interrupt handle ? Best regards, Andre
If you choose a reload value that has a zero low byte (TL0) then you can just reload the high byte in the ISR without stopping the timer. This means the timer will remain accurate even if there is some variation in the interrupt latency and you won't have to mess about measuring the period on a scope. You will have to be certain that the time between the rollover triggering the interrupt and the instruction that reloads TH0 will always be less than 256 cycles of whatever is clocking timer0. Making timer0 the highest priority interrupt and ensuring that interrupts are only disabled very briefly elsewhere in your code should achieve this unless you are using a very fast external clock. A good idea is to use a different register bank for the ISR (using x) to reduce the amount of pushing and popping. Your ISR could be as simple as: bit volatile timerflag=0; void handler(void) interrupt 1 using 1 { TH0=TH0_VAL; timerflag=1; } As mentioned by other posters you will have to also ensure that any additional code in the ISR doesn't slow it down to the point where the timer rolls over again before the ISR has finished executing. My preference would be to set a bit flag in the ISR, monitor the flag in your main loop, reset it and do whatever is necessary when the flag goes true. At least the absolute timing of your system won't be upset if your main loop misses a timer event. Maintaining a tick count in the ISR may help your main program 'know where it is': unsigned char volatile ticks=0; void handler(void) interrupt 1 using 1 { TH0=TH0_VAL; ticks++; } If you use a larger integer for 'ticks' you will need to disable the timer interrupt momentarily while reading the value elsewhere in your program. In the above scheme the reload of TH0 should be the first instruction in your ISR. You can calculate the code running time by looking at the assembler generated by the compiler (.cod file) and adding up the machine cycles for each instruction. Stefan
Is it better to set TR, TH and TL at the end of the ISR ? Not "better", the difference is that with setting TR at the start of the ISR, the time will be ((timer time) + (5 instruction cycles) + interrupt overhead. If you set TR at the exit, the time will be ((timer time) + (ISR execution time) + (possibly and intermittently the time to execute a higher priority interrupt) + interrupt overhead. So, setting it at the start gives you ISR code independent timing, setting it at the end make the time code dependent. Again, if the execution of the timer interrupt and the sum total of all higher priority interrupts is more than your timer time you are hosed. Erik
"If you set TR at the exit, the time will be ((timer time) + (ISR execution time) + (possibly and intermittently the time to execute a higher priority interrupt) + interrupt overhead." No matter where you clear TR0, reload TH0/TL0 and set TR0 the ISR can be interrupted by a higher priority interrupt before the timer has been restarted. This will mess up your timing. Furthermore, if you do have any other interrupts enabled at a higher or equal priority your timer ISR will not be able to pre-empt those ISRs which will further affect your timing. Even if you run with all other interrupts disabled you will be unable to achieve truly accurate timing with this scheme due to the variation in the number of machine cycles required for different instructions. Stefan
OK Stefan, timerISR ea = 0 set timer ea =1 Erik
Erik, Can you explain your point? Stefan
1) The interrupts (according to the manual) always execute the fitst instruction. 2) access to IE and RETI acn not be interrupted. Thus by doing as suggested the timer interrupt can not be interrupted. OOPS This, of course, does not help if the timer interrupt happens while a higher priority interrupt is already active. so To make the time "precision" the timer interrupt must be the only interrupt having the highest priority and the EA manipulation can be omitted. Erik
"1) The interrupts (according to the manual) always execute the fitst instruction." Quoting from the manual: "Note that if an interrupt of higher priority level goes active prior to S5P2 of the machine cycle labeled C3 in Figure 20 [first machine cycle of LCALL to the ISR], then in accordance with the above rules it will be vectored to during C5 and C6 [the two machine cycles following the first LCALL], without any instruction of the lower priority routine having been executed." "2) access to IE and RETI acn not be interrupted." Correct, but only if an access to IE/IP or a reti is the instruction actually in progress. A higher priority interrupt occuring during the previous instruction will still be vectored to at the end of that instruction. I only know of two ways to maintain an accurate clock using timer interrupts: 1) Use hardware autoreload. 2) Choose a software reload value that doesn't require the timer to be stopped or the low byte to be reloaded. Stefan
Erik: To make the time "precision" the timer interrupt must be the only interrupt having the highest priority and the EA manipulation can be omitted Stefan: Quoting from the manual: "Note that if an interrupt of higher priority level goes active prior to S5P2 of the machine cycle labeled C3 in Figure 20 [first machine cycle of LCALL to the ISR], then in accordance with the above rules it will be vectored to during C5 and C6 [the two machine cycles following the first LCALL], without any instruction of the lower priority routine having been executed." If the timer interrupt is the only one at the highest priority, your statement above does not apply Stefan: Correct, but only if an access to IE/IP or a reti is the instruction actually in progress. A higher priority interrupt occuring during the previous instruction will still be vectored to at the end of that instruction. as above Stefan: I only know of two ways to maintain an accurate clock using timer interrupts: 1) Use hardware autoreload. 2) Choose a software reload value that doesn't require the timer to be stopped or the low byte to be reloaded. That, of course is the right solution; however, the question did not refer to timer 2 Erik
You must note that the timer continues running when interrupt goes active. If a higher priority interrupt exists, you can add a constant to TH0-TL0 and not load a constant. You can adjust constant by calculting time to execute add.
clr ea clr tr0 xch a,tl0 add a,#low(constant) xch a,tl0 xch a,th0 addc a,#high(constant xch a,th0 setb tr0 setb ea
Erik: "If the timer interrupt is the only one at the highest priority, your statement above does not apply" I think that is pretty obvious from the first sentence: "Note that if an interrupt of higher priority level goes active..." And please note, that was a quotation from the manual, not my statement. The intention was to correct your inaccurate statement: "1) The interrupts (according to the manual) always execute the fitst instruction." Stefan
Eric, This is a good solution if programming in assembler, although I note you have not mentioned compensating for the 'lost' timer counts during the period the timer is disabled. Presumably you would recalculate your constant to take this into account? In 'C' techniques that rely on code being compiled into a specific sequence of instructions are too difficult to maintain for my liking. Stefan
Andre, Has any of this been of any help to you? Stefan