网站开发人员主要干什么的公司注册资金可以随便填吗
网站开发人员主要干什么的,公司注册资金可以随便填吗,全屋定制十大名牌口碑,广州市网站建设制作费用基于天空星STM32F407的L298N电机驱动模块PWM调速实战
最近在做一个智能小车项目#xff0c;用到了经典的L298N电机驱动模块来控制直流电机。我发现很多刚开始接触嵌入式或机器人项目的朋友#xff0c;虽然能照着教程把电机转起来#xff0c;但一到自己调速度、换方向#x…基于天空星STM32F407的L298N电机驱动模块PWM调速实战最近在做一个智能小车项目用到了经典的L298N电机驱动模块来控制直流电机。我发现很多刚开始接触嵌入式或机器人项目的朋友虽然能照着教程把电机转起来但一到自己调速度、换方向或者想把代码移植到自己的板子上时就有点懵了。今天我就以手头的“天空星STM32F407”开发板为例带大家从头到尾走一遍看看怎么用STM32的PWM功能让L298N驱动电机实现精准的调速和正反转控制。整个过程我会尽量讲得细一些把原理和代码都掰开揉碎了说保证你跟着做一遍就能完全掌握。1. 认识我们的“肌肉”L298N电机驱动模块在开始写代码之前咱们得先搞清楚要控制的“对象”是什么。L298N模块可以说是电子爱好者手边的常客了它就像一个小型电机的“肌肉放大器”。它到底是什么简单来说L298N是一块电机驱动芯片来自ST公司它能接受我们单片机发出的微弱控制信号3.3V或5V然后去控制需要较高电压和较大电流才能工作的电机比如12V的直流电机。它内部集成了两个H桥电路这意味着一个L298N模块可以独立控制两个直流电机或者一个两相/四相的步进电机。关键参数要记牢根据资料咱们手头这个模块有几个关键参数接线和供电前一定要核对清楚驱动电压给电机供电的5V ~ 24V。常见的小车电机用7.2V两节锂电池或12V三节锂电池比较多。驱动电流持续工作电流2A瞬间峰值能到3A。驱动一般的130、TT马达绰绰有余。逻辑电压给芯片大脑供电的5V。这个电压决定了模块能否正确识别你单片机发来的控制信号。控制信号支持PWM脉冲宽度调制调速这是我们今天实现调速功能的核心。供电的“坑”我踩过这里有个特别容易接错的地方就是供电。模块上通常有两处需要供电电机驱动电源VCC接5V-24V这个是给电机提供动力的“主电源”。逻辑电源5V给L298N芯片内部的逻辑电路供电让它能正常工作。模块上一般有个“5V使能”的跳线帽。这里分两种情况情况一最常用当你的驱动电压在7V~12V之间时比如用9V电池可以保留这个跳线帽。模块会通过板载的78M05稳压芯片自动从驱动电源里“榨”出5V给逻辑部分用。此时5V端子可以输出5V电压给你的单片机或其他传感器供电。情况二当驱动电压高于12V比如24V时必须拔掉这个跳线帽否则78M05可能会过载发热甚至损坏。然后你需要从外部比如另一个5V电源或开发板的5V引脚单独引一根线接到模块的5V端子上给逻辑部分供电。注意无论哪种供电方式务必将单片机天空星开发板的GND和L298N模块的GND用导线连接在一起这叫“共地”是所有信号比如PWM能够被正确识别的基准。不共地控制信号就乱套了。2. 控制原理PWM与H桥是如何协作的知道了模块怎么接电接下来咱们聊聊它是怎么听我们话让电机转起来、停下去、换个方向的。PWM调速不是调电压是调“能量”PWM中文叫脉冲宽度调制。你可以把它想象成一种非常快速开关电源的技术。我们通过改变一个周期内“开”高电平的时间比例即占空比来改变平均输送给电机的功率。占空比0%一直关着电机不转。占空比50%一半时间开一半时间关电机以中等速度转。占空比100%一直开着电机全速转。 STM32的定时器外设就能非常精准地产生这种PWM波形。H桥控制方向让电流“掉头”L298N内部每个电机通道都是一个H桥电路它有四个“开关”实际是晶体管。通过控制这四个开关的不同组合可以改变流过电机的电流方向从而控制电机正转或反转。对于电机A我们主要用到三个控制引脚ENA使能端A高电平有效。接PWM信号用于调速。IN1IN2逻辑输入1和2用于控制方向。它们配合的真值表是这样的ENA (PWM)IN1IN2电机A状态有效 (PWM)10正转 (速度由PWM占空比决定)有效 (PWM)01反转 (速度由PWM占空比决定)有效 (PWM)11刹车 (电机快速停止)有效 (PWM)00滑行停止 (电机惯性停下)0 (低电平)XX停止 (不使能电机不受控)所以我们的控制策略就清晰了将IN1和IN2引脚也配置为PWM输出。通过程序动态改变IN1和IN2两个PWM通道的占空比一个给高占空比一个给0就能同时实现方向和速度的控制。ENA引脚在模块上通常用跳线帽直接接到高电平VCC使其常有效这样我们只用IN1/IN2就能搞定一切。3. 硬件连接把天空星和L298N“手拉手”理论懂了开始动手接线。拿出你的天空星STM32F407开发板和L298N模块。引脚分配计划我们计划用STM32的TIM12定时器来产生两路PWM分别控制电机A的IN1和IN2。查阅天空星开发板的原理图或数据手册可知TIM12的通道1和通道2对应着PB14和PB15引脚正好可以复用为PWM输出。所以连接关系如下表天空星STM32F407引脚L298N模块引脚功能说明PB14(TIM12_CH1)IN1控制电机A的方向和速度PWMPB15(TIM12_CH2)IN2控制电机A的方向和速度PWM5V5V仅当L298N驱动电压12V时需要为模块逻辑部分供电GNDGND必须连接共地—ENA用跳线帽短接到模块上的5V端子使其常有效—VCC接外部电机电源如12V电池正极—GND接外部电机电源如12V电池负极—OUT1OUT2接直流电机的两个线提示电机电源接VCC和单片机电源最好是独立的避免电机启动时的大电流干扰单片机稳定工作。但两者的GND一定要连在一起。4. 代码实战一步步配置PWM驱动电机硬件连好了现在来写代码。我会把关键代码和解释都列出来你可以直接移植到你的工程里。4.1 建立驱动文件与宏定义首先在你的工程里新建两个文件bsp_L298N.c和bsp_L298N.h“bsp”意为板级支持包是一种常见的驱动文件命名方式。在bsp_L298N.h里我们主要做引脚和定时器的宏定义这样以后想换引脚或定时器改这里就行了非常方便。#ifndef _BSP_L298N_H #define _BSP_L298N_H #include stm32f4xx.h #include board.h // 天空星开发板的板级支持头文件 /* GPIO引脚定义 - 使用PB14, PB15 */ #define RCC_GPIO RCC_AHB1Periph_GPIOB #define PORT_GPIO GPIOB #define GPIO_IN1 GPIO_Pin_14 #define GPIO_IN1_SOURCE GPIO_PinSource14 #define GPIO_IN2 GPIO_Pin_15 #define GPIO_IN2_SOURCE GPIO_PinSource15 /* 定时器定义 - 使用TIM12 */ #define RCC_IN1_TIMER RCC_APB1Periph_TIM12 #define BSP_IN1_TIMER TIM12 // IN1和IN2共用TIM12所以IN2的定义与IN1相同 #define RCC_IN2_TIMER RCC_APB1Periph_TIM12 #define BSP_IN2_TIMER TIM12 /* 函数声明 */ void L298N_Init(uint16_t pre, uint16_t per); void AO_Control(uint8_t dir, uint32_t speed); #endif /* BSP_L298N_H */4.2 核心初始化函数配置PWM接下来是重头戏在bsp_L298N.c中编写初始化函数L298N_Init。这个函数负责初始化GPIO和定时器使其能输出PWM信号。#include bsp_L298N.h #include board.h /** * brief L298N PWM初始化函数 * param pre: 定时器预分频值用于设定定时器时钟频率 * param per: 定时器自动重装载值决定PWM波形的周期 * note 定时器时钟源为84MHz (天空星STM32F407的APB1总线时钟) * PWM频率 84MHz / (pre * per) */ void L298N_Init(uint16_t pre, uint16_t per) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; /* 1. 开启外设时钟 */ RCC_APB1PeriphClockCmd(RCC_IN1_TIMER, ENABLE); // 使能TIM12时钟 RCC_AHB1PeriphClockCmd(RCC_GPIO, ENABLE); // 使能GPIOB时钟 /* 2. 配置GPIO引脚为复用推挽输出模式 */ GPIO_InitStructure.GPIO_Pin GPIO_IN1 | GPIO_IN2; // 同时初始化PB14和PB15 GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF; // 复用功能 GPIO_InitStructure.GPIO_Speed GPIO_Speed_100MHz; // 高速输出 GPIO_InitStructure.GPIO_OType GPIO_OType_PP; // 推挽输出 GPIO_InitStructure.GPIO_PuPd GPIO_PuPd_NOPULL; // 不上拉不下拉 GPIO_Init(PORT_GPIO, GPIO_InitStructure); /* 3. 将GPIO引脚连接到TIM12的复用功能上 */ GPIO_PinAFConfig(PORT_GPIO, GPIO_PinSource14, GPIO_AF_TIM12); // PB14 - TIM12_CH1 GPIO_PinAFConfig(PORT_GPIO, GPIO_PinSource15, GPIO_AF_TIM12); // PB15 - TIM12_CH2 /* 4. 配置定时器时基单元 */ TIM_TimeBaseStructure.TIM_Period per - 1; // 自动重装载值决定PWM周期 TIM_TimeBaseStructure.TIM_Prescaler pre - 1; // 预分频值 TIM_TimeBaseStructure.TIM_ClockDivision TIM_CKD_DIV1; // 时钟不分频 TIM_TimeBaseStructure.TIM_CounterMode TIM_CounterMode_Up; // 向上计数模式 TIM_TimeBaseInit(BSP_IN1_TIMER, TIM_TimeBaseStructure); /* 5. 配置PWM输出模式 */ TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; // PWM模式1 TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; // 输出使能 TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; // 输出极性高 // 初始化通道1 (对应IN1/PB14) TIM_OC1Init(BSP_IN1_TIMER, TIM_OCInitStructure); // 初始化通道2 (对应IN2/PB15) TIM_OC2Init(BSP_IN1_TIMER, TIM_OCInitStructure); /* 6. 使能预装载寄存器保证改变占空比时波形平滑 */ TIM_OC1PreloadConfig(BSP_IN1_TIMER, TIM_OCPreload_Enable); TIM_OC2PreloadConfig(BSP_IN1_TIMER, TIM_OCPreload_Enable); /* 7. 启动定时器开始输出PWM */ TIM_Cmd(BSP_IN1_TIMER, ENABLE); }参数计算小贴士函数需要两个参数pre预分频值和per周期值。PWM频率定时器时钟源频率 / ( (pre) * (per) )天空星STM32F407上TIM12挂载在APB1总线时钟是84MHz。假设我们想要一个1kHz的PWM频率可以设pre 84per 1000。计算84,000,000 Hz / (84 * 1000) 1000 Hz。频率太高电机响应不过来太低会有噪音1kHz-10kHz是常用范围。4.3 电机控制函数一句话控制转向和速度初始化完成后我们需要一个函数来灵活控制电机。下面这个AO_Control函数你只需要告诉它方向和速度它就能自动设置好两个PWM通道的占空比。/** * brief 控制电机A端口OUT1OUT2 * param dir: 方向1正转0反转 * param speed: 速度值范围应在 0 到 (周期值per-1) 之间 * note 速度值越大占空比越高电机转速越快。 * 此函数通过设置一个通道为高占空比speed另一个为0来实现方向控制。 */ void AO_Control(uint8_t dir, uint32_t speed) { if(dir 1) // 正转 { // IN1 (PB14/TIM12_CH1) 输出低电平 (占空比0) TIM_SetCompare1(BSP_IN1_TIMER, 0); // IN2 (PB15/TIM12_CH2) 输出PWM占空比由speed决定 TIM_SetCompare2(BSP_IN1_TIMER, speed); } else // 反转 { // IN1 输出PWM TIM_SetCompare1(BSP_IN1_TIMER, speed); // IN2 输出低电平 TIM_SetCompare2(BSP_IN1_TIMER, 0); } }这个函数的逻辑完美对应了前面讲的真值表。通过给一个引脚PWM信号另一个引脚低电平就构成了“1和0”或“0和1”的组合从而控制电流方向。speed参数直接写入比较寄存器CCRx它和自动重装载值per的比值就是占空比。5. 上机验证让电机转起来最后我们在主函数里调用这些驱动写个简单的测试程序。#include board.h #include bsp_uart.h #include stdio.h #include bsp_L298N.h int main(void) { uint8_t direction 0; // 方向标志0反转1正转 uint32_t motor_speed 0; // 速度值 board_init(); // 天空星开发板系统初始化 uart1_init(115200U); // 初始化串口用于打印信息可选 printf(L298N Motor PWM Control Demo Start!\r\n); // 初始化PWM预分频84周期1000得到约1kHz的PWM频率 L298N_Init(84, 1000); while(1) { // 速度逐渐增加 motor_speed 10; if(motor_speed 1000) // 速度达到最大值后归零并切换方向 { motor_speed 0; direction !direction; // 方向取反 } // 调用控制函数 AO_Control(direction, motor_speed); delay_ms(100); // 延时100ms让速度变化可见 } }下载并观察现象将代码编译下载到天空星开发板。如果一切顺利你应该能看到电机先朝一个方向从静止逐渐加速到最高速然后减速到零接着朝反方向重复这个过程。这就证明了我们的PWM调速和方向控制都成功了调试如果电机不转按这个顺序排查查电源万用表量一下L298N的VCC和GND之间电压对吗电机电源接了吗5V逻辑电源有吗查共地单片机GND和模块GND用导线连上了吗这是最容易被忽略的一步查信号用示波器或者LED加限流电阻测一下PB14和PB15引脚看看有没有PWM波形输出波形频率对吗查接线ENA跳线帽接了吗电机线接在OUT1和OUT2上了吗查代码定时器和GPIO的时钟使能了吗引脚复用配置对了吗AO_Control函数里的方向逻辑和你预期一致吗把这个流程走通你对电机驱动和STM32的PWM应用就算入门了。以后做小车、机械臂之类的项目需要控制电机的地方这套方法可以直接搬过去用。