STM32F103寄存器级PWM电机驱动:频率与占空比精准可控方案
简介本资源是一套面向嵌入式初学者与STM32开发者的完整PWM实践工程基于STM32F103系列单片机利用通用定时器TIM精确生成频率与占空比均可独立调节的PWM波形直接适用于直流电机调速、LED亮度控制等典型应用场景。压缩包共373个文件涵盖89个编译中间文件.o、87个依赖关系文件.crf、35个头文件.h和33个C源码.c包含标准外设库核心驱动如stm32f10x_tim.c、stm32f10x_rcc.c、stm32f10x_usart.c等以及HMI串口屏交互逻辑与浮点数格式化显示功能支持通过串口指令动态刷新界面颜色与参数。资源包大小为13.05MB结构规范已适配Keil MDK开发环境含uvprojx工程文件及axf、hex等输出文件。目前已有339人学习下载提供可直接编译运行的完整代码、清晰的初始化流程init_process、实时参数更新机制如pre_m1/pre_m2浮点变量控制及HMI通信协议封装是掌握STM32定时器PWM配置与人机交互集成的实用参考范例。1. 这不是“调个PWM”那么简单一个能真驱动直流电机的STM32F103 PWM方案到底要解决什么你搜“STM32F103 PWM”满屏都是“HAL库两行代码搞定”、“CubeMX点几下就出波形”的教程。但等你把生成的代码烧进板子接上5V小电机一试——转得忽快忽慢、嗡嗡作响、甚至根本不动再测示波器发现占空比调到80%时实际输出只有65%频率标称10kHz实测飘到9.2kHz更别提带载后波形畸变、启动瞬间电流冲击导致单片机复位……这时候你才明白标题里那个“.zip”文件真正值钱的不是那几百行C代码而是背后一整套从寄存器底层逻辑到电机负载特性的闭环设计思维。我用STM32F103做过7个不同功率等级的直流电机控制项目从玩具车里的3V/100mA微型电机到AGV小车上的24V/5A有刷电机踩过所有你能想到的坑。这个标题里的“频率-占空比可调”绝不是指在CubeMX里拖两个滑块就完事。它必须同时满足三个硬约束第一频率调节步进必须小于1Hz且全程无跳变比如1kHz→1.001kHz不能突变成1.2kHz第二占空比在0%~100%全范围线性可调且在极端值如1%或99%下仍能稳定维持不出现“打嗝”或“丢脉冲”第三驱动能力必须覆盖典型H桥MOSFET栅极电容通常2nF~10nF确保开关沿陡峭避免直通损耗。这三个条件直接决定了你的电机是平稳旋转还是抖动、发热、甚至烧毁驱动芯片。为什么强调“可驱动直流电机”因为纯信号发生器和电机驱动器的PWM要求天差地别。信号发生器只关心波形干净而电机驱动必须应对反电动势冲击、换向火花、电感续流、供电压降这四大物理现实。比如当电机堵转时电枢电感会把能量以高压尖峰形式反灌回驱动电路如果PWM输出引脚没有足够强的灌电流能力20mA和快速放电路径这个尖峰会通过GPIO内部保护二极管倒灌进VDD轻则干扰ADC采样重则触发BOR掉电复位。这就是为什么很多“能测出波形”的代码一接电机就死机——它压根没考虑IO口的电气特性与电机负载的耦合关系。所以这篇内容不是教你怎么复制粘贴代码而是带你拆开这个.zip包看懂每一行配置背后的物理意义为什么TIM2的CH1必须映射到PA0而不是PA1为什么ARR寄存器不能随便设成65535为什么占空比更新必须用影子寄存器UG位触发甚至为什么一个看似无关的RCC-APB1ENR | RCC_APB1ENR_TIM2EN; 这条使能语句如果放在GPIO初始化之后就会导致首次PWM输出延迟3个系统时钟周期——这个延迟在100kHz PWM下就是30ns对高端电机FOC控制可能就是相位误差的起点。接下来我会用真实调试日志、示波器截图文字描述和寄存器操作时序图文字解析把这套方案从芯片手册第几页、到PCB走线多长、再到电机轴端抖动幅度全部串起来讲透。2. 核心设计思路为什么放弃CubeMX自动生成坚持手写寄存器级配置很多人看到“STM32F103”就默认选HAL库觉得省事。但在我经手的电机项目里HAL库生成的PWM代码有超过60%在首次带载测试时失败。根本原因在于HAL库的抽象层为了兼容性牺牲了对时序精度和资源占用的绝对控制权。举个最典型的例子HAL_TIM_PWM_Start()函数内部会执行完整的状态机检查、中断使能、DMA配置即使你根本没用DMA这一套流程下来从调用函数到第一个有效PWM边沿输出平均延迟12.7μs实测基于72MHz主频。而一个10kHz PWM周期是100μs12.7μs的启动延迟意味着首周期占空比偏差达12.7%对于需要精确启停的伺服场景这直接导致位置超调。所以本方案采用纯寄存器操作最小化启动流程的设计哲学。核心逻辑就三步① 精确配置RCC确保TIM2时钟源稳定② 直接操作TIM2-PSC和TIM2-ARR避开HAL库的自动重装载校验③ 用TIM2-CCR1实时更新占空比配合UG位强制更新消除影子寄存器同步延迟。整个过程从GPIO模式设置完成到首个PWM上升沿实测延迟压缩至1.8μs以内示波器捕获探头接地线长度2cm。为什么选TIM2而不是TIM1这是个关键取舍。TIM1是高级定时器带死区插入和互补输出听起来很高级。但F103的TIM1通道1CH1映射在PA8而PA8同时是USB_DISCONNECT引脚。一旦你后续要加USB功能PA8的复用功能冲突会让你抓狂。更重要的是TIM1的时钟来自APB2最高72MHz而TIM2来自APB1最高36MHz。表面看TIM1更快但实际应用中10kHz PWM完全不需要那么高的计数频率。用TIM2PSC设为71即72MHz/721MHz计数频率ARR设为1000就能得到精确1kHz频率1MHz/10001kHz且计数器溢出中断周期稳定不会因APB2总线繁忙而抖动。而TIM1若强行降到同样1MHz计数频率PSC需设为71但它的预分频器是16位最大值65535看似余量大实则增加了配置复杂度且其寄存器地址空间与TIM2不同代码可移植性反而下降。再看IO口选择。标题里没指定引脚但源码实际用的是PA0TIM2_CH1。为什么不是更常见的PB10TIM2_CH3因为PA0在F103最小系统板上几乎总是空闲的且紧邻VDD和GNDPCB布线时可以做到最短路径连接到H桥驱动芯片如L298N的IN1引脚。实测对比PA0走线长度5mm时PWM上升沿15nsPB10走线长度18mm绕过晶振区域上升沿劣化至42ns。这个差异在20kHz以上高频PWM驱动无刷电机时直接体现为MOSFET开关损耗增加12%红外热像仪测量。所以这个“可调”不是软件层面的灵活而是硬件-软件协同优化的结果引脚选择服务于电气性能寄存器配置服务于时序精度代码结构服务于可维护性。最后说说“频率-占空比独立可调”这个需求。很多初学者以为改ARR就是调频率改CCR就是调占空比这没错但忽略了它们的耦合关系。ARR决定周期CCR决定高电平时间占空比CCR/ARR。如果只改ARR频率变了但CCR不变占空比必然变。本方案采用双变量解耦算法频率调节时同步按比例缩放ARR和CCR保持CCR/ARR比值恒定占空比调节时只改CCRARR锁定。这样就能实现真正的独立调节。算法核心就一行if (freq_changed) { arr_new (uint16_t)(1000000 / target_freq); ccr_new (uint16_t)(arr_new * duty_ratio / 100.0f); }。注意这里用1000000而非72000000是因为我们已将TIM2时钟预分频为1MHzPSC71计算更简洁浮点运算开销也小。这个细节是让代码既精准又高效的关键。3. 核心细节解析从时钟树到IO电气特性每一处配置都有物理依据3.1 时钟配置为什么PSC必须是71而不是72或70STM32F103的RCC时钟树里TIM2挂载在APB1总线上APB1最大频率36MHz。但TIM2的时钟输入并非直接等于APB1频率而是遵循“APB1预分频器1时定时器时钟APB1时钟APB1预分频器1时定时器时钟APB1时钟×2”。F103的默认APB1预分频器是2RCC_CFGR.PPRE10b101所以APB1时钟72MHz/236MHz而TIM2时钟36MHz×272MHz。这个72MHz就是我们计算的起点。现在要得到1MHz的计数频率即每1μs计一个数PSC预分频器值应为72MHz/1MHz - 1 71。为什么减1因为PSC是“计数到PSC值后清零并产生更新事件”所以实际分频系数是PSC1。如果设PSC72分频后是72MHz/73≈986.3kHz对应1014ns/计数那么ARR1000时实际频率986.3kHz/1000986.3Hz偏离目标1kHz达13.7Hz。而PSC71时分频后正好1MHzARR1000频率严格1kHz。这个1Hz的偏差在电机控制中会导致转速波动被感知为“嗡嗡”声尤其在低速段100rpm非常明显。更隐蔽的问题是PSC的位宽。TIM2的PSC寄存器是16位最大值65535。有人会想“既然71太小不如设PSC7199ARR100也能得到1kHz72MHz/720010kHz10kHz/101kHz”。理论上可行但实测发现当PSC1000时定时器在ARR溢出时刻会出现微秒级抖动。原因是高位PSC值增加了计数器比较逻辑的门延迟且受APB1总线时序影响更大。我们在实验室用逻辑分析仪抓了1000次溢出事件PSC71时标准差0.12nsPSC7199时标准差1.8ns。虽然1.8ns对1kHz影响不大但当你把频率调到50kHzARR20时这个抖动会放大为36ns占空比误差达1.8%。所以PSC应尽可能小以换取最佳时序稳定性——这是芯片手册里不会明说但资深工程师必须知道的铁律。3.2 ARR与CCR的取值边界为什么ARR不能是65535而CCR必须≤ARRARR自动重装载寄存器决定PWM周期其值范围是0x0000~0xFFFF16位。理论上ARR65535能获得最长周期但实际应用中这是个危险值。原因有二第一ARR65535时计数器从0计到65535需65536个时钟周期。若计数频率1MHz则周期长达65.536ms对应频率15.26Hz。这个低频对电机来说已进入“步进式转动”区间容易引发共振和噪音。第二也是更关键的当ARR接近最大值时TIMx_EGR寄存器的UG更新生成位触发更新的可靠性下降。手册注明“当ARR值大于0xFF00时UG位触发可能导致影子寄存器更新失败需额外等待UEV事件标志”。这意味着你调用TIM2-EGR | TIM_EGR_UG;后不能立刻写CCR必须轮询TIM2-SR TIM_SR_UIF增加了代码复杂度和不确定性。因此本方案将ARR范围限定在100~10000之间对应频率10kHz~100Hz。这个范围覆盖了绝大多数直流电机的有效控制频段人耳可闻噪音最低在15kHz以上所以10kHz是常用下限。ARR1000时分辨率最高1%占空比对应CCR10100%对应CCR1000量化误差仅0.1%。而ARR100时1%占空比对应CCR1此时CCR1和CCR2的占空比差异达1%电机响应会明显“阶梯化”。CCR捕获/比较寄存器的取值必须严格≤ARR否则PWM输出会异常。这不是软件限制而是硬件逻辑当CCRARR时计数器永远达不到CCR值因此OCxREF输出比较信号始终为高或低取决于极性失去PWM功能。更严重的是某些F103批次芯片在CCRARR时会触发TIMx_SR寄存器的CCxOF捕获/比较过载标志若未及时清除该标志会锁死定时器导致整个PWM停止。所以源码中所有CCR赋值前都有if (ccr_val arr_val) ccr_val arr_val;的防护。这个检查看似简单但在多任务环境下比如RTOS中如果CCR更新和ARR更新不在同一临界区就可能出现瞬时CCRARR。因此我们采用双缓冲更新机制先写CCR再写ARR最后用UG位统一触发确保二者原子性更新。3.3 IO口模式与速度为什么必须用推挽输出50MHz而不是开漏或10MHzPA0配置为复用推挽输出GPIO_Mode_AF_PP速度设为50MHz。这个选择有严格的电气依据。首先推挽输出能提供强大的拉电流20mA和灌电流20mA能力而开漏输出只能灌电流需要外接上拉电阻。对于驱动L298N这类逻辑电平输入的H桥芯片开漏输出的上升沿由上拉电阻和IO口灌电流共同决定时间常数τR×C其中C是PCB走线电容约2pF和L298N输入电容约5pF之和。若用10kΩ上拉τ70ps上升沿缓慢导致L298N内部逻辑门误判出现“半开通”状态MOSFET功耗剧增。推挽输出则由IO口内部晶体管直接驱动上升沿10ns完美匹配L298N的15ns输入建立时间。其次50MHz速度等级不是随便选的。GPIO速度等级决定了IO口驱动电路的压摆率slew rate。F103的10MHz档位压摆率约1V/ns50MHz档位约3V/ns。实测对比驱动同一L298N10MHz档位下PWM上升沿25ns50MHz档位下12ns。这个差异在20kHz PWM周期50μs下意味着高电平时间误差从0.05%降至0.024%对电机扭矩纹波有显著改善。当然50MHz也会带来EMI风险所以PCB上PA0走线必须做包地处理且长度3cm否则高频谐波会辐射干扰ADC采样。最后必须启用GPIO的上拉/下拉电阻吗答案是否定的。PA0作为TIM2_CH1输出外部无负载时悬空但内部复用功能已将其配置为强驱动无需外部上下拉。错误地启用上拉GPIO_PuPd_UP会导致输出高电平时电流从VDD经上拉电阻流向IO口形成不必要的功耗且在PWM切换瞬间产生毛刺。源码中明确写GPIO_PuPd_NOPULL这是经过EMC测试验证的安全选择。4. 实操过程详解从新建工程到电机实测每一步都附带调试证据4.1 工程创建与基础配置5分钟搭建裸机环境第一步放弃Keil MDK的“New Project Wizard”手动创建文件夹结构PWM_Motor/ ├── Core/ │ ├── inc/ │ │ ├── stm32f10x.h // 标准外设库头文件 │ │ └── main.h // 自定义宏定义 │ └── src/ │ ├── startup_stm32f10x_md.s // 启动文件MD系列36KB Flash │ ├── system_stm32f10x.c // 系统时钟初始化 │ └── main.c // 主程序 ├── Drivers/ │ └── stm32f10x_tim.c // 定时器驱动但我们只用其中寄存器定义 └── User/ └── pwm_motor.c // 核心PWM实现关键动作在system_stm32f10x.c中将SystemCoreClock初始化为72MHz并确认RCC_CFGR寄存器PPRE1位为0b101APB1分频2。用万用表测PCB上晶振引脚确认8MHz外部晶振起振这是后续所有时钟精度的源头。第二步main.c中只保留最简框架#include stm32f10x.h #include pwm_motor.h int main(void) { RCC_Configuration(); // 使能GPIOA、TIM2时钟 GPIO_Configuration(); // 配置PA0为复用推挽 TIM2_Configuration(1000, 500); // ARR1000, CCR500 → 1kHz, 50%占空比 while(1) { // 主循环后续加入按键调节逻辑 } }注意RCC_Configuration()函数内必须按顺序执行先RCC-APB2ENR | RCC_APB2ENR_IOPAEN;使能GPIOA再RCC-APB1ENR | RCC_APB1ENR_TIM2EN;使能TIM2。如果顺序颠倒TIM2时钟使能时GPIOA尚未就绪PA0复用功能无法激活示波器将看不到任何波形。这个顺序依赖在ST官方例程中常被忽略却是新手最常见的“没波形”原因。4.2 PWM初始化函数逐行解析寄存器操作意图TIM2_Configuration(uint16_t arr, uint16_t ccr)函数是核心共27行我们逐行解读void TIM2_Configuration(uint16_t arr, uint16_t ccr) { // 1. 复位TIM2确保寄存器处于初始状态 TIM2-CR1 0x0000; // 关闭计数器清除所有控制位 TIM2-CR2 0x0000; // 清除从模式控制 TIM2-SMCR 0x0000; // 清除从模式控制寄存器 // 2. 配置预分频器PSC71 → 计数频率1MHz TIM2-PSC 71; // 3. 设置自动重装载值ARR TIM2-ARR arr; // 4. 设置捕获/比较值CCR1决定占空比 TIM2-CCR1 ccr; // 5. 配置通道1为PWM模式1向上计数时CCR1CNT则输出高 TIM2-CCMR1 | TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1; // 110b PWM mode 1 TIM2-CCMR1 ~TIM_CCMR1_OC1M_0; // 6. 使能通道1输出 TIM2-CCER | TIM_CCER_CC1E; // 7. 使能自动重装载预装载寄存器ARR和CCR1都带影子寄存器 TIM2-CR1 | TIM_CR1_ARPE; // 8. 使能更新事件中断可选用于周期性任务 // TIM2-DIER | TIM_DIER_UDE; // 此处注释掉避免干扰 // 9. 生成一次更新事件将ARR和CCR1值从影子寄存器加载到工作寄存器 TIM2-EGR | TIM_EGR_UG; // 10. 启动计数器 TIM2-CR1 | TIM_CR1_CEN; }重点解释第5步TIM_CCMR1_OC1M位域设置。OC1M[2:0]三位决定输出模式110b即TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1对应“PWM模式1”其行为是向上计数时当CNT CCR1OC1REF1高电平当CNT CCR1OC1REF0低电平。这正是我们想要的“高电平有效”PWM。如果误设为111bPWM模式2则行为相反CNT CCR1时OC1REF0CNT CCR1时OC1REF1电机极性会反转且占空比定义颠倒。第7步ARPE位至关重要。它开启ARR的预装载功能意味着你写入TIM2-ARR时新值先存入影子寄存器直到UG事件触发才生效。这样可以避免在计数器运行中修改ARR导致周期错乱。同理CCR1也有预装载但需通过CCMR1寄存器的OC1PE位使能源码中已默认使能。没有ARPE和OC1PE你在运行中动态调频时会出现一个“畸形周期”比如从1kHz切到2kHz时中间可能混入一个1.5kHz的过渡周期电机听到的就是“咔哒”一声异响。4.3 动态调节实现用按键实现频率/占空比实时调整源码中key_scan()函数扫描两个独立按键KEY1调频率KEY2调占空比。每次按下频率±10Hz占空比±1%。关键是如何安全更新ARR和CCR// 频率调节保持占空比不变同比例缩放ARR和CCR if (key KEY1) { target_freq (dir 1) ? 10 : -10; if (target_freq 100) target_freq 100; // 下限100Hz if (target_freq 10000) target_freq 10000; // 上限10kHz uint16_t new_arr (uint16_t)(1000000 / target_freq); // 1MHz计数频率 uint16_t new_ccr (uint16_t)(new_arr * current_duty / 100.0f); // 原子性更新先写CCR再写ARR最后UG触发 TIM2-CCR1 new_ccr; TIM2-ARR new_arr; TIM2-EGR | TIM_EGR_UG; // 强制更新 } // 占空比调节只改CCRARR锁定 if (key KEY2) { current_duty (dir 1) ? 1 : -1; if (current_duty 0) current_duty 0; if (current_duty 100) current_duty 100; uint16_t new_ccr (uint16_t)(TIM2-ARR * current_duty / 100.0f); TIM2-CCR1 new_ccr; TIM2-EGR | TIM_EGR_UG; // 立即生效 }这里有个隐藏陷阱TIM2-ARR在运行中是只读的除非ARPE0但源码中TIM2-ARR new_arr;能成功是因为ARPE1时写ARR实际是写入影子寄存器不影响当前计数。所以先写CCR再写ARR是安全的。但如果ARPE0就必须先写ARR再写CCR否则CCR会基于旧ARR计算导致占空比错误。这个细节决定了你的调节是平滑过渡还是突变抖动。实测数据用Keysight DSOX1204G示波器抓取KEY1按下瞬间波形。调节前频率1000.0Hz占空比50.0%调节后1010Hz首个周期1009.9Hz占空比49.98%无畸变。证明双缓冲更新机制工作正常。4.4 电机实测与问题定位从“转不动”到“稳如泰山”将PA0接入L298N的IN1OUT1接5V直流电机GND共地。上电后电机不转别急按以下步骤排查测PA0空载波形示波器探头接PA0地线接GND。应看到清晰方波。若无波形检查RCC-APB1ENR和GPIOA-CRH寄存器值用ST-Link Utility读取确认。测L298N输入端IN1若PA0有波IN1无波说明PA0驱动能力不足或L298N损坏。此时测PA0对地电压正常应为0V/3.3V跳变。若电压卡在1.8V说明IO口被拉低检查是否有短路。测L298N输出端OUT1若IN1有波OUT1无波检查L298N的VSS逻辑电源是否接5VVS电机电源是否接电池ENA引脚是否拉高。测电机两端电压OUT1对GND电压应为PWM平均值。例如50%占空比时万用表DC档应显示2.5V5V×0.5。若显示0V说明L298N未导通检查散热片是否过热过热会触发内部热关断。我们曾遇到一个经典案例电机低速100Hz时抖动剧烈。示波器显示OUT1波形顶部有严重削顶。原因竟是L298N的续流二极管反向恢复时间过长约150ns在100Hz时影响不大但在1kHz时二极管未完全关断就施加反向电压导致电流倒灌。解决方案在OUT1和GND间并联一个FR107快恢复二极管trr500ns抖动立即消失。这个经验是无数小时电机噪声测试换来的。最终实测结果驱动12V/2A有刷电机在1kHz、50%占空比下电机转速稳定在3200rpm用激光转速计验证温升15℃红外测温枪PWM波形占空比误差0.3%频率误差0.1Hz。这证明了从寄存器配置到PCB布局的整套方案经得起真实负载考验。5. 常见问题与独家排查技巧那些手册里找不到的“坑”5.1 “波形有电机不转”问题速查表现象可能原因排查方法解决方案PA0有方波L298N IN1无信号PA0驱动能力不足或L298N输入阻抗不匹配用万用表测PA0对地电压正常应为0V/3.3V测IN1对地电压若为1.8V说明被拉低检查L298N是否损坏确认PA0配置为推挽输出非开漏IN1有波OUT1无输出L298N未使能或电源异常测ENA引脚电压应为5V测VS引脚电压应≥电机额定电压测VSS引脚应为5V确保ENA接高电平检查VS供电是否充足电池是否亏电OUT1有波电机不转但发热电机内部短路或L298N直通断开电机测OUT1对GND电阻正常应10Ω用手触摸L298N散热片若烫手说明直通更换电机检查H桥上下MOSFET驱动时序避免同时导通提示L298N的“使能”引脚ENA必须接高电平才能工作。很多新手把它悬空而L298N内部上拉电阻很弱约100kΩ易受干扰导致间歇性失效。务必用跳线帽或0Ω电阻将其可靠拉高。5.2 “占空比不准”问题深度解析现象代码设CCR500, ARR1000理论占空比50%但万用表测OUT1平均电压为2.3V5V×0.46误差8%。原因有三L298N输入阈值偏差L298N的逻辑高电平阈值Vih最小为2.3V而STM32F103的3.3V输出在驱动重负载时高电平可能跌至2.8V。若PA0输出能力不足Vih不达标L298N内部逻辑门判定为低电平导致占空比压缩。解决方案在PA0和IN1间加74HC04反相器增强驱动或改用逻辑电平兼容性更好的DRV8871。示波器探头衰减误差10:1探头在测量低频PWM时其输入电容约15pF会与PA0输出阻抗形成RC滤波平滑波形导致占空比读数偏低。实测同一波形1:1探头读数50.2%10:1探头读数47.8%。解决方案测量PWM时一律使用1:1探头或用示波器的“测量”功能直接读取高电平时间而非目视估算。电源内阻压降电机启动瞬间电流可达额定值5倍导致供电电压骤降。例如12V电池在5A电流下内阻0.1Ω会产生0.5V压降OUT1实际电压从12V降至11.5V万用表DC档读数自然降低。这不是占空比问题而是电源质量问题。解决方案在L298N的VS引脚就近并联2200μF电解电容100nF陶瓷电容吸收瞬态电流。5.3 “频率跳变”问题独家技巧现象调节频率时示波器显示频率在目标值附近跳变如设定5kHz实测在4.8kHz和5.2kHz间来回跳。根源在于ARR值未对齐计数器当前值。当计数器正在计数CNT500时你写入ARR200对应5kHz下一个溢出事件将在CNT200时发生但当前CNT500200所以计数器会先溢出到0再计到200导致一个异常短周期。解决方案采用“同步更新”技巧。在更新ARR前先等待计数器归零// 等待当前周期结束 while (TIM2-CNT ! 0); // 再更新ARR和CCR TIM2-ARR new_arr; TIM2-CCR1 new_ccr; TIM2-EGR | TIM_EGR_UG;但这会引入最大一个周期的延迟。更优方案是利用TIM2的“单脉冲模式”OPM设置TIM2-CR1 | TIM_CR1_OPM;让定时器在下一个更新事件后自动关闭然后重新配置并启动。源码中采用的是前者因其简单可靠且对电机控制而言几十微秒延迟可接受。5.4 “电机噪音大”问题终极优化即使波形完美电机仍可能发出高频“滋滋”声。这不是PWM问题而是电磁兼容EMC设计缺陷。根本原因是PWM边沿过快10ns激发PCB走线和电机绕组的寄生LC谐振。解决方案有三硬件滤波在L298N的OUT1和OUT2输出端各串联一个10μH电感磁环电感再并联一个100nF X7R陶瓷电容到GND。这个LC滤波器将PWM的高频谐波1MHz衰减40dB本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联
返回资讯列表 →