STM32输出PWM驱动直流电机

本文介绍了如何使用STM32F103C8T6主控芯片配合L298N模块控制直流有刷电机,涉及L298N接口、电机控制逻辑、直流电机工作原理、左手定则应用及PWM实现。还提供了电机初始化、方向控制和实验代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        本文是主控芯片采用STM32F103C8T6,电机驱动用L298N,驱动直流有刷电机的学习笔记。

L298N模块介绍

        L298N是比较常用的电机驱动模块,可以同时驱动两个电机,控制正反转和调速,其接口说明如下:

①、输出A和输出B的两个引脚直接连两个电机的GND和VCC即可。

②、板载5V使能需要接高电平,驱动板才能工作,可以将其接到按键以控制电机的启停。

③、供电部分:GND接单片机的GND,可以选择12V或5V供电。

④、通道使能部分:两个通道使能引脚分别控制两个电机,一般接单片机的PWM输出,ENA控制输出A,ENB控制输出B,如果只是想让电机转起来,不用PWM的话,通道使能引脚直接接高电平即可。

⑤、逻辑输入部分:这部分一共有四个引脚,IN1、IN2、IN3、IN4,这四个引脚用于控制电机正反转和制动,IN1和IN2控制输出A,IN3和IN4控制输出B,直接接到单片机的四个IO口即可,控制IO口输出高低电平即可控制电机正反转,具体逻辑如下:

ENA/ENBIN1/IN3IN2/IN4电机状态
低电平任意电平任意电平停止
PWM或高电平高电平低电平正转
PWM或高电平低电平低电平制动
PWM或高电平低电平高电平反转
PWM或高电平高电平高电平制动

直流有刷电机

        直流有刷电机(BDC)是内含电刷装置的将直流电能转换成机械能的电动机,直流有刷电机由定子、转子、电刷和换向器这四个结构组成。拆解后的直流有刷电机如图所示:

下面我们来分析一下图中各个结构的作用:

① 定子:用于产生固定的磁场,通常由永磁体或电磁绕组制成。

② 转子:由一个或多个铜线绕组构成,通电后可以在磁场中受力运动。

③ 电刷:将外部电流输入到转子绕组上。

④ 换向器:改变转子绕组中电流的流向,是电机可以持续转动的关键结构。

        在对电机输出扭矩(即输出的力)有高要求的场景,我们会给直流有刷电机加上减速齿轮组,以增大输出扭矩,这一类电机就是直流有刷减速电机。其原理为:在电机输出功率一定的条件下,转速和扭矩成反比例关系,我们通过减速齿轮组降低电机的转速,即可提高电机的输出扭矩。

左手定则

        直流有刷电机原理的本质是:通电导线在磁场中受力运动。左手定则是判断通电导线处于磁场中时,所受安培力 F (或运动)的方向、磁感应强度 B的方向以及通电导体棒的电流 I 三者方向之间的关系的定律。左手定则的具体内容:将左手四指并拢伸直,使拇指与其他四指在平面内垂直,手掌方向代表磁场的方向(从 N 级到 S 级),四指代表电流的方向(从正极到负极),那拇指所指的方向就是受力的方向。我们可以借助示意图对左手定则进行理解,示意图如下:

 直流有刷电机基本工作原理

        为了方便分析,我们先把直流有刷电机的结构简化, A 和 B 代表的是两块电刷,C 和 D 代表两片换向器,E 代表简化后的单匝转子线圈,S 和 N 为两块定子磁极,磁场方向从 N 极到 S 极。 简化后的结构如图:

         直流有刷电机的工作原理可分为以下几步:第一步,电流从电池正极流出,进入电刷 A,经过换向器 C,输入到转子线圈 E 的左侧导线,此时已经知道电流的方向(从 a1 到 a2)和磁场的方向(N 极到 S 极),根据左手定则,可以判断出线圈 E 左侧导线的受力 F1 是垂直于导线向上的。第二步,电流从转子线圈 E 的左侧流向右侧(从 b2 到 b1),经过换向器 D 和电刷 B,流回电池负极,同理,我们根据左手定则,就可以判断出线圈 E 右侧导线的受力 F2 是垂直于导线向下的。结合转子线圈 E 左右两侧导线的受力情况,可得知线圈会沿顺时针方向转动,如下图所示:

         第三步,当转子线圈 E 沿顺时针方向转过一定角度(在简化模型上就是 90°,实际应用中并不一定),换向器 C 和 D 的位置会改变,此时电刷和换向器的接触关系就改变了,电流的方向发生了变化,此时电流从电刷 A 流入换向器 D,经过转子线圈E,再流出到换向器 C 和电刷 B。这个时候,虽然转子线圈 E 中电流的方向发生了改变,但是从转子线圈 E 的整体受力来看,左右两侧导线受力的方向并没有改变,所以转子线圈 E 会继续沿顺时针方向旋转下去,如下图所示:

        注意:单匝转子线圈运动到磁场的不同位置时,其受力是不均匀的,因此,在实际的应用中,转子通常都会有三匝或以上的线圈,它的受力情况会复杂很多,但是基本的原理是相通的。 

