1. 项目概述为什么通用定时器是嵌入式开发的“瑞士军刀”如果你玩过GD32或者STM32这类ARM Cortex-M内核的MCU肯定对定时器不陌生。但很多人对它的理解可能还停留在“定时中断”或者“简单PWM输出”的层面。今天我想以一个在工控和电机驱动项目里摸爬滚打多年的老工程师视角跟你深入聊聊GD32H7系列里的通用定时器General-purpose Timer 简称GPTM。这玩意儿远比你想象的要强大和复杂它就像一把嵌入式开发的“瑞士军刀”输入捕获、输出比较、PWM生成这三板斧用好了能解决项目中80%跟时间、频率、脉冲相关的棘手问题。GD32H7作为GD32家族的高性能成员其定时器外设继承了ARM生态的优良传统同时又有一些自身的增强特性。我们常说的通用定时器通常指TIMER0到TIMER5这类具体型号和数量需查数据手册它们结构相对标准但功能齐全。输入捕获能让你精准测量外部信号的脉宽或频率比如测旋转编码器的速度、超声波的回波时间输出比较则可以让你在精确的时刻翻转一个引脚的电平用于生成特定时序或触发其他外设而PWM模式则是驱动电机、控制LED亮度、发声等应用的基石。很多人调PWM只会改改占空比但背后关于计数器模式、对齐方式、死区插入的学问直接决定了系统能否稳定可靠地运行。接下来我就把这“三板斧”的里里外外、从寄存器配置到实战避坑给你一次性掰扯清楚。2. 核心原理与结构拆解通用定时器如何运转要玩转定时器的三大功能你必须先理解它的核心——那个不断累加或递减的计数器以及围绕它搭建的一整套控制逻辑。GD32H7的通用定时器通常是一个16位或32位的自动重载计数器配合一系列可编程的预分频器、捕获/比较通道和复杂的触发控制器构成。2.1 定时器的“心脏”计数器与时钟源计数器的行为是整个定时器功能的基石。它的时钟源可以是内部系统时钟CK_INT经过一个可编程的预分频器PSC分频后得到计数器时钟CK_CNT。比如系统时钟是200MHz你将PSC设置为199那么计数器时钟就是200MHz / (1991) 1MHz计数器每1微秒跳动一次。这个分频系数是动态可调的但通常修改后需要等到下一次更新事件UEV才会生效这是一个常见的坑点。计数器本身有几种工作模式向上计数模式从0累加到自动重载值ARR然后产生一个更新事件并归零如此循环。这是最常用的PWM生成模式。向下计数模式从ARR值递减到0产生更新事件后重新加载ARR值。中央对齐模式又称向上/向下计数先向上计数到ARR产生一个更新事件再向下计数到0再产生一个更新事件。这种模式能让你在计数器到达ARR和0时都产生中断或DMA请求常用于需要对称PWM或复杂时序的场景。这里的关键是自动重载寄存器ARR。它决定了计数器的周期。结合预分频器PSC输出信号的频率公式为Fpwm CK_INT / ((PSC1) * (ARR1))。很多人调不出想要的频率就是没搞懂这个“1”。因为PSC和ARR都是0基的写入0代表分频系数为1。2.2 捕获/比较通道多功能引脚的核心每个通用定时器通常有多个独立的通道比如4个每个通道都对应一个特定的GPIO引脚。这个通道在硬件上可以被配置成两种截然不同的角色输入捕获模式此时该通道的引脚用于“侦听”外部信号。当引脚上出现指定的边沿上升沿、下降沿或双边沿时硬件会瞬间将当前计数器的值“冻结”并锁存到一个专用的捕获/比较寄存器CCRx中。同时可以产生中断或DMA请求通知CPU“快来看这是信号跳变发生时的精确时间戳”。通过连续捕获两个边沿的时间戳就能计算出脉冲宽度或周期。输出比较模式此时该通道的引脚用于“主动发声”。你需要预先在捕获/比较寄存器CCRx中设定一个比较值。计数器运行时硬件会持续将计数器的当前值CNT与CCRx的值进行比较。当两者匹配时根据你设定的模式如翻转电平、强制高、强制低、PWM模式等硬件会自动改变对应输出引脚的电平状态。这是生成精确时间间隔或PWM波形的核心机制。一个非常重要的概念是CCRx寄存器在两种模式下复用但行为完全不同。在输入捕获时它是只读的由硬件写入捕获的时间戳在输出比较时它是可读写的由你写入比较值。模式的选择通过另一个寄存器CCMRx来配置千万别搞混了。2.3 高级控制逻辑预装载、影子寄存器与死区时间为了保证操作的同步性和安全性定时器引入了“预装载”和“影子寄存器”机制。预装载允许你提前设置好新的PSC或ARR值但这个新值不会立即生效而是先存放在一个“缓冲区”预装载寄存器里。直到下一个更新事件UEV发生时这个新值才会从缓冲区真正加载到当前工作的“影子寄存器”中从而生效。这避免了在计数器运行时修改周期或分频导致的脉冲紊乱。在需要动态调整PWM频率变频的应用中这个特性至关重要。死区时间插入这是电机驱动和电源控制中的保命功能。当定时器生成一对互补的PWM信号比如驱动H桥的上管和下管时绝对不能出现上下管同时导通的情况直通会短路烧管。死区时间插入就是在互补信号切换的过程中插入一个两者都为低电平或无效状态的小段时间确保一个管子完全关断后另一个管子才开启。GD32H7的定时器硬件支持可编程的死区时间生成你只需要配置一个寄存器BDTR或类似硬件就会自动处理好复杂的时序远比软件延时精准可靠。理解了这些底层原理我们再去看具体的功能实现就会觉得豁然开朗不再是对着库函数盲目调参了。3. 输入捕获模式深度解析与实战输入捕获功能的核心价值在于非侵入式地、高精度地测量外部信号的时间参数。它的精度直接取决于计数器时钟CK_CNT。假设CK_CNT是1MHz1us那么理论上你的测量分辨率就是1微秒。这对于测量毫秒甚至微秒级的脉冲宽度已经足够。3.1 输入捕获的完整工作流程GPIO与定时器通道映射首先需要将某个GPIO引脚配置为复用功能AF并映射到定时器的特定通道如TIMER2_CH1。同时根据信号特性配置上拉/下拉电阻以提高抗干扰能力。定时器基础配置初始化定时器时基单元。设置PSC得到合适的CK_CNT频率决定测量精度设置ARR为一个足够大的值要大于待测信号周期否则会溢出。通常让定时器处于自由运行模式即ARR设为最大值0xFFFF或0xFFFFFFFF。输入捕获通道配置这是关键步骤。通过CCMRx寄存器将通道配置为输入模式并选择输入滤波器和边沿检测器。例如你可以选择“无滤波上升沿捕获”。同时需要配置捕获信号到TIx输入端的路径直连或交叉。使能捕获与中断使能该通道的捕获功能并配置中断。通常需要使能两种中断一是“捕获/比较1中断”CC1IE用于在捕获事件发生时读取CCR1的值二是“更新中断”UIE用于处理计数器溢出扩展测量范围。中断服务程序ISR编写这是软件逻辑的核心。当捕获中断发生时读取当前的CCRx值这就是边沿到来时的时间戳t1。如果这是第一个边沿则记录t1并改变捕获边沿为相反的边沿如从上升沿改为下降沿等待下一次捕获。当捕获到第二个边沿如下降沿时再次读取CCRx值得到t2。那么高电平脉宽Width (t2 - t1) * (1 / CK\_CNT)。这里必须考虑计数器可能溢出过。如果t2 t1说明在t1到t2之间计数器发生了溢出那么实际的计数差值应该是(0xFFFF - t1) t2 1对于16位计数器。更新中断用于维护一个溢出计数器overflow_cnt。每次更新中断overflow_cnt。在计算长周期信号时最终的捕获时间需要结合overflow_cnt和CCRx值来综合计算。3.2 提高测量精度与可靠性的技巧使用更高频率的时钟在系统负载允许的情况下尽量提高CK_CNT频率。例如使用定时器的内部时钟通常与APB总线时钟相关并设置较小的PSC值。GD32H7性能强劲可以轻松支持百MHz级别的定时器时钟。利用输入滤波如果被测信号有毛刺可以启用数字滤波器。滤波器实际上是一个事件计数器只有当连续N个采样时钟都检测到有效电平时才认为边沿有效。这能有效抑制噪声但会引入几个时钟周期的延迟在测量超窄脉冲时需注意。使用PWM输入模式这是一个特殊的“大招”。某些定时器通道支持将两个输入映射到同一个通道的TI1和TI2上并自动设置为上升沿和下降沿交替捕获且能自动计算占空比和频率。硬件自动完成了一次捕获两个边沿并产生中断的流程软件只需要读取两个CCR寄存器即可得到周期和占空比极大简化了代码并提高了可靠性。在测量编码器信号或标准PWM信号时强烈推荐。溢出处理策略对于频率很低的信号计数器溢出会非常频繁。除了用overflow_cnt扩展计数范围还可以考虑使用定时器的“从模式”中的复位模式用被测信号本身来复位计数器这样CCRx中直接存储的就是信号的周期无需软件处理溢出但这种方法会占用定时器全部资源。注意在中断服务程序中读取CCRx值和处理溢出标志的操作要尽可能快并且要注意清除中断标志位的顺序。通常先读取数据再清除标志。避免因中断响应延迟或标志位清除不当导致丢失后续的捕获事件。4. 输出比较模式精准的定时触发器输出比较模式的核心思想是**“比较-动作”**。你设定一个目标值CCRx计数器CNT不断奔跑当CNT等于CCRx时硬件立即触发预设的动作同时可以产生中断或DMA请求。这为你提供了在精确时间点控制输出的能力。4.1 输出比较的四种工作模式通过配置CCMRx寄存器中的OCxM位可以指定匹配时引脚的动作冻结匹配时什么也不做通常不用于此模式。匹配时设置通道为有效电平引脚输出高电平或低电平取决于极性设置。匹配时设置通道为无效电平引脚输出低电平或高电平。匹配时翻转引脚电平反转。这是生成固定频率方波最简单的方法设置ARR为周期值CCRx为ARR的一半模式为翻转。每当CNT匹配CCRx或到达ARR时都会翻转从而生成50%占空比的方波。强制输出高/低软件强制引脚状态与比较器无关。PWM模式1和模式2这是输出比较的进阶应用我们下一章详细讲。4.2 输出比较的典型应用场景生成精确时间间隔配置为“匹配时翻转”模式并开启比较中断。在中断里重新计算并更新下一个CCRx值例如CCRx_new CCRx_old interval。这样就能在引脚上产生一个间隔非常精确的脉冲序列其精度仅由计数器时钟决定不受软件中断延迟的抖动影响。可用于驱动步进电机的脉冲信号。单脉冲输出结合定时器的单脉冲模式OPM可以生成一个宽度精确可控的单脉冲。先设置好ARR脉冲长度和CCRx脉冲开始后的某个动作点在启动定时器后它计数到ARR就自动停止完美产生一个单次脉冲。触发其他外设输出比较事件不仅可以控制自己的引脚还可以通过定时器内部触发总线ITRx去触发其他外设比如启动一次ADC转换、触发另一个定时器、或使能DMA传输。这在构建精确定时的信号采集链时非常有用。4.3 输出比较的配置要点与避坑输出极性通过CCER寄存器的CCxP位设置。通常“有效电平”指的是控制逻辑上的有效比如PWM模式下你希望占空比大时输出高电平那么高电平就是有效电平。这里配置错了整个控制逻辑就反了。预装载使能对于CCRx寄存器同样有预装载功能。如果你需要在一个PWM周期结束后才更新比较值就必须使能CCRx的预装载。这样你写入的新CCRx值会先进入影子寄存器在下一个更新事件时才生效确保整个PWM周期完整不会出现“毛刺”或“裂波”。即时更新与同步在定时器未启动时CEN0你可以通过生成软件更新事件UG位来立即更新所有预装载寄存器ARR PSC CCRx。但在定时器运行中修改动态参数要格外小心最好配合刹车、触发或从模式来实现同步修改避免运行中修改导致输出异常。5. PWM生成模式从基础到高级应用PWM脉冲宽度调制是通用定时器最广泛的应用。GD32H7的通用定时器支持多种PWM模式适应从呼吸灯到电机矢量控制FOC的各种需求。5.1 PWM模式1与模式2详解本质上PWM模式是输出比较模式的一种特化和自动化。你只需要设定ARR周期和CCRx比较值硬件就会在每个周期自动产生对应的PWM波形无需软件干预。PWM模式1在向上计数时当CNT CCRx时通道输出有效电平当CNT ≥ CCRx时输出无效电平。在向下计数时当CNT CCRx时输出无效电平当CNT ≤ CCRx时输出有效电平。简单记法模式1下计数器小于比较值时输出有效通常为高。PWM模式2逻辑与模式1完全相反。简单记法模式2下计数器小于比较值时输出无效通常为低。模式1和模式2本身没有优劣选择哪一个取决于你定义的“有效电平”和计数方向。通常我们使用向上计数 PWM模式1并定义高电平为有效电平。此时占空比 CCRx / (ARR 1)。通过修改CCRx就能线性调节输出脉冲的高电平时间。5.2 中央对齐PWM与边沿对齐PWM这是PWM生成的两种计数方式直接影响波形特性。边沿对齐模式计数器只向上或只向下计数。这是最常用的模式波形生成简单。但在改变CCRx值时如果时机不对可能会在当前周期就生效导致产生一个宽度异常的脉冲“裂波”。必须配合CCRx预装载功能来避免。中央对齐模式计数器先向上再向下计数。PWM输出在周期中心对称。这种模式有两个主要优点开关损耗低对于电机驱动等应用功率器件在电流过零点附近开关损耗和电磁干扰EMI更小。更新安全ARR和CCRx的更新事件发生在计数器为0时向下计数到0。由于波形是对称的在0点更新参数对波形对称性影响最小更适合需要频繁平滑调整PWM参数的场合如音频D类放大或高级电机控制。5.3 互补输出与死区时间插入对于驱动半桥或全桥电路需要一对互补的PWM信号如CHx和CHxN。GD32H7的定时器高级控制定时器如TIMER0 TIMER7和部分通用定时器支持硬件生成互补输出。 配置步骤使能定时器的互补输出功能通常通过一个高级控制寄存器。配置主通道CHx为PWM输出模式。配置死区时间寄存器DTR。死区时间以计数器时钟周期为单位。你需要根据所驱动的功率器件MOSFET IGBT的开关特性开通延迟td(on)、关断延迟td(off)来计算所需死区时间。公式通常为死区时间 td(off)_max - td(on)_min。确保在所有工况下死区时间都足以防止上下管直通。使能刹车功能如果需要。刹车输入BKIN通常连接过流保护信号一旦触发硬件会立即将互补输出强制到一个安全状态通常都为无效电平响应速度远快于软件中断是重要的安全特性。5.4 高级PWM应用多通道同步与触发在复杂系统中可能需要多个定时器或多个通道协同工作输出相位相关的PWM波形。定时器主从同步可以将一个定时器主的更新事件作为另一个定时器从的时钟源或触发源。这样从定时器会与主定时器严格同步启动和运行适合需要多个严格同步PWM波的应用。通道间的相位偏移通过设置各个通道CCRx值的不同可以让他们输出的PWM波形具有固定的相位差。例如在三相逆变器中三个通道的PWM相位互差120度。结合DMA实现PWM序列播放对于需要动态、复杂变化的PWM波形如生成特定形状的SPWM波形用于逆变可以将一个波形表包含多个CCRx值存放在内存中配置DMA在每次PWM周期更新事件时自动将下一个数据从内存搬运到CCRx寄存器。这样CPU只需初始化之后波形生成完全由DMA和定时器硬件完成极大节省CPU资源并保证时序精确。6. 实战配置指南与代码片段以GD32H7标准外设库为例理论说了这么多我们来看点实际的。以下以GD32H7的TIMER2_CH1生成1kHz 50%占空比PWM以及CH2做输入捕获为例展示关键配置代码和思路。6.1 PWM输出配置关键代码// 1. 时钟与GPIO使能 rcu_periph_clock_enable(RCU_GPIOA); rcu_periph_clock_enable(RCU_TIMER2); // 2. 配置GPIOA.0为复用推挽输出 (TIMER2_CH1) gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_0); gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_0); gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_0); // AF1 对应 TIMER2 // 3. 定时器时基单元配置 timer_parameter_struct timer_initpara; timer_struct_para_init(timer_initpara); timer_initpara.prescaler 199; // 假设系统时钟200MHz 200M/(1991)1MHz timer_initpara.alignedmode TIMER_COUNTER_EDGE; // 边沿对齐模式 timer_initpara.counterdirection TIMER_COUNTER_UP; // 向上计数 timer_initpara.period 999; // 周期值 ARR: 1MHz/(9991)1kHz timer_initpara.clockdivision TIMER_CKDIV_DIV1; timer_init(TIMER2, timer_initpara); // 4. 输出比较/PWM通道配置 timer_oc_parameter_struct oc_initpara; timer_channel_output_struct_para_init(oc_initpara); oc_initpara.outputstate TIMER_CCX_ENABLE; // 使能通道输出 oc_initpara.ocpolarity TIMER_OC_POLARITY_HIGH; // 有效电平为高 oc_initpara.ocidlestate TIMER_OC_IDLE_STATE_LOW; // 空闲状态低电平 timer_channel_output_config(TIMER2, TIMER_CH_1, oc_initpara); // 5. 配置PWM模式 timer_channel_output_pulse_value_config(TIMER2, TIMER_CH_1, 500); // CCR1 500, 占空比 500/(9991)50% timer_channel_output_mode_config(TIMER2, TIMER_CH_1, TIMER_OC_MODE_PWM0); // PWM模式0 (对应模式1逻辑) timer_channel_output_shadow_config(TIMER2, TIMER_CH_1, TIMER_OC_SHADOW_DISABLE); // 通常使能预装载 // 6. 使能自动重载预装载 (重要!) timer_auto_reload_shadow_enable(TIMER2); // 7. 使能定时器 timer_enable(TIMER2);6.2 输入捕获配置关键代码// 1. GPIO配置为输入映射到TIMER2_CH2 gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLDOWN, GPIO_PIN_1); // 下拉默认低电平 gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_1); gpio_af_set(GPIOA, GPIO_AF_1, GPIO_PIN_1); // AF1 对应 TIMER2 // 2. 定时器时基配置 (与PWM共用定时器时需注意此处假设独立) // ... 类似PWM配置PSC决定测量精度ARR可设最大 // 3. 输入捕获通道配置 timer_ic_parameter_struct ic_initpara; timer_channel_input_struct_para_init(ic_initpara); ic_initpara.icpolarity TIMER_IC_POLARITY_RISING; // 初始捕获上升沿 ic_initpara.icselection TIMER_IC_SELECTION_DIRECTTI; // 直接映射到TI2 ic_initpara.icprescaler TIMER_IC_PSC_DIV1; // 不分频每个边沿都捕获 ic_initpara.icfilter 0x0; // 无滤波器 timer_input_capture_config(TIMER2, TIMER_CH_2, ic_initpara); // 4. 使能捕获中断和更新中断 timer_interrupt_enable(TIMER2, TIMER_INT_CH2); // 通道2捕获中断 timer_interrupt_enable(TIMER2, TIMER_INT_UP); // 更新溢出中断 nvic_irq_enable(TIMER2_IRQn, 2, 0); // 使能NVIC中断 // 5. 使能定时器 timer_enable(TIMER2); // 6. 中断服务程序框架 uint32_t capture_cnt 0; uint16_t overflow_cnt 0; uint16_t t1 0, t2 0; uint32_t period_ticks 0; void TIMER2_IRQHandler(void) { if(timer_interrupt_flag_get(TIMER2, TIMER_INT_CH2) ! RESET) { // 捕获中断 if(capture_stage 0) { // 第一次捕获记录上升沿时间 t1 timer_channel_capture_value_register_read(TIMER2, TIMER_CH_2); // 切换为下降沿捕获 timer_input_capture_polarity_config(TIMER2, TIMER_CH_2, TIMER_IC_POLARITY_FALLING); capture_stage 1; overflow_cnt 0; // 重置溢出计数 } else { // 第二次捕获记录下降沿时间计算脉宽 t2 timer_channel_capture_value_register_read(TIMER2, TIMER_CH_2); period_ticks (uint32_t)overflow_cnt * 65536 (t2 - t1); // 假设16位ARR最大值 // 计算实际脉宽 (us): period_ticks * (1 / CK_CNT_MHz) // 切换回上升沿捕获准备下一次测量 timer_input_capture_polarity_config(TIMER2, TIMER_CH_2, TIMER_IC_POLARITY_RISING); capture_stage 0; } timer_interrupt_flag_clear(TIMER2, TIMER_INT_CH2); } if(timer_interrupt_flag_get(TIMER2, TIMER_INT_UP) ! RESET) { // 更新溢出中断 overflow_cnt; timer_interrupt_flag_clear(TIMER2, TIMER_INT_UP); } }7. 常见问题排查与调试心得调了这么多年定时器坑没少踩。下面这些经验可能数据手册里不会写得这么直白。7.1 PWM输出无信号或波形异常检查时钟树这是第一步也是最容易忽略的一步。确认定时器所在APB总线的时钟是否使能且频率正确。GD32的时钟树比STM32更灵活也更容易配错。确认GPIO复用映射GPIO的AF编号一定要查《GD32H7xx用户手册》的“复用功能映射”表格不同型号、不同引脚可能不同。AF1不对就试试AF2。检查输出使能与极性outputstate是否使能ocpolarity设反了会导致预期高电平输出却是低电平。ocidlestate空闲状态在互补输出和刹车功能启用时尤为重要。预装载寄存器未生效修改了ARR或CCRx但波形没变检查是否使能了对应寄存器的预装载功能timer_auto_reload_shadow_enable,timer_channel_output_shadow_config。使能后新值要在下次更新事件才生效。可以手动产生一个软件更新事件timer_event_software_generate来立即生效。占空比计算错误牢记公式占空比 CCRx / (ARR 1)。如果你设置ARR999 CCRx500占空比是50%不是50.05%。CCRx不能大于ARR否则输出可能常高或常低。7.2 输入捕获值不准或跳变信号质量问题用示波器看这是硬件工程师的第一准则。信号边沿是否有振铃电平是否稳定如果信号质量差需要增加硬件滤波RC电路或启用定时器的输入数字滤波器。中断响应延迟在高速信号捕获时如果中断服务程序太长可能导致错过后续的捕获事件。尽量精简ISR代码只做必要的读数、记录和标志位操作将复杂计算放到主循环。或者考虑使用DMA将捕获值直接搬运到内存数组。溢出处理逻辑错误长周期测量必须处理溢出。我的经验是在更新中断里只做overflow_cnt在捕获中断里根据capture_stage和当前计数器值计算时间差。计算差值时使用(uint32_t)overflow_cnt * (ARR_MAX1) (t_now - t_last)的公式并处理好t_now t_last的边界情况。滤波器与分频器混淆icprescaler是捕获分频器比如设为DIV4则每4个事件才捕获1次用于测量频率。icfilter是数字滤波器用于抗毛刺。根据需求正确配置。7.3 互补PWM与死区时间问题死区时间计算死区时间寄存器配置的值DTG与实际插入的死区时间t_dtg关系可能非线性需仔细查阅数据手册的公式。通常是一个分段函数低几位是线性值高位是指数倍乘。一定要算对否则死区时间可能远大于或小于预期。互补输出无信号除了使能主通道还必须显式使能互补输出通道timer_channel_complementary_output_config和刹车功能控制timer_break_enable即使你不用刹车功能也可能需要使能这个控制位。刹车功能误触发检查刹车输入引脚BKIN的电平。如果悬空或受噪声干扰可能误触发刹车将输出强制到空闲状态。通常需要给该引脚一个明确的上拉或下拉。7.4 性能与资源优化减少CPU干预对于固定频率的PWM配置好后就让硬件全权负责CPU无需理会。对于需要频繁更新占空比的如电机FOC控制使用DMA双缓冲模式是王道。CPU只需填充下一个周期的CCR值数组DMA会在更新事件时自动切换缓冲并搬运数据实现无延迟、无抖动更新。定时器级联对于需要超长定时的场合如分钟、小时级可以将一个定时器配置为从模式以另一个定时器的更新事件作为时钟。这样可以将两个16位定时器组合成一个32位定时器使用。利用霍尔接口与编码器接口GD32H7的某些高级定时器直接集成了针对电机控制的霍尔传感器接口和正交编码器接口。它们内部就是利用输入捕获和定时器资源实现的硬件逻辑比用通用定时器软件模拟稳定高效得多在做电机项目时优先考虑。调试定时器示波器和逻辑分析仪是最好的朋友。一定要养成习惯配置完寄存器立刻用探头去看引脚上的实际波形和你心中预期的波形对比。寄存器配置是“你以为的”实际波形才是“真实的”。很多时候问题就出在“你以为”和“真实”之间那一点点微妙的差异上。