FOC——无刷电机的简单驱动

本文介绍了无刷电机的工作原理,包括其结构与换向机制,并详细讲述了如何使用STM32CubeMX配置硬件,通过Keil或Clion编写代码来控制无刷电机转动。作者通过实验验证了PWM信号的生成和电机控制逻辑,展示了从理论到实际操作的过程。
摘要由CSDN通过智能技术生成


   写这个是为了记录学习过程,为了方便日后快速理解所以话比较通俗,当然也会有些许理解错误,欢迎各位大佬指正,小弟在此感激不尽

一、什么是无刷电机?

1、长什么样?

  无刷无刷,跟有刷电机的区别就是有无电刷(电刷的作用是导电换向),在有刷电机中电刷会随着使用时间的增加逐渐磨损,所以寿命受限。
  下图里面是一种无刷电机,无刷电机分两种:外转子、内转子。图中这种如果我没理解错,应该叫外转子无刷电机?应该是的(60%确定吧)。
无刷电机实物图

2、怎么工作?

  无刷电机与有刷电机不同,有刷电机是两根线(也就是一个直流电源)加合适的电压就可以转起来,而无刷电机是有三根线(A、B、C相)按照一定的规律才可以转起来
  下图可表示无刷电机的简易驱动动画(在同一时间内有两根线通的,我觉着理解为三个有刷电机的驱动,一次只用两根线,用完了再换线),如果你手速够快,手动调整通电顺序,电机也可以转起来,但是你应该做不到速度那么快,所以尝尝采用MOS管控制电路的切换
在这里插入图片描述
你需要知道怎么用右手螺旋定则判断磁场方向
  根据右手螺旋定则(手心握着那个定子,四指是电流方向,大拇指方向为产生的磁场方向),判断在不同通电时刻下通电相(A、B、C)产生的磁场方向。
右手螺旋定则
在这里插入图片描述


  无刷电机中,三相星形联结的二导通方式最为常用,这里用该模型做简单分析:
在这里插入图片描述
  当对A、B分别施加正负电压,根据上文提到的右手螺旋定则可推断出定子产生的磁极方向如下图的右边部分所示:
在这里插入图片描述
  想象一下,在上面这个图中右边产生的这个磁场中,在中心点处随便放一块磁体(有N、S极),这个磁体最终的姿态应该是什么样的? 对,就是跟右边这个一样。 因为要保证这个磁场内的磁感应线方向是统一的,所以要一样。 那么如果这个随便放的磁铁是无刷电机的转子,那么这个转子就会转到这个位置,电机也就转了起来(理论上转了一丢丢)


  接着,给A、C分别施加正负电压,分析产生的新磁场,看下图:
在这里插入图片描述
  同理可得,转子会转到上图右边那样的位置。


  继续,给B、C分别施加正负电压,分析产生的新磁场,看下图:
在这里插入图片描述
  同理可得,转子会转到上图右边那样的位置。

  依次推,可以得到6种通电状态下转子的位置角度,每个状态依次相差60度,6个过程完成了无刷电机的依次完整转动。
在这里插入图片描述

二、试着让它转起来

1、STM32CubeMX配置

  (1)新建工程:这一块老规矩,穷,所以用stm32F103C8T6这块板子了。
  (2)配置相关功能
SYS设置
在这里插入图片描述


RCC设置
在这里插入图片描述


时钟树设置
  关于时钟树这一块不清楚可看STM32基础知识(三)-- 系统时钟RCC详解这个文章。
在这里插入图片描述


定时器TIM1设置
  因为要生成PWM信号,所以用定时器方便一点。此处用的TIM1属于高级定时器,由APB2负责。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
  占空比在程序中进行设置,此处不设置占空比


工程输出设置
在这里插入图片描述
在这里插入图片描述
之后点击右上角的 GENERATE CODE 生成工程文件。

2、keil/Clion代码编写

  在生成的工程文件下 MDK-ARM 文件夹中点击后缀名为“.uvprojx”的文件打开工程。打开工程后先编译(保证工程代码正确)。如果出现下图情况
在这里插入图片描述
  按照下图更改设置即可(好像是因为高级版本多了个啥,还是用老版本好一点感觉)。
在这里插入图片描述
  编译通过,0 Error,0 Warning。
