STM32 TIM定时器的使用(5)——PWM驱动电调控制无刷电机

本文详细介绍了使用STM32F1精英板、30A无刷电调和A22121000KV电机,通过TIM4定时器实现的按键控制电机转速实验。通过中断服务函数调整PWM占空比,演示了从基本计时到电机刹车的完整过程。

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

2022年4月7日增加源码地址

https://github.com/masterdrone1999/Four_axis.git

1、系列目录

  1. 基本计时实验
  2. 输入捕获实验(实验3的基础)
  3. 电容按键检测实验
  4. 输出PWM实验
  5. PWM驱动无刷电机实验

2、程序设计分析

本次我们采用按键控制无刷电机的转速,实验本质是通过按键中断改变CCR的值,从而使PWM的占空比跟随按键改变,将PWM信号输入电调,最终实现对无刷电机的控制。

3、实验用具

  1. 正点原子STM32F1精英板
  2. 新西达30A无刷电调
  3. A2212 1000KV无刷电机

4、程序设计分析

程序设计可以分为三大块:

  1. 定时器、按键配置
  2. 电机控制程序
  3. 按键中断服务函数

1、定时器、按键的配置:
定时器选择TIM4,因为TIM4的四个通道引脚刚好都在板子上,并且不需要重定义端口,比较方便,四个通道分别为PB6、7、8、9。
原子的板子上总共有KEY0(PE4),KEY1(PE3),KEY_UP(PA0)三个按键。刚好可以配置为加速键(KEY1)、减速键(KEY0)、刹车键(PA0)。
2、电机控制程序:
根据按键,改变写入CCR寄存器的值,CCR/ARR的比值及为输出PWM的占空比。直接通过TIMx->CCR1 = x;写入CCR的值。这是寄存器变成的一种方法,可以直接给CCR寄存器赋值,很好用。
3、按键中断函数,这里可以设置两个变量ccr_val和add_val。ccr_val代表输出占空比5%的PWM的CCR的值。电调通过5%-10%的PWM信号控制电机0-100%的转速。所以占空比最高为10%的PWM。add_val是每次按键增加或者减少的CCR。最后写入寄存器的CCR=ccr_val+add_val。

电机控制流程

电路连接——开发板上电,电机上电——电调校对油门——按键——电机启动

如果不理解电调校对油门以及相关操作,点击这里

5、代码示例,很多思想一看程序就明白

1、TIM初始化

//MOT_GPIO PB6,7,8,9
#define MOT_GPIO					GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9
#define MOT_GPIO_APBxClock_FUN		RCC_APB2PeriphClockCmd
#define MOT_GPIO_CLK				RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO

#define MOT_TIM						TIM4
#define MOT_TIM_APBxClock_FUN 		RCC_APB1PeriphClockCmd
#define MOT_TIM_CLK 				RCC_APB1Periph_TIM4

/**  TIM4定时器基础配置
  *  功能:
  *  入口参数:arr;psc
  *  返回值:无
  */
void PWM_TIM_GPIO_Config(u16 arr,u16 psc)
{
	GPIO_InitTypeDef			GPIO_InitStructure;		
	TIM_TimeBaseInitTypeDef		TIM_TimeBaseStructure;
	
	MOT_GPIO_APBxClock_FUN(MOT_GPIO_CLK,ENABLE);
	MOT_TIM_APBxClock_FUN(MOT_TIM_CLK,ENABLE);
		
	//PB6,7,8,9 配置
	GPIO_InitStructure.GPIO_Pin = MOT_GPIO;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
	GPIO_Init(GPIOB,&GPIO_InitStructure);	

	//TIM5基础配置	
	//计时器时钟 = APB总线时钟/分频因子
	//							psc
	TIM_TimeBaseStructure.TIM_Period = arr;//重装载值/最大计数值
	TIM_TimeBaseStructure.TIM_Prescaler = psc;//预分频值 
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
	TIM_TimeBaseInit(MOT_TIM,&TIM_TimeBaseStructure);	
	
}

/**  PWM 配置
  *  功能:配置四路PWM控制电机,后期可扩展为电机解锁程序
  *  入口参数:无
  *  返回值:无
  */
