| bald 发表于 2014-9-26 09:45  如果有中断源,软件延时很难准确。
 bne指令在RAM中运行三个周期没问题。在Flash中运行恐怕不是三个周期,应 ...
大侠 不要求太准。20%精度就行。
 
 网上找的代码
 
 
 另一种方法解决
 
 先上测试代码(普通版)
 
 #include "stm32f10x.h"
 #include "core_cm3.h"
 
 __asm int Dellayus(u32 usec)
 {
 ALIGN
 PUSH.W {r1}  //2时钟周期
 MOV r1,#18  //1时钟周期
 MUL r0,r1  //1时钟周期
 SUB r0,#3  //1时钟周期
 loop
 SUBS r0,#1   //1时钟周期
 BNE loop   //如果跳转则为3个周期,不跳则只有1个周期
 POP {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时钟周期,同样验证上面的结论
 }
 }
 
 |