在这里插入图片描述
在main.c函数中增添代码,main.c代码如下:

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "tim.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/***********************************************************************************************/
//按照CubeMX中设置:APB2为72MHz,Prescaler预分频系数为36-1,Counter Period(AutoReload Register)为100-1
//可计算PWM(定时器)周期为72MHz/((36-1)+1)/((100-1)+1)=20KHz,也就是PWM(定时器)周期为0.00005s=50us

//设置PWM占空比为duty%    
#define duty 10			//高电平在一个PWM中占空比为10%,换算为时间是0.000005s=5us的高电平时间

//设置(上桥臂)PWM占空比为0
#define A0 __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,0)
#define B0 __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_2,0)
#define C0 __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_3,0)
//设置(下桥臂)PWM占空比为10
#define A1 __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_1,duty)
#define B1 __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_2,duty)
#define C1 __HAL_TIM_SET_COMPARE(&htim1,TIM_CHANNEL_3,duty)
/***********************************************************************************************/

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM1_Init();
  /* USER CODE BEGIN 2 */
	
/***********************************************************************************************/
//开启PWM输出,输出6路PWM信号
	HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
	HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_2);
	HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_3);
	
	HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_1);
	HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_2);
	HAL_TIMEx_PWMN_Start(&htim1,TIM_CHANNEL_3);
/***********************************************************************************************/

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		
/***********************************************************************************************/
		A1;B0;C0;			//打开A上、B下、C下		关闭A下、B上、C上
		HAL_Delay(10);
		A0;B1;C0;			//打开A下、B上、C下		关闭A上、B下、C上
		HAL_Delay(10);
		A0;B0;C1;			//打开A下、B下、C上		关闭A上、B上、C下
		HAL_Delay(10);
/***********************************************************************************************/
		
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

3、结果分析

  手上没有示波器,只有一个之前做的逻辑分析仪,接上stm32f103c8t6对应的6个引脚,对其进行逻辑分析,可以看出个大概。
  我这里用到的是PA8、PA9、PA10、PAB13、PB14、PB15:
在这里插入图片描述
在这里插入图片描述

  分析仪与stm32f103c8t6引脚对应关系如下:

D0——PA8
D1——PB13
D2——PA9
D3——PB14
D4——PA10
D5——PB15

按照

//按照CubeMX中设置:APB2为72MHz,Prescaler预分频系数为36-1,Counter Period(AutoReload Register)为100-1
//可计算PWM(定时器)周期为72MHz/((36-1)+1)/((100-1)+1)=20KHz,也就是PWM(定时器)周期为0.00005s=50us

//设置PWM占空比为duty%    
#define duty 10			//高电平在一个PWM中占空比为10%,换算为时间是0.000005s=5us的高电平时间

以及while中的

/***********************************************************************************************/
		A1;B0;C0;			//打开A上、B下、C下		关闭A下、B上、C上
		HAL_Delay(10);
		A0;B1;C0;			//打开A下、B上、C下		关闭A上、B下、C上
		HAL_Delay(10);
		A0;B0;C1;			//打开A下、B下、C上		关闭A上、B上、C下
		HAL_Delay(10);
/***********************************************************************************************/

中的设置,理论上一个PWM的周期为50us,PWM中高电平信号时间为50us*10%=5us。

  查看逻辑分析仪中的时间:
在这里插入图片描述
在这里插入图片描述
  对照着逻辑分析仪查看不同端口的输出电平状态:
初始时刻

/ABC
上桥臂1(PA8)0(PA9)0(PA10)
下桥臂0(PB13)1(PB14)1(PB15)

在这里插入图片描述

延迟10ms

/ABC
上桥臂0(PA8)1(PA9)0(PA10)
下桥臂1(PB13)0 (PB14)1(PB15)

在这里插入图片描述

延迟10ms

/ABC
上桥臂0(PA8)0(PA9)1(PA10)
下桥臂1(PB13)1(PB14)0(PB15)

在这里插入图片描述

参考的资料

1.有刷电机与无刷电机的区别,就是这么简单明了
2.一文看懂有刷电机与无刷电机的工作原理及区别
3.【自制FOC驱动器】深入浅出讲解FOC算法与SVPWM技术

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值