不用定时器得到精确定时
先上测试代码(普通版)
#include "stm32f10x.h"
#include "core_cm3.h"
__asm int Dellayus(u32 usec)
{
ALIGN
 USH.W {r1} //2时钟周期
MOV r1,#18 //1时钟周期
MUL r0,r1 //1时钟周期
SUB r0,#3 //1时钟周期
loop
SUBS r0,#1 //1时钟周期
BNE loop //如果跳转则为3个周期,不跳则只有1个周期
 OP {r1} //2时钟周期
BX lr //3个时钟周期
//总共所用周期为(usec*4)-4,此处减4主要用于抵消调用此函数的消耗时钟周期(传参1时钟,BLX跳转3时钟)
}
int main(void)
{
while(1)
{
//运行到此处时32.93us,第1379时钟周期
Dellayus(100);
//运行到此处时132.93us,第8579时钟周期,运行上条指令共花8579-1379=7200时钟周期
//因系统时钟为72MHz,所以每72时钟周期所花时间为1微妙,上条指令所花时间
//等于7200 ÷ 72 = 100微妙,延时完全准确
Dellayus(100);
//运行到此处时232.93us,第15779时钟周期,同样验证上面的结论
}
}
调试:
第一个100微妙延时函数运行前
第一个100微妙延时函数运行后
所花系统时钟周期8579-1379=7200个系统时钟,时间精确为0.00013293-0.0003293=0.0001秒,
也就是100微秒。延时函数通过软件模拟以及硬件调试同样精确,如果延时参数大于255微秒,调用
时会多耗两个时钟周期(0.028微秒)用于从代码段加载常数。可以修改代码修正误差。最大定时不能
超过(232-1) ÷ 18 ≈ 238.6秒。
以上方法可以节约系统定时器资源,避免和其他代码争用定时器。通常用于微秒級延时。
版主的建议非常好,是该增加时钟参数以适应不同的时钟频率,改了一下代码,目前软件仿真测试没问题,等晚上再用JLink
测试一下(理论上应该没问题,已经考虑了闪存预取优化)。
#include "stm32f10x.h"
#include "core_cm3.h"
__asm void Dellayus(u32 usec,u8 freq) //freq参数为系统时钟频率(SYSCLK),单位MHz,且必须能被4整除,且必须大 于等于16,常用的
{ //有24,36,48,56,72,如果一定要使用8MHz则必须满足延时时间大于2微秒,但freq一定不要
//小于8MHz,否则函数将出现混乱。条件为 ((usec >= 1) && (freq >=16)) || ((usec >= 2) && (freq >= 8))
ALIGN
LSR r1,r1,#2 //1时钟周期,除以单次循环所用的时钟数(4个)即得到延时1微妙所需的循环数
MUL r0,r1 //1时钟周期
SUB r0,#3 //1时钟周期
NOP //用于匹配延时周期以及使loop循环处指令在8字节边界对齐,提高精度(因为指令预取单元一次预取8字节指令)
NOP //所以循环时都不用再从闪存内取指令,避免闪存延时影响延时精度
loop
SUBS r0,#1 //1时钟周期
BNE loop //延时循环,每次4个时钟周期,最后一次只需两个时钟周期(如果跳转则为3个周期,不跳则只有1个周期)
NOP
BX lr //3个时钟周期
//本函数内总共所用周期为usec*(freq/4)-2 +9,调用此函数的消耗5个时钟周期(传参2时钟,BLX跳转3时钟)
} //函数最低耗时11个时钟周期,上面usec*(freq/4) - 2为循环代码的耗时(此处减2是因为最后一次循环BNE没有跳转,只消耗1个时钟比跳转的3个时钟节约2个所以减去2才是最终循环的耗时),9就是其它代码的耗时
//比如频率为8MHz时延时2微秒所需延时周期数为2*8=16个时钟,将值带入上面的公式即为 2 * (8 / 4) - 2 + 9 =11 即为函数体耗时,再加上5个周期的调用开销最终消耗16个时钟周期,同时这也是最低延时周期数。
int main(void)
{
while(1)
{
//运行到此处时32.93us,第1379时钟周期
Dellayus(100,72);
//运行到此处时132.93us,第8579时钟周期,运行上条指令共花8579-1379=7200时钟周期
//因系统时钟为72MHz,所以每72时钟周期所花时间为1微妙,上条指令所花时间
//等于7200 ÷ 72 = 100微妙,延时完全准确
Dellayus(100,72);
//运行到此处时232.93us,第15779时钟周期,同样验证上面的结论
}
}
示例代码见附件
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
--------------------------回复【5楼】xiaoyan:
---------------------------------
需要将JTAG设为JTAG模式才能读出SEC值,另外返回值用int 当时主要是想以后增加函数功能
一周热门 更多>