Điều khiển động cơ không chổi than vẫn luôn là một đề tài nhận được nhiều sự quan tâm từ các kỹ sư và những nhà khoa học từ khi động cơ không chổi than được phát minh vào những năm 1960 cho đến ngày nay. Nhờ những ưu điểm vượt trôi so với động cơ sử dụng chổi than và dải công suất rộng mà động cơ không chổi than là một trong nhữa lựa chọn ưu tiên trong nhiều lĩnh vực công nghiệp đòi hỏi hiệu năng làm việc, độ chính xác và tính an toàn cao. Vì thế việc phát triển các chương trình điều khiển, các thuật toán phục vụ cho việc vận hành cùng với sự đơn giản hóa quá trình điều khiển của động cơ cũng được đầu tư trong nhiều năm nay.
Phương pháp điều khiển 6 bước với sự hỗ trợ của cảm biến Hall là phương pháp đơn giản nhất được sử dụng để điều khiển các động cơ không chổi than công suất nhỏ. Việc phát triển chương trình để có thể điều khiển động cơ mà không cần cảm biến sẽ giúp đơn giản hóa quá trình chế tạo động cơ và mạch điều khiển. Đối với các hệ thống sử dụng động cơ công suất lớn hay đặt năng vấn đề về năng lượng tiêu thụ, chương trình điều khiển sử dụng phương pháp FOC sẽ đem đến hiệu quả tối đa, đồng thời kết hợp với các kỹ thuật khác như thuật toán điều khiển FOC không cảm biến hay phát hiện vị trí ban đầu của động cơ sẽ giúp đơn giản hóa quá trình điều khiển và tăng sự ổn định khi động cơ đang vận hành.
Để điều khiển và theo dõi động cơ khi hoạt động, phát triển một ứng dụng trên máy tính để kết nối với vi điều khiển cũng là một hướng đi cần thiết. Ứng dụng được sử dụng trong đồ án là một ứng dụng mã nguồn mở được sử dụng để đọc dữ liệu từ cổng COM của máy tính qua giao thức UART, mặc dù có thể hoạt động ổn định và có nhiều tính năng hỗ trợ cho việc lưu trữ dữ liệu nhưng ứng dụng này không được thiết kế để điều khiển động cơ không chổi than. Các chế độ hoạt động, thông số làm việc của các ngoại vi và dữ liệu được lựa chọn để xuất lên đồ thị vẫn cần có sự tác động bởi mã nguồn chương trình. Việc phát triển một ứng dụng máy tính bao gồm tất cả những tính năng trên sẽ hỗ
trợ cho quá trình nghiên cứu và phát triển mạch điều khiển cũng như chương trình điều khiển động cơ không chổi than trở nên thuận tiện và dễ dàng hơn.
TÀI LIỆU THAM KHẢO
Các trang web sau:
https://www.youtube.com/watch?v=44W8SLDjd8s https://www.youtube.com/watch?v=m6TW1WZn9CA https://www.youtube.com/watch?v=E5VS4s-R7vk&t=191s https://www.carparts.com/water-pump/gmb/gmb1152300 https://www.nidec.com/en/technology/capability/brushless/ https://www.gmb.jp/en/product/cooling/e_water_pump.html https://www.vovyopump.com/automotive-electric-water-pump/ https://www.parvalux.com/news/when-was-the-electric-motor-invented/ https://www.idolz.com/en/2021/04/06/types-of-automotive-water-pumps/ https://www.ti.com/motor-drivers/brushless-dc-bldc-drivers/applications.html http://www.volcanomotor.com/products/list-1-2-hp-brushless-dc-motor-en.html https://kienthuctudonghoa.com/dong-co-bldc/#4_Dac_tinh_co_va_dac_tinh_lam_viec http://automation.net.vn/Dien-dan/Cong-nghe-tu-dong-hoa-trong-thoi-dai-moi-ket.html https://toshiba.semicon-storage.com/ap-en/semiconductor/product/automotive- devices.html http://terlabclub.webmienphi.vn/xemchude/4/gioi-thieu-ve-vi-dieu-khien-arm-cortex-m3- stm32.html https://topsflo.en.made-in-china.com/product/UyMQnlJusPVK/China-Topsflo-Mini- 24V-BLDC-Automotive-Engine-Cooling-Water-Pumps.html http://automation.net.vn/Cong-nghe-Ung-dung/Tong-quan-nhung-nghien-cuu-va-xu- huong-phat-trien-cua-Dien-tu-cong-suat-truyen-dong-dien.html
https://www.infoplease.com/encyclopedia/science/tech/terms/automobile/development- of-the-automobile#:~:text=The%20development%20of%20the%20automobile,1885. https://www.ti.com/motor-drivers/brushless-dc-bldc- drivers/products.html?pqs=paqs&familyid=2009#p1131=Trapezoidal%20Control&p219 2=Hall%20Element%20Comparators https://www.bldcmotor.org/bldc-motor-for-automotive- industry.html#:~:text=At%20present%2C%20BLDC%20motors%20are,exhauster%20of %20the%20automatic%20industry.&text=DC%20brushless%20motor%20is%20often,bl ade%20to%20discharge%20polluted%20air.
Và các tài liệu sau:
Electric Motor Control AC, DC and BLDC Motors – Sang Hoon Kim
Xây dựng hệ truyền động điện động cơ một chiều sử dụng bộ điều khiển PID - Lưu Đức Trưởng
Tìm hiểu động cơ một chiều không chổi than (BLDC) - Lê Quang Tuyến, Trường Đại học Dân lập Hải Phòng
Electrical Motors for Electric Vehicle – A Comparative Study - Pooja Naresh Bhatta, Hemant Meharb, Manish Sahajwani
RM0091 Reference manual: STM32F0x1/STM32F0x2/STM32F0x8 advance ARM- based 32-bit MCUs by STMicroelectronics
Application Note: Motor Control by uPD78F0714 by Renesas STM32 developement boards portfolio by STMicroelectronics
PHỤ LỤC 1
MÃ NGUỒN CHƯƠNG TRÌNH
Phần này chỉ bao gồm các tập tin mã nguồn được chỉnh sửa bởi người dùng, phần mã nguồn do phần mềm tạo ra và không bị chỉnh sửa sẽ không được đề cập đến trong phần này.
Tập tin main.c
/* USER CODE BEGIN Header */ /**
******************************************************************************
* @file : main.c
* @brief : Main program body
****************************************************************************** * @attention
*
* <h2><center>© Copyright (c) 2021 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"
/* Private includes ---*/ /* USER CODE BEGIN Includes */
#include "stdio.h"
#include "string.h"
#include "math.h"
#include "limit.h"
/* USER CODE END Includes */
/* Private typedef ---*/ /* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ---*/ /* USER CODE BEGIN PD */
#define SampleTime 0.00005 // Sample time = 5ms
#define inv_SampleTime 1/SampleTime // invert Sample time = 1/SampleTime
#define outputMax 95
#define outputMin -95
#define pulsePerRev 65 /* USER CODE END PD */
/* Private macro ---*/ /* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---*/
ADC_HandleTypeDef hadc;
DMA_HandleTypeDef hdma_adc;
TIM_HandleTypeDef htim3; TIM_HandleTypeDef htim6; TIM_HandleTypeDef htim14; TIM_HandleTypeDef htim16; TIM_HandleTypeDef htim17; UART_HandleTypeDef huart2;
/* USER CODE BEGIN PV */
uint8_t hallState;
signed int dir = 0;
long sensorPulse = 0; uint32_t ADC_value[4]; uint32_t Pot_value; int NTC_Temp; int Vin_Sense; int Curr_Sense;
/*PID controller variables*/
volatile double rSpeed, des_Speed, Error, pre_Error;
volatile double Kp = 0.5, Ki = 0.02, Kd = 0;
volatile double pPart = 0, iPart = 0, dPart = 0, output;
/* USER CODE END PV */
/* Private function prototypes ---*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_DMA_Init(void);
static void MX_ADC_Init(void);
static void MX_TIM3_Init(void);
static void MX_TIM6_Init(void);
static void MX_TIM14_Init(void);
static void MX_TIM16_Init(void);
static void MX_TIM17_Init(void);
static void MX_IWDG_Init(void); /* USER CODE BEGIN PFP */
static void Peripheral_Initiate ();
static uint8_t Set_PWM_Value(double duty);
static double getSpeed();
static void Read_ADC_Value();
static void BLDCStart();
static void BLDCStop();
static void BLDCBackwardCommutate(double dutySet);
static void BLDCForwardCommutate(double dutySet);
static void dirCheck(uint16_t GPIO);
static void hallCheck();
static void Speed_PID(double set_speed);
/* USER CODE END PFP */
/* Private user code ---*/ /* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point. * @retval int
*/
/* USER CODE BEGIN 1 */
int uart_buf_lens = 0;
char uart_buf[2000]; /* 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 */ /* USER CODE BEGIN 2 */
Peripheral_Initiate();
while (ADC_value[0] != 0);
hallCheck();
sensorPulse = INTMAX; /* USER CODE END 2 */
/* USER CODE BEGIN WHILE */ while (1) { HAL_IWDG_Refresh(&hiwdg); des_Speed = (Pot_value*1800/4096)+200; BLDCStart();
uart_buf_lens = sprintf(uart_buf, "%d, %d, %d, %d, %d ¥n", (int)(des_Speed*100),
(int)(getSpeed()*100), (int)(NTC_Temp*100), (int)(Vin_Sense*100), (int)(Curr_Sense*100));
HAL_UART_Transmit(&huart1, (uint8_t*) uart_buf, uart_buf_lens, 100); /* USER CODE END WHILE */
/* USER CODE BEGIN 3 */ }
/* USER CODE END 3 */ }
/**
* @brief System Clock Configuration * @retval None
*/
void SystemClock_Config(void) {
/** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType =
RCC_OSCILLATORTYPE_HSI14|RCC_OSCILLATORTYPE_HSI48 |RCC_OSCILLATORTYPE_LSI; RCC_OscInitStruct.HSI48State = RCC_HSI48_ON;
RCC_OscInitStruct.HSI14State = RCC_HSI14_ON; RCC_OscInitStruct.HSI14CalibrationValue = 16; RCC_OscInitStruct.LSIState = RCC_LSI_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
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_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI48; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK) {
Error_Handler(); }
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART2; PeriphClkInit.Usart2ClockSelection = RCC_USART2CLKSOURCE_PCLK1;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) {
} }
/**
* @brief ADC Initialization Function * @param None
* @retval None */
static void MX_ADC_Init(void) {
/* USER CODE BEGIN ADC_Init 0 */
/* USER CODE END ADC_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC_Init 1 */
/* USER CODE END ADC_Init 1 */
/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc.Instance = ADC1;
hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1; hadc.Init.Resolution = ADC_RESOLUTION_12B; hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD; hadc.Init.EOCSelection = ADC_EOC_SEQ_CONV;
hadc.Init.LowPowerAutoWait = DISABLE; hadc.Init.LowPowerAutoPowerOff = DISABLE; hadc.Init.ContinuousConvMode = ENABLE;
hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE; hadc.Init.DMAContinuousRequests = ENABLE;
hadc.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
if (HAL_ADC_Init(&hadc) != HAL_OK) {
Error_Handler(); }
/** Configure for the selected ADC regular channel to be converted. */
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) {
Error_Handler(); }
/** Configure for the selected ADC regular channel to be converted. */
sConfig.Channel = ADC_CHANNEL_8;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) {
Error_Handler(); }
/** Configure for the selected ADC regular channel to be converted. */
sConfig.Channel = ADC_CHANNEL_10;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) {
Error_Handler(); }
*/
sConfig.Channel = ADC_CHANNEL_11;
if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK) {
Error_Handler(); }
/* USER CODE BEGIN ADC_Init 2 */
/* USER CODE END ADC_Init 2 */
}
/**
* @brief IWDG Initialization Function * @param None
* @retval None */
static void MX_IWDG_Init(void) {
/* USER CODE BEGIN IWDG_Init 0 */
/* USER CODE END IWDG_Init 0 */
/* USER CODE BEGIN IWDG_Init 1 */
/* USER CODE END IWDG_Init 1 */ hiwdg.Instance = IWDG;
hiwdg.Init.Prescaler = IWDG_PRESCALER_32; hiwdg.Init.Window = 2500;
{
Error_Handler(); }
/* USER CODE BEGIN IWDG_Init 2 */
/* USER CODE END IWDG_Init 2 */
}
/**
* @brief TIM2 Initialization Function * @param None
* @retval None */
static void MX_TIM2_Init(void) {
/* USER CODE BEGIN TIM2_Init 0 */
/* USER CODE END TIM2_Init 0 */
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
/* USER CODE BEGIN TIM2_Init 1 */
/* USER CODE END TIM2_Init 1 */ htim2.Instance = TIM2;
htim2.Init.Prescaler = 0;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 2400-1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_PWM_Init(&htim2) != HAL_OK) {
Error_Handler(); }
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) {
Error_Handler(); }
sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_2) != HAL_OK) {
Error_Handler(); }
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_3) != HAL_OK) {
Error_Handler(); }
/* USER CODE BEGIN TIM2_Init 2 */
/* USER CODE END TIM2_Init 2 */ HAL_TIM_MspPostInit(&htim2);
}
* @param None * @retval None */
static void MX_TIM3_Init(void) {
/* USER CODE BEGIN TIM3_Init 0 */
/* USER CODE END TIM3_Init 0 */
TIM_MasterConfigTypeDef sMasterConfig = {0};
TIM_OC_InitTypeDef sConfigOC = {0};
/* USER CODE BEGIN TIM3_Init 1 */
/* USER CODE END TIM3_Init 1 */ htim3.Instance = TIM3;
htim3.Init.Prescaler = 0;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP; htim3.Init.Period = 2400-1;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_PWM_Init(&htim3) != HAL_OK) {
Error_Handler(); }
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK) {
Error_Handler(); }
sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) {
Error_Handler(); }
if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK) {
Error_Handler(); }
/* USER CODE BEGIN TIM3_Init 2 */
/* USER CODE END TIM3_Init 2 */ HAL_TIM_MspPostInit(&htim3);
}
/**
* @brief TIM6 Initialization Function * @param None
* @retval None */
static void MX_TIM6_Init(void) {
/* USER CODE BEGIN TIM6_Init 0 */
/* USER CODE BEGIN TIM6_Init 1 */
/* USER CODE END TIM6_Init 1 */ htim6.Instance = TIM6;
htim6.Init.Prescaler = 300-1;
htim6.Init.CounterMode = TIM_COUNTERMODE_UP; htim6.Init.Period = 65535;
htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim6) != HAL_OK) {
Error_Handler(); }
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK) {
Error_Handler(); }
/* USER CODE BEGIN TIM6_Init 2 */
/* USER CODE END TIM6_Init 2 */
}
/**
* @brief TIM14 Initialization Function * @param None
* @retval None */
static void MX_TIM14_Init(void) {
/* USER CODE BEGIN TIM14_Init 0 */
/* USER CODE END TIM14_Init 0 */
TIM_OC_InitTypeDef sConfigOC = {0};
/* USER CODE BEGIN TIM14_Init 1 */
/* USER CODE END TIM14_Init 1 */ htim14.Instance = TIM14;
htim14.Init.Prescaler = 0;
htim14.Init.CounterMode = TIM_COUNTERMODE_UP; htim14.Init.Period = 65535;
htim14.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim14.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim14) != HAL_OK) { Error_Handler(); } if (HAL_TIM_PWM_Init(&htim14) != HAL_OK) { Error_Handler(); }
sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim14, &sConfigOC, TIM_CHANNEL_1) != HAL_OK) {
/* USER CODE BEGIN TIM14_Init 2 */
/* USER CODE END TIM14_Init 2 */ HAL_TIM_MspPostInit(&htim14);
}
/**
* @brief TIM16 Initialization Function * @param None
* @retval None */
static void MX_TIM16_Init(void) {
/* USER CODE BEGIN TIM16_Init 0 */
/* USER CODE END TIM16_Init 0 */
TIM_OC_InitTypeDef sConfigOC = {0};
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};
/* USER CODE BEGIN TIM16_Init 1 */
/* USER CODE END TIM16_Init 1 */ htim16.Instance = TIM16;
htim16.Init.Prescaler = 0;
htim16.Init.CounterMode = TIM_COUNTERMODE_UP; htim16.Init.Period = 2400-1;
htim16.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim16.Init.RepetitionCounter = 0;
if (HAL_TIM_Base_Init(&htim16) != HAL_OK) { Error_Handler(); } if (HAL_TIM_PWM_Init(&htim16) != HAL_OK) { Error_Handler(); }
sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCNPolarity = TIM_OCNPOLARITY_LOW;