ARTICLE DETAIL

资讯详情

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

STM32F103驱动L298N控制直流减速电机:从PWM配置到状态机设计

STM32F103驱动L298N控制直流减速电机:从PWM配置到状态机设计 简介本资源是一套面向嵌入式初学者与项目开发者的STM32F103实战驱动例程聚焦直流减速电机的精准控制解决L298N双H桥驱动芯片与单片机协同工作的核心问题适用于智能小车、机电控制系统等典型物联网终端场景。压缩包共128个文件含32个C源码与32个头文件实现GPIO、TIM、RCC、USART等外设驱动辅以编译中间文件.o/.d/.crf、工程配置文件.uvproj/.uvopt/.sct及可执行镜像.axf/.hex总大小1.52MB结构完整开箱即用。已有200人学习下载代码基于KEIL标准库开发兼容STM32F103全系列芯片接线定义清晰标注于代码中支持J-Link与ST-Link两种调试器切换。读者可直接编译运行快速掌握PWM调速、方向控制、硬件定时器中断等关键技能并为接入编码器、红外传感器等扩展模块提供可靠底层支撑。1. 项目缘起从“电机不转”到“精准控制”的实战跨越如果你玩过STM32大概率是从点亮一个LED或者驱动一个舵机开始的。但当你第一次尝试用单片机去控制一个真正的、带负载的直流减速电机时可能会遇到一个尴尬的局面代码写了PWM也输出了但电机要么纹丝不动要么就是一阵抽搐后冒烟。这背后往往不是单片机本身的问题而是驱动环节的缺失。单片机GPIO那几十毫安的驱动能力在需要几百毫安甚至几安培电流的电机面前显得力不从心。这个项目要解决的就是这个从“信号”到“动力”的鸿沟。我手头这个项目核心就是利用STM32F103这款经典的Cortex-M3内核单片机去驱动L298N这款同样经典的电机驱动模块最终实现对直流减速电机的正反转、调速PWM以及简单的启停控制。听起来像是电子爱好者入门必做的项目对吧但恰恰是这种基础项目藏着很多从原理图到代码、从理论到实践的细节坑。比如PWM频率选多少合适L298N的使能逻辑怎么接电机的反电动势和续流二极管保护如何考虑这些细节没处理好轻则控制不灵重则烧毁芯片。网上相关的代码和教程很多但往往要么只给一段核心控制代码缺头少尾要么原理讲得云里雾里和实际接线对不上。我这个项目例程就是从一块空白的STM32F103C8T6最小系统板开始手把手带你完成硬件连接、软件配置、代码编写到功能调试的全过程。我会重点分享那些在数据手册里不会明说但在实际调试中一定会遇到的“坑”比如如何避免L298N的逻辑电源和驱动电源共地问题导致的单片机复位如何计算并设置一个既能让电机安静运行又不产生可闻噪音的PWM频率。我们的目标不仅仅是让电机转起来而是让它转得稳定、可靠、可控。2. 核心器件选型与电路设计解析在动手写代码之前我们必须先吃透硬件。硬件是软件的基石电路设计上的一个疏忽可能会让后续的软件调试变得异常艰难甚至徒劳无功。2.1 为什么是STM32F103和L298N首先看主控。选择STM32F103C8T6俗称“蓝桥杯”或“最小系统板”款原因很实在资源足够、价格低廉、生态成熟。它拥有多达7个定时器其中高级定时器TIM1和通用定时器TIM2/3/4都支持PWM输出这对于电机控制来说是刚需。72MHz的主频应对简单的电机控制算法绰绰有余。更重要的是它的社区支持度极高任何问题几乎都能找到解决方案非常适合学习和原型开发。再看驱动芯片L298N。这是一款双H桥驱动芯片可以同时驱动两个直流电机或者一个步进电机。它的最大驱动能力是2A单桥峰值电流可达3A足以驱动中小型的直流减速电机。它的逻辑部分工作电压是5V驱动部分电机电源电压范围可以从5V到46V灵活性很高。选择它一方面是因为其经典、可靠、易于获取另一方面它的控制逻辑非常直观通过两个输入引脚IN1, IN2和一个使能引脚ENA即可控制一个电机的方向和速度非常适合教学和原理理解。2.2 直流减速电机参数与驱动需求直流减速电机是在普通直流电机的基础上集成了一组齿轮箱从而降低了输出转速增大了输出扭矩。在选择时你需要关注几个关键参数额定电压例如6V、12V。这决定了你给电机供电的电压。空载转速单位是RPM转/分钟。加了减速箱后这个值会大幅降低。减速比例如1:30表示电机转30圈输出轴转1圈。额定扭矩单位是kg.cm或N.cm表示电机在额定电压下能带动的负载大小。空载电流和堵转电流空载电流通常很小几十到几百mA但堵转电机轴被卡住时电流会急剧上升可能达到安培级。L298N和你的电源必须能承受短时间的堵转电流否则会烧毁。对于本项目我们假设使用一个额定电压12V减速比1:30的直流减速电机。这意味着我们需要一个12V的电源可以是电源适配器或电池为L298N的驱动部分VMS供电。2.3 硬件连接电路详解与避坑指南这是最容易出错的一环。错误的接线轻则电机不转重则损坏单片机或L298N。下面是一个标准的单电机控制连接图文字描述电源部分重中之重单片机电源STM32F103最小系统板通过USB线或外部5V/3.3V供电。L298N逻辑电源VSS此引脚必须接5V为芯片内部的逻辑电路供电。一个常见错误是将其接到3.3V。虽然有些L298N模块在3.3V下也能工作但可能不稳定导致控制信号识别错误。最稳妥的方法是接5V。可以从单片机板的5V引脚取电或者使用独立的5V电源但必须与单片机共地。L298N驱动电源VMS接你的电机额定电压比如12V。这个电源的地GND必须和单片机的地、L298N逻辑电源的地连接在一起即“共地”。这是信号正确传递的基础。L298N板载5V输出很多L298N模块有一个5V输出引脚。注意这个引脚是当你的驱动电源VMS高于5V时由模块上的稳压芯片如78M05降压产生的5V。如果你已经用外部5V为VSS供电这个引脚可以悬空或用作他用。如果VMS输入电压就是5V这个引脚可能没有输出或电压不准不建议使用。信号连接部分ENA使能A连接STM32的一个具有PWM输出功能的引脚例如PA8TIM1_CH1。通过改变这个引脚PWM的占空比来调节电机速度。IN1 IN2输入1 输入2连接STM32的两个普通GPIO引脚例如PA0和PA1。它们控制电机的方向。OUT1 OUT2输出1 输出2连接直流减速电机的两根线。控制逻辑真值表 这是理解L298N如何工作的核心。假设ENA通过PWM使能高电平有效。IN1IN2电机状态00刹车电机两端短接到地01反转10正转11刹车电机两端短接到电源重要提示在改变方向IN1/IN2组合之前最好先将ENA置为低电平或PWM占空比为0让电机停止然后再改变方向信号最后重新使能。这样可以避免H桥上下管瞬间直通的风险虽然L298N内部有死区保护但养成这个好习惯能提升系统可靠性。关键外围电路续流二极管L298N模块上通常已经集成了。它的作用是在电机断电瞬间为线圈产生的反向电动势反电动势提供泄放回路保护H桥开关管不被击穿。务必确保你使用的模块上有这些二极管。滤波电容在L298N的VMS和GND之间靠近芯片引脚处并联一个100uF以上的电解电容和一个0.1uF的瓷片电容用于滤除电源噪声和电机工作时产生的电流突变防止电压跌落干扰单片机。3. STM32F103的PWM配置深度剖析让电机转起来不难但要让电机转得平稳、安静、响应快PWM的配置是关键。这里我们选择使用STM32F103的通用定时器TIM3的通道1PA6来产生PWM信号连接到L298N的ENA引脚。3.1 定时器时钟树与PWM频率计算STM32的PWM频率由定时器的时钟和重装载值决定。首先要理清时钟来源。默认情况下系统时钟SYSCLK是72MHz。TIM3挂载在APB1总线上APB1的预分频器默认为2所以APB1的时钟是36MHz。但是当APB1预分频系数不为1时连接到定时器的时钟会倍频x2因此TIM3的实际输入时钟CK_INT是72MHz。PWM频率的计算公式为PWM_Freq CK_INT / ((PSC 1) * (ARR 1))其中CK_INT定时器内部时钟频率这里是72,000,000 Hz。PSC预分频器寄存器值。ARR自动重装载寄存器值。占空比的计算公式为Duty_Cycle (CCR / (ARR 1)) * 100%其中CCR是捕获/比较寄存器值。如何选择PWM频率频率太低如几十Hz电机会产生明显的“嗡嗡”声因为线圈电流断续扭矩不平稳。频率太高如几十kHz开关损耗会增加可能导致L298N发热加剧。同时频率超过一定值后由于电机线圈的电感特性电流来不及变化调速效果会变差。常用范围对于直流减速电机1kHz 到 20kHz是一个比较好的范围。我个人的经验是5kHz到10kHz是一个甜点区间既能保证调速线性度又能避免可闻噪音L298N的发热也在可控范围内。假设我们目标PWM频率为10kHzARR设置为719那么可以计算PSCPSC CK_INT / (Freq * (ARR1)) - 1 72,000,000 / (10,000 * 720) - 1 10 - 1 9这样配置后PWM频率为72,000,000 / ((91)*720) 10,000 Hz。3.2 使用STM32CubeMX进行可视化配置对于初学者我强烈推荐使用STM32CubeMX进行初始化配置它能直观地生成代码避免手动操作寄存器出错。Pinout Configuration在TIM3的设置中选择Channel1为“PWM Generation CH1”。对应的引脚PA6会自动被配置为复用推挽输出Alternate Function Push Pull。Configuration - Parameter SettingsPrescaler (PSC)设置为9。Counter ModeUp向上计数。Counter Period (ARR)设置为719。Internal Clock Division (CKD)No Division。auto-reload preloadEnable使能自动重装载预装载可以避免更新参数时产生毛刺。在下方 PWM Generation Channel 1 的设置中ModePWM mode 1在向上计数时当TIMx_CNT TIMx_CCR1时通道为有效电平。Pulse (CCR)初始占空比例如设置为360即50%占空比。Fast ModeDisable。CH PolarityHigh有效电平为高。这很重要因为L298N的ENA是高电平使能。生成代码配置好时钟树确保HCLK为72MHz后生成MDK-ARM或IDE对应的工程代码。3.3 手动配置代码详解理解本质如果你不用CubeMX或者想深入理解以下是关键代码基于标准外设库// 1. 开启时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // 2. 配置GPIO PA6为复用推挽输出 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin GPIO_Pin_6; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF_PP; // 复用推挽输出 GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); // 3. 配置定时器TIM3 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_TimeBaseStructure.TIM_Period 719; // ARR TIM_TimeBaseStructure.TIM_Prescaler 9; // PSC TIM_TimeBaseStructure.TIM_ClockDivision TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, TIM_TimeBaseStructure); // 4. 配置PWM输出模式 TIM_OCInitTypeDef TIM_OCInitStructure; TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; // PWM模式1 TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; // 使能输出 TIM_OCInitStructure.TIM_Pulse 360; // 初始CCR值占空比50% TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; // 输出极性高 TIM_OC1Init(TIM3, TIM_OCInitStructure); // 初始化通道1 // 5. 使能预装载寄存器重要 TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable); TIM_ARRPreloadConfig(TIM3, ENABLE); // 6. 启动定时器 TIM_Cmd(TIM3, ENABLE); // 7. 启动PWM输出高级定时器需要通用定时器可省略但建议加上 TIM_CtrlPWMOutputs(TIM3, ENABLE);关键点解析TIM_OCPolarity_High这个设置必须和L298N的使能逻辑匹配。我们设置有效电平为高那么当CCR值大于计数器值时输出高电平电机使能。TIM_OC1PreloadConfig和TIM_ARRPreloadConfig使能预装载后你对CCR或ARR的修改会在下一次更新事件计数器溢出时才生效这能保证PWM波形的完整性避免在周期中间改变占空比产生奇怪的脉冲。改变占空比在程序运行中你只需要修改捕获/比较寄存器CCR的值即可。例如TIM_SetCompare1(TIM3, 180);会将占空比设置为25% (180/720)。4. 电机驱动状态机与软件架构设计控制一个电机不仅仅是输出PWM更需要一个清晰、稳定的软件状态机来管理其启动、停止、正转、反转、调速等行为并处理异常情况。4.1 定义电机控制对象与状态首先我们定义一个结构体来封装一个电机的所有控制参数和状态这样代码更模块化易于维护和扩展例如控制多个电机。typedef enum { MOTOR_STOP 0, MOTOR_FORWARD, MOTOR_BACKWARD, MOTOR_BRAKE } Motor_State_t; typedef struct { GPIO_TypeDef* IN1_Port; // IN1引脚端口 uint16_t IN1_Pin; // IN1引脚号 GPIO_TypeDef* IN2_Port; // IN2引脚端口 uint16_t IN2_Pin; // IN2引脚号 TIM_TypeDef* TIMx; // 使用的定时器用于PWM uint16_t TIM_Channel; // 定时器通道 Motor_State_t State; // 当前状态 uint16_t Speed; // 当前速度0-ARR最大值 uint16_t ARR_Max; // ARR最大值用于计算速度百分比 } Motor_t;4.2 核心控制函数实现基于上面的结构体我们实现几个核心函数。1. 电机初始化函数 这个函数负责初始化GPIOIN1, IN2和PWM定时器。PWM的初始化可以复用上一节的代码这里主要展示GPIO和控制逻辑的初始化。void Motor_Init(Motor_t* motor, GPIO_TypeDef* IN1_Port, uint16_t IN1_Pin, GPIO_TypeDef* IN2_Port, uint16_t IN2_Pin, TIM_TypeDef* TIMx, uint16_t TIM_Channel, uint16_t ARR_Max) { // 保存参数到结构体 motor-IN1_Port IN1_Port; motor-IN1_Pin IN1_Pin; motor-IN2_Port IN2_Port; motor-IN2_Pin IN2_Pin; motor-TIMx TIMx; motor-TIM_Channel TIM_Channel; motor-ARR_Max ARR_Max; motor-State MOTOR_STOP; motor-Speed 0; // 初始化IN1, IN2为推挽输出 GPIO_InitTypeDef GPIO_InitStruct {0}; GPIO_InitStruct.Pin IN1_Pin; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(IN1_Port, GPIO_InitStruct); GPIO_InitStruct.Pin IN2_Pin; HAL_GPIO_Init(IN2_Port, GPIO_InitStruct); // 初始状态停止IN10, IN20 HAL_GPIO_WritePin(motor-IN1_Port, motor-IN1_Pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(motor-IN2_Port, motor-IN2_Pin, GPIO_PIN_RESET); // PWM初始化假设已通过CubeMX或其它方式完成此处省略详细代码 // ... // 启动PWM但占空比设为0Speed0 __HAL_TIM_SET_COMPARE(motor-TIMx, motor-TIM_Channel, 0); HAL_TIM_PWM_Start(motor-TIMx, motor-TIM_Channel); }2. 设置电机速度函数 这个函数用于改变PWM占空比。一个重要的安全设计是当电机处于停止状态时设置速度不会立即生效只有调用启动函数后才会生效。void Motor_SetSpeed(Motor_t* motor, uint16_t speed) { // 限制速度在有效范围内 if(speed motor-ARR_Max) { speed motor-ARR_Max; } motor-Speed speed; // 只有当电机处于运行状态时才立即更新PWM占空比 if(motor-State MOTOR_FORWARD || motor-State MOTOR_BACKWARD) { __HAL_TIM_SET_COMPARE(motor-TIMx, motor-TIM_Channel, speed); } // 如果电机是停止状态速度值会被保存但PWM输出保持为0直到下次启动。 }3. 电机运行控制函数状态机核心 这是最关键的函数它根据目标状态来安全地控制IN1、IN2和PWM。void Motor_Run(Motor_t* motor, Motor_State_t targetState) { // 如果目标状态与当前状态相同则无需操作除调速外 if(motor-State targetState targetState ! MOTOR_STOP) { return; } // 状态转换前的安全操作先停止PWM输出将占空比设为0 // 这是一个好习惯避免在切换方向时产生大电流。 if(motor-State ! MOTOR_STOP targetState ! MOTOR_STOP) { // 如果是从一个运行状态切换到另一个运行状态如正转切反转先刹车再切换。 Motor_Brake(motor); // 刹车函数见下文 HAL_Delay(10); // 短暂延时确保电机停稳。延时时间可根据电机惯性调整。 } else { // 其他情况直接关闭PWM输出 __HAL_TIM_SET_COMPARE(motor-TIMx, motor-TIM_Channel, 0); } // 根据目标状态设置IN1, IN2引脚电平 switch(targetState) { case MOTOR_STOP: HAL_GPIO_WritePin(motor-IN1_Port, motor-IN1_Pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(motor-IN2_Port, motor-IN2_Pin, GPIO_PIN_RESET); motor-Speed 0; // 停止后速度清零 break; case MOTOR_FORWARD: HAL_GPIO_WritePin(motor-IN1_Port, motor-IN1_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(motor-IN2_Port, motor-IN2_Pin, GPIO_PIN_RESET); // 恢复之前设置的速度 __HAL_TIM_SET_COMPARE(motor-TIMx, motor-TIM_Channel, motor-Speed); break; case MOTOR_BACKWARD: HAL_GPIO_WritePin(motor-IN1_Port, motor-IN1_Pin, GPIO_PIN_RESET); HAL_GPIO_WritePin(motor-IN2_Port, motor-IN2_Pin, GPIO_PIN_SET); __HAL_TIM_SET_COMPARE(motor-TIMx, motor-TIM_Channel, motor-Speed); break; case MOTOR_BRAKE: // 刹车将电机两端短接 HAL_GPIO_WritePin(motor-IN1_Port, motor-IN1_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(motor-IN2_Port, motor-IN2_Pin, GPIO_PIN_SET); // 刹车时PWM占空比应设为0或最大值这里设为0让电机自由刹车。 // 实际上L298N在IN1IN21时是“快衰减”刹车电机线圈被短接制动快。 __HAL_TIM_SET_COMPARE(motor-TIMx, motor-TIM_Channel, 0); break; default: break; } // 更新状态 motor-State targetState; } // 刹车函数 void Motor_Brake(Motor_t* motor) { Motor_Run(motor, MOTOR_BRAKE); HAL_Delay(50); // 刹车保持一段时间 Motor_Run(motor, MOTOR_STOP); // 刹车后回到停止状态 }4.3 主程序逻辑与应用示例有了上面的驱动层主程序变得非常清晰。下面是一个简单的示例让电机以不同速度正反转运行。int main(void) { // 系统初始化时钟、延时等 HAL_Init(); SystemClock_Config(); // 初始化电机对象 // 假设IN1-PA0, IN2-PA1, PWM使用TIM3_CH1 (PA6), ARR最大值为719 Motor_t myMotor; Motor_Init(myMotor, GPIOA, GPIO_PIN_0, GPIOA, GPIO_PIN_1, TIM3, TIM_CHANNEL_1, 719); while(1) { // 正转50%速度 Motor_SetSpeed(myMotor, 360); // 设置速度 Motor_Run(myMotor, MOTOR_FORWARD); HAL_Delay(2000); // 刹车停止 Motor_Brake(myMotor); HAL_Delay(500); // 反转30%速度 Motor_SetSpeed(myMotor, 216); Motor_Run(myMotor, MOTOR_BACKWARD); HAL_Delay(2000); // 平滑减速停止而非急刹 for(int i216; i0; i-10) { Motor_SetSpeed(myMotor, i); HAL_Delay(50); } Motor_Run(myMotor, MOTOR_STOP); HAL_Delay(1000); } }5. 调试实战常见问题排查与性能优化代码写完了硬件连好了但电机可能还是不听话。这一章我们来系统性地排查问题和优化性能。5.1 电机完全不转的排查流程检查电源用万用表测量L298N的VMS和GND之间是否有12V或你的电机电压测量VSS和GND之间是否有5V特别注意单片机的地、L298N的逻辑地、驱动电源地是否可靠连接在一起这是最常见的问题。测量电机两端OUT1和OUT2在运行时是否有电压变化检查控制信号使用逻辑分析仪或示波器是最佳选择。如果没有可以用一个简单的办法将STM32控制IN1、IN2、ENA的引脚通过杜邦线连接到几个LED上串联限流电阻观察LED的亮灭是否符合程序逻辑。重点检查ENA引脚的PWM波形。用示波器看是否有波形频率是否正确约10kHz占空比是否随程序改变一个坑如果GPIO引脚配置错误比如配置成了输入模式就不会有输出。检查L298N模块很多L298N模块有使能跳线帽。如果ENA引脚插了跳线帽那么该通道会被强制使能高电平此时单片机输出的PWM将失效。务必拔掉连接ENA引脚的跳线帽让单片机控制。模块上可能有电源指示灯检查是否亮起。检查代码确认定时器和PWM初始化代码是否被执行。可以在初始化后加一个while(1)死循环测试PWM输出。确认HAL_TIM_PWM_Start()函数被调用。确认你修改的是正确的CCR寄存器。例如使用TIM3的通道1应该用__HAL_TIM_SET_COMPARE(htim3, TIM_CHANNEL_1, speed)。5.2 电机抖动、异响或转速不稳定的排查PWM频率问题频率是否太低低于100Hz电机会明显抖动和发声。用示波器确认频率。尝试提高PWM频率到5kHz以上。电源功率不足这是导致转速不稳、带载能力差的头号原因。电机启动和堵转时电流很大如果电源特别是12V驱动电源最大电流不足电压会被拉低导致L298N工作异常甚至单片机复位。解决方法使用功率足够的开关电源如12V 3A以上并在VMS入口处并联一个大电容如470uF~1000uF储能。软件消抖与死区在改变方向的控制代码中虽然我们加入了HAL_Delay(10)但对于某些惯性大的电机可能不够。可以适当增加延时或更优的方法是通过检测电机反电动势或电流来判断电机是否已停止再进行换向这属于更高级的控制。L298N内部没有硬件死区但在我们软件上通过“先关闭PWM再换向”的步骤实现了类似死区的保护。5.3 发热与效率优化L298N发热严重L298N是线性驱动芯片其发热主要来自导通损耗P_loss I * V_drop。V_drop是芯片内部的压降在驱动电流大时比如1A以上即使压降只有2V功耗也有2W必须加散热片。优化方法加装散热片这是必须的尤其是长时间工作或驱动电流较大时。降低驱动电压在满足电机转速要求的前提下适当降低VMS电压可以减小芯片压降从而降低功耗。例如电机额定12V用10V也能转发热会小一些。使用外部续流二极管虽然模块集成了二极管但通常是普通的1N4007反向恢复时间较慢。如果开关频率很高比如20kHz可以尝试在电机两端并联肖特基二极管如1N5819以减少开关损耗和发热。选择更高效的驱动方案如果项目对效率和发热要求很高可以考虑使用MOSFET H桥驱动芯片如DRV8833、TB6612FNG等。这些芯片采用同步整流技术导通电阻Rds_on极小效率远高于L298N发热也小得多非常适合电池供电的设备。5.4 进阶功能速度闭环控制初探开环PWM控制简单但负载变化时转速也会变化。要实现稳速需要引入反馈构成闭环。最常用的反馈是编码器。增量式编码器电机轴上安装一个光栅盘可以输出A、B两相正交脉冲。STM32的定时器支持编码器模式可以直接读取脉冲数和方向。速度计算在固定时间间隔如10ms内读取编码器计数值的变化量即可算出速度。PID控制将计算出的实际速度与目标速度比较得到误差通过PID算法计算出新的PWM占空比从而调整电机输出使实际速度逼近目标速度。这是一个完整的项目延伸方向。你需要将编码器的A、B相接至STM32定时器的通道1和通道2如TIM2或TIM4并配置为编码器模式。编写一个定时中断如SysTick或通用定时器在中断里计算速度。实现一个简单的PID控制器可以先从P控制开始。将PID的输出作为Motor_SetSpeed的参数。这个过程比开环控制复杂得多但能让你对电机控制的理解提升一个层次。从让电机“转起来”到让电机“按我想要的转速精准转起来”这才是嵌入式电机控制的精髓。本文还有配套的精品资源点击获取
返回列表