void PWM_OC_Config(u16 ccr)
{
	TIM_OCInitTypeDef			TIM_OCInitStructure;
	
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	TIM_OCInitStructure.TIM_Pulse = ccr;
	
	//前左电机 CCR1 PB6     
	TIM_OC1Init(MOT_TIM, &TIM_OCInitStructure); 
	TIM_OC1PreloadConfig(MOT_TIM, TIM_OCPreload_Enable); //使能MOT_TIM在CCR1上的预装载寄存器
	//前右电机 CCR2 PB7 
	TIM_OC2Init(MOT_TIM, &TIM_OCInitStructure); 
	TIM_OC2PreloadConfig(MOT_TIM, TIM_OCPreload_Enable); //使能MOT_TIM在CCR2上的预装载寄存器
	//后左电机 CCR3 PB8
//	TIM_OC3Init(MOT_TIM, &TIM_OCInitStructure); 
//	TIM_OC3PreloadConfig(MOT_TIM, TIM_OCPreload_Enable); //使能MOT_TIM在CCR3上的预装载寄存器
	//后右电机 CCR4 PB9
	TIM_OC4Init(MOT_TIM, &TIM_OCInitStructure); 
	TIM_OC4PreloadConfig(MOT_TIM, TIM_OCPreload_Enable); //使能MOT_TIM在CCR4上的预装载寄存器

	TIM_ARRPreloadConfig(MOT_TIM, ENABLE); //使能MOT_TIM在ARR上的预装载寄存器
	TIM_Cmd(MOT_TIM, ENABLE);  //使能MOT_TIM外设
	
}

void PWM_Config(void)
{
	PWM_TIM_GPIO_Config(2000,720-1);
	PWM_OC_Config(200);	
}

2、电机驱动,实验初期先不需要考虑各个CCR的准确值,后期加入PID之后可以通过PID精确控制每个电机

/*****************************************************
* 						通过按键中断方式控制电机转速
(优先级 KEY0和KEY1属于不同操作,优先级KEY0>KEY1(减速>加速))
*满油门  CCR 200 10%
*零油门	 CCR 100 5%	
*	KEY0	(PE4) 减速		[0,20]次
*	KEY1	(PE3) 加速		[0,20]次
*	KEY_UP	(PA0) 刹车 		CCR=5%
*现阶段控油门转速仅有五个等级,后期按比例增加,按等比例分配为 100,105,110,115,120,125,130,135,140,145,150,155,160,165,170,175,180
*其中KEY_UP仅用作电调初始化,初始CCR=200(10%),KEY_UP为CCR=100(5%),可以做紧急刹车使用
*
*
2021年1月31日10:13:03
*
**************************************************************/

#include "bsp_motor.h"
#include "delay.h"
#include "usart.h"
#include "key.h"
#include "led.h"
#include "beep.h"

/**  电机控制程序
  *  功能:控制四个通道的CCR
  *  入口参数:ccr1,ccr2,ccr3,ccr4
  *  返回值:无
  *	 注:取值[0,0xFFFF]
  */
void MOT_Control(u16 ccr1,u16 ccr2,u16 ccr3,u16 ccr4)
{
	TIM4->CCR1 = ccr1;
	TIM4->CCR2 = ccr2;
	TIM4->CCR3 = ccr3;
	TIM4->CCR4 = ccr4;
}

3、按键中断服务函数,通过这个函数控制CCR的改变
(1)中断配置

/**  按键中断配置
  *  功能:配置三个按键的中断设置
  *  入口参数:无
  *  返回值:无
  */
static void EXTI_Config(void)
{
	EXTI_InitTypeDef EXTI_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
	
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);//加速键PE3
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4);//减速键PE4
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);//停止键PA0

	EXTI_InitStructure.EXTI_Line = EXTI_Line3 | EXTI_Line4 | EXTI_Line0;
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
	EXTI_Init(&EXTI_InitStructure);
	
}

static void NVIC_Config(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	
	//加速键PE3
	NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);  
	//减速键PE4
	NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);  
	//停止键PA0 
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);  
}

void KEY_EXTI_Config(void)
{
	EXTI_Config();
	NVIC_Config();
	EXTI_ClearFlag(EXTI_Line0);
	EXTI_ClearFlag(EXTI_Line3);
	EXTI_ClearFlag(EXTI_Line4);
}

(2)中断服务函数

u16 ccr_val = 100;//5%的CCR,起始状态
int add_val = 0;//每次按键CCR增加的值
int a =0;
//实际设置写入的CCR=ccr_val+add_val

/**  按键中断服务函数
  *  功能:根据不同的按键设置不同的CCR的值
  *  入口参数:无
  *  返回值:无
  */
