I wrote a simple code counting 30 seconds using Timer 0 (Mode 0, it's 13-bit counter) of Atmel 89S51, and I used Proteus to simulate. After 30 seconds the LED light should be turned on.
I found that the LED light would be turned on at about 31 second, that seems to be an error of 1 second. I think this error is not acceptable since I only count 30 seconds.
In this picture you can see the simulation result:
http://i.imgur.com/etXD8cG.png
Simulation result
Here is the code:
#include <reg51.h>
long i=0;
main()
{
EA=1; //Enable EA bit
ET0=1; //Enable Timer 0
TMOD=0x00; //Use Timer 0, Mode 0
TH0=(8192-1000)/32; //Count 1ms
TL0=(8192-1000)%32;
TR0=1; //Start Timer 0
while(1);
}
void T0_int(void) interrupt 1
{
TH0=(8192-1000)/32;
TL0=(8192-1000)%32;
//if i==30000,30000*1ms=30s
if(++i==30000)
{
P1=~0x01;
}
}
Did I miss something or is there any way that can reduce this error?
-
\$\begingroup\$ I assume they're 16-bit counters, so shouldn't you have something more like TH0=(65536L-1000)/256; (with the same change elsewhere)? \$\endgroup\$PeterJ– PeterJ2013年04月04日 04:01:15 +00:00Commented Apr 4, 2013 at 4:01
-
\$\begingroup\$ Sorry I didn't make it clear, it's 13-bit counter. I'll edit my question. \$\endgroup\$Po-Jen Lai– Po-Jen Lai2013年04月04日 04:11:58 +00:00Commented Apr 4, 2013 at 4:11
2 Answers 2
I am no expert on this chip. Still, I see a common source of inaccuracy in your program: when the counter times out, the interrupt is activated, and some instructions after that you set the TL0, which makes the counter start to count down your 1ms again. Hence there is some dead time between each 1ms interval that is 'lost'. I am not sure this is enough to explain your 1s deviation but it could be.
There are various ways to reduce this 'lost' time:
- experiment, measure, and adapt the value you assign to TH0 accordingly (duct tape development style)
- exchange the TL0 and TH0 assignments (effect will be small)
- (assuming the counter keeps running) instead of assigning a new value to TL0 you can update it (keeping the counts it has already accumulated): TL0 = TL0 - ((8192 - 1000) % 32 );
But the only real solution is to keep the timer running freely and be more intelligent with the counting of the timeouts.
-
\$\begingroup\$ Some chips have an extra register that contains the value that the timer should overflow. On AVR it is called "Output Compare Register". This would automate the
TH0=
andTL0=
lines \$\endgroup\$jippie– jippie2013年04月04日 19:23:24 +00:00Commented Apr 4, 2013 at 19:23
++i and i++ are different.
- i++ will return the value of i and then increment it
- ++i will first increment the value stored in i and then return its value