本帖最后由 尹小舟 于 2024-5-18 15:47 编辑
GD32H7是一款基于ARM Cortex-M7内核的32位高性能MCU(微控制器),通常用于需要高性能和复杂功能的应用中.它通常包含多种类型的定时器,以满足不同的应用需求。
以下是一些GD32H7可能包含的定时器资源及其简要描述:
- 1.基本定时器(Basic Timer):
- - 通常用于产生简单的定时或延迟。
- - 不支持输出比较或捕获/输入功能。
- 2.通用定时器(General-Purpose Timer):
- - 提供基本的定时功能,同时支持输出比较、PWM(脉冲宽度调制)和输入捕获功能。
- - 通常用于需要精确控制和测量的应用。
- 3.高级定时器(Advanced Timer):
- - 提供更复杂的定时和控制功能,如互补PWM输出、死区时间控制、编码器接口等。
- - 通常用于需要高性能电机控制或精确位置/速度测量的应用。
- 4.系统定时器(SysTick Timer):
- - 用于操作系统任务调度和时间管理。
- - 通常由RTOS(实时操作系统)或裸机程序使用。
- 5.看门狗定时器(Watchdog Timer):
- - 用于检测系统是否正常运行,并在系统出现故障时执行复位操作。
- - 可以是独立的硬件看门狗定时器或基于软件实现的看门狗。
# 1.通用定时器L0简述
通用定时器 L0(TIMER1/2/3/4/22/23/30/31)
1.4通道定时器
: 每个通用定时器都有四个独立的通道,每个通道都可以独立配置为输出比较、输入捕获或PWM输出等功能。
2.输入捕获
: 定时器的输入捕获功能允许它捕获外部事件的精确时间戳。这对于测量外部信号的频率、周期或脉冲宽度非常有用。
3.输出比较
: 输出比较功能允许定时器在计数器达到预设的值时改变其输出电平。这可以用于生成精确的延迟或触发其他电路。
4.PWM信号生成
:通过配置定时器的输出比较通道,可以生成PWM信号。这些信号对于电机控制、LED亮度调节等应用非常有用。
5.计数器
:通用定时器L0的计数器可以是16位或32位无符号计数器,具体取决于定时器的配置。计数器可以由内部时钟、外部时钟或外部触发事件驱动。
6.可编程性和外部事件驱动
:通用定时器是可编程的,这意味着用户可以通过配置定时器的各种参数(如预分频器、计数方向、计数模式等)来改变其行为。此外,外部事件(如外部触发信号)也可以用来驱动定时器的计数器。
7.定时器同步
:虽然每个定时器都是独立的,但它们的计数器可以被同步在一起,以便它们以相同的速率或相位运行。这对于需要多个定时器协同工作的应用非常有用。
# 2. GD32H7系统框图
![809552](/data/attachment/forum/202405/17/202826owd1bsedbpie40se.jpg.thumb.jpg?rand=2358.3549443800434)
定时器1的时钟可达300M,这可真高啊
# 3.通用定时器 L0结构框图
![809553](/data/attachment/forum/202405/17/203041gwftakvbbcfeg63s.jpg.thumb.jpg?rand=6731.697315374529)
3.捕获/比较通道
通用定时器L0的捕获模式
通用定时器L0的捕获模式允许其通道测量输入波形的时序参数,如频率、周期、占空比等。这对于需要精确测量外部信号特性的应用非常有用。
输入级组件
- - 1.数字滤波器:用于减少输入信号中的噪声和干扰,提高捕获的准确性和可靠性。
- - 2.通道极性选择:允许用户选择捕获上升沿、下降沿或两者都捕获。这取决于输入信号的特性以及需要测量的参数。
- - 3.边沿检测:当在输入引脚上检测到所选的边沿(上升沿或下降沿)时,触发捕获操作。
- - 4.通道预分频器:用于对输入信号进行分频,以调整捕获的分辨率和频率范围。通过预分频器,可 以将输入信号的频率降低到更适合捕获的范围内。
- 捕获操作
- 当在输入引脚上检测到所选的边沿时,TIMERx_CHxCV 寄存器会捕获当前定时器的值(即计数器当前的值)。这个值代表了从定时器开始计数到捕获到边沿所经过的时间。同时,CHxIF 位被置 1,表示捕获操作已完成。
如果 CHxIE(通道中断使能位)被设置为 1,当捕获操作完成时,会产生一个通道中断。这允许应用程序在捕获到边沿时执行特定的操作,如读取捕获的值、处理数据或触发其他事件。
捕获模式在多种应用中都非常有用,例如:
- 频率测量:通过测量两个连续边沿之间的时间差,可以计算出输入信号的频率。
- 占空比测量:通过捕获PWM信号的上升沿和下降沿,可以计算出其占空比。
- 波形分析:捕获模式可以用于分析复杂波形的时序特性,如脉冲宽度、脉冲间隔等。
#
4.参数结构体分析
```c
/* channel input parameter struct definitions */
typedef struct {
uint16_t icpolarity; /*!< channel input polarity */
uint16_t icselection; /*!< channel input mode selection */
uint16_t icprescaler; /*!< channel input capture prescaler */
uint16_t icfilter; /*!< channel input capture filter control */
} timer_ic_parameter_struct;
```
timer_ic_parameter_struct 结构体,它用于表示定时器(timer)的输入捕获(参数。下面是对每个字段的详细解释:
1.icpolarity(uint16_t):
- 这个字段用于设置输入捕获的极性。它有两个值:
- - 正边沿触发(例如,上升边沿)
- - 负边沿触发(例如,下降边沿)
- 这决定了在什么边沿上捕获输入信号的值。
2.icselection (uint16_t):
- 这个字段用于选择输入捕获的模式或类型。
- 这决定了如何捕获输入信号的值。
3.icprescaler(uint16_t):
- 输入捕获预分频器。
- 这是一个用于降低输入捕获时钟频率的计数器。通过预分频,可以减少捕获的频率,从而降低CPU的负载或提高捕获的分辨率。
- 例如,如果预分频器设置为4,那么每4个输入捕获时钟周期才会进行一次捕获。
4.icfilter(uint16_t):
- 输入捕获滤波器控制。
- 这是一个用于过滤输入信号中不需要的噪声或毛刺的滤波器。
- 通过设置滤波器的参数,可以控制其带宽或截止频率,从而去除高频噪声。、
- 最大值15
```c
/* TIMER init parameter struct definitions */
typedef struct {
uint16_t prescaler; /*!< prescaler value */
uint16_t alignedmode; /*!< aligned mode */
uint16_t counterdirection; /*!< counter direction */
uint64_t period; /*!< period value */
uint16_t clockdivision; /*!< clock division value */
uint32_t repetitioncounter; /*!< the counter repetition value */
} timer_parameter_struct;
```
timer_parameter_struct 的结构体,它用于表示定时器的初始化参数。下面是对每个字段的详细解释:
- 1.prescaler (uint16_t):
- - 预分频器的值。预分频器用于降低定时器的时钟频率。例如,如果定时器的时钟源是1MHz,并且预分频器设置为1000,那么定时器的实际计数频率就是1kHz。
- 2.alignedmode (uint16_t):
- - 对齐模式
- 3.counterdirection (uint16_t):
- - 计数器方向 向上计数、向下计数或双向计数(先向上再向下,或先向下再向上)。
- 4.period (uint64_t):
- - 周期值。这通常表示定时器在达到此值后会产生一个中断或触发一个事件。由于使用了uint64_t类型,定时器可以支持非常长的周期值,有的定时器是32位的
- 5.clockdivision (uint16_t):
- - 时钟分频值。这可能与预分频器不同,它可能用于控制定时器内部其他功能的时钟频率,如输出比较功能或输入捕获功能。
- 6.repetitioncounter (uint32_t):
- - 重复计数器值。这个字段通常用于在每个周期内的重复次数。如果设置了重复计数器,在(TIMERx_CREP0/1+1)次上溢后产生更新事件,否则在每次溢出时都会产生更新事件。在向上计数模式中,TIMERx_CTL0 寄存器中的计数方向控制位 DIR 应该被设置成 0。
# 5 .例程定时器配置
```c
/*!
\brief configure the TIMER peripheral
\param[in]none
\param[out] none
\retval none
*/
void timer_config(void)
{
/* TIMER1 configuration: input capture mode -------------------
the external signal is connected to TIMER1 CH0 pin (PA5)
the rising edge is used as active edge
the TIMER1 CH0CV is used to compute the frequency value
------------------------------------------------------------ */
timer_ic_parameter_struct timer_icinitpara;
timer_parameter_struct timer_initpara;
rcu_periph_clock_enable(RCU_TIMER1);
rcu_periph_clock_enable(RCU_SYSCFG);
timer_deinit(TIMER1);
/* TIMER1 configuration */
timer_struct_para_init(&timer_initpara);
timer_initpara.prescaler = 299;
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection= TIMER_COUNTER_UP;
timer_initpara.period = 65535;
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_initpara.repetitioncounter = 0;
timer_init(TIMER1, &timer_initpara);
/* TIMER1 configuration */
/* TIMER1 CH0 input capture configuration */
timer_channel_input_struct_para_init(&timer_icinitpara);
timer_icinitpara.icpolarity= TIMER_IC_POLARITY_RISING;
timer_icinitpara.icselection = TIMER_IC_SELECTION_DIRECTTI;
timer_icinitpara.icprescaler = TIMER_IC_PSC_DIV1;
timer_icinitpara.icfilter = 0x0;
timer_input_capture_config(TIMER1, TIMER_CH_0, &timer_icinitpara);
/* auto-reload preload enable */
timer_auto_reload_shadow_enable(TIMER1);
/* clear channel 0 interrupt bit */
timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_CH0);
/* channel 0 interrupt enable */
timer_interrupt_enable(TIMER1, TIMER_INT_CH0);
/* TIMER1 counter enable */
timer_enable(TIMER1);
}
```
# 7.例程使用
![809554](/data/attachment/forum/202405/17/203913pi4xwj4zhacjfaix.jpg.thumb.jpg?rand=9275.50999718568)
在GD32H7xx_Firmware_Library_V1.2.0复制Template文件文件夹出来,并改名TIMER1_inputcapture
同时在里面新建IDE文件夹将Template的文件复制到IDE文件夹里面,
同时复制Fimware和Utilities文件夹到TIMER1_inputcapture中,然后复制例程到IDE_project
#
# 8.例程测试
使用例程捕获18,19,HZ 后,就乱码了
# 9. 尝试改进例程
定时器配置代码
```c
/*!
\brief configure the TIMER peripheral
\param[in]none
\param[out] none
\retval none
*/
void timer_config(void)
{
/* TIMER1 configuration: input capture mode -------------------
the external signal is connected to TIMER1 CH0 pin (PA5)
the rising edge is used as active edge
the TIMER1 CH0CV is used to compute the frequency value
------------------------------------------------------------ */
timer_ic_parameter_struct timer_icinitpara;
timer_parameter_struct timer_initpara;
rcu_periph_clock_enable(RCU_TIMER1);
rcu_periph_clock_enable(RCU_SYSCFG);
timer_deinit(TIMER1);
/* TIMER1 configuration */
timer_struct_para_init(&timer_initpara);
timer_initpara.prescaler = 299;
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection= TIMER_COUNTER_UP;
timer_initpara.period = 65535;
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_initpara.repetitioncounter = 0;
timer_init(TIMER1, &timer_initpara);
/* TIMER1 configuration */
/* TIMER1 CH0 input capture configuration */
timer_channel_input_struct_para_init(&timer_icinitpara);
timer_icinitpara.icpolarity= TIMER_IC_POLARITY_RISING;
timer_icinitpara.icselection = TIMER_IC_SELECTION_DIRECTTI;
timer_icinitpara.icprescaler = TIMER_IC_PSC_DIV1;
timer_icinitpara.icfilter = 0x0;
timer_input_capture_config(TIMER1, TIMER_CH_0, &timer_icinitpara);
/* auto-reload preload enable */
timer_auto_reload_shadow_enable(TIMER1);
/* clear channel 0 interrupt bit */
timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_CH0|TIMER_INT_FLAG_UP);
/* channel 0 interrupt enable */
timer_interrupt_enable(TIMER1, TIMER_INT_CH0|TIMER_INT_UP);
/* TIMER1 counter enable */
timer_enable(TIMER1);
}
```
中断处理函数
```c
/*!
\brief this function handles TIMER1 interrupt request
\param[in]none
\param[out] none
\retval none
*/
void TIMER1_IRQHandler(void)
{
static char flag_h = 0;
if(0 == flag_h)
{
if(SET == timer_interrupt_flag_get(TIMER1, TIMER_INT_FLAG_CH0)) {
/* clear channel 0 interrupt bit */
timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_CH0);
readvalue1 = timer_channel_capture_value_register_read(TIMER1, TIMER_CH_0);
flag_h= 1;
}
} else {
if(SET == timer_interrupt_flag_get(TIMER1, TIMER_INT_FLAG_UP)) {
timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_UP);
count_up++;
} else if(SET == timer_interrupt_flag_get(TIMER1, TIMER_INT_FLAG_CH0)) {
readvalue2 = timer_channel_capture_value_register_read(TIMER1, TIMER_CH_0);
timer_interrupt_flag_clear(TIMER1, TIMER_INT_FLAG_CH0);
if(0 == count_up)
{
count = readvalue2 - readvalue1;
}
else{
count = count_up* 0xffff - readvalue1 +readvalue2;
}
fre = 1000000 / count;
count_up = 0;
count =0 ;
readvalue1 = 0;
readvalue2 = 0;
flag_h = 0;
}
}
}
```
误差也比较大
TIMER1_inputcapture.zip
(1.52 MB, 下载次数: 9)