//加速
void EXTI3_IRQHandler(void)
{
	delay_ms(10);
	if(EXTI_GetITStatus(EXTI_Line3) != RESET)
	{
		if(KEY1 == 1)
		{
			add_val += 5;
			LED1 = !LED1;
			if(add_val<81)//最高允许加速到80%
			{	
				MOT_Control(ccr_val+add_val,ccr_val+add_val,ccr_val+add_val,ccr_val+add_val);	
				printf("3CCR = %d\r\n",TIM_GetCapture1(TIM4));
			}
			else		
			{
				BEEP;
				add_val = 80;
			}				
		}
		EXTI_ClearITPendingBit(EXTI_Line3);
	}
}
//减速
void EXTI4_IRQHandler(void)
{
	delay_ms(10);
	if(EXTI_GetITStatus(EXTI_Line4) != RESET)
	if(KEY0 == 1)
	{
		add_val -=5;
		printf("%d\r\n",add_val);
		LED0 = !LED0;
		if(add_val > -1)
		{
			MOT_Control(ccr_val+add_val,ccr_val+add_val,ccr_val+add_val,ccr_val+add_val);
			printf("4CCR = %d\r\n",TIM_GetCapture1(TIM4));			
		}
		else
		{	
			BEEP;
			add_val = 0;
			printf("add_val已归零,add_val = %d\r\n",add_val);
		}
	}	
	EXTI_ClearITPendingBit(EXTI_Line4);
}
//停止
void EXTI0_IRQHandler(void)
{
	delay_ms(10);
	if(EXTI_GetITStatus(EXTI_Line0) != RESET)
	{	
		if(KEY1 == 1)
		{
			BEEP = !BEEP;
			MOT_Control(ccr_val,ccr_val,ccr_val,ccr_val);
			printf("0CCR = %d\r\n",TIM_GetCapture1(TIM4));
		}
		printf("刹车成功\r\n");
		EXTI_ClearITPendingBit(EXTI_Line0);
	}
}

6、实验现象

在这里插入图片描述
可以看到加速成功,绿色LED灯闪烁,电机速度加快。
在这里插入图片描述
串口输出CCR,ccr_val和add_val正常。

7、总结

PWM控制无刷电机的使用在显示中非常广泛,还可以控制步进电机、伺服电机。现在的高精度加工制造产业都脱离不了伺服电机,所以先学习好PWM控制无刷电机这种简单的控制,才能为以后打好基础。后期我将会把四旋翼无人机的设计上传,本节课的控制电机实验就是无人机所需要使用的电机控制程序。

在Keil uVision 5集成开发环境中,如果你想要通过STM32F103C8T6微控制器利用定时器2( TIM2)和PWM1通道来控制30A电调驱动无刷电机,你需要编写相应的硬件初始化、定时器配置以及Pulse Width Modulation (PWM) 控制部分的代码。 首先,确保已包含必要的头文件并初始化硬件资源: ```c #include "stm32f10x.h" #include "tim2_pwm1.h" // 自定义的TIM2 PWM1配置文件 void SystemClock_Config(void); void TIM2_PWM1_Init(void); // ... 其他必要的全局变量声明 ... int main(void) { // 系统时钟配置 SystemClock_Config(); // 初始化TIM2和PWM1 TIM2_PWM1_Init(); // 开启定时器2的计数器 TIM_TimeBaseInitTypeDef.TIM_Period = 1000; // 设置周期(毫秒) TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitTypeDef); TIM_Cmd(TIM2, ENABLE); // 启动定时器 while (1) { // 更新PWM1,设置占空比来控制电机速度 SetPWM1DutyCycle(50); // 示例中设置50% duty cycle // 检查是否需要调整电机速度或其他操作 // ... } } // 定义TIM2初始化函数 void TIM2_PWM1_Init() { TIM扞ChannelInitTypeDef sConfig; // 配置TIM2 Channel1作为PWM模式 sConfig.TIM_Pin = GPIO_Pin_15; // TIM2 Channel1对应的GPIO引脚 sConfig.TIM_OutputState = DISABLE; sConfig.TIM_PulseWidthMode = TIM_PulseWidthMode_T通断; // PWM模式 sConfig.TIM_Oversampling = TIM_Oversampling_2; // 可选的超采样率 HAL_TIM_PWM_Init(TIM2); // 初始化定时器PWM模式 HAL_TIM_PWM_ConfigChannel(TIM2, &sConfig); // 配置特定通道为PWM HAL_TIM_PWM_MspInit(TIM2); // 初级时钟和中断管理器配置 } ```
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一个旅者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值