从入门单片机就在写延时函数,但是一直不知道延时具体时间,就连个大概都难知道。但都没关系,一般用不到比较精确的,精确的用定时器就好了,但是最近用到了DS18B20,那个时序的要求太严格了……
蓝桥杯用单片机为1T,就是一个机器周期就是一个时钟周期,时钟周期对应的是始终频率。时钟频率为11.0592,那么机器周期为0.09042us。在keil里,利用仿真功能可以看到我们写的C语言对应的汇编语言,然后我们就可以对照指令表分析函数的延时时间了。
使用keil进行仿真,可以看到对应的指令,然后去查询指令表,就可以计算了。指令表在stc的使用手册或者STC-ISP软件上都可以找到;
拿比较简单常用的延时函数来举例子:
void delay(unsigned int t)
{
while(t--);
}
void main()
{
delay(500);
}
对应汇编为
C: 地址 ** 指令 操作数 功能 机器周期数
/***********************函数调用*****************************/
C:0x001A 7F0A MOV R7,#0xF4 //2
C:0x001C 7E00 MOV R6,#0x01 //2
C:0x001E 02000F LJMP delay(C:000F) //4
/***********************函数调用****************************/
C:0x000F EF MOV A,R7 //A=R7 //1
C:0x0010 1F DEC R7 //R7-- //2
C:0x0011 AC06 MOV R4,0x06 //A = &0x06 //3
C:0x0013 7001 JNZ C:0016 //A==0 N:---->0x0016 Y:GoOn //4
C:0x0015 1E DEC R6 //R6-- //2
C:0x0016 4C ORL A,R4 //A=A|R4 //1
C:0x0017 70F6 JNZ delay(C:000F) //A==0 N--->0x00F //4
C:0x0019 22 RET //4
//***************************************//
大致画了个流程图
可以看到,调用函数需要8个机器周期,函数里循环一次需要15个机器周期,每次借位需要2个机器周期,函数返回需要4个机器周期。这样就可以得到公式了
T 延时 = 0.09042 ∗ ( 8 + 4 + 2 ∗ t 255 + 15 ∗ t ) T_{延时} = 0.09042*(8 + 4 + 2*\frac t {255} + 15*t) T延时=0.09042∗(8+4+2∗255t+15∗t)
所以当t = 500时, T 延时 = 0.09042 ∗ ( 8 + 4 + 2 ∗ 500 255 + 500 ∗ 15 ) = 679.4 u s T_{延时} = 0.09042*(8+4+2*\frac {500} {255} +500*15) = 679.4us T延时=0.09042∗(8+4+2∗255500+500∗15)=679.4us
当 t 稍微大点或者不要求精确,可以直接用t*15*0.09来计算。
下面是和前面差不多的
void delay(unsigned t)
{
while(t--){
_nop_();
_nop_();
}
}
C:0x0003 EF MOV A,R7 //1
C:0x0004 1F DEC R7 //2
C:0x0005 AC06 MOV R4,0x06 //3
C:0x0007 7001 JNZ C:000A //4
C:0x0009 1E DEC R6 //2
C:0x000A 4C ORL A,R4 //1
C:0x000B 6004 JZ C:0011 //4
C:0x000D 00 NOP //1
C:0x000E 00 NOP //1
C:0x000F 80F2 SJMP delay(C:0003) //3
C:0x0011 22 RET //4
也可以分析计算出其大致时间:传递参数4+调用函数4 + 循环 ((18+nop的个数)*t +2*t/255 )+返回4。 T 延时 = 0.09042 ∗ ( 8 + 4 + 2 ∗ t 255 + ( 18 + K n o p ) ∗ t ) T_{延时} = 0.09042*(8 + 4 + 2*\frac t {255} + (18+K_{nop})*t) T延时=0.09042∗(8+4+2∗255t+(18+Knop)∗t)
当然这里都是理论分析,凭感觉应该是对的,如果真的不知道不确定,这种方法还是可以参考一下的。
描述版的流程图