找回密码
 立即注册
查看: 38|回复: 2

请详细讲解一下不同时钟下延时、定时自适配问题

[复制链接]
  • 打卡等级:以坛为家I
  • 打卡总天数:244
  • 最近打卡:2025-09-02 07:22:54

152

主题

194

回帖

401

积分

中级会员

积分
401
发表于 7 天前 | 显示全部楼层 |阅读模式
请高手们详细讲解一下,在不同时钟频率下,不用改代码,有关延时函数、定时时间、波特率等自适配问题,代码怎么写?最好出一期详细的视频讲解。
回复

使用道具 举报 送花

3

主题

2001

回帖

850

积分

等待验证会员

积分
850
发表于 7 天前 | 显示全部楼层
在不同时钟频率下实现延时、定时及波特率等参数的自适配,是嵌入式系统开发中常见的问题。尤其在使用不同主频的微控制器(如STM32、ESP32、RISC-V等)时,若希望代码具备良好的可移植性与通用性,需设计出不依赖固定时钟频率的自适应机制。

一、延时函数的自适应

1. 延时原理
延时函数的核心在于基于系统时钟周期进行循环计数。例如,在标准的 for 循环延时中,通常会根据时钟频率计算所需循环次数,从而达到预期的延时时间。

2. 自适应方法
为实现不依赖固定时钟频率的延时,可以采用以下方式:
使用系统时钟频率变量:在程序中定义一个全局变量 SystemCoreClock 或类似变量,用于存储当前系统的主频。
动态计算延时周期:根据目标延时时间与当前系统时钟频率,动态计算所需的循环次数。
  1. c
  2. void Delayms(uint32t ms) {
  3.     uint32t ticks = ms  (SystemCoreClock / 1000);
  4.     for (uint32t i = 0; i < ticks; i++);
  5. }
复制代码
注意:此方法适用于低精度延时场景,高精度延时建议使用定时器或看门狗模块。

3. 使用定时器实现自适应延时
更可靠的方式是使用定时器(如STM32的TIMx),通过配置定时器的预分频值和自动重载寄存器,实现精确延时。该方式不受主频影响,只需根据当前时钟频率动态设置定时器参数。
  1. c
  2. void TimerInit(uint32t freq, uint32t ms) {
  3.     uint32t arr = (freq / 1000)  ms;
  4.     TIMTimeBaseInitTypeDef TIMInitStruct;
  5.     TIMInitStruct.TIMPrescaler = 0;
  6.     TIMInitStruct.TIMPeriod = arr;
  7.     TIMInitStruct.TIMCounterMode = TIMCounterModeUp;
  8.     TIMTimeBaseInit(TIMx, &TIMInitStruct);
  9.     TIMCmd(TIMx, ENABLE);
  10. }
复制代码

二、定时功能的自适应

1. 定时器的基本原理
定时器的核心是根据系统时钟进行计数,并在计数值达到设定值时触发中断或事件。因此,定时器的配置需要根据系统时钟频率进行调整。

2. 自适应配置策略
动态计算预分频值和自动重载值:
  
  1. c
  2.   void AdaptiveTimerConfig(uint32t targetfreq, uint32t periodms) {
  3.       uint32t ticks = (targetfreq / 1000)  periodms;
  4.       uint32t prescaler = (SystemCoreClock / targetfreq) - 1;
  5.       TIMTimeBaseInitTypeDef TIMInitStruct;
  6.       TIMInitStruct.TIMPrescaler = prescaler;
  7.       TIMInitStruct.TIMPeriod = ticks;
  8.       TIMTimeBaseInit(TIMx, &TIMInitStruct);
  9.   }
复制代码
使用系统时钟变量:确保所有定时器配置都基于当前系统时钟频率,避免硬编码。

三、波特率的自适应

1. 波特率计算原理
串口通信的波特率由系统时钟、分频系数、以及USART的寄存器配置决定。其公式如下:

$$
\text{BaudRate} = \frac{\text{SystemClock}}{16 \times (\text{USARTDIV})}
$$

其中,USARTDIV 是由寄存器配置决定的分频值。

2. 自适应配置方法
动态计算分频值:根据目标波特率和当前系统时钟频率,计算合适的分频系数。
  1. c
  2. void USARTBaudrateSet(USARTTypeDef USARTx, uint32t baudrate) {
  3.     uint32t usartdiv = SystemCoreClock / (16  baudrate);
  4.     USARTInitStruct.USARTBaudRate = baudrate;
  5.     USARTInitStruct.USARTParity = USARTParityNo;
  6.     USARTInitStruct.USARTWordLength = USARTWordLength8b;
  7.     USARTInitStruct.USARTStopBits = USARTStopBits1;
  8.     USARTInitStruct.USARTMode = USARTModeRx | USARTModeTx;
  9.     USARTInitStruct.USARTHardwareFlowControl = USARTHardwareFlowControlNone;
  10.     USARTInitStruct.USARTFIFOMode = USARTFIFOModeDisable;
  11.     USARTInit(USARTx, &USARTInitStruct);
  12.     USARTCmd(USARTx, ENABLE);
  13. }
复制代码
注意:部分MCU的USART模块支持自动分频,可通过配置寄存器实现自适应波特率。

四、总结

| 功能       | 实现方式                     | 关键点                         |
|------------|------------------------------|--------------------------------|
| 延时函数   | 动态计算循环次数             | 使用系统时钟变量               |
| 定时器     | 配置预分频和自动重载         | 根据当前时钟频率动态计算       |
| 波特率     | 计算分频系数                 | 确保基于当前系统时钟频率       |

以上方法均实现了“不改代码”即可适应不同主频的方案,适用于多平台、多时钟频率的嵌入式系统开发。如需进一步深入讲解,可结合具体MCU型号(如STM32F1/F4、ESP32、RISC-V等)进行示例分析,也可制作详细视频教程进行演示。

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

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:512
  • 最近打卡:2025-09-02 14:38:16

33

主题

2513

回帖

5427

积分

论坛元老

积分
5427
发表于 6 天前 | 显示全部楼层
总感觉你问了很多类似的问题。。。。。

ISP软件上的是根据生成代码的时钟数来完成确定时间的延时,不考虑延时当中中断的情况。

如果你也想弄一个的话,把你上述的需求实现的时钟数都考虑进去,大概也行。。。

最简单的现在不是有T11定时器了么,你可以用这个定时器来做延时。。
参考例程并不是对技术参 考手册的补充,而是对技术参 考手册的解释。
技术参 考手册不应该需要参考例程作为补充,而是解释成了参考例程的样子
回复

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2025-9-3 05:15 , Processed in 0.120079 second(s), 63 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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