实验代码

pwm原理

         图中,我们假定定时器工作在向上计数PWM 模式,当 CNT 值小于 CCRx 的时候,IO 输出低电平(0),当 CNT 值大于等于 CCRx 的时候,IO 输出高电平(1),当 CNT 达到 ARR 值的时候,重新归零,然后重新向上计数,依次循环。改变 CCRx 的值,就可以改变 PWM 输出的占空比,改变 ARR 的值,就可以改变 PWM输出的频率,这就是 PWM 输出的原理。

PWM模式1和PWM模式2

        PWM模式1:CNT 值小于 CCRx 的时候为有效电平,否则为无效电平。

        PWM模式2:CNT 值大于 CCRx 的时候为有效电平,否则为无效电平。

PWM配置流程

①、使能定时器和相关IO口时钟

②、初始化PWM输出通道对应的IO口为复用推挽输出

③、初始化定时器

④、初始化PWM输出比较参数

⑤、使能预装载,使能定时器

电机配置代码如下:

#include "motor_ctl.h"

//PWM输出初始化,采用定时器3的通道4,在PB1
//arr:自动重装值
//psc:时钟预分频数
void TIM3_PWM_Init(u16 arr,u16 psc)
{  
	GPIO_InitTypeDef GPIO_InitStructure; //定义一个引脚初始化的结构体
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStrue; //定义一个定时中断的结构体	
	TIM_OCInitTypeDef TIM_OCInitTypeStrue; //定义一个PWM输出的结构体
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能GPIOB时钟,GPIOB挂载在APB2时钟下,在STM32中使用IO口前都要使能对应时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能通用定时器3时钟
	
	//PWM输出引脚
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;//引脚PB1
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出模式,定时器功能为PB1引脚复用功能
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //定义该引脚输出速度为50MHZ
	GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化引脚PB1
	//定时器结构体初始化
	TIM_TimeBaseInitStrue.TIM_Period=arr; //计数模式为向上计数时,定时器从0开始计数,计数超过到arr时触发定时中断服务函数
	TIM_TimeBaseInitStrue.TIM_Prescaler=psc; //预分频系数,决定每一个计数的时长
	TIM_TimeBaseInitStrue.TIM_CounterMode=TIM_CounterMode_Up; //计数模式:向上计数
	TIM_TimeBaseInitStrue.TIM_ClockDivision=TIM_CKD_DIV1; //一般不使用,默认TIM_CKD_DIV1
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStrue); //根据TIM_TimeBaseInitStrue的参数初始化定时器TIM3
	
	TIM_OCInitTypeStrue.TIM_OCMode=TIM_OCMode_PWM1; //PWM模式1,当定时器计数小于TIM_Pulse时,定时器对应IO输出有效电平
	TIM_OCInitTypeStrue.TIM_OCPolarity=TIM_OCNPolarity_High; //输出有效电平为高电平
	TIM_OCInitTypeStrue.TIM_OutputState=TIM_OutputState_Enable; //使能PWM输出
	TIM_OCInitTypeStrue.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值
	TIM_OC4Init(TIM3, &TIM_OCInitTypeStrue); //根TIM_OCInitTypeStrue参数初始化定时器3通道4

	TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Disable); //CH4预装载 失能后改变TIM_Pulse(即PWM)的值立刻生效,使能则下个周期生效
	
	TIM_ARRPreloadConfig(TIM3, ENABLE); //TIM3预装载使能,使能后改变arr立即生效,不使能则下个周期生效
	
	TIM_Cmd(TIM3, ENABLE); //使能定时器TIM3
}
//设置L298N的IN1,IN2引脚为PB12和PB13,控制电机转向
void Dir_GPIO_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure; //定义一个引脚初始化的结构体
	
	
	//L298N控制方向引脚
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_12|GPIO_Pin_13; 
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; //引脚输入输出模式为推挽输出模式
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //引脚输出速度为50MHZ
	GPIO_Init(GPIOB, &GPIO_InitStructure); //根据上面设置好的GPIO_InitStructure参数,初始化引脚
	
	GPIO_ResetBits(GPIOB, GPIO_Pin_12|GPIO_Pin_13); //初始化设置引脚低电平

	
}
//电机初始化
void Motor_Init(void)
{
	TIM3_PWM_Init(7199,0);//pwm初始化
	Dir_GPIO_Init();//方向控制引脚初始化
}
//电机方向控制,pwm为正就是正转,为负就是反转
void Dir_Ctl(int pwm)
{
	if(pwm>=0)//pwm>=0 (BIN2, BIN2)=(0, 1) 正转 顺时针
  {
		PBout(13)=0; //BIN2=0
		PBout(12)=1; //BIN1=1
		TIM_SetCompare4(TIM3, pwm);//设置PWM值
  }
  else if(pwm<0)//pwm<0 (BIN2, BIN1)=(1, 0) 反转 逆时针
  {
		PBout(13)=1; //BIN2=1
		PBout(12)=0; //BIN1=0
		TIM_SetCompare4(TIM3, -pwm);//设置PWM值
  }
}

        PB1为定时器3的通道4,用作PWM输出,接到L298N的通道A使能,PB12和PB13为普通IO口,控制电机正反转,接到L298N的IN1和IN2。

