for 循环,延时的时间长度相差两三倍。
本帖最后由 玄德 于 2024-10-9 11:13 编辑使用 AT32F403ACGT7 芯片,for( i=0; i <0x8000000; i++ ); 语句,
做不考虑精度的延时,比如 LED 亮、灭时间的长短。
以前正常的版本是 v31,亮灭的时间长短经过调整,一直很合适。
复制 v31 整个工程项目,命名为 v32 。做了少量的修改,我发誓和下面的问题无关。
现在,同样的 I-A-R 版本,同一块硬件电路板,同样的 for 语句,下载、运行,
发现 LED 亮灭时间明显变长,v32 的时间是 v31 的 2~3 倍,很明显。
顺便说一下,同样的情况,大概五六年前在 STM32F407VGT6 芯片上也遇到过。
下面的帖子将把我的努力和结果发上来,供大家参考、会诊。
本帖最后由 玄德 于 2024-10-8 16:39 编辑
首先想到的就是观察 for 语句的汇编语言是否相同。
分别打开 v31、v32 ,发现汇编语句是完全相同的。
如下图:
证明不是汇编造成的问题。
本帖最后由 玄德 于 2024-10-8 16:42 编辑
其次就怀疑时钟设置不同,v31 的频率高, v32 不知什么原因变低了。利用芯片的 pA8 引脚,输出内部的时钟信号,分频选择为 4 分频。
用示波器观察,无论 v31 还是 v32,pA8 输出的都是 48MHz 时钟,如下图:
至此再想不到其他原因。
特来求助。
@ArteryMCU @ArterySW
很可能是:
1-中断服务。验证方法是关闭全局中断
2-Flash访问时间参数不同 做了啥修改?可以把做的修改去掉,看时间一样不,如果一样,那一点点添加修改,直到不一样的时候,就找到添加了啥,会改变时间。 这是合理现象,每次for循环结束都会多一些loop back指令。没有汇编指令精炼。
如果要做延时函数,最好是使用定时器或systick做延时函数。或者尝试使用-o3优化等级再试试 会不会是两个代码位置不一样,导致指令预取缓存结果不一样 emm 别用delay 这种for循环的延时确实不同单片机不一样,单片机里面也是电路,哪怕你的时钟设置的是一样的 也会有差别的,你要重新测试一个值,最好用systick,或者定时器。 32位指令作为转移目标地址,并且不在4字节对齐地址时,会插入额外的取指等待周期,不过相差2~3倍有点夸张了
这种延时与芯片的具体实现有关,比如有指令高速缓存时,可能就没有这个额外的取指等待周期 早期的403、413等的取指零等待是用SRAM作为指令存储器实现的,后期的带指令预取或者也有高速指令缓存,指令执行的行为是有差异的
这种阻塞形式的延时会受很多因素影响,特别是有中断就会打断 编译器可能会对for循环进行优化,特别是当循环体内没有实际的操作或者操作非常简单时。优化后的代码可能会减少循环迭代的次数,从而缩短延时时间。 编译器可能会对代码进行优化,导致实际执行的指令数量与预期不同。例如,编译器可能会合并某些操作或删除未使用的变量。 编译器可能会对循环进行优化,导致实际执行的指令数少于预期,从而影响延时的准确性。可以通过关闭编译器优化或使用特定的编译器指令来避免这种情况。 建议使用单片机内部的定时器/计数器模块来产生延时,而不是依赖for循环。 如果for循环中涉及到外设的访问(如I/O操作),外设的响应时间和访问速度也会对延时长度产生影响。 在编译设置中选择较低的优化级别或完全关闭优化。 不同的编译器和硬件平台可能会对for循环的执行产生不同的影响。例如,某些编译器可能会生成更高效的代码来执行循环,而某些硬件平台可能具有更快的指令执行速度。