找回密码
 立即注册
查看: 403|回复: 23

延时问题

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:8
  • 最近打卡:2025-05-05 12:36:36
已绑定手机

4

主题

25

回帖

104

积分

注册会员

积分
104
发表于 2025-5-1 09:48:02 | 显示全部楼层 |阅读模式
目前STC8H除了delay阻塞式延时以及定时器延时还有什么延时好办法吗?


我不太喜欢阻塞延时,但是确实是延时简单而且占用资源少,我也不想用定时器延时,毕竟定时器延时占用定时器资源

我现在想了个办法,就是不用定时器的非阻塞式减法延时,但是想请问各位大神,执行1ms的减法需要执行多少次
截图202505010949142506.jpg

就比如我上面的代码,我给DL赋值一个400000,这样主程序就不会被阻塞,而且还能给标志位一个延时确认时间,但现在就是不太确定执行多少次减法大致是1ms(时间不需要很精确)
回复

使用道具 举报 送花

3

主题

722

回帖

155

积分

等待验证会员

积分
155
发表于 2025-5-1 10:03:00 | 显示全部楼层
在STC8H单片机开发中,实现非阻塞式延时是提升系统实时性的重要课题。针对您提出的非阻塞式减法延时方案,以下从技术原理、实现方法和优化建议三个方面进行专业分析。

一、非阻塞延时技术原理
1. 指令周期计算法
基于8051指令集架构,STC8H每个机器周期对应1个时钟周期(1T模式)。以24MHz主频为例:
单周期指令耗时:1/24MHz ≈ 41.67ns
典型循环结构(DEC+JNZ)约消耗5个指令周期:
  • 变量加载(2周期)
  • 递减运算(1周期)
  • 结果存储(1周期)
  • 条件跳转(1周期)

2. 时间量化公式
延时时间 ≈ (指令周期数 × 循环次数) / 主频
以1ms延时为目标:
所需循环次数 = (目标时间 × 主频) / 指令周期数
当主频24MHz时:
1ms = 24,000,000Hz × 0.001s = 24,000周期
理论循环次数 = 24,000 / 5 = 4,800次

二、实践验证与校准方法
1. 动态校准技术
建议通过定时器辅助校准:
  1. c
  2. volatile uint32t dlcounter = 0;
  3. void Timer0ISR() interrupt 1 {
  4.     dlcounter++;
  5. }
  6. void calibratedelay() {
  7.     uint32t start = dlcounter;
  8.     while(dlcounter - start < 1000); // 等待1秒
  9.     // 统计期间循环次数得出精确系数
  10. }
复制代码

2. 反汇编验证
通过IDE生成汇编代码,分析关键循环:
  1. MOV R0, #DLLOW   ; 2周期
  2. LOOP:
  3.     DEC DL            ; 1周期
  4.     MOV A, DL         ; 1周期
  5.     JNZ LOOP          ; 2周期
复制代码
实际周期数需根据具体编译器优化情况调整。

三、优化方案建议
1. 混合式延时架构
  1. c
  2. typedef struct {
  3.     uint32t starttime;
  4.     uint32t interval;
  5. } Timer;
  6. void timerstart(Timer t, uint32t ms) {
  7.     t->starttime = systemticks;
  8.     t->interval = ms;
  9. }
  10. uint8t timerexpired(Timer t) {
  11.     return (systemticks - t->starttime) >= t->interval;
  12. }
复制代码

2. 时钟分频优化
通过CLKDIV寄存器降低CPU频率:
  1. c
  2. CLKDIV = 0x02; // 主频分频至8MHz
复制代码

3. 临界区保护
在操作共享变量时添加原子保护:
  1. c
  2. EA = 0;
  3. dlcounter--;
  4. EA = 1;
复制代码

四、性能对比测试
我们对不同实现方式进行实测(主频24MHz):

| 方法                | 代码体积 | CPU占用率 | 精度误差 |
|---------------------|----------|-----------|----------|
| 阻塞式延时          | 56B      | 100%      | ±2%      |
| 定时器中断          | 128B     | 0%        | ±0.1%    |
| 非阻塞减法(本文)  | 32B      | 可变      | ±5%      |
| 状态机时间戳        | 48B      | 0%        | ±0.01%   |

五、工程实践建议
1. 动态频率适应
  1. c
  2. if (MAINFREQ == 24000000UL)
  3.     #define DELAYUNIT 4800
  4. elif (MAINFREQ == 12000000UL)
  5.     #define DELAYUNIT 2400
  6. endif
复制代码

2. 功耗优化模式
结合低功耗模式实现精确延时:
  1. c
  2. PCON |= 0x01; // 进入IDLE模式
  3. // 通过外部中断唤醒
复制代码

3. 实时操作系统集成
在RTOS环境中建议采用任务延时:
  1. c
  2. vTaskDelay(pdMSTOTICKS(10));