main.c测试函数如下:

#include "led.h"
#include "delay.h"
#include "sys.h"
#include "motor_ctl.h"
int PWM=0;          //PWM控制变量
int Step=500;   //速度渐变速率 相当于加速度
 int main(void)
 {		
	delay_init();	    	 //延时函数初始化	  
	Motor_Init();		  	//初始化电机
   	while(1)
	{
            //速度循环变化 
				if(PWM<=-7000)Step=500;      //减速到反转最大速度后加速
				else if(PWM>=7000)Step=-500; //加速到正转最大速度后减速
				PWM=PWM+Step; //速度渐变
				Dir_Ctl(PWM);  //设置PWM
	} 

}

关于MOE主输出使能

        上述定时器输出PWM配置针对的是通用定时器,如果要用高级定时器输出PWM还要使能刹车和死区寄存器(TIM1_BDTR)的 MOE 位,以使能整个 OCx(即 PWM)输出。

TIM_CtrlPWMOutputs(TIM1,ENABLE);    //MOE 主输出使能    

        如果不是高级定时器不能加这句话,会卡在这里。

### 使用 STM32 PWM 驱动直流电机 #### 理解 PWM 控制原理 PWM(脉冲宽度调制)技术通过改变占空比来调整输出电压的有效值,从而实现对电机速度的精确控制。对于直流电机而言,PWM信号能够有效地管理其运行状态。 #### 设置 STM32 的 TIM 模块生成 PWM 波形 为了利用 STM32 来产生用于驱动直流电机所需的 PWM 信号,需先初始化定时器(TIM)模块并设置相应的参数[^2]: - **选择合适的定时器**:通常可以选择通用型定时器如 TIM2, TIM3 或者高级定时器 TIM1。 - **设定预分频系数(PSC)** 和 自动重装载寄存器(ARR),这决定了载波频率。 - **配置通道模式**:决定是采用边沿对齐还是中心对齐方式。 - **指定极性和初始占空比**:定义 PWM 输出电平以及启动时的工作比例。 #### 编写代码实例 下面给出一段简单的 C 语言程序片段,展示如何在 STM32 上创建一个基本的 PWM 功能以驱动直流电机: ```c #include "stm32f1xx_hal.h" // 定义使用的 GPIO 口和定时器编号 #define MOTOR_PWM_CHANNEL TIM_CHANNEL_1 #define MOTOR_GPIO_PORT GPIOA #define MOTOR_PIN GPIO_PIN_0 #define TIMER_INSTANCE TIM2 void Motor_Init(void){ __HAL_RCC_TIM2_CLK_ENABLE(); // 开启定时器时钟 __HAL_RCC_GPIOA_CLK_ENABLE(); // 初始化GPIO口作为PWM输出端 GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = MOTOR_PIN; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(MOTOR_GPIO_PORT,&GPIO_InitStruct); // 创建TIM对象并进行基础配置 TIM_HandleTypeDef htim_pwm; htim_pwm.Instance = TIMER_INSTANCE; htim_pwm.Init.Prescaler = 79; /* 设定PSC */ htim_pwm.Init.CounterMode = TIM_COUNTERMODE_UP; htim_pwm.Init.Period = 999; /* ARR 值 */ htim_pwm.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim_pwm.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_PWM_Init(&htim_pwm)!= HAL_OK){ Error_Handler(); } // 配置PWM通道的具体属性 TIM_OC_InitTypeDef sConfigOC; sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 499; /* 初始占空比50% */ sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; if(HAL_TIM_PWM_ConfigChannel(&htim_pwm,&sConfigOC,MOTOR_PWM_CHANNEL)!= HAL_OK){ Error_Handler(); } } int main(){ HAL_Init(); SystemClock_Config(); Motor_Init(); while (true){ // 这里可以根据实际需求动态修改占空比 uint32_t duty_cycle = ... ; // 计算新的占空比 // 更新PWM通道的脉冲宽度 __HAL_TIM_SET_COMPARE(&htim_pwm,TIM_CHANNEL_1,duty_cycle); // 添加其他必要的处理逻辑... } } ``` 此段代码实现了最基本的 PWM 功能,在 `main` 函数循环体内可根据实际情况更新占空比数值,以此达到调节电机转速的效果。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值