ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

基于Proteus的STM32直流电机PWM调速仿真:从L298N驱动到定时器配置

基于Proteus的STM32直流电机PWM调速仿真:从L298N驱动到定时器配置 做电机控制实验我最常用的组合就是 Proteus 加 STM32F103C8T6用定时器输出 PWM 去驱动直流电机。这个组合的好处是不需要实物板子也能把逻辑完整跑通特别适合刚入门 STM32 或者还没买驱动模块的同学。这篇文章我会把从 Proteus 搭建电路、L298N 驱动接线、定时器 PWM 初始化到按键调速的完整代码全部拆开讲文末还会把我在仿真里踩过的坑整理成速查表方便你直接对照排查。先说明一下我用的方案是标准外设库不是 HAL 库。虽然现在 STM32CubeMX 很流行但标准库代码直白、寄存器逻辑清楚用来理解 PWM 这种基础外设再合适不过。工程代码里只有 main.c 一个文件可以在 Proteus 里直接加载跑起来整个流程不复杂适合课程设计、入门练习也适合做小型项目原型验证时快速搭一套电机调速框架。1. 调通一个电机控制方案需要考虑哪三件事1.1 为什么我选了 Proteus 加标准库这条路线很多人在 Proteus 里做 STM32 仿真时第一步就卡住了Proteus 里到底有没有 STM32F103C8T6 这个型号我的答案是8.15 版本及之后的主流版本里搜索“STM32F103C8”或者“STM32F103R6”都能找到对应模型只是封装显示可能和实际芯片不一样这不影响功能仿真。用 Proteus 的核心价值在于把硬件调试的试错成本几乎降为零你不用买芯片、焊电路、担心烧引脚改代码再重新加载一次就能看结果。选择标准库的另一个原因是我发现很多新手在 CubeMX 里一键生成代码后对定时器到底怎么工作的一头雾水。标准库逼迫你手动配置 TIM_TimeBaseInitTypeDef、TIM_OCInitTypeDef每一步要设置哪些寄存器都明明白白。等你把标准库这套流程走一遍再看 HAL 库就会觉得非常顺。我在这篇文章里用标准库但并不代表 HAL 库不行工程上两者都大量存在你按自己团队习惯选就好。这个项目适合什么人来参考我觉得有三类人最合适一是刚学完 GPIO 点灯、想进阶到定时器应用的 STM32 初学者二是要做课程设计题目是“直流电机PWM调速”的同学三是想用 Proteus 先验证逻辑再转实物开发的小型项目爱好者。1.2 PWM 调速和直流电机负载特性的底层逻辑PWM 的全称是脉冲宽度调制简单说就是输出一个频率固定、高电平时间可变的方波。占空比就是指高电平时间占整个周期的比例。比如 10kHz 的 PWM一个周期是 100 微秒如果高电平占 50 微秒占空比就是 50%。为什么改变占空比能调直流电机的转速因为直流电机的转速近似正比于它端电压的平均值。如果电源电压是 12V占空比 50% 时电机感受到的平均电压大约是 6V转速自然降下来了。你可以把 PWM 调速想象成用开关快速开关灯开关次数足够快时人眼感知到的是平均亮度PWM 调速也是同样的思路只是“眼睛”换成了电机的机械惯性。但这里有一个不能忽略的物理细节直流电机是感性负载电感的电流不能突变。当 PWM 信号从高电平跳到低电平电机线圈里的电流需要一条回路继续流否则会产生很高的反向电动势损坏驱动器件。所以电机驱动电路里必须要有续流二极管或者内部的续流结构这就是为什么我不建议把电机直接接在单片机引脚上的原因。关于 PWM 频率的选择我习惯取 10kHz 到 20kHz。低于 10kHz 时电机绕组会发出人耳可听见的啸叫声听起来就像“滋滋滋”的噪声高于 20kHz 虽然更安静但功率管开关损耗会增加驱动芯片发热会更明显。所以 10kHz 是一个比较折中的起点Proteus 仿真里用这个频率也足够真实了。1.3 驱动芯片选型L298N 为什么是起步阶段最稳的选择直流电机驱动方案我试过很多种从 ULN2003 到达林顿管、从分立 MOS 管 H 桥到集成驱动芯片。如果让我给初学者推荐一个最稳的我会毫不犹豫选 L298N。原因很简单它内部是双 H 桥结构自带续流二极管逻辑输入可以直接接单片机的 GPIO驱动能力最大到 2A对小功率直流电机来说完全够用。L298N 和 ULN2003 的区别很关键。ULN2003 是达林顿管阵列只能做单向电流控制意思是它只能把电机往一个方向驱动想反转就得额外加继电器改接线。L298N 内部是 H 桥通过控制四个功率开关管的通断可以让电机两端电压反向所以正转、反转、刹车都能轻松实现。如果你用分立 MOS 管搭 H 桥虽然压降小、成本低但你得自己解决栅极驱动电压、死区时间、续流二级管布局等一系列问题在仿真里这些看不到一到实物就非常头疼。在 Proteus 里L298N 的模型名通常搜“L298”就能找到引脚和实物基本一致。比如 VS 接电机电源、VSS 接逻辑电源、ENA 接单片机的 PWM 输出IN1 和 IN2 接普通 GPIOOUT1 和 OUT2 接电机两极。这套连接方式我在后面章节会展开细讲。2. 硬件连接与关键参数“抠”细节2.1 Proteus 元件放置与引脚连接注意事项Proteus 里新建工程时我建议选一个 A4 左右的图纸方便放元件和走线。放置元件的时候重点关注这几个关键字STM32F103C8、L298、MOTOR-DC、BUTTON、RES。其中直流电机在 Proteus 的元件库里通常叫“MOTOR-DC”搜索“MOTOR”就能看到。如果你找不到 STM32F103C8T6 这个具体型号可以选同系列的 STM32F103R6引脚数量会多一些但功能一致不影响代码运行。连接时最重要的原则是所有需要共地的地方必须连到同一个地网络。STM32 的 GND、L298N 的 GND、直流电机的负极、电源的负极这四个地方在原理上必须连在一起否则信号没有参考电平仿真时会出现各种奇怪的随机错误。电源方面Proteus 提供 5V 和 12V 电源端子直接用“POWER”端子引出就可以但要注意L298N 的 VS 接 12V 电机电源VSS 接 5V 逻辑电源两者不能颠倒。连接 STM32F103C8T6 的时候还有个容易忽略的地方VDDA、VSSA 等模拟电源引脚。在 Proteus 里部分模型默认已经处理好了但如果你用的是 R6 这类封装最好仔细确认每个电源引脚都接好了否则会出现程序不跑或者复位异常的现象。NRST 引脚建议通过一个 10k 电阻上拉到 3.3V防止复位引脚受干扰这在实物设计里同样适用。2.2 L298N 电路仿真里的默认坑L298N 在 Proteus 里仿真的时候有四个地方特别容易踩坑。第一ENA 引脚不能悬空。很多教程里只画了 IN1、IN2没画 ENA结果电机怎么都不转。ENA 必须接到单片机的 PWM 输出引脚而且高电平才有效。第二VSS 必须单独接 5V不能和 VS 接同一个电源。L298N 内部的逻辑电路靠 VSS 供电VS 是电机电源把 VS 接到 3.3V 或 5V 也可能转但驱动能力很差而且不符合实际芯片的工作条件。第三共地问题我再强调一次。仿真中如果 STM32 的地和 L298N 的地没有连接PWM 信号就没有参考电位波形确实是有的但 L298N 无法识别出高电平还是低电平表现就是电机一抖一抖的。第四如果你在电机两端并联了一个 LED 做指示要注意 LED 需要串限流电阻。直接接上去会烧 LED仿真里表现为 LED 急剧变亮然后灭掉。很多初学者在画电路图时会用“连线交叉”代替节点Proteus 里默认交叉点是不连接的必须放一个蓝色小圆点才表示连接。这个操作在放置元件后尤其容易出问题我建议连线完成后用“电气规则检查”跑一遍可以快速找到悬空引脚和未连接的电源网络。2.3 定时器时钟与 PWM 频率计算STM32F103C8T6 的定时器资源很丰富TIM1 是高级定时器TIM2、TIM3、TIM4 是通用定时器每个都有多路 PWM 输出通道。我在这篇博文里用的是 TIM2 的 CH1 通道引脚映射到 PA0。为什么不用 TIM1因为 TIM1 作为高级定时器除了常规配置外还必须额外调用 TIM_CtrlPWMOutputs 使能主输出很多新手用 TIM1 时忘了这一步导致 PWM 死活没有输出。用 TIM2 就能少踩这个坑。PWM 的频率计算公式非常关键PWM频率 定时器时钟频率 / ((PSC 1) * (ARR 1))其中 PSC 是预分频值ARR 是自动重装载值。STM32F103C8T6 的定时器挂载在 APB1 总线上当系统时钟为 72MHz 时APB1 分频器预分频为 2定时器时钟最高是 72MHz。我们实际配置 TIM_Prescaler 71TIM_Period 99算一下72,000,000 / ((71 1) * (99 1)) 72,000,000 / 7,200 10,000 Hz正好是 10kHz。ARR 是 99意味着占空比的分辨率是 100 级也就是 CCR 寄存器可以从 0 到 99 变化占空比从 0% 到 99%。对于按键调速演示来说100 级已经足够平滑了。如果你想提高分辨率可以把 ARR 增大到 999对应 1000 级但 PSC 也要相应调小否则频率会掉下去。这里我给出一个省事的选择PSC 71ARR 9910kHz100 级分辨率。这是我在演示项目里用得最多的组合兼顾了仿真波形的美观和代码的可读性。实物调试时如果电机噪声大你可以把频率提高到 20kHz具体就是保持 PSC 71把 ARR 改成 49分辨率变成 50 级噪声改善会很明显但调速精细度会变差你需要根据自己的应用做权衡。3. 完整工程实现从初始化到按键调速3.1 GPIO、定时器、PWM 初始化代码详解整个工程的核心代码分成三部分GPIO 初始化、定时器 PWM 初始化、主循环按键逻辑。我先给出完整的 main.c 代码然后逐段解释关键点。这个代码基于标准外设库工程里需要包含 stm32f10x.h 和相关外设驱动文件。#include stm32f10x.h void Delay_Init(void); void Delay_ms(uint32_t ms); void GPIO_Config(void); void TIM2_PWM_Config(void); int main(void) { uint8_t duty 50; // 初始占空比 50% Delay_Init(); GPIO_Config(); TIM2_PWM_Config(); while (1) { // PA3 按键按下加速 if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3) RESET) { Delay_ms(10); if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3) RESET) { while (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3) RESET); if (duty 90) duty 10; TIM_SetCompare1(TIM2, duty); } } // PA4 按键按下减速 if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_4) RESET) { Delay_ms(10); if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_4) RESET) { while (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_4) RESET); if (duty 10) duty - 10; TIM_SetCompare1(TIM2, duty); } } } } void GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // PA0 作为 PWM 输出由定时器复用控制 GPIO_InitStructure.GPIO_Pin GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); // PA1、PA2 控制 L298N 的 IN1、IN2普通推挽输出 GPIO_InitStructure.GPIO_Pin GPIO_Pin_1 | GPIO_Pin_2; GPIO_InitStructure.GPIO_Mode GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed GPIO_Speed_2MHz; GPIO_Init(GPIOA, GPIO_InitStructure); // 默认正转IN11IN20 GPIO_SetBits(GPIOA, GPIO_Pin_1); GPIO_ResetBits(GPIOA, GPIO_Pin_2); // PA3、PA4 接按键上拉输入 GPIO_InitStructure.GPIO_Pin GPIO_Pin_3 | GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode GPIO_Mode_IPU; GPIO_Init(GPIOA, GPIO_InitStructure); } void TIM2_PWM_Config(void) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); // 10kHz72MHz / (711) / (991) TIM_TimeBaseStructure.TIM_Prescaler 71; TIM_TimeBaseStructure.TIM_CounterMode TIM_CounterMode_Up; TIM_TimeBaseStructure.TIM_Period 99; TIM_TimeBaseStructure.TIM_ClockDivision TIM_CKD_DIV1; TIM_TimeBaseInit(TIM2, TIM_TimeBaseStructure); TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; TIM_OCInitStructure.TIM_Pulse 50; // 初始占空比 50/99 TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; TIM_OC1Init(TIM2, TIM_OCInitStructure); TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable); TIM_Cmd(TIM2, ENABLE); } void Delay_Init(void) { SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK); } void Delay_ms(uint32_t ms) { uint32_t i; SysTick-LOAD 72000 - 1; // 72MHz 时 1ms SysTick-VAL 0; SysTick-CTRL | SysTick_CTRL_ENABLE_Msk; for (i 0; i ms; i) { while (!(SysTick-CTRL SysTick_CTRL_COUNTFLAG_Msk)); } SysTick-CTRL ~SysTick_CTRL_ENABLE_Msk; }这段代码里有几个细节需要注意。PA0 的模式是 GPIO_Mode_AF_PP也就是复用推挽输出。这里的“复用”值得特别强调PA0 的普通 GPIO 控制权被移交给了 TIM2 的外设功能所以你不能再用 GPIO_SetBits 去直接控制 PA0 的高低电平而要通过 TIM_SetCompare1 去改变比较寄存器的值从而改变占空比。如果你把 PA0 配成普通推挽输出定时器虽然也在工作但引脚不会输出 PWM 波形这是新手最常见的坑之一。定时器初始化时TIM_OCMode 选择 PWM1 模式。PWM1 和 PWM2 的区别在于输出电平的极性逻辑PWM1 模式在计数小于比较值时输出有效电平PWM2 则相反。我统一习惯用 PWM1。TIM_Pulse 是初始比较值它决定初始占空比。后面通过 TIM_SetCompare1 修改它就能实时改变占空比不需要重新初始化定时器。3.2 主循环里的按键调速逻辑与占空比限制主循环的逻辑很直接检测 PA3 是否被按下如果按下先把占空比加 10再调用 TIM_SetCompare1 更新 PWM 比较值PA4 按下则减 10。代码里我加了两个保护机制也是实际项目中必须考虑的。第一个是软件消抖。机械按键在按下和松开的瞬间会产生抖动持续时间通常有几毫秒到十几毫秒。如果不做消抖一次按键可能被识别成多次触发占空比会跳好几格。消抖的做法是先检测到按下延时 10ms 再检测一次如果仍然是按下状态说明真的是人按下去的不是抖动。然后我加了一个 while 等待按键松开这样可以保证每次按键只触发一次调整按住不放也不会连续加减。第二个是占空比限幅。我在代码里把占空比限制在 10% 到 90% 之间为什么不是 0% 到 100%因为占空比太低时L298N 输出电压不足电机可能根本不转处于临界抖动状态占空比太高时电机接近全速再往上调没有实际意义而且如果是大功率电机持续满占空比工作驱动芯片发热会非常严重。从开环控制的角度看限制上下限也能避免操作失误导致电机飞车这个后面章节会详细讲。这里有个细节我用 uint8_t 类型的变量存占空比。因为占空比始终在 0 到 99 之间uint8_t 足够用还省内存。按键触发加减时我判断的是 duty 是不是在边界内而不是直接修改 TIM 的寄存器边界判断放在逻辑层而不是硬件层这样代码更清晰以后想改上下限也方便。3.3 Keil 工程配置与 HEX 文件加载代码写完后需要在 Keil 里配置工程。新建工程时选择 STM32F103C8如果你用的是标准库需要把 stm32f10x_gpio.c、stm32f10x_tim.c、stm32f10x_rcc.c 这些外设源文件添加到工程里头文件路径也别忘了加否则编译会报找不到头文件。生成 HEX 文件是 Proteus 仿真最关键的一步。在 Keil 中点击“Options for Target”切到“Output”选项卡勾选“Create HEX File”。然后重新编译工程编译完成后去工程的 Objects 目录下就能找到后缀为 .hex 的文件。这个文件就是 Proteus 需要加载的程序文件。接着打开 Proteus右键点击原理图里的 STM32F103C8 芯片选择“Edit Properties”在“Program File”一栏选择刚才生成的 .hex 文件。这里有个我踩过的坑修改代码重新编译后Proteus 不会自动重新加载新的 .hex 文件你必须重新打开属性窗口确认路径或者干脆删掉旧芯片重新放一个。否则你会发现改了代码仿真却没有任何变化这种问题非常容易让人误判是代码错误。时钟设置方面Proteus 里双击芯片打开属性窗口把“Clock Frequency”设为 8MHz同时我们的标准库默认 HSE_VALUE 也是 8MHz这样 SystemInit 会把系统时钟配置到 72MHz。如果你在 Proteus 里设置的晶振频率和代码里的 HSE_VALUE 不匹配程序初始化就可能卡在时钟配置部分表现就是仿真运行后主循环不执行。这个问题我会在常见问题里再提一次。3.4 用虚拟示波器观察 PWM 波形Proteus 自带的虚拟示波器在左侧工具栏的“Virtual Instruments”里面图标是一个示波器形状。接法很简单把示波器的 A 通道接到 STM32 的 PA0 引脚B 通道可以接到 L298N 的 OUT1 输出端这样能同时看到单片机输出 PWM 和电机端实际驱动波形。运行仿真后按一次加速按键你会发现 PA0 的波形高电平时间变长占空比增大。按减速按键则相反。这一步能非常直观地验证 PWM 输出是否正常。虚拟示波器的时基需要调整我记得默认的时间刻度可能不太合适10kHz 的波形一个周期是 100 微秒时基可以设在 50 微秒/格或者 100 微秒/格这样屏幕上能看到两三个完整的周期。如果你觉得虚拟示波器显示不稳定也可以把 PWM 频率调低到 1kHz 再观察具体做法是把 ARR 改成 999同时 PSC 保持 71频率就变成 1kHz。只是注意调速效果会变差电机转动噪声也会变大观察完波形后再改回来就行。这个技巧在波形分析和调试阶段非常实用。4. 仿真过程常见问题与排查技巧4.1 电机不转或抖动先查这三个地方仿真运行后电机完全不动是最多新手遇到的问题。我建议按下面的顺序排查先看 L298N 的 ENA 有没有接鼠标点的 PA0或者是否接错了引脚再看占空比初始值如果初始占空比设置成 5% 甚至 0%电机可能因为启动电压不足不转最后看 VS 和 VSS 的电源VS 至少要高于电机的额定电压仿真里常用的直流电机模型用 12V 供电不能用 5V 代替。电机抖动不转的情况也很常见。抖动说明 PWM 信号已经到电机了但平均电压处于电机启动临界值附近可能原因有两个一是占空比取值太小比如低于 10% 时电机无法稳定克服静摩擦力二是 PWM 频率太低低频 PWM 下电机绕组受到的电流不连续导致转矩脉动比较大。解决办法就是提高初始占空比并确保 PWM 频率在 10kHz 以上。我按照实际调试经验整理了一张速查表你可以保存下来现象可能原因处理办法电机完全不动ENA 未接 PWM 或悬空用示波器确认 PA0 有波形电机完全不动占空比太低初始值调到 30% 以上电机抖动PWM 频率太低频率提高到 10kHz 以上电机抖动电源电压偏低VS 按电机额定值接 12V电机能转但调速不明显IN1/IN2 接反交换 IN1/IN2 或调整代码电机反转不如预期H 桥方向逻辑反了检查 GPIO_SetBits 和 ResetBits4.2 PWM 没有输出时该如何定位如果电机不转你把示波器探头接在 PA0 上发现没有任何波形这时候问题大概率出在代码配置上。我的排查套路是先检查定时器时钟有没有使能。TIM2 挂在 APB1 总线上必须调用 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE)GPIO 挂在 APB2 上要调用 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE)。忘了开时钟的典型表现就是寄存器写不进去外设完全没反应。接着检查 PA0 的模式。我见过有人把 PA0 配置成 GPIO_Mode_Out_PP这是普通推挽输出不是复用功能PWM 信号压根出不来。必须改成 GPIO_Mode_AF_PP。再检查定时器配置里的 TIM_OCInitTypeDef如果 TIM_OutputState 是 DISABLE输出自然也是关闭的。还有一个高级定时器的特殊坑。如果你用的是 TIM1 而不是 TIM2在 TIM_Cmd 使能定时器后还必须调用 TIM_CtrlPWMOutputs(TIM1, ENABLE)。这个函数的作用是使能 TIM1 的 MOE 主输出引脚忘了它 PWM 波形就永远是高阻态。TIM2、TIM3、TIM4 这些通用定时器没有这个问题这也是我建议初学阶段先用 TIM2 的原因。4.3 按键调速失败与消抖处理按键调速出现“按一下跳好几格”的情况大概率是消抖没做好。我代码里用了延时 10ms 加电平二次确认的方式实测下来在仿真环境足够稳定。如果你在实物上也这么写建议把消抖延时提高到 20ms因为实物的机械抖动时间可能更长。按键不灵敏或者完全没响应的排查方向是检查上下拉配置。我的电路里按键一端接 PA3另一端接地PA3 配置为上拉输入 GPIO_Mode_IPU。如果没有上拉按键松开时引脚会悬空电平不确定程序可能会误判成一直按下。按键的另一端如果没接地按下时没有电流回路GPIO 读到的永远是高电平看起来就是按键没反应。调试按键时我建议在按键触发分支里临时加一个翻转 LED 的逻辑比如每按一次就翻转 PC13 的电平。这样你能直观看到主循环是否跑到了按键分支如果 LED 正常翻转但占空比没变那就是 TIM_SetCompare1 的参数有问题如果 LED 也不翻转那问题在按键检测逻辑本身。4.4 Proteus 仿真实物差异与“飞车”预防Proteus 里能跑通的逻辑到实物上不一定一次成功这是很多人忽略的。仿真里的电机模型不考虑换向火花、电刷压降、绕组电感变化、负载扭矩这些真实因素所以实际电机的启动电流、转速响应都会和仿真有差异。更关键的是仿真里电源是理想电源而实物的电源存在内阻和压降大电流启动时电压会被拉低可能导致单片机复位。我建议做实物前一定留足电源余量电机电源和控制电源最好分开。说到“飞车”这是电机控制里一个非常危险的故障状态。飞车通常指驱动电路输出异常比如 PWM 信号突然变为常高或者 MOSFET 栅极被击穿导致 H 桥同侧导通电机失去控制全速运转。在 Prosteus 仿真里很少出现这种物理损坏但代码逻辑上的“飞车”却可以通过占空比限幅来预防。我在代码里把占空比限制在 10% 到 90%并且在每次调整时只加减 10不让你一次从 30% 跳到 90%这其实就是一种软件保护。如果需要更可靠的保护实际工程中还会加上看门狗。看门狗的作用是当主循环跑飞或者死循环时定时器溢出复位单片机PWM 输出会被强制关断电机自然停转。你还可以在 L298N 的 VS 输入端串联一个保险丝或者用带电流检测的驱动芯片电流超过阈值就主动切断输出。仿真阶段这些保护暂时不用但你要在设计之初就把它们的位置留出来。最后分享一个我自己的习惯做完一个 Proteus 电机控制实验后我会顺手把占空比调节改成 ADC 电位器控制再把正反转按键改成拨码开关。这个小改动涉及 ADC、电位器采样、中断、GPIO 输入多个外设的配合练一次就能把 STM32 常用的外设串起来。你在实际调试中如果遇到和文章里不太一样的现象建议先用示波器观察关键节点的波形再结合占空比数值逐层排查大部分问题都能在十分钟内定位。
返回列表