本帖最后由 eehome 于 2013-1-5 09:52 编辑
自己测试和计算了一些已有的延时函数。
这里假定单片机是时钟频率为12MHz,则一个机器周期为:1us.
参考了51单片机 Keil C 延时程序的简单研究后,我们可知道, 在Keil C中获得最为准确的延时函数将是
void delay(unsigned char t)
{
while(--t);
}
反汇编代码如下:
执行DJNZ指令需要2个机器周期,RET指令同样需要2个机器周期,根据输入t,在不计算调用delay()所需时间的情况下,具体时间延时如下:
t | Delay time (us) | 1 | 2×1+2 =4 | 2 | 2×2+2=6 | N | 2×N+2=2(N+1) |
当在main函数中调用delay(1)时, 进行反汇编如下:
调用delay()时,多执行了两条指令,其中MOV R, #data需要1个机器周期,LJMP需要2个机器周期,即调用delay()需要3us.
Keil C 仿真截图与计算过程:
加上调用时间,准确的计算时间延时与Keil C仿真对比如下:(可见,仿真结果和计算结果是很接近的)
t | Delay Time (us) | 仿真11.0592Mhz时钟(us) | 1 | 3+2×1+2 =7 | 7.7(实际) | 7.60 | 2 | 3+2×2+2=9 | 9.9 | 9.76 | N | 3+2×N+2=2N+5 | (2N+5)*1.1 | / | 3 | 11 | 12.1 | 11.94 | 15 | 35 | 38.5 | 37.98 | 100 | 205 | 225.5 | 222.44 | 255 | 515 | 566.5 | 558.81 |
也就是说,这个延时函数的精度为2us,最小的时间延时为7us,最大的时间延时为3+255×2+2=515us.
实际中使用11.0592MHz的时钟,这个延时函数的精度将为2.2us,最小时间延时为7.7us, 最大时间延时为566.5us.
这个时间延时函数,对于与DS18B20进行单总线 通信,已经足够准确了。
现在,我们将时钟换成11.0592MHz这个实际用到的频率,每个机器周期约为1.1us.
现在让我们来分析一下这个之前用过的延时函数:
//延时函数, 对于11.0592MHz时钟, 例i=10,则大概延时10ms.
void delayMs(unsigned int i)
{
unsigned int j;
while(i--)
{
for(j = 0; j < 125; j++);
}
}
它的反汇编代码如下:
分析: T表示一个机器周期(调用时间相对于这个ms级的延时来说,可忽略不计)
1 C:0000 MOV A, R7 ;1T
2 DEC R7 ;1T 低8位字节减1
3 MOV R2, 0x06 ;2T
4 JNZ C:0007 ;2T 若低8位字节不为0, 则跳到C:0007
5 DEC R6 ;1T 低8位字节为0, 则高8位字节减1
6 C:0007 ORL A, R2 ;1T
7 JZ C:001D ;2T 若高8位也减为0, 则RET
8 CLR A ;1T A清零
9 MOV R4, A ;1T R4放高位
10 MOV R5, A ;1T R5放低位
11 C:000D CLR C ;1T C清零
12 MOV A, R5 ;1T
13 SUBB A, #0x7d ;1T A = A-125
14 MOV A, R4 ;1T
15 SUBB A, #0x00 ;1T A
16 JNC C:0000 ;2T A为零则跳到C:0000
17 INC R5 ;1T R5增1
18 CJNE R5,#0x00, C:001B ;2T R5>0, 跳转到C:000D
19 INC R4 ;1T
20 C:001B SJMP C:000D ;2T
21 C:001D RET
对于delayMs(1), 执行到第7行就跳到21行, 共需时12T, 即13.2us
对于delayMs(2), 需时9T+13T+124×10T+7T+12T = 9T+13T+1240T+7T+12T =1281T =1409.1us.
对于delayMs(3), 需时9T×(3-1)+(13T+124×10T+7T)×(3-1)+12T
=1269T×(3-1)+12T=2550T=2805us.
对于delayMs(N),N>1, 需时1269T×(N-1)+12T = 1269NT-1257T=(1395.9N-1382.7)us.
利用Keil C仿真delayMs(1) = 0.00166558s = 1.67ms 截图如下:
由分析可知具体的计算延时时间与Keil C仿真延时对比如下:
i | Time Delay | 仿真延时 | 1 | 13.2us | 1.67ms | 2 | 1409.1us | 3.31ms | 3 | 2805us | 4.96ms | N | (1395.9N-1382.7)us |
| 10 | 12.6ms | 16.50ms | 20 | 26.5ms | 32.98ms | 30 | 40.5ms | 49.46ms | 50 | 68.4ms | 82.43ms | 100 | 138.2ms | 164.84ms | 200 | 277.8ms | 329.56ms | 500 | 696.6ms | 824.13ms | 1000 | 1394.5ms | 1648.54ms | 1500 | 2092.5ms | 2472.34ms | 2000 | 2790.4ms | 3296.47ms | 5 | 5.6ms | 8.26ms | 73 | 100.5ms | 120.34ms | 720 | 1003.7ms = 1s | 1186.74ms |
计算delayMs(10)得到延时时间为:12576.3us约等于12.6ms,接近我们认为的10ms。
计算结果和仿真结果只要delayMs(1)有很大出入, 其它都接近, 在接受范围内.
经过以上分析,可见用C语言来做延时并不是不太准确,只是不容易做到非常准确而已,若有一句语句变了,延时时间很可能会不同,因为编译程序生成的汇编指令很可能不同。
PS:
对于每条51单片机汇编指令的字长和所需机器周期汇总如下:
- Appendix E - 8051 Instruction Set
- Arithmetic Operations
- Mnemonic Description Size Cycles
- ADD A,Rn Add register to Accumulator (ACC). 1 1
- ADD A,direct Add direct byte to ACC. 2 1
- ADD A,[url=home.php?mod=space&uid=98313]@ri[/url] Add indirect RAM to ACC. 1 1
- ADD A,#data Add immediate data to ACC. 2 1
- ADDC A,Rn Add register to ACC with carry. 1 1
- ADDC A,direct Add direct byte to ACC with carry. 2 1
- ADDC A,@Ri Add indirect RAM to ACC with carry. 1 1
- ADDC A,#data Add immediate data to ACC with carry. 2 1
- SUBB A,Rn Subtract register from ACC with borrow. 1 1
- SUBB A,direct Subtract direct byte from ACC with borrow 2 1
- SUBB A,@Ri Subtract indirect RAM from ACC with borrow. 1 1
- SUBB A,#data Subtract immediate data from ACC with borrow. 2 1
- INC A Increment ACC. 1 1
- INC Rn Increment register. 1 1
- INC direct Increment direct byte. 2 1
- INC @Ri Increment indirect RAM. 1 1
- DEC A Decrement ACC. 1 1
- DEC Rn Decrement register. 1 1
- DEC direct Decrement direct byte. 2 1
- DEC @Ri Decrement indirect RAM. 1 1
- INC DPTR Increment data pointer. 1 2
- MUL AB Multiply A and B Result: A <- low byte, B <- high byte. 1 4
- DIV AB Divide A by B Result: A <- whole part, B <- remainder. 1 4
- DA A Decimal adjust ACC. 1 1
- Logical Operations
- Mnemonic Description Size Cycles
- ANL A,Rn AND Register to ACC. 1 1
- ANL A,direct AND direct byte to ACC. 2 1
- ANL A,@Ri AND indirect RAM to ACC. 1 1
- ANL A,#data AND immediate data to ACC. 2 1
- ANL direct,A AND ACC to direct byte. 2 1
- ANL direct,#data AND immediate data to direct byte. 3 2
- ORL A,Rn OR Register to ACC. 1 1
- ORL A,direct OR direct byte to ACC. 2 1
- ORL A,@Ri OR indirect RAM to ACC. 1 1
- ORL A,#data OR immediate data to ACC. 2 1
- ORL direct,A OR ACC to direct byte. 2 1
- ORL direct,#data OR immediate data to direct byte. 3 2
- XRL A,Rn Exclusive OR Register to ACC. 1 1
- XRL A,direct Exclusive OR direct byte to ACC. 2 1
- XRL A,@Ri Exclusive OR indirect RAM to ACC. 1 1
- XRL A,#data Exclusive OR immediate data to ACC. 2 1
- XRL direct,A Exclusive OR ACC to direct byte. 2 1
- XRL direct,#data XOR immediate data to direct byte. 3 2
- CLR A Clear ACC (set all bits to zero). 1 1
- CPL A Compliment ACC. 1 1
- RL A Rotate ACC left. 1 1
- RLC A Rotate ACC left through carry. 1 1
- RR A Rotate ACC right. 1 1
- RRC A Rotate ACC right through carry. 1 1
- SWAP A Swap nibbles within ACC. 1 1
- Data Transfer
- Mnemonic Description Size Cycles
- MOV A,Rn Move register to ACC. 1 1
- MOV A,direct Move direct byte to ACC. 2 1
- MOV A,@Ri Move indirect RAM to ACC. 1 1
- MOV A,#data Move immediate data to ACC. 2 1
- MOV Rn,A Move ACC to register. 1 1
- MOV Rn,direct Move direct byte to register. 2 2
- MOV Rn,#data Move immediate data to register. 2 1
- MOV direct,A Move ACC to direct byte. 2 1
- MOV direct,Rn Move register to direct byte. 2 2
- MOV direct,direct Move direct byte to direct byte. 3 2
- MOV direct,@Ri Move indirect RAM to direct byte. 2 2
- MOV direct,#data Move immediate data to direct byte. 3 2
- MOV @Ri,A Move ACC to indirect RAM. 1 1
- MOV @Ri,direct Move direct byte to indirect RAM. 2 2
- MOV @Ri,#data Move immediate data to indirect RAM. 2 1
- MOV DPTR,#data16 Move immediate 16 bit data to data pointer register. 3 2
- MOVC A,@A+DPTR Move code byte relative to DPTR to ACC (16 bit address). 1 2
- MOVC A,@A+PC Move code byte relative to PC to ACC (16 bit address). 1 2
- MOVX A,@Ri Move external RAM to ACC (8 bit address). 1 2
- MOVX A,@DPTR Move external RAM to ACC (16 bit address). 1 2
- MOVX @Ri,A Move ACC to external RAM (8 bit address). 1 2
- MOVX @DPTR,A Move ACC to external RAM (16 bit address). 1 2
- PUSH direct Push direct byte onto stack. 2 2
- POP direct Pop direct byte from stack. 2 2
- XCH A,Rn Exchange register with ACC. 1 1
- XCH A,direct Exchange direct byte with ACC. 2 1
- XCH A,@Ri Exchange indirect RAM with ACC. 1 1
- XCHD A,@Ri Exchange low order nibble of indirect RAM with low order nibble of ACC. 1 1
- Boolean Variable Manipulation
- Mnemonic Description Size Cycles
- CLR C Clear carry flag. 1 1
- CLR bit Clear direct bit. 2 1
- SETB C Set carry flag. 1 1
- SETB bit Set direct bit. 2 1
- CPL C Compliment carry flag. 1 1
- CPL bit Compliment direct bit. 2 1
- ANL C,bit AND direct bit to carry flag. 2 2
- ANL C,/bit AND compliment of direct bit to carry. 2 2
- ORL C,bit OR direct bit to carry flag. 2 2
- ORL C,/bit OR compliment of direct bit to carry. 2 2
- MOV C,bit Move direct bit to carry flag. 2 1
- MOV bit,C Move carry to direct bit. 2 2
- JC rel Jump if carry is set. 2 2
- JNC rel Jump if carry is not set. 2 2
- JB bit,rel Jump if direct bit is set. 3 2
- JNB bit,rel Jump if direct bit is not set. 3 2
- JBC bit,rel Jump if direct bit is set & clear bit. 3 2
- Program Branching
- Mnemonic Description Size Cycles
- ACALL addr11 Absolute subroutine call. 2 2
- LCALL addr16 Long subroutine call. 3 2
- RET Return from subroutine. 1 2
- RETI Return from interrupt. 1 2
- AJMP addr11 Absolute jump. 2 2
- LJMP addr16 Long jump. 3 2
- SJMP rel Short jump (relative address). 2 2
- JMP @A+DPTR Jump indirect relative to the DPTR. 1 2
- JZ rel Jump relative if ACC is zero. 2 2
- JNZ rel Jump relative if ACC is not zero. 2 2
- CJNE A,direct,rel Compare direct byte to ACC and jump if not equal. 3 2
- CJNE A,#data,rel Compare immediate byte to ACC and jump if not equal. 3 2
- CJNE Rn,#data,rel Compare immediate byte to register and jump if not equal. 3 2
- CJNE @Ri,#data,rel Compare immediate byte to indirect and jump if not equal. 3 2
- DJNZ Rn,rel Decrement register and jump if not zero. 2 2
- DJNZ direct,rel Decrement direct byte and jump if not zero. 3 2
- Other Instructions
- Mnemonic Description Size Cycles
- NOP No operation. 1 1
复制代码
其它可查看《单片机基础》-李广弟等编著,P70 “MCS-51单片机指令汇总”
|