STM32定时器与PWM实战指南:从原理到调试,彻底掌握电机与舵机控制 📅 发布时间:2026/9/3 16:38:50 👁 浏览次数: 如果你正在学习STM32或者准备参加RoboMaster、智能车等嵌入式竞赛那么“定时器”和“PWM”这两个词一定让你又爱又恨。爱的是它们是控制电机、舵机、LED、蜂鸣器乃至通信的基石几乎无处不在恨的是STM32的定时器功能繁杂寄存器众多CubeMX配置项眼花缭乱稍有不慎生成的代码要么不工作要么效果诡异。很多人学完GPIO、串口后信心满满地打开定时器章节却被“预分频器”、“自动重装载值”、“计数模式”、“PWM模式”、“互补输出”、“死区时间”等一系列术语瞬间击垮。网上的教程要么过于简单只讲如何点一点CubeMX生成代码要么过于底层大段分析寄存器让人望而生畏。结果就是你能“依葫芦画瓢”让一个LED呼吸起来但一旦需要精确控制舵机角度、无刷电机转速或者需要多个定时器协同工作时立刻束手无策。这篇文章正是为了解决这个核心痛点。它不是一次培训的回放记录而是将培训中的核心知识结合大量实际项目中的“坑”和“最佳实践”重新梳理成一套从理解到精通的STM32定时器与PWM实战指南。我们将彻底讲清楚为什么需要定时器PWM的本质是什么CubeMX每个配置项背后的物理意义是什么以及当你的PWM控制电机抖动、舵机角度不准时第一步应该检查哪里。读完本文你将不仅能复现培训中的示例更能建立起一套完整的知识框架真正掌握STM32定时器的配置逻辑和调试方法从而在电控项目中游刃有余。1. 这篇文章真正要解决的问题从“会用”到“懂为什么”在嵌入式开发尤其是机器人、智能车等实时控制领域对时间的精确管理是灵魂。STM32的定时器TIM模块就是这颗灵魂的硬件载体。而PWM脉冲宽度调制则是其最经典、最广泛的应用输出。然而大多数初学者面临的问题不是“不知道有这个功能”而是**“知道功能但不懂原理导致无法灵活运用和调试”**。具体表现为配置依赖症完全依赖CubeMX的图形化配置一旦某个功能在界面上找不到或者需要更复杂的模式如中心对齐模式、互补输出带死区就无从下手。参数意义模糊知道要改“Prescaler”和“Counter Period”但改完之后频率、周期到底是多少占空比怎么计算心里没底。调试手段匮乏PWM输出没波形或者波形不对除了检查代码不知道如何利用示波器、逻辑分析仪甚至单片机本身的调试功能来定位问题。应用场景单一只知道PWM能控制LED亮度呼吸灯但面对需要精确时间戳、编码器接口、定时中断、脉冲计数等高级应用时无法将知识迁移。因此本文的目标是带你穿透CubeMX配置的表象深入理解STM32定时器的工作机制。我们将聚焦于通用定时器TIM2-TIM5在PWM输出模式下的应用因为这是竞赛和项目中最高频的使用场景。通过本文你将获得清晰的定时器时钟树概念知道时钟如何一步步分配到定时器。PWM参数频率、占空比的精确计算方法并能反向根据需求配置参数。一套可复用的HAL库驱动代码框架并理解其底层操作。完整的调试思路和常见问题排查清单让你能独立解决大部分PWM相关问题。2. 基础概念与核心原理定时器与PWM到底是什么在深入代码之前我们必须统一认知。很多混乱源于对基本概念理解不清。2.1 定时器Timer不仅仅是“定时”你可以把STM32的定时器想象成一个精密且可编程的“计数器”。核心部件一个向上或向下或上下计数的寄存器CNT。时钟源它需要一颗“心脏”来跳动这个心脏就是时钟信号。定时器的时钟通常来源于系统时钟SYSCLK经过分频后的APB总线时钟。如何工作时钟每来一个脉冲计数器CNT的值就加1或减1。当计数器的值达到某个预设值自动重装载寄存器ARR时产生一个“溢出”事件计数器清零或重新加载并可以触发中断或DMA请求。关键参数定时器时钟频率CK_CNT计数器累加的“心跳速度”。单位是Hz。预分频器PSC用于对输入时钟进行分频以得到所需的CK_CNT。CK_CNT 输入时钟频率 / (PSC 1)。自动重装载值ARR计数器的上限。计数器从0计数到ARR即完成一个计数周期。定时周期计算完成一个计数周期的时间T (ARR 1) / CK_CNT。这个时间就是定时器产生一次更新事件的周期。定时器远不止“定时中断”。通过不同的工作模式它还能实现输出比较当CNT的值与某个通道的比较寄存器CCR的值相等时可以翻转对应引脚的电平从而产生PWM波。输入捕获测量外部脉冲的宽度或频率。编码器接口直接读取正交编码器的位置和速度。2.2 PWM脉冲宽度调制用数字信号模拟“模拟量”PWM是一种用固定频率的数字脉冲信号通过改变脉冲的“宽度”高电平时间来等效模拟不同电平的技术。关键参数频率Frequency一秒钟内有多少个完整的脉冲周期。Freq CK_CNT / (ARR 1)。周期Period一个完整脉冲的时间长度是频率的倒数。Period (ARR 1) / CK_CNT。脉冲宽度Pulse Width一个周期内高电平持续的时间。占空比Duty Cycle脉冲宽度与周期的比值通常用百分比表示。Duty (Pulse / Period) * 100%。在STM32中Pulse对应于比较寄存器CCR的值。如何控制外设LED亮度高电平驱动LED发光。占空比越大一个周期内LED亮的时间越长平均亮度就越高。由于人眼有视觉暂留看到的是“连续”的亮度变化。舵机角度舵机控制需要的是特定宽度的脉冲而非占空比。常见舵机控制脉冲周期为20ms频率50Hz脉冲宽度在0.5ms到2.5ms之间对应0到180度。此时我们固定频率50Hz通过改变Pulse即CCR值来改变脉冲宽度从而控制角度。直流电机速度通过电机驱动板如TB6612、DRV8833PWM信号控制电机的平均电压占空比越大平均电压越高转速越快。STM32如何生成PWM定时器工作在PWM模式通常为模式1或模式2下CNT计数器不断与ARR和CCR比较。当CNT CCR时输出有效电平高或低可配置。当CCR CNT ARR时输出无效电平。如此循环便产生了周期为(ARR1)高电平时间为CCR的PWM波。理解了这个原理再看CubeMX的配置就不再是黑盒了。3. 环境准备与前置条件在开始实操前请确保你的开发环境已就绪。本文以最通用的场景为例你可以轻松迁移到自己的项目。硬件平台任意一款STM32系列单片机如STM32F103C8T6、STM32F407ZGT6等。本文示例基于STM32F103系列但其概念和HAL库API是通用的。软件开发环境STM32CubeMX用于图形化配置引脚和时钟。版本建议6.x及以上。IDE/编译器Keil MDK-ARM、IAR Embedded Workbench 或 STM32CubeIDE。本文代码示例基于HAL库在任何支持HAL库的IDE中均可运行。调试工具ST-LINK/V2或J-Link等仿真器用于下载和调试程序。调试设备强烈建议示波器或逻辑分析仪用于观察生成的PWM波形验证频率和占空比是否正确。这是学习定时器不可或缺的工具。万用表辅助测量。目标外设可选用于验证LED灯和限流电阻。SG90舵机。直流电机及驱动板如TB6612。4. 核心流程拆解从CubeMX配置到代码控制我们以一个具体的任务为例使用TIM3的通道1PA6引脚产生一个频率为1kHz占空比可调的PWM信号用以控制一个LED实现呼吸灯效果。4.1 第一步CubeMX工程创建与时钟配置新建工程打开CubeMX选择你的MCU型号。配置系统时钟RCC在Pinout Configuration标签页找到System Core-RCC。将High Speed Clock (HSE)设置为Crystal/Ceramic Resonator如果你使用外部晶振。这是保证系统时钟准确的基础。配置时钟树Clock Configuration点击Clock Configuration标签页。这是理解定时器时钟源的关键。STM32F103的APB1总线时钟TIM2-TIM4挂载于此最大为36MHz。如果使用8MHz晶振通常通过PLL倍频到72MHz系统时钟SYSCLK然后APB1预分频器设置为2得到36MHz的APB1时钟PCLK1。关键点在STM32中如果APB预分频系数不为1那么定时器的时钟会在APB时钟的基础上倍频。对于APB1当预分频系数为2/4/8/16时定时器时钟TIMxCLK PCLK1 * 2。在我们的配置中PCLK136MHzTIM3CLK 36MHz * 2 72MHz。这个72MHz就是定时器3的输入时钟频率。务必在时钟树图中确认这个值它是后续所有计算的基础。4.2 第二步定时器模式与参数配置找到并启用TIM3在Pinout Configuration的左侧分类中找到Timers-TIM3。将Clock Source设置为Internal Clock内部时钟源。配置PWM Generation Channel 1在下方Channel1下拉菜单中选择PWM Generation CH1。此时右侧的引脚图PA6会自动被标记为TIM3_CH1。设置参数Parameter SettingsPrescaler (PSC - 16 bits value)预分频器。我们的目标是1kHz PWM输入时钟是72MHz。计算公式CK_CNT TIMxCLK / (PSC 1)。我们先确定ARR。Counter Mode计数模式。选择Up向上计数这是最常用的模式。Counter Period (ARR - 16 bits value)自动重装载值。它决定了PWM的频率。目标频率Freq CK_CNT / (ARR 1) TIMxCLK / ((PSC1)*(ARR1))。为了计算方便我们通常先设定一个合适的PSC让CK_CNT是一个整数。例如设PSC 71则CK_CNT 72MHz / (711) 1MHz。此时要得到1kHz频率ARR CK_CNT / Freq - 1 1,000,000 / 1,000 - 1 999。所以设置Prescaler 71Counter Period 999。Internal Clock Division (CKD)时钟分频保持默认No Division。auto-reload preload自动重装载预装载使能Enable。这样可以在更新事件发生时才将新ARR值载入防止在周期中间产生毛刺。配置PWM模式PWM Generation Channel 1 子标签Mode选择PWM mode 1。在此模式下当CNT CCR时通道输出有效电平默认为高。Pulse (16 bits value)脉冲宽度即初始的CCR值。我们先设为500即初始占空比为500 / (9991) 50%。Output compare preload输出比较预装载使能Enable。作用类似ARR预装载保证CCR值在更新事件时同步更新。Fast Mode快速模式禁用Disable。通常用于需要快速响应的场合呼吸灯不需要。CH Polarity通道极性。选择High表示有效电平为高。如果选择Low则输出波形会反转。4.3 第三步生成工程与代码框架项目管理转到Project Manager标签页设置项目名称、路径、IDE如MDK-ARM V5。代码生成在Code Generator中选择Copy only necessary library files。勾选Generate peripheral initialization as a pair of ‘.c/.h’ files这样定时器配置代码会独立成文件结构更清晰。生成代码点击GENERATE CODE。CubeMX会自动生成包含HAL库初始化代码的完整工程。5. 完整示例与代码实现打开生成的工程我们主要关注两个文件tim.c包含TIM3的初始化函数MX_TIM3_Init和main.c。5.1 初始化代码分析 (tim.c)// 文件路径Core/Src/tim.c #include tim.h TIM_HandleTypeDef htim3; void MX_TIM3_Init(void) { TIM_ClockConfigTypeDef sClockSourceConfig {0}; TIM_MasterConfigTypeDef sMasterConfig {0}; TIM_OC_InitTypeDef sConfigOC {0}; // 步骤1配置定时器基础参数 htim3.Instance TIM3; htim3.Init.Prescaler 71; // 预分频器 PSC 71 htim3.Init.CounterMode TIM_COUNTERMODE_UP; // 向上计数模式 htim3.Init.Period 999; // 自动重装载值 ARR 999 htim3.Init.ClockDivision TIM_CLOCKDIVISION_DIV1; // 时钟分频 CKD htim3.Init.AutoReloadPreload TIM_AUTORELOAD_PRELOAD_ENABLE; // ARR预装载使能 if (HAL_TIM_Base_Init(htim3) ! HAL_OK) { Error_Handler(); } // 步骤2配置时钟源内部时钟 sClockSourceConfig.ClockSource TIM_CLOCKSOURCE_INTERNAL; if (HAL_TIM_ConfigClockSource(htim3, sClockSourceConfig) ! HAL_OK) { Error_Handler(); } // 步骤3配置PWM通道1 if (HAL_TIM_PWM_Init(htim3) ! HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(htim3, sMasterConfig) ! HAL_OK) { Error_Handler(); } // 步骤4配置输出比较参数PWM模式、占空比等 sConfigOC.OCMode TIM_OCMODE_PWM1; // PWM模式1 sConfigOC.Pulse 500; // 初始CCR值决定初始占空比 sConfigOC.OCPolarity TIM_OCPOLARITY_HIGH; // 输出极性高电平有效 sConfigOC.OCFastMode TIM_OCFAST_DISABLE; // 快速模式禁用 if (HAL_TIM_PWM_ConfigChannel(htim3, sConfigOC, TIM_CHANNEL_1) ! HAL_OK) { Error_Handler(); } // 步骤5配置GPIO引脚此部分通常在gpio.c中生成但由CubeMX统一管理 // HAL_TIM_MspPostInit(htim3); // 对于高级定时器可能需要通用定时器通常不需要 }这段代码完全对应了我们在CubeMX中的图形化配置。HAL库将其封装成了清晰的结构体和函数。5.2 主程序控制逻辑 (main.c)生成代码后PWM通道并不会自动开始输出。我们需要在main.c中启动PWM并动态改变占空比来实现呼吸灯效果。// 文件路径Core/Src/main.c #include main.h #include tim.h int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_TIM3_Init(); // 初始化TIM3 uint16_t pwmVal 0; // 当前CCR值 uint8_t dir 1; // 方向1为增加0为减少 // 启动TIM3的PWM通道1输出 HAL_TIM_PWM_Start(htim3, TIM_CHANNEL_1); while (1) { // 动态改变CCR值实现呼吸灯效果 HAL_Delay(10); // 延时10ms控制呼吸速度 if(dir 1) { pwmVal; if(pwmVal 1000) { // ARR是999CCR最大有效值也是999 dir 0; } } else { pwmVal--; if(pwmVal 0) { dir 1; } } // 更新TIM3通道1的占空比 // 方法1直接写寄存器快速但需注意时机 // __HAL_TIM_SET_COMPARE(htim3, TIM_CHANNEL_1, pwmVal); // 方法2使用HAL库函数更安全会处理预装载 TIM3-CCR1 pwmVal; // 直接操作寄存器效果同方法1但更直观 // 或者使用htim3.Instance-CCR1 pwmVal; } }代码关键点解析HAL_TIM_PWM_Start(htim3, TIM_CHANNEL_1);这是必须调用的函数用于启动指定定时器通道的PWM输出。没有它引脚不会有波形。占空比更新在while循环中我们不断改变pwmVal即CCR值然后更新到定时器中。__HAL_TIM_SET_COMPARE(htim3, TIM_CHANNEL_1, pwmVal)是一个宏底层也是操作CCR1寄存器。直接操作TIM3-CCR1 pwmVal;是等效的且更直接。由于我们使能了“输出比较预装载”新写入的CCR值会在下一个更新事件计数器溢出时生效避免了在一个PWM周期中间改变占空比可能导致的脉冲残缺。呼吸逻辑pwmVal从0递增到999再递减到0循环往复。占空比从0%变化到近100%LED亮度也随之平滑变化。5.3 进阶示例精确控制舵机角度舵机控制要求固定的50Hz频率和精确的脉冲宽度。我们使用TIM2的通道1PA0为例。CubeMX配置差异频率50Hz。假设TIM2的输入时钟TIM2CLK 72MHz。计算ARR和PSC为了得到精确的50Hz我们需要(PSC1)*(ARR1) TIM2CLK / Freq 72,000,000 / 50 1,440,000。我们可以选择PSC 7199则CK_CNT 72MHz / 7200 10kHz。那么ARR 10,000 / 50 - 1 199。Period (1991)/10,000 20ms正确。脉冲宽度对应0.5ms~2.5ms。CCR值计算CCR PulseWidth * CK_CNT。CK_CNT 10kHz即每毫秒10个计数。0.5ms -CCR 51.5ms中位-CCR 152.5ms -CCR 25因此CCR值范围约为5~25。主程序代码片段// 初始化TIM2为50HzPWM模式 // ... CubeMX生成初始化代码 ... // 定义一个函数将角度0-180转换为CCR值 uint16_t AngleToCCR(uint8_t angle) { // 角度限幅 if(angle 180) angle 180; // 线性映射0.5ms(0度) - CCR5, 2.5ms(180度) - CCR25 // 公式CCR 5 angle * (25-5) / 180 return (5 angle * 20 / 180); } int main(void) { // ... 系统初始化 ... HAL_TIM_PWM_Start(htim2, TIM_CHANNEL_1); while(1) { // 示例让舵机从0度转到180度再转回来 for(uint8_t ang 0; ang 180; ang10) { __HAL_TIM_SET_COMPARE(htim2, TIM_CHANNEL_1, AngleToCCR(ang)); HAL_Delay(500); // 等待舵机转动到位 } for(uint8_t ang 180; ang 0; ang-10) { __HAL_TIM_SET_COMPARE(htim2, TIM_CHANNEL_1, AngleToCCR(ang)); HAL_Delay(500); } } }注意实际舵机的中位和极限位置可能需要微调CCR值上述计算为理论值。务必用示波器测量实际输出的脉冲宽度进行校准。6. 运行结果与效果验证代码编写完成后编译并下载到单片机。硬件连接将PA6TIM3_CH1引脚连接到一个LED的阳极阴极接地记得串联一个约220Ω的限流电阻。或者将PA0TIM2_CH1连接到舵机的信号线通常为橙色或白色并为舵机提供合适的电源通常5V。观察现象呼吸灯LED应呈现从暗到亮再从亮到暗的循环变化。变化速度由主循环中的HAL_Delay(10)决定。舵机控制舵机应按照代码指示每次转动10度并在端点来回运动。波形验证强烈推荐使用示波器或逻辑分析仪的探头连接到PWM输出引脚PA6或PA0。测量频率应测得约1kHzTIM3或50HzTIM2的方波信号。测量占空比/脉宽对于呼吸灯占空比应随时间线性变化。对于舵机脉冲宽度应在0.5ms到2.5ms之间变化周期固定为20ms。如果波形频率不对检查时钟树配置和PSC、ARR计算。如果脉宽或占空比不对检查CCR值的计算和设置。7. 常见问题与排查思路PWM输出不正常是新手常遇到的问题。请按以下清单系统性排查问题现象可能原因排查方式解决方案完全没有波形输出1. 定时器未启动。2. PWM通道未启动。3. 引脚复用功能未正确配置。4. 引脚被其他功能占用如JTAG。1. 检查代码是否调用了HAL_TIM_Base_Init和HAL_TIM_PWM_Init。2. 检查main函数是否调用了HAL_TIM_PWM_Start。3. 在CubeMX中确认引脚已正确配置为TIMx_CHy。4. 检查原理图确认引脚没有连接错误。1. 确保初始化流程正确。2.务必调用HAL_TIM_PWM_Start。3. 在CubeMX中检查引脚配置。4. 对于PA13, PA14, PA15, PB3, PB4等引脚默认是JTAG/SWD功能用作普通GPIO或外设前需在Pinout页的System Core-SYS里将Debug改为Serial Wire或禁用JTAG。波形频率不对1. 系统时钟配置错误。2. PSC或ARR值计算错误。3. 定时器时钟源选择错误。1. 在main.c的SystemClock_Config函数中打断点或读取SystemCoreClock变量确认系统时钟频率。2. 使用示波器测量实际频率反推CK_CNT。3. 检查CubeMX中定时器的Clock Source配置。1. 仔细检查时钟树配置特别是PLL倍频和APB分频系数。2. 复核PSC和ARR的计算公式Freq TIMxCLK / ((PSC1)*(ARR1))。3. 确保定时器使用的是Internal Clock。占空比不可控或不变1. CCR值未成功更新。2. 更新CCR的时机不当导致写入被忽略。3. 输出极性配置错误。1. 在调试模式下观察CCRx寄存器的值是否随代码变化。2. 检查是否使能了Output compare preload。如果使能CCR值在更新事件后才生效。3. 用示波器观察波形看有效电平是否与预期相反。1. 确保更新CCR的语句被执行如__HAL_TIM_SET_COMPARE。2. 如果使能了预装载CCR更新会有延迟这是正常现象。如需立即更新可在写入后调用__HAL_TIM_MOE_ENABLE高级定时器或生成更新事件。3. 在CubeMX中检查CH Polarity设置。电机/舵机抖动或噪音大1. PWM频率不合适。2. 电源功率不足或纹波大。3. 死区时间未配置对于互补PWM驱动H桥。4. 占空比变化过快。1. 检查PWM频率是否在电机/舵机推荐范围内舵机50Hz直流电机通常几kHz到几十kHz。2. 测量电源电压电机启动时是否被拉低。3. 如果使用高级定时器产生互补PWM驱动电机必须配置死区时间防止上下桥臂直通。4. 增加改变占空比的时间间隔。1. 调整PSC和ARR至合适的频率。2. 为电机提供独立电源并增加大容量滤波电容。3. 在CubeMX定时器配置的Parameter Settings-Break and Dead Time中配置死区时间。4. 降低主循环中更新CCR的速度。输出波形上有毛刺1. 软件在PWM周期中间修改了ARR或CCR。2. 引脚受到外部干扰。3. 接地不良。1. 使用示波器放大观察毛刺出现的位置是否与代码更新寄存器的时间点相关。2. 检查PCB布局PWM信号线是否远离高频或大电流线路。1.务必使能auto-reload preload和output compare preload确保参数在周期边界更新。2. 优化布线必要时在输出端加小电容滤波但可能影响边沿速度。3. 确保共地良好。8. 最佳实践与工程建议掌握了基础操作后以下建议能帮助你在实际项目中更稳健地使用定时器和PWM。规划定时器资源STM32的定时器数量有限功能各异基本、通用、高级。在项目初期就规划好每个定时器的用途PWM输出、输入捕获、编码器、基础定时等避免后期资源冲突。精确计算参数善用CubeMX计算器CubeMX的定时器配置界面有实时频率计算显示。输入PSC和ARR后查看Estimated counter frequency和Period是否满足要求。对于高精度应用如舵机尽量让CK_CNT是1MHz、10MHz等整数方便计算CCR值。使用DMA传输PWM数据用于复杂波形如果需要产生任意波形如正弦波、复杂PWM序列频繁在中断中更新CCR会消耗大量CPU资源。可以配置定时器的更新事件触发DMA将预先计算好的CCR值数组自动搬运到定时器寄存器中实现“硬件播放”。互补PWM与死区时间电机驱动关键驱动直流有刷电机或步进电机时常使用H桥电路需要两路互补的PWM信号控制上下桥臂。必须配置死区时间防止上下桥臂同时导通造成短路。STM32的高级定时器TIM1, TIM8硬件支持带死区的互补PWM输出在CubeMX中可直接配置。利用定时器中断进行精准定时除了PWM输出定时器溢出中断更新中断是进行毫秒/微秒级精准延时的最佳方式比HAL_Delay基于SysTick更节省资源且可嵌套。在CubeMX中使能定时器的更新中断在stm32f1xx_it.c中编写中断服务函数并清除中断标志。调试技巧软件调试在Keil/IAR中可以查看TIMx-CNT、TIMx-ARR、TIMx-CCRy等寄存器的实时值。硬件调试示波器是验证PWM波形的最权威工具。没有示波器时可以用LED电阻简单判断是否有输出LED微亮或用万用表测电压PWM输出时电压为平均电压。代码封装与可维护性将不同外设如舵机、电机、蜂鸣器的PWM控制封装成独立的.c/.h文件提供清晰的初始化、设置占空比/角度/速度的接口。在头文件中使用宏定义或枚举来定义频率、最大最小值等参数避免魔法数字。9. 总结与后续学习方向通过本文我们系统地拆解了STM32定时器生成PWM的完整流程从核心概念定时器、PWM的理解到CubeMX的图形化配置再到HAL库代码的编写与控制最后到问题排查和最佳实践。我们不仅学会了如何让一个LED呼吸更掌握了如何根据需求计算参数、如何验证结果、如何解决实际问题的方法论。STM32的定时器是一座宝库PWM只是其最常用的功能之一。以此为起点你可以继续深入探索输入捕获测量脉冲宽度或频率用于读取红外遥控信号、超声波测距模块的回波等。编码器接口直接连接正交编码器轻松读取电机的位置和速度这是机器人底盘控制的必备技能。高级定时器学习互补输出、刹车功能、带死区插入的PWM这是驱动无刷电机BLDC和伺服电机的核心。定时器级联使用一个定时器控制另一个定时器实现更复杂的定时或PWM序列。低功耗定时器在STM32的低功耗模式下如何使用LPTIM维持基本的定时功能。建议你拿出开发板将文中的示例亲手实现一遍并用示波器观察波形。然后尝试改造代码控制一个真正的舵机或直流电机。当你成功让一个机械结构按照你的代码精确运动时你对嵌入式实时控制的理解将会达到一个新的层次。本文的代码和思路已为你铺好了路真正的精通源于动手实践和举一反三。建议收藏本文在后续的电控项目开发中它将成为你随时可查的实用指南。