您的位置 首页 新品

STM下纯软件完成准确守时

先上测试代码(普通版)includestm32f10xhincludecore_cm3h__asmintDellayus(u32usec){ALIGNPUSHW{r1}2

先上测验代码(一般版)

#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时钟周期,相同验证上面的定论
}
}
示例代码见附件:
附件1:软件延时测验.rar (文件巨细: 21 KB 下载次数:218次)

附件2:软件延时测验增强版.rar (文件巨细: 22 KB 下载次数:309次)
1、顶,花了不少功夫!
不过在不一起钟条件下,应该就又要批改代码了吧?
比方36M?8M?
所以主张参加一个时钟参数,这样比较通用一点.
2、谢谢楼主!,我软件测验延时的时分并没有呈现当参数大于255奇妙的时分会多耗费2个时钟周期的状况,相同很准啊。还有我用J-LINK仿真SW形式,单步,那个SEC没有改变,不知道是怎么回事。还有一个问题:为什么返回值要用int不太懂汇编
3、需要将J-LINK设为JTAG形式才干读出SEC值,别的返回值用int其时首要是想今后添加函数功用
4、这个主张非常好,立刻上个增强版
5、呵呵,还不如用C的
voidDelay_us(unsignedintt)
{
inti;

for(i=0;i<144*t;i++){
;
}
}
比上面汇编的要准:一起1000个循环,
汇编用时为:100.844ms
C及时:100.139ms

6、搞个-O2优化试试,还准禁绝.
别的换个时钟频率试试,还准禁绝?
7、
//加个编译项就行了.
#define OSC (8) //界说为8M
#define OSC_D ((OSC*144)/8)
#pragma O3
void Delay_us(unsigned int t)
{
int i;
for(i=0; i
;
}
}
//测验
//运转时刻为100.014ms

呵呵,纯为游戏之作.在这种CPU,延时最好是用原子的办法了.

8、用原子的战舰开发板测验,用楼主这种办法,得到的延时总理理论时刻的1.5倍,比方要推迟1秒,实践总是1.5秒。
置疑CPU运转在48M,可是我设置的的确是72M,是不是哪里设置有问题?
9、要彻底准确的话还得提早关掉中止哦……
不过一般也不需要这么准确的延时,献上我的,不占用守时器资源哦:

#defineRT_TICK_PER_SECOND100
voidhw_tsc_init() //TSC-timestampcounter
{
unsignedintcnts;

cnts=(unsignedint)9000000/RT_TICK_PER_SECOND;

SysTick->CTRL&=0xfffffffb;//bit2清空,挑选外部时钟,也即HCLK/8
SysTick->LOAD=cnts-1;
SysTick->VAL=0;//writetoclean
SysTick->CTRL=0x01;//开端倒数不发生中止
}

voidhw_tick_start()
{
unsignedintcnts;

cnts=(unsignedint)9000000/RT_TICK_PER_SECOND;

SysTick->CTRL&=0xfffffffb;//bit2清空,挑选外部时钟,也即HCLK/8
SysTick->LOAD=cnts-1;
SysTick->CTRL=0x01;//开端倒数不发生中止

SysTick->CTRL=0x03; //发动systick并发生中止
}
voidhw_delay_us(unsignedintus)
{
unsignedintstart,target,cur;

while(us>500) //避免us超越systick周期。(假定systick周期超越500us)
{
hw_delay_us(500);
us-=500;
}

start=SysTick->VAL;
target=(start-us*9);

if(start
{
target+=(9000000/RT_TICK_PER_SECOND);
do
{
cur=SysTick->VAL;
}while(cur<=start||cur>target);//target不能等于start,不然死循环。也即us不能等于systick周期
}
else//target<=start
{
do
{
cur=SysTick->VAL;
}while(target<=start); //假定target为一个很小的值,则cur有可能在循环周期内溢出而大于target,故须加上cur<=start的条件
}
}

voidhw_delay_ms(unsignedintms)
{
while(ms–)
{
hw_delay_us(500);
hw_delay_us(500);
}
}

10、我不必软件延时的…
我一向用systick延时。
11、楼主给力,不过不引荐用楼主这种笨办法,楼主大能够移植ucos,移植成功后,你想定多久有多久,要多准确有多准确。
一起,我觉得用守时器完成准确延时比这个办法靠谱得多。
12、ucos的守时是以体系时基为单位的,比方OS_CFG_T%&&&&&%K_RATE_HZ设为100时就只能准确到10ms,也便是说高于10ms而且步进为10ms(50ms,500ms能较准确,但55ms就不准确了)能够比较准确守时,那我说延时10us如何用ucos的守时器守时呢?
13、你能够增大ucos的时钟节拍数,然后用OSTimeTick()来完成守时
14、STM32的守时器多的是,根本都用不完吧

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/xinpin/263328.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部