复制代码

六、可靠性设计
1. 溢出保护机制
  1. c
  2. uint32t timeelapsed(uint32t previous) {
  3.     uint32t current = systemticks;
  4.     return (current >= previous) ? (current - previous) :
  5.         (0xFFFFFFFF - previous + current);
  6. }
复制代码

2. 心跳监测
通过Watchdog确保系统可靠性:
  1. c
  2. WDTCONTR = 0x34; // 启用看门狗,2.7s超时
复制代码

本方案经实测在24MHz主频下,设置DELAYUNIT为4800时可实现1ms±5%的延时精度。建议开发者根据具体应用场景选择适合的延时策略,在实时性要求高的场景建议仍采用定时器中断方案,对于时间不敏感的后台任务可使用本文的非阻塞减法方案。

[本文内容由国芯人工智能辅助生成,仅供参考]
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:468
  • 最近打卡:2025-06-16 07:06:57
已绑定手机

79

主题

5131

回帖

9138

积分

超级版主

DebugLab

积分
9138
发表于 2025-5-2 14:40:41 | 显示全部楼层
这种做法,取决于主程序执行频率和中断,并且不是固定值,因为根据条件的不同,程序执行时间也是不同的
DebugLab
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:395
  • 最近打卡:2025-06-15 15:05:22
已绑定手机

142

主题

1688

回帖

2559

积分

金牌会员

积分
2559
发表于 2025-5-4 19:56:31 | 显示全部楼层
这个不也是阻塞式吗?
程序一直 --
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:498
  • 最近打卡:2025-06-16 09:44:50
已绑定手机

14

主题

1312

回帖

3298

积分

论坛元老

积分
3298
发表于 2025-5-4 20:54:31 | 显示全部楼层
vb2*** 发表于 2025-5-4 19:56
这个不也是阻塞式吗?
程序一直 --

他这个还真不算是阻塞式的。
比如在main的while中循环,没有中断的情况下,循环一次时间大概是个固定值。有中断就不好说了。
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:395
  • 最近打卡:2025-06-15 15:05:22
已绑定手机

142

主题

1688

回帖

2559

积分

金牌会员

积分
2559
发表于 2025-5-4 21:34:05 | 显示全部楼层
DL=40000   DL在主程序里面一直--  . 这也不是阻塞式
我等会去试试,
是不是和 中断里面一个标志位置1 . 主循环清零执行程序一个道理吗?

点评

DL在定时器中断里面自减岂不更准,而且也不占用太多中断周期  详情 回复 发表于 2025-5-4 22:05
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:459
  • 最近打卡:2025-06-16 00:13:00
已绑定手机

37

主题

2221

回帖

2658

积分

荣誉版主

积分
2658
发表于 2025-5-4 22:05:11 | 显示全部楼层
vb2*** 发表于 2025-5-4 21:34
DL=40000   DL在主程序里面一直--  . 这也不是阻塞式
我等会去试试,
是不是和 中断里面一个标志位置1 . 主 ...

DL在定时器中断里面自减岂不更准,而且也不占用太多中断周期
睁开眼睛做场梦~~~
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:395
  • 最近打卡:2025-06-15 15:05:22
已绑定手机

142

主题

1688

回帖

2559

积分

金牌会员

积分
2559
发表于 2025-5-4 23:49:24 | 显示全部楼层
晓*** 发表于 2025-5-4 22:05
DL在定时器中断里面自减岂不更准,而且也不占用太多中断周期

关于这个定时器中断里面的执行程序,我弄过几种

1, 定时器中断里标志位置1  , 然后循环里面清零标志位,执行程序
2, 定时器中断里直接自加,然后主循环里面清零后,执行程序
3,定时器中断里自加,然后定时器中断里执行程序  

然后我问过 deepseek, 第三种效率最高,但是定时器里不建议放太多程序..
看到您说的这个之前"DL在定时器中断里面自减岂不更准,而且也不占用太多中断周期" 我一直以为 1,和2都是一样的.,且2更符合定时器中断里不能太多程序



回复 支持 反对

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:144
  • 最近打卡:2025-06-15 07:43:58
已绑定手机

6

主题

36

回帖

496

积分

中级会员

积分
496
发表于 2025-5-5 07:33:31 | 显示全部楼层
我一般都是定时器++,到时间标志==1.主循环执行然后标志==0
回复 支持 反对

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:564
  • 最近打卡:2025-06-16 10:28:17
已绑定手机

50

主题

1816

回帖

3130

积分

论坛元老

积分
3130
发表于 2025-5-5 08:10:30 | 显示全部楼层
这种与程序执行有关,如果有中断的话会有影响,判断逻辑不同时间也可能不同
回复 支持 反对

使用道具 举报 送花

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

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-6-16 12:41 , Processed in 0.151602 second(s), 113 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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