基于STM32無刷直流電機(jī)控制器的設(shè)計仿真與實現(xiàn)(原理圖+源碼+仿真工程+論文+PPT+參考英文文獻(xiàn))
資料
包含此題目畢業(yè)設(shè)計全套資料:
原理圖工程文件
原理圖截圖
仿真模型工程文件
仿真截圖
低重復(fù)率文檔(22642字)
英文文獻(xiàn)及翻譯
資料鏈接
任務(wù)書
1.基于單片機(jī)實現(xiàn)無刷直流電機(jī)控制器的設(shè)計,完成系統(tǒng)芯片選型;
2.確定無刷直流電機(jī)控制器的總體設(shè)計方案;
3.給出系統(tǒng)的硬件設(shè)計,包括主控模塊、位置檢測模塊、PWM驅(qū)動模塊、換向邏輯模塊、逆變模塊、速度反饋模塊等硬件模塊的電路設(shè)計;
4.給出系統(tǒng)的軟件設(shè)計,并繪制主要模塊的流程圖;
5.基于Proteus對系統(tǒng)進(jìn)行仿真。
綜上分析本設(shè)計目標(biāo)如下:
能夠驅(qū)動直流無刷電機(jī)的運轉(zhuǎn)并有電路保護(hù)以免器件燒壞。
能夠?qū)崟r準(zhǔn)確的檢測到直流無刷電機(jī)轉(zhuǎn)子的位置。
能夠?qū)崿F(xiàn)對電機(jī)啟動和停止的控制。
能夠通過滑動變阻器來實現(xiàn)直流無刷電機(jī)的無極調(diào)速。
電路具有電流、電壓保護(hù),以免對電路產(chǎn)生不良影響。
現(xiàn)在已經(jīng)確定直流無刷無感電機(jī)的控制系統(tǒng)需要實現(xiàn)的主要功能和技術(shù)有:
能夠準(zhǔn)確實時的檢測到無刷直流電機(jī)轉(zhuǎn)子的位置;
用三段式技術(shù)使電機(jī)能夠很好的啟動;
PID調(diào)節(jié)技術(shù);
速度環(huán)的控制;
電壓保護(hù)、電流保護(hù)。
設(shè)計說明書
摘要
本文的主要工作是基于STM32設(shè)計無刷直流電機(jī)控制系統(tǒng)。隨著科學(xué)的進(jìn)步,電子技術(shù)的成熟,現(xiàn)在已經(jīng)有了很大一部分電子產(chǎn)品開始實現(xiàn)智能化,并且已經(jīng)開始廣泛的應(yīng)用于當(dāng)前的生活中來,通過嵌入式設(shè)備來使系統(tǒng)達(dá)到更好的技術(shù)的控制。本文選擇使用STM32主控芯片控制無刷直流電機(jī),可以通過按鍵實現(xiàn)對無刷直流電機(jī)的速度控制,并可以將轉(zhuǎn)速顯示到液晶顯示器。
本文首先闡述了無刷直流電機(jī)的研究背景和意義,然后對無刷直流電機(jī)實現(xiàn)方案進(jìn)行了論證分析,并給出無刷直流電機(jī)的總體設(shè)計方案。接著詳細(xì)介紹了無刷直流電機(jī)的硬件設(shè)計,對主控模塊,電源模塊,顯示模塊的電路原理圖進(jìn)行了繪制,重點是無刷直流電機(jī)的驅(qū)動模塊和調(diào)速模塊的程序設(shè)計。最后基于Proteus對系統(tǒng)進(jìn)行仿真、調(diào)試。通過這種方式,不僅能精確驗證設(shè)計后的系統(tǒng)是否滿足技術(shù)要求,還在提高系統(tǒng)效率、質(zhì)量的設(shè)計基礎(chǔ)上降低了開發(fā)成本。
設(shè)計框架架構(gòu)
電機(jī)調(diào)速框架思路:
設(shè)計說明書及設(shè)計文件
文章來源:http://www.zghlxwxcb.cn/news/detail-467921.html
低重復(fù)率文檔(22642字)文章來源地址http://www.zghlxwxcb.cn/news/detail-467921.html
源碼展示
/* USER CODE BEGIN Header */
/** ******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2020 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 "adc.h"
#include "tim.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "includes.h"
#include "lcd.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define HALL_GPIO GPIOA
//START 任務(wù)
//設(shè)置任務(wù)優(yōu)先級
#define START_TASK_PRIO 10 //開始任務(wù)的優(yōu)先級設(shè)置為最低
//設(shè)置任務(wù)堆棧大小
#define START_STK_SIZE 64
//任務(wù)堆棧
OS_STK START_TASK_STK[START_STK_SIZE];
//任務(wù)函數(shù)
void start_task(void *pdata);
//LED0任務(wù)
//設(shè)置任務(wù)優(yōu)先級
#define LED0_TASK_PRIO 2
//設(shè)置任務(wù)堆棧大小
#define LED0_STK_SIZE 64
//任務(wù)堆棧
OS_STK LED0_TASK_STK[LED0_STK_SIZE];
//任務(wù)函數(shù)
void led0_task(void *pdata);
//Speed_ADC 任務(wù)
//設(shè)置任務(wù)優(yōu)先級
#define SPEED_ADC_TASK_PRIO 1
//設(shè)置任務(wù)堆棧大小
#define SPEED_ADC_STK_SIZE 64
//任務(wù)堆棧
OS_STK SPEED_ADC_TASK_STK[SPEED_ADC_STK_SIZE];
//任務(wù)函數(shù)
void speed_adc_task(void *pdata);
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);//設(shè)置中斷優(yōu)先級分組為組2:2位搶占優(yōu)先級,2位響應(yīng)優(yōu)先級
OSInit();
OSTaskCreate(start_task,(void *)0,(OS_STK *)&START_TASK_STK[START_STK_SIZE-1],START_TASK_PRIO );//創(chuàng)建起始任務(wù)
/* 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();
MX_ADC1_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
OSStart();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* 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};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Initializes the CPU, AHB and APB busses clocks
*/
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_MUL2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB busses 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_DIV2;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV2;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
//LED0任務(wù)
void speed_adc_task(void *pdata)
{
lcd_system_reset();
unsigned char temp_table[16] ={"Cur_Speed:"};
unsigned char temp_table1[16] ={"Tar_Speed:"};
for(uint8_t i=0;i<10;i++)
{
lcd_char_write(i,0,temp_table[i]);
lcd_char_write(i,1,temp_table1[i]);
}
HAL_ADC_Start(&hadc1);
while(1)
{
HAL_ADC_PollForConversion(&hadc1,0); //等待轉(zhuǎn)換完成,第二個參數(shù)代表最長等待時間ms
if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
{
ADC_Value = HAL_ADC_GetValue(&hadc1); // 讀取ADC數(shù)據(jù) ,4096 -> 3.3V
ADC_Speed = ADC_Value + 500; //轉(zhuǎn)換公式 0-4096 -> 500 - 4596
// if(ADC_Speed > 100){
// HAL_GPIO_TogglePin(led_GPIO_Port, led_Pin);
// }
}
//當(dāng)前速度
temp_table[10]=current_speed/1000+'0';
temp_table[11]=current_speed/100%10+'0';
temp_table[12]=current_speed/10%10+'0';
temp_table[13]=current_speed%10+'0';
//目標(biāo)速度
temp_table1[10]=ADC_Speed/1000+'0';
temp_table1[11]=ADC_Speed/100%10+'0';
temp_table1[12]=ADC_Speed/10%10+'0';
temp_table1[13]=ADC_Speed%10+'0';
for(uint8_t i=10;i<14;i++)
{
lcd_char_write(i,0,temp_table[i]);
lcd_char_write(i,1,temp_table1[i]);
}
}
}
//speed adc 采樣函數(shù)
void led0_task(void *pdata)
{
while(1)
{
HAL_GPIO_WritePin(led_GPIO_Port, led_Pin, GPIO_PIN_SET);
OSTimeDly(10);
HAL_GPIO_WritePin(led_GPIO_Port, led_Pin, GPIO_PIN_RESET);
OSTimeDly(10);
}
}
//外部中斷服務(wù)函數(shù)
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(!state)
{
__IO uint8_t uwStep = 0;
uint16_t hall_read=(HALL_GPIO->IDR)&0x0007; // 獲取霍爾傳感器狀態(tài) pin0 1 2
uwStep = hall_read;
BLDC_PHASE_CHANGE(uwStep); // 驅(qū)動換相
}
uint16_t key_read =(Start_GPIO_Port->IDR)&0x00e0;
if(key_read == 0x00c0)
{
// state = !state;
// HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1);
// HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_2);
// HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_3);//
// //BLDC_PHASE_CHANGE(7);
// HAL_TIM_Base_MspDeInit(&htim1);//
// HAL_Delay(300);
// HAL_TIM_Base_MspDeInit(&htim1);
// HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);
// HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);
// HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);
// BLDC_PHASE_CHANGE(7);
//HAL_GPIO_TogglePin(led_GPIO_Port, led_Pin);
}else if(key_read == 0x00a0)
{
clock_wise = 0;
}else if(key_read == 0x0060)
{
clock_wise = 1;
}
}
//定時器2中斷函數(shù)
//溢出時間為1s
//溢出值1000 每個點為1ms
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) //捕獲中斷
{
/*
測速邏輯
1、中斷產(chǎn)生,先判斷是否為第一次上升沿
2、捕獲到上升沿后,將時間點存入變量,切換捕獲下降沿
3、捕獲到下降沿后,記下時間點,切換為捕獲上升沿
4、捕獲到上升沿后,記下時間點
5、計算周期和占空比
6、問題如果經(jīng)過多個周期才有一次上升沿和下降沿怎么辦,需要記錄溢出次數(shù)
如果溢出的時候有上升沿標(biāo)志位
問題:proteus三路輸入捕獲計算,測轉(zhuǎn)速時,如果第一個上升沿和第二個上升沿不在一個定時器計數(shù)周期,會計算失敗
*/
if(Channel1Edge == 0)
{
//獲取通道1上升沿時間點
Channel1RisingTimeNow = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_1);
Channel1Edge = 1;//捕獲上升沿置位
Channel1RisingTimeLast = Channel1RisingTimeNow;
}else if(Channel1Edge == 1)
{
Channel1RisingTimeNow = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_1);
if(Channel1RisingTimeNow > Channel1RisingTimeLast)
{
Channel1Period = Channel1RisingTimeNow - Channel1RisingTimeLast;
}
else
{
//Channel2Period = Channel2RisingTimeNow + 1000 - Channel2RisingTimeLast + 1;
}
Channel1Edge = 0;
//pid計算
// current_speed = 60*1000 / Channel1Period; //轉(zhuǎn)速計算
// current_speed = current_speed * 5; //速度調(diào)整系數(shù)
// motor_duty = Speed_PIDAdjust(current_speed);
}
}else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{
if(Channel2Edge == 0)
{
Channel2RisingTimeNow = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_2);
Channel2Edge = 1;
Channel2RisingTimeLast = Channel2RisingTimeNow;
}
else if(Channel2Edge == 1)
{
Channel2RisingTimeNow = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_2);
if(Channel2RisingTimeNow > Channel2RisingTimeLast)
{
Channel2Period = Channel2RisingTimeNow - Channel2RisingTimeLast;
}
else
{
//Channel2Period = Channel2RisingTimeNow + 1000 - Channel2RisingTimeLast + 1;
}
current_speed = 60*1000 / Channel2Period;
current_speed = current_speed * 5; //速度調(diào)整系數(shù)
motor_duty = Speed_PIDAdjust(current_speed);
Channel2Edge = 0;
}
}
else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_3)
{
if(Channel3Edge == 0)
{
Channel3RisingTimeNow = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_3);
Channel3Edge = 1;
Channel3RisingTimeLast = Channel3RisingTimeNow;
}
else if(Channel3Edge == 1)
{
Channel3RisingTimeNow = HAL_TIM_ReadCapturedValue(&htim2, TIM_CHANNEL_3);
if(Channel3RisingTimeNow > Channel3RisingTimeLast)
{
Channel3Period = Channel3RisingTimeNow - Channel3RisingTimeLast;
}
else
{
//Channel3Period = Channel3RisingTimeNow + 1000 - Channel3RisingTimeLast + 1;
}
// current_speed = 60*1000 / Channel3Period;
// current_speed = current_speed * 5; //速度調(diào)整系數(shù)
// motor_duty = Speed_PIDAdjust(current_speed);
Channel3Edge = 0;
}
}
}
/* 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 */
/* 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,
tex: 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****/
#define ADC_Speed_Max 4596 //800 3500
#define ADC_Speed_Min 500
#define PWM_Max 800
#define PWM_Min 60
extern int ADC_Speed; //ADC采樣值轉(zhuǎn)換成轉(zhuǎn)速
extern int motor_period;
extern int motor_duty;
/*====================================================================================================
增量式PID
The PID (????????) function is used in mainly
control applications. PIDCalc performs one iteration of the PID
algorithm.
While the PID function works, main is just a dummy program showing
a typical usage.
=====================================================================================================*/
typedef struct PID
{
int Target; //目標(biāo)轉(zhuǎn)速 相差10%左右,所以顯示90%
int Uk; //Uk
int Udk; //Udk
int Uk_1; //Uk-1
double P; // Proportional Const
double I; // Integral Const
int b;
}PID;
static PID Speed_PID;
static PID *Speed_Point = &Speed_PID;
/*====================================================================================================
Initialize PID Structure PID
=====================================================================================================*/
void Speed_PIDInit(void)
{
Speed_Point->Target = ADC_Speed *10 / 9;
Speed_Point->Uk = 0;
Speed_Point->Udk = 0;
Speed_Point->Uk_1 = PWM_Min;
Speed_Point->ek_0 = 0; //ek=0
Speed_Point->ek_1 = 0; //ek-1=0
Speed_Point->ek_2 = 0; //ek-2=0
Speed_Point->P = 1; //Proportional Const
}
/*====================================================================================================
???PID????
=====================================================================================================*/
int Speed_PIDAdjust(int Next_Point)
{
Speed_Point->Target = ADC_Speed *10 / 9; //重新調(diào)整速度
Speed_Point->ek_0= Speed_Point->Target - Next_Point;
if(((Speed_Point->Uk_1>=PWM_Max)&&(Speed_Point->ek_0>=0))||((Speed_Point->Uk_1<=PWM_Min)&&(Speed_Point->ek_0<=0)))
{
Speed_Point->b=0;
}
else
{
Speed_Point->b=1;
}
//Speed_Point->Udk=Speed_Point->P*(Speed_Point->ek_0-Speed_Point->ek_1) + Speed_Point->b*Speed_Point->I*Speed_Point->ek_0
// + Speed_Point->D*(Speed_Point->ek_0-2*Speed_Point->ek_1+Speed_Point->ek_2);//PID
Speed_Point->Udk=Speed_Point->P*(Speed_Point->ek_0-Speed_Point->ek_1);//P
Speed_Point->Uk = Speed_Point->Uk_1 + Speed_Point->Udk;
Speed_Point->ek_2 = Speed_Point->ek_1;
Speed_Point->ek_1 = Speed_Point->ek_0;
Speed_Point->Uk_1 = Speed_Point->Uk;
if(Speed_Point->Uk >= PWM_Max)
{
return PWM_Max;
}
else if(Speed_Point->Uk <= PWM_Min)
{
return PWM_Min;
}
return(Speed_Point->Uk);
}
到了這里,關(guān)于9-基于STM32無刷直流電機(jī)控制器的設(shè)計仿真與實現(xiàn)(原理圖+源碼+仿真工程+論文+PPT+參考英文文獻(xiàn))的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!