【毕业设计】9-基于STM32无刷直流电机控制器的设计仿真与实现(原理图+源码+仿真工程+论文+PPT+参考英文文献)
创始人
2024-03-09 07:57:45

毕业设计】基于STM32无刷直流电机控制器的设计仿真与实现(原理图+源码+仿真工程+论文+PPT+参考英文文献)

文章目录

  • 毕业设计】基于STM32无刷直流电机控制器的设计仿真与实现(原理图+源码+仿真工程+论文+PPT+参考英文文献)
    • 任务书
    • 设计说明书
      • 摘要
      • 设计框架架构
      • 设计说明书及设计文件
      • 源码展示

任务书

1.基于单片机实现无刷直流电机控制器的设计,完成系统芯片选型;
2.确定无刷直流电机控制器的总体设计方案;
3.给出系统的硬件设计,包括主控模块、位置检测模块、PWM驱动模块、换向逻辑模块、逆变模块、速度反馈模块等硬件模块的电路设计;
4.给出系统的软件设计,并绘制主要模块的流程图;
5.基于Proteus对系统进行仿真。
资料链接
原理图工程文件
原理图截图
仿真模型工程文件
仿真截图
低重复率文档(22642字)
英文文献及翻译

综上分析本设计目标如下:

能够驱动直流无刷电机的运转并有电路保护以免器件烧坏。
能够实时准确的检测到直流无刷电机转子的位置。
能够实现对电机启动和停止的控制。
能够通过滑动变阻器来实现直流无刷电机的无极调速。
电路具有电流、电压保护,以免对电路产生不良影响。
现在已经确定直流无刷无感电机的控制系统需要实现的主要功能和技术有:

能够准确实时的检测到无刷直流电机转子的位置;
用三段式技术使电机能够很好的启动;
PID调节技术;
速度环的控制;
电压保护、电流保护。

设计说明书

摘要

本文的主要工作是基于STM32设计无刷直流电机控制系统。随着科学的进步,电子技术的成熟,现在已经有了很大一部分电子产品开始实现智能化,并且已经开始广泛的应用于当前的生活中来,通过嵌入式设备来使系统达到更好的技术的控制。本文选择使用STM32主控芯片控制无刷直流电机,可以通过按键实现对无刷直流电机的速度控制,并可以将转速显示到液晶显示器。
本文首先阐述了无刷直流电机的研究背景和意义,然后对无刷直流电机实现方案进行了论证分析,并给出无刷直流电机的总体设计方案。接着详细介绍了无刷直流电机的硬件设计,对主控模块,电源模块,显示模块的电路原理图进行了绘制,重点是无刷直流电机的驱动模块和调速模块的程序设计。最后基于Proteus对系统进行仿真、调试。通过这种方式,不仅能精确验证设计后的系统是否满足技术要求,还在提高系统效率、质量的设计基础上降低了开发成本。

设计框架架构

电机调速框架思路:
在这里插入图片描述

设计说明书及设计文件

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

低重复率文档(22642字)在这里插入图片描述

源码展示

/* USER CODE BEGIN Header */
/**  ******************************************************************************* @file           : main.c* @brief          : Main program body******************************************************************************* @attention** 

© Copyright (c) 2020 STMicroelectronics.* All rights reserved.

** 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 任务 //设置任务优先级 #define START_TASK_PRIO 10 //开始任务的优先级设置为最低 //设置任务堆栈大小 #define START_STK_SIZE 64 //任务堆栈 OS_STK START_TASK_STK[START_STK_SIZE]; //任务函数 void start_task(void *pdata); //LED0任务 //设置任务优先级 #define LED0_TASK_PRIO 2 //设置任务堆栈大小 #define LED0_STK_SIZE 64 //任务堆栈 OS_STK LED0_TASK_STK[LED0_STK_SIZE]; //任务函数 void led0_task(void *pdata); //Speed_ADC 任务 //设置任务优先级 #define SPEED_ADC_TASK_PRIO 1 //设置任务堆栈大小 #define SPEED_ADC_STK_SIZE 64 //任务堆栈 OS_STK SPEED_ADC_TASK_STK[SPEED_ADC_STK_SIZE]; //任务函数 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);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级OSInit();OSTaskCreate(start_task,(void *)0,(OS_STK *)&START_TASK_STK[START_STK_SIZE-1],START_TASK_PRIO );//创建起始任务/* 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任务 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); //等待转换完成,第二个参数代表最长等待时间msif(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC)){ADC_Value = HAL_ADC_GetValue(&hadc1); // 读取ADC数据 ,4096 -> 3.3VADC_Speed = ADC_Value + 500; //转换公式 0-4096 -> 500 - 4596 // if(ADC_Speed > 100){ // HAL_GPIO_TogglePin(led_GPIO_Port, led_Pin); // }}//当前速度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';//目标速度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 采样函数 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);} } //外部中断服务函数 void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if(!state){__IO uint8_t uwStep = 0;uint16_t hall_read=(HALL_GPIO->IDR)&0x0007; // 获取霍尔传感器状态 pin0 1 2uwStep = hall_read;BLDC_PHASE_CHANGE(uwStep); // 驱动换相 }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中断函数 //溢出时间为1s //溢出值1000 每个点为1ms void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) { if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) //捕获中断{/*测速逻辑1、中断产生,先判断是否为第一次上升沿2、捕获到上升沿后,将时间点存入变量,切换捕获下降沿3、捕获到下降沿后,记下时间点,切换为捕获上升沿4、捕获到上升沿后,记下时间点5、计算周期和占空比6、问题如果经过多个周期才有一次上升沿和下降沿怎么办,需要记录溢出次数如果溢出的时候有上升沿标志位 问题:proteus三路输入捕获计算,测转速时,如果第一个上升沿和第二个上升沿不在一个定时器计数周期,会计算失败*/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; //转速计算 // current_speed = current_speed * 5; //速度调整系数 // 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; //速度调整系数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; //速度调整系数 // 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采样值转换成转速 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; //目标转速 相差10%左右,所以显示90%int Uk; //Ukint Udk; //Udkint Uk_1; //Uk-1double P; // Proportional Const double I; // Integral Constint 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=0Speed_Point->ek_1 = 0; //ek-1=0Speed_Point->ek_2 = 0; //ek-2=0Speed_Point->P = 1; //Proportional Const } /*==================================================================================================== ???PID???? =====================================================================================================*/ int Speed_PIDAdjust(int Next_Point) { Speed_Point->Target = ADC_Speed *10 / 9; //重新调整速度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);//PIDSpeed_Point->Udk=Speed_Point->P*(Speed_Point->ek_0-Speed_Point->ek_1);//PSpeed_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); }

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...