※ 引述《a45601236qq (Ming)》之铭言:
: C_CPP 板问 51 相关问题的人好像比较少,所以就来这边借问了...
: 今天试着做一下模拟 ms 计算的(高阶语言 sleep 都喜欢以 1ms * n 为单位)
: 试着计时 60 秒后,发现每分钟都会误差五秒钟(感觉有点大)
60秒误差一秒都嫌太大
: 想请大家帮忙看一下是否有问题...
: 感谢<_ _)
: #include <AT89X51.h>
: int Timer1Ms = 0; //1ms * n
: int Timer1Value = 0;
时脉没写, 那我就假设最一般的case, 输入给timer的周期 = 1us
: void main()
: {
: TMOD = 0x10; //7-2 tmod
: TL0 = ( 8192 - 5000 ) % 32;
: TH0 = ( 8192 - 5000 ) / 32;
: TL1 = ( 65536 - 1000 ) % 256;
: TH1 = ( 65536 - 1000 ) / 256;
这里看起来是因为要以 ms 为单位, 需要计数超过 256 所以用 mode1,
但是中断要去 reload 就影响计时准确度,
我的作法是改用 mode2, 数到 200个pulse*1us=200us,
在中断累积50次overflow时, 秒数++
: Timer1Value = 60000;
: Timer1Ms = Timer1Value;
: //TR0 = 1;
: TR1 = 1;
: EA = 1; ET0 = 1; ET1 = 1; //6-3 IE
: while (1) ;
: }
: void timer1_isr() interrupt 3
: {
: TL1 = ( 65536 - 1000 ) % 256;
: TH1 = ( 65536 - 1000 ) / 256;
如果这边硬是要用mode1, 那也有一些作法可以提高计时准确性
1. 在 main 就先算出 TH1 TL1 的常数值(也许compiler已经帮你做)
2. reload 前先TR1=0,reload后TR1=1,
因为只要 TR1==1 的情况下
reload 过程中 Timer1 依然在计数, TH1 TL1 依然在累加,没停过
: Timer1Ms -= 1;
3.如果 main 没有在跑 UART 或 LCD 什么的跑得够快的话, 以下这几行可以留到main去做
: if (Timer1Ms == 0)
: {
: Timer1Ms = Timer1Value;
: P1_2 = ~(P1_2);
: }
: }