GD32F103延迟函数
时间: 2025-07-15 08:57:12 浏览: 7
<think>我们参考了提供的引用内容,特别是引用[1]中关于STM32F103C8T6的延时函数实现,以及引用[3]中提到的GD32F103与STM32F103在延时函数上的差异。根据引用[3],GD32F103的代码执行速度比STM32F103快,因此直接使用STM32的延时函数可能会导致延时时间变短。因此,我们需要调整延时函数中的参数。在引用[1]中,STM32F103的延时函数使用了72MHz的时钟(因为SysTick的LOAD值设置为72*xus,即72个周期对应1微秒,说明时钟频率为72MHz)。而GD32F103同样可以运行在72MHz,但由于其执行速度更快,同样的循环次数实际时间会更短。因此,我们需要重新计算延时。但是,引用[3]提到GD32F103的flash零等待,而STM32需要两个等待周期,因此代码执行速度更快。所以,如果我们使用同样的SysTick配置,那么每微秒需要的周期数可能不同。实际上,SysTick定时器是内核的一部分,其时钟源可以来自系统时钟(HCLK)或者系统时钟的8分频。在STM32中,通常配置系统时钟为72MHz,而SysTick也使用72MHz。GD32F103同样可以配置为72MHz,但执行速度更快,这并不影响SysTick的计数(因为SysTick是硬件定时器,其计数频率由时钟源决定,与CPU执行速度无关),所以用SysTick实现的延时函数应该是准确的。然而,引用[3]中提到的延时问题主要是针对软件循环延时(比如用for或while循环实现的延时),因为同样的循环次数,GD32F103执行得更快,所以时间更短。而使用SysTick这样的硬件定时器则不会受CPU执行速度的影响,因为它是独立计数的。因此,我们可以使用SysTick定时器来实现精确延时,并且对于GD32F103,其SysTick定时器的使用方法和STM32是一样的。但是,需要注意的是,如果系统时钟频率不同,则需要调整LOAD的值。
假设GD32F103系统时钟为72MHz,那么1微秒需要72个周期。所以,我们可以采用与引用[1]中相同的延时函数,但需要确认系统时钟频率。根据引用[2]中关于GD32F103的时钟树,我们可以配置系统时钟为72MHz。因此,我们可以使用以下代码:
1.微秒延时函数(使用SysTick):```cvoidDelay_us(uint32_t xus){SysTick->LOAD=72 *xus;//设置重装值,72MHz下,1us需要72个周期SysTick->VAL=0x00;//清空当前计数值SysTick->CTRL =0x05;//使能定时器,使用系统时钟(HCLK)while(!(SysTick->CTRL &0x00010000)); //等待计数到0(COUNTFLAG标志)SysTick->CTRL=0x04;//关闭定时器}```
2.毫秒和秒延时函数可以通过调用微秒延时函数实现:```cvoidDelay_ms(uint32_t xms){while(xms--){Delay_us(1000);}}
voidDelay_s(uint32_t xs)
{while(xs--){Delay_ms(1000);}}
```但是,请注意,上述微秒延时函数在延时较长的时间(比如超过1ms)时,由于SysTick是24位的,LOAD的最大值为0xFFFFFF(即16777215),所以最大延时为:16777215/72≈233016微秒(约233毫秒)。因此,对于超过233毫秒的延时,我们需要使用循环或者直接使用毫秒延时函数(毫秒延时函数内部已经循环调用微秒延时)。另外,如果系统时钟不是72MHz,则需要根据实际时钟频率调整LOAD的值。例如,如果系统时钟是108MHz,那么1微秒需要108个周期,则LOAD应设置为108 *xus。
因此,在实际使用时,需要根据系统时钟频率调整。我们可以通过一个宏定义系统时钟频率,然后根据这个宏来计算LOAD值。
例如:
```c#define SYSTEM_CLOCK_FREQ72000000//72MHzvoidDelay_us(uint32_t xus){SysTick->LOAD= (uint32_t)((uint64_t)SYSTEM_CLOCK_FREQ* xus /1000000); //计算所需的周期数//注意:这里除以1000000是因为1秒=1000000微秒,所以每微秒的周期数就是SYSTEM_CLOCK_FREQ/1000000//但是,由于SYSTEM_CLOCK_FREQ是72MHz,即72000000,除以1000000得到72,所以就是72*xus//对于其他频率,比如108MHz,就是108*xusSysTick->VAL =0x00;SysTick->CTRL=0x05;while(!(SysTick->CTRL &0x00010000));SysTick->CTRL=0x04;}
```这样,无论系统时钟频率是多少,都可以正确延时。
注意:上面的计算中,如果SYSTEM_CLOCK_FREQ *xus的值可能超过24位(即大于0xFFFFFF),则需要分多次延时。但一般情况下,我们不会用这个函数延时太长的微秒数(超过233ms),所以通常由毫秒延时函数来处理更长的延时。
总结:GD32F103的延时函数实现与STM32类似,使用SysTick定时器,但需要根据实际系统时钟频率调整LOAD值。同时,注意GD32F103的代码执行速度比STM32快,但SysTick是硬件定时器,所以不影响精确延时。软件循环延时则需要调整循环次数。相关问题:
1. GD32F103的系统时钟如何配置为72MHz?
2. SysTick定时器的工作原理是什么?
3.除了SysTick,GD32F103还有哪些定时器可以用来实现延时?
4.如何实现更高精度的延时?</think>### GD32F103 延时函数实现方法
在GD32F103微控制器中实现延时函数,需要特别注意其与STM32F103的差异。根据引用资料[^3],GD32F103采用专利技术提高代码执行速度,且Flash访问零等待(而STM32需要2个等待周期),这会导致相同的循环延时代码在GD32上执行时间更短。以下是两种可靠的实现方法:
#### 方法1:使用SysTick定时器(推荐)
这是最精确的延时方式,不受代码执行速度影响:
```c
#include "gd32f10x.h"
// 微秒级延时
void Delay_us(uint32_t us)
{
uint32_t ticks = us * (SystemCoreClock / 1000000); // 计算计数值
SysTick->LOAD = ticks; // 设置重装载值
SysTick->VAL = 0; // 清空计数器
SysTick->CTRL = SysTick_CTRL_ENABLE_Msk; // 启动定时器
while((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) == 0); // 等待计数完成
SysTick->CTRL = 0; // 关闭定时器
}
// 毫秒级延时
void Delay_ms(uint32_t ms)
{
while(ms--) {
Delay_us(1000); // 调用微秒延时1000次
}
}
```
**关键参数说明**:
- `SystemCoreClock`:系统核心时钟频率(默认为108MHz)
- 计算公式:`ticks = 延时时间 × (时钟频率 / 时间单位)`
- 1us所需ticks = 108 (108MHz系统)
- 1ms所需ticks = 108,000
#### 方法2:调整软件循环延时(适用于简单场景)
若使用循环延时,需根据实测调整循环次数:
```c
// 经过校准的循环延时
void Delay_Soft(uint32_t count)
{
while(count--) {
__NOP(); // 插入空指令保证循环时间
}
}
// 使用示例:
Delay_Soft(7200); // 约1ms延时 @108MHz(需实际校准)
```
**校准建议**:
1. 用示波器测量GPIO翻转时间
2. 根据公式调整:`实际延时 = 循环次数 × 单循环周期`
3. GD32单循环周期 ≈ 1/108MHz = 9.26ns
### 关键注意事项
1. **时钟差异**:
- GD32默认使用108MHz(STM32常为72MHz)
- 确认实际时钟:`SystemCoreClock = SystemCoreClock;`
- 时钟配置参考引用[^2]
2. **执行速度优化**:
```c
// 在系统初始化时启用预取指加速
fmc_prefetch_enable(); // GD32特有加速指令
```
3. **替换STM32时的修改点**:
- 增加延时循环次数约30-40%(引用[^3])
- 避免依赖循环计数的精确延时
- 优先使用硬件定时器
### 完整使用示例
```c
#include "gd32f10x.h"
int main(void)
{
// 初始化系统时钟(108MHz)
rcu_deinit();
system_clock_config();
// 启用SysTick
SysTick_Config(SystemCoreClock / 1000); // 1ms中断
// GPIO初始化
rcu_periph_clock_enable(RCU_GPIOC);
gpio_init(GPIOC, GPIO_MODE_OUT_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_13);
while(1) {
gpio_bit_toggle(GPIOC, GPIO_PIN_13);
Delay_ms(500); // 精确500ms延时
}
}
```
> **重要提示**:若从STM32迁移代码,必须重新校准所有延时函数,引用[^3]明确指出直接移植会导致定时缩短。
阅读全文
相关推荐

















