硬汉嵌入式论坛

 找回密码
 立即注册
查看: 807|回复: 12
收起左侧

[技术讨论] 想法:一个新的软件精确延时方式

  [复制链接]

1

主题

4

回帖

7

积分

新手上路

积分
7
发表于 2026-1-15 10:27:24 | 显示全部楼层 |阅读模式



使用硬件延时有其局限性,而软件延时局限性较小
软件延时不是加就是减 , 现使用systick来进行矫正(CortexM内核都有systick),代码复用性强,优化等级无关

伪代码,只是一个想法 , 没有实践
  
static int times  ;


void delayInit ( void )
{
   volatile int cnt = 0 ;
   int val , times ,max  ;

   maxTimes = 1000000 ;
   systick_start ( )  ; // 最大计数
   for ( cnt = 0 ; cnt < maxTimes ; cnt++) ;  // for 循环执行时间必须小于systick的最大执行时间
   val = systick_val ( )  ; // 获取计数值 , 可以用来计算获取执行 maxTimes 使用了多少时间
   systick_stop ( ) ; // 停止systick
   times = xxxxxxx  ; // 计算 maxTimes 使用多少时间 ,并提取1微妙使用的times计数
}
   
void delay1us ( void )
{
   for ( volatile  int i = 0 ; i < times  ;  i++) ;
}  
   
回复

使用道具 举报

0

主题

3

回帖

3

积分

新手上路

积分
3
发表于 2026-1-15 11:45:10 | 显示全部楼层
回复

使用道具 举报

0

主题

35

回帖

35

积分

新手上路

积分
35
发表于 2026-1-15 16:00:25 | 显示全部楼层
不使用硬件的延时,在之前的51单片机上可以直接用计算运行了多少指令周期,就能计算出精确的延时时间。当调用这个函数的时候,如果函数运行期间没有中断打断,那么定时就是精准的。

但是这些arm内核的单片机,,,我不太好说。。。
回复

使用道具 举报

4

主题

457

回帖

469

积分

高级会员

积分
469
发表于 2026-1-15 16:46:46 | 显示全部楼层
perf_counte 就是这么实现的,用keil的还可以RTE一键增加
https://github.com/GorgonMeducer/perf_counte
回复

使用道具 举报

7

主题

167

回帖

188

积分

初级会员

积分
188
发表于 2026-1-15 23:22:53 | 显示全部楼层
我直接在定时器中断程序里放了一个计数程序,用批量操作实现状态查询和定时增加以及清零复位,256个软件定时器大约占了F4的15us,H7的大约4us,如果数学好进行更多优化应该还有优化空间。

程序不优化或者O1优化下测试的。
回复

使用道具 举报

10

主题

154

回帖

184

积分

初级会员

积分
184
发表于 2026-1-16 09:02:30 | 显示全部楼层
我现在都是开两个硬件定时器, 一个作为毫秒一个作为微秒, 将定时器对应的寄存器映射为变量, 溢出值为FFFFFFFF, 不使用任何中断,
每次比较上次值和当前值的区别, 定时器的精度仅仅与总线访问寄存器的速度有关. 毫秒基本上没有问题, 在总线速度比较慢的内核中, 微秒定时会有一点影响.
回复

使用道具 举报

1

主题

10

回帖

13

积分

新手上路

积分
13
发表于 2026-1-16 10:47:55 | 显示全部楼层
片上有32位定时器的话全局时钟的方式好点,计数频率1m,1秒中断一次,直接记录unix时间戳,要延时的话记录一个时间戳计算一下到达时间就行了
回复

使用道具 举报

1万

主题

7万

回帖

12万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
121120
QQ
发表于 2026-1-16 10:50:29 | 显示全部楼层
除了M0和M23,其它内核都可以使用DWT时钟周期计数器。

DWT实现一个精确微秒延迟的参考例程
https://forum.anfulai.cn/forum.p ... 9128&fromuid=58
(出处: 硬汉嵌入式论坛)
回复

使用道具 举报

1

主题

89

回帖

92

积分

初级会员

积分
92
发表于 2026-1-16 12:07:33 | 显示全部楼层
本帖最后由 dukelec 于 2026-1-16 12:27 编辑

楼主这种做法不准,譬如 dma 传输会让 cpu 运行速度降低

用 systick 做 us 级别的精准延迟,我的代码如下(不影响 systick 全局 1ms 计时):

[C] 纯文本查看 复制代码
// from: [url]https://github.com/dukelec/cdnet/blob/master/arch/stm32/arch_wrapper.c[/url]

void delay_us(uint32_t us)
{
    uint32_t cnt_1ms = SysTick->LOAD + 1;
    uint32_t last = SysTick->VAL;
    uint32_t total = 0;
    uint32_t target = cnt_1ms / 1000 * us;

    while (total < target) {
        uint32_t cur = SysTick->VAL;
        int32_t diff = last - cur;
        if (diff < 0)
            diff += cnt_1ms;
        total += diff;
        last = cur;
    }
}



回复

使用道具 举报

723

主题

3797

回帖

5991

积分

论坛元老

自定义头衔

积分
5991
发表于 2026-1-16 14:27:38 | 显示全部楼层
dukelec 发表于 2026-1-16 12:07
楼主这种做法不准,譬如 dma 传输会让 cpu 运行速度降低

用 systick 做 us 级别的精准延迟,我的代码如 ...

这个延时方法如果使用在 模拟 i2c 上长期工作稳定不 ?
回复

使用道具 举报

3

主题

95

回帖

104

积分

初级会员

积分
104
发表于 2026-1-16 15:41:52 来自手机 | 显示全部楼层
要微秒级精度,前提是要关中断吧
回复

使用道具 举报

1

主题

4

回帖

7

积分

新手上路

积分
7
 楼主| 发表于 2026-1-16 16:24:02 | 显示全部楼层
哪有完美的延时函数, 要么移植方便,要么硬件定制
1.被中断打断
2.被RTOS任务切换打断
3.开关中断影响实时性
4.总线带宽导致运行慢
5.有些代码还可能在中断函数里面调用延时函数
...
代码做好容错处理才是真的
回复

使用道具 举报

3

主题

14

回帖

23

积分

新手上路

积分
23
发表于 2026-1-20 21:02:47 | 显示全部楼层
cctv180 发表于 2026-1-15 16:46
perf_counte 就是这么实现的,用keil的还可以RTE一键增加
https://github.com/GorgonMeducer/perf_cou ...

us级别的延时并不精确
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2026-2-24 07:23 , Processed in 0.057644 second(s), 25 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表