STM32F103RCT6PID算法控制四个电机,基于HAL,希望可以给各位一些帮助,仅供参考,请勿他用
单片机源程序如下:
- /* USER CODE END Header */
- /* Includes ------------------------------------------------------------------*/
- #include "main.h"
- #include "dma.h"
- #include "tim.h"
- #include "usart.h"
- #include "gpio.h"
- /* Private includes ----------------------------------------------------------*/
- /* USER CODE BEGIN Includes */
- #include "string.h"
- #include "Motr_conter.h"
- #include "pid.h"
- /* 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 */
-
- uint8_t Left_Front_or_Right_rear; //用于保存电机行驶方向的变量
- uint8_t RX_buff[100],Start_Flag=0; //接收缓冲区,和电机运行开始的标志位
- int16_t pwm_duth_A=0,pwm_duth_B=0,pwm_duth_C=0,pwm_duth_D=0;//四个电机的pwm变量
- uint16_t save_Ecoder_A=0,save_Ecoder_B=0,save_Ecoder_C=0,save_Ecoder_D=0; //保存四个电机的编码值
- extern PID sPID; //PID结构体变量,用于改变目标值
- /* USER CODE END 0 */
- /**
- * @brief The application entry point.
- * @retval int
- */
- int main(void)
- {
- /* USER CODE BEGIN 1 */
- uint8_t TX_buff[500]={"今天是个好日子,天气有点凉快!!\n"};
- /* 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(); //GPIO的初始化
- MX_DMA_Init(); //DMA的初始化
- MX_TIM2_Init(); //定时器2的初始化
- MX_USART1_UART_Init(); //串口1的初始化
- MX_TIM1_Init(); //定时器1的初始化
- MX_TIM6_Init(); //定时器6的初始化
- MX_USART2_UART_Init(); //串口2的初始化
- MX_TIM3_Init(); //定时器3的初始化
- MX_TIM4_Init(); //定时器4的初始化
- MX_TIM5_Init(); //定时器5的初始化
- MX_TIM8_Init(); //定时器8的初始化
- /* USER CODE BEGIN 2 */
- Motor_Stop; //电机初始化状态位停止的
- HAL_TIM_Base_Start_IT(&htim6); //启动定时器
- HAL_UART_Transmit(&huart2,TX_buff,strlen((char*)TX_buff),1000); //串口2发送一串数据,表示串口2工作正常
- HAL_UART_Transmit(&huart1,TX_buff,strlen((char*)TX_buff),100); //串口发送数据测试 ,表示串口1工作正常
- printf("电机编码器测试,测试通过\n"); //发送实验测试名称
- IncPIDInit(); //pPID参数初始化
- HAL_TIM_Encoder_Start(&htim2,TIM_CHANNEL_ALL); //开始电机D编码器接口计数
- HAL_TIM_Encoder_Start(&htim3,TIM_CHANNEL_ALL); //开启电机C的编码器接口计数
- HAL_TIM_Encoder_Start(&htim4,TIM_CHANNEL_ALL); //开启电机B的编码器接口计数
- HAL_TIM_Encoder_Start(&htim5,TIM_CHANNEL_ALL); //开启电机C的编码器接口计数
- HAL_UART_Receive_DMA(&huart2,RX_buff,5); //开启串口2的DMA接收数据
- /* USER CODE END 2 */
- /* Infinite loop */
- /* USER CODE BEGIN WHILE */
- while (1)
- {
- /* USER CODE END WHILE */
- /* USER CODE BEGIN 3 */
- if(RX_buff[0]==0x31)
- {
- if(RX_buff[1]==0x31&&RX_buff[2]==0x31&&RX_buff[3]==0x31) Derection_Control(1,3,1,3); //左前行驶
- }
- if(RX_buff[0]==0x32)
- {
- if(RX_buff[1]==0x32&&RX_buff[2]==0x32&&RX_buff[3]==0x32) Derection_Control(1,1,1,1); //向前行驶
- }
- if(RX_buff[0]==0x33)
- {
- if(RX_buff[1]==0x33&&RX_buff[2]==0x33&&RX_buff[3]==0x33) Derection_Control(3,1,3,1); //右前行驶
- }
- if(RX_buff[0]==0x34)
- {
- if(RX_buff[1]==0x34&&RX_buff[2]==0x34&&RX_buff[3]==0x34) Derection_Control(1,2,1,2); //向左平行行驶
- }
- if(RX_buff[0]==0x35)
- {
- if(RX_buff[1]==0x35&&RX_buff[2]==0x35&&RX_buff[3]==0x35) Derection_Control(1,2,2,1); //顺时针旋转
- }
- if(RX_buff[0]==0x36)
- {
- if(RX_buff[1]==0x36&&RX_buff[2]==0x36&&RX_buff[3]==0x36) Derection_Control(2,1,2,1); //向右平行行驶
- }
- if(RX_buff[0]==0x37)
- {
- if(RX_buff[1]==0x37&&RX_buff[2]==0x37&&RX_buff[3]==0x37) Derection_Control(3,2,3,2); //左后行驶
- }
- if(RX_buff[0]==0x38)
- {
- if(RX_buff[1]==0x38&&RX_buff[2]==0x38&&RX_buff[3]==0x38) Derection_Control(2,2,2,2); //向后行驶
- }
- if(RX_buff[0]==0x39)
- {
- if(RX_buff[1]==0x39&&RX_buff[2]==0x39&&RX_buff[3]==0x39) Derection_Control(2,3,2,3); //右后行驶
- }
- if(RX_buff[0]==0x30)
- {
- if(RX_buff[1]==0x30&&RX_buff[2]==0x30&&RX_buff[3]==0x30) Derection_Control(2,1,1,2); //逆时针旋转
- }
- if(RX_buff[0]==0x2E)
- {
- if(RX_buff[1]==0x31&&RX_buff[2]==0x32&&RX_buff[3]==0x33) {Derection_Control(3,3,3,3); } //停止
- }
- if(RX_buff[0]==0x2B)
- {
- sPID.SetPoint_A=sPID.SetPoint_B=sPID.SetPoint_C=sPID.SetPoint_D=(RX_buff[1]-0x30)*1000+(RX_buff[2]-0x30)*100+(RX_buff[3]-0x30)*10+(RX_buff[4]-0x30); //设置行驶的速度
- }
- }
- /* 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 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_MUL9;
- 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_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();
- }
- /** Enables the Clock Security System
- */
- HAL_RCC_EnableCSS();
- }
- /* USER CODE BEGIN 4 */
- uint8_t direction_A,direction_B,direction_C,direction_D; //保存四个电机方向的变量
- uint32_t Code_val_A=0,Code_val_B=0,Code_val_C=0,Code_val_D=0; //保存四个编码器计数器的的值
- uint16_t last_Code_val_A=0,last_Code_val_B=0,last_Code_val_C=0,last_Code_val_D=0;//保存上一秒计数器的值,与下一秒的相比较到底计数了多少次
- void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
- {
-
- if(htim->Instance==TIM6) //判断是不是定时器6达到更新事件
- {
- if(Start_Flag==1) //判断电机的行驶标志位
- {
- direction_A=__HAL_TIM_IS_TIM_COUNTING_DOWN(&htim5);//获取电机A转动的方向
- direction_B=__HAL_TIM_IS_TIM_COUNTING_DOWN(&htim4);//获取电机B 的旋转方向
- direction_C=__HAL_TIM_IS_TIM_COUNTING_DOWN(&htim3);//获取电机C 的旋转方向
- direction_D=__HAL_TIM_IS_TIM_COUNTING_DOWN(&htim2);//获取电机D的旋转方向
- Code_val_A=__HAL_TIM_GET_COUNTER(&htim5); //读取电机A的计数器的值
- Code_val_B=__HAL_TIM_GET_COUNTER(&htim4); //读取电机B的计数器的值
- Code_val_C=__HAL_TIM_GET_COUNTER(&htim3); //读取电机C的计数器的值
- Code_val_D=__HAL_TIM_GET_COUNTER(&htim2); //读取电机D的计数器的值
- if(direction_A==0) save_Ecoder_A=(Code_val_A>=last_Code_val_A?Code_val_A-last_Code_val_A:Code_val_A+65535-last_Code_val_A); //方向为正定时器向上计数
- if(direction_A==1) save_Ecoder_A=(Code_val_A>last_Code_val_A?last_Code_val_A+65535-Code_val_A:last_Code_val_A-Code_val_A); //方向为反转代表计数器是向下计数
- if(direction_B==0) save_Ecoder_B=(Code_val_B>=last_Code_val_B?Code_val_B-last_Code_val_B:Code_val_B+65535-last_Code_val_B); //方向为正定时器向上计数
- if(direction_B==1) save_Ecoder_B=(Code_val_B>last_Code_val_B?last_Code_val_B+65535-Code_val_B:last_Code_val_B-Code_val_B); //方向为反转代表计数器是向下计数
- if(direction_C==0) save_Ecoder_C=(Code_val_C>=last_Code_val_C?Code_val_C-last_Code_val_C:Code_val_C+65535-last_Code_val_C); //方向为正定时器向上计数
- if(direction_C==1) save_Ecoder_C=(Code_val_C>last_Code_val_C?last_Code_val_C+65535-Code_val_C:last_Code_val_C-Code_val_C); //方向为反转代表计数器是向下计数
- if(direction_D==0) save_Ecoder_D=(Code_val_D>=last_Code_val_D?Code_val_D-last_Code_val_D:Code_val_D+65535-last_Code_val_D); //方向为正定时器向上计数
- if(direction_D==1) save_Ecoder_D=(Code_val_D>last_Code_val_D?last_Code_val_D+65535-Code_val_D:last_Code_val_D-Code_val_D); //方向为反转代表计数器是向下计数
- if(Left_Front_or_Right_rear==0) //如果小车是按照前后左右的某一个方向行驶,将ABCD四个电机进行PID控制
- {
- pwm_duth_A+=(IncPIDCalc_C(save_Ecoder_A)); //电机A的PID算法值返回
- pwm_duth_B+=(IncPIDCalc_B(save_Ecoder_B)); //电机B的PID算法值返回
- pwm_duth_C+=(IncPIDCalc_C(save_Ecoder_C)); //电机C的PID算法值返回
- pwm_duth_D+=(IncPIDCalc_D(save_Ecoder_D)); //电机D的PID算法值返回
- }
- if(Left_Front_or_Right_rear==1) //电机向左前或者右后行驶
- {
- pwm_duth_A+=(IncPIDCalc_C(save_Ecoder_A)); //就只进行电机AC的PID算法,不进行电机BD的算法
- pwm_duth_C+=(IncPIDCalc_C(save_Ecoder_C)); //就只进行电机AC的PID算法,不进行电机BD的算法
- }
- if(Left_Front_or_Right_rear==2) //电机向右前或者左后行驶
- {
- pwm_duth_B+=(IncPIDCalc_B(save_Ecoder_B)); //就只进行电机BD的PID算法,不进行电机AC的PID算法
- pwm_duth_D+=(IncPIDCalc_D(save_Ecoder_D)); //就只进行电机BD的PID算法,不进行电机AC的PID算法
- }
- if(pwm_duth_A<0) pwm_duth_A=-pwm_duth_A; //处理电机A,当PWM值为负时变为正
- if(pwm_duth_B<0) pwm_duth_B=-pwm_duth_B; //处理电机B,当PWM值为负时变为正
- if(pwm_duth_C<0) pwm_duth_C=-pwm_duth_C; //处理电机C,当PWM值为负时变为正
- if(pwm_duth_D<0) pwm_duth_D=-pwm_duth_D; //处理电机D,当PWM值为负时变为正
- if(pwm_duth_A>=7199) pwm_duth_A=7200*4/6; //限制电机A的速度为最大占空比的百分之六十六
- if(pwm_duth_B>=7199) pwm_duth_B=7200*4/6; //限制电机B的速度为最大占空比的百分之六十六
- if(pwm_duth_C>=7199) pwm_duth_C=7200*4/6; //限制电机C的速度为最大占空比的百分之六十六
- if(pwm_duth_D>=7199) pwm_duth_D=7200*4/6; //限制电机D的速度为最大占空比的百分之六十六
- Set_compare(motor_A,pwm_duth_A); //将电机A经过PID算法之后得到的PWM赋给电机,让电机真正的按照目标运行起来
- Set_compare(motor_B,pwm_duth_B); //将电机B经过PID算法之后得到的PWM赋给电机,让电机真正的按照目标运行起来
- Set_compare(motor_C,pwm_duth_C); //将电机C经过PID算法之后得到的PWM赋给电机,让电机真正的按照目标运行起来
- Set_compare(motor_D,pwm_duth_D); //将电机D经过PID算法之后得到的PWM赋给电机,让电机真正的按照目标运行起来
- last_Code_val_A=Code_val_A; //保存电机A的编码值,便于进行脉冲值的计算
- last_Code_val_B=Code_val_B; //保存电机B的编码值,便于进行脉冲值的计算
- last_Code_val_C=Code_val_C; //保存电机C的编码值,便于进行脉冲值的计算
- last_Code_val_D=Code_val_D; //保存电机D的编码值,便于进行脉冲值的计算
- }
- }
- }
- void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
- {
- if(huart->Instance==USART1) //判断是不是串口1接收完成
- {
- // HAL_UART_Receive_IT(&huart1,RX_buff,8);
- }
- if(huart->Instance==USART2) //判断是否是串口2接收完成
- {
- HAL_UART_Transmit_DMA(&huart2,RX_buff,5); //DMA发送数据
- }
- }
- void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) //发送完成回调函数
- {
- if(huart->Instance==USART2)
- {
- HAL_UART_Receive_DMA(&huart2,RX_buff,5); //使能DMA接收数据
- }
- }
- /* 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****/
复制代码
所有资料51hei提供下载:
蓝牙+PID控制的小车.7z
(264.82 KB, 下载次数: 90)
|