找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3494|回复: 3
收起左侧

基于stm32f103rct6的PID算法控制四驱车程序—基于HAL库的

[复制链接]
ID:507807 发表于 2019-7-30 20:41 | 显示全部楼层 |阅读模式
STM32F103RCT6PID算法控制四个电机,基于HAL,希望可以给各位一些帮助,仅供参考,请勿他用

单片机源程序如下:
  1. /* USER CODE END Header */

  2. /* Includes ------------------------------------------------------------------*/
  3. #include "main.h"
  4. #include "dma.h"
  5. #include "tim.h"
  6. #include "usart.h"
  7. #include "gpio.h"

  8. /* Private includes ----------------------------------------------------------*/
  9. /* USER CODE BEGIN Includes */
  10. #include "string.h"
  11. #include "Motr_conter.h"
  12. #include "pid.h"
  13. /* USER CODE END Includes */

  14. /* Private typedef -----------------------------------------------------------*/
  15. /* USER CODE BEGIN PTD */

  16. /* USER CODE END PTD */

  17. /* Private define ------------------------------------------------------------*/
  18. /* USER CODE BEGIN PD */

  19. /* USER CODE END PD */

  20. /* Private macro -------------------------------------------------------------*/
  21. /* USER CODE BEGIN PM */

  22. /* USER CODE END PM */

  23. /* Private variables ---------------------------------------------------------*/

  24. /* USER CODE BEGIN PV */

  25. /* USER CODE END PV */

  26. /* Private function prototypes -----------------------------------------------*/
  27. void SystemClock_Config(void);
  28. /* USER CODE BEGIN PFP */

  29. /* USER CODE END PFP */

  30. /* Private user code ---------------------------------------------------------*/
  31. /* USER CODE BEGIN 0 */
  32.                                                
  33. uint8_t Left_Front_or_Right_rear;                        //用于保存电机行驶方向的变量
  34. uint8_t RX_buff[100],Start_Flag=0;                //接收缓冲区,和电机运行开始的标志位
  35. int16_t pwm_duth_A=0,pwm_duth_B=0,pwm_duth_C=0,pwm_duth_D=0;//四个电机的pwm变量
  36. uint16_t save_Ecoder_A=0,save_Ecoder_B=0,save_Ecoder_C=0,save_Ecoder_D=0;        //保存四个电机的编码值

  37. extern PID sPID;                        //PID结构体变量,用于改变目标值
  38. /* USER CODE END 0 */

  39. /**
  40.   * @brief  The application entry point.
  41.   * @retval int
  42.   */
  43. int main(void)
  44. {
  45.   /* USER CODE BEGIN 1 */
  46. uint8_t TX_buff[500]={"今天是个好日子,天气有点凉快!!\n"};

  47.   /* USER CODE END 1 */
  48.   

  49.   /* MCU Configuration--------------------------------------------------------*/

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

  52.   /* USER CODE BEGIN Init */

  53.   /* USER CODE END Init */

  54.   /* Configure the system clock */
  55.   SystemClock_Config();

  56.   /* USER CODE BEGIN SysInit */

  57.   /* USER CODE END SysInit */

  58.   /* Initialize all configured peripherals */
  59.   MX_GPIO_Init();                                                //GPIO的初始化
  60.   MX_DMA_Init();                                                //DMA的初始化
  61.   MX_TIM2_Init();                                                //定时器2的初始化
  62.   MX_USART1_UART_Init();                //串口1的初始化
  63.   MX_TIM1_Init();                                                //定时器1的初始化
  64.   MX_TIM6_Init();                                                //定时器6的初始化
  65. MX_USART2_UART_Init();                        //串口2的初始化
  66.   MX_TIM3_Init();                                                //定时器3的初始化
  67.   MX_TIM4_Init();                                                //定时器4的初始化
  68.   MX_TIM5_Init();                                                //定时器5的初始化
  69.   MX_TIM8_Init();                                                //定时器8的初始化
  70.   /* USER CODE BEGIN 2 */
  71.         Motor_Stop;                                                                //电机初始化状态位停止的
  72.         HAL_TIM_Base_Start_IT(&htim6);                                                                                                                                        //启动定时器
  73.         HAL_UART_Transmit(&huart2,TX_buff,strlen((char*)TX_buff),1000);        //串口2发送一串数据,表示串口2工作正常
  74.         HAL_UART_Transmit(&huart1,TX_buff,strlen((char*)TX_buff),100);        //串口发送数据测试        ,表示串口1工作正常
  75.         printf("电机编码器测试,测试通过\n");                                                                                                                //发送实验测试名称
  76.         IncPIDInit();                                                                                                                                                                                                                //pPID参数初始化
  77.         HAL_TIM_Encoder_Start(&htim2,TIM_CHANNEL_ALL);                                                                //开始电机D编码器接口计数
  78.         HAL_TIM_Encoder_Start(&htim3,TIM_CHANNEL_ALL);                                                                //开启电机C的编码器接口计数
  79.         HAL_TIM_Encoder_Start(&htim4,TIM_CHANNEL_ALL);                                                                //开启电机B的编码器接口计数
  80.         HAL_TIM_Encoder_Start(&htim5,TIM_CHANNEL_ALL);                                                                //开启电机C的编码器接口计数
  81.         HAL_UART_Receive_DMA(&huart2,RX_buff,5);                                                                                        //开启串口2的DMA接收数据
  82.   /* USER CODE END 2 */

  83.   /* Infinite loop */
  84.   /* USER CODE BEGIN WHILE */
  85.   while (1)
  86.   {
  87.     /* USER CODE END WHILE */

  88.     /* USER CODE BEGIN 3 */
  89.                 if(RX_buff[0]==0x31)
  90.                 {
  91.                         if(RX_buff[1]==0x31&&RX_buff[2]==0x31&&RX_buff[3]==0x31)        Derection_Control(1,3,1,3);                                //左前行驶
  92.                 }
  93.                 if(RX_buff[0]==0x32)
  94.                 {
  95.                         if(RX_buff[1]==0x32&&RX_buff[2]==0x32&&RX_buff[3]==0x32)        Derection_Control(1,1,1,1);                                //向前行驶
  96.                 }
  97.                 if(RX_buff[0]==0x33)
  98.                 {
  99.                         if(RX_buff[1]==0x33&&RX_buff[2]==0x33&&RX_buff[3]==0x33)        Derection_Control(3,1,3,1);                                //右前行驶
  100.                 }
  101.                 if(RX_buff[0]==0x34)
  102.                 {
  103.                         if(RX_buff[1]==0x34&&RX_buff[2]==0x34&&RX_buff[3]==0x34)        Derection_Control(1,2,1,2);                                //向左平行行驶
  104.                 }
  105.                 if(RX_buff[0]==0x35)
  106.                 {
  107.                         if(RX_buff[1]==0x35&&RX_buff[2]==0x35&&RX_buff[3]==0x35)        Derection_Control(1,2,2,1);                                //顺时针旋转
  108.                 }
  109.                 if(RX_buff[0]==0x36)
  110.                 {
  111.                         if(RX_buff[1]==0x36&&RX_buff[2]==0x36&&RX_buff[3]==0x36)        Derection_Control(2,1,2,1);                                //向右平行行驶
  112.                 }
  113.                 if(RX_buff[0]==0x37)
  114.                 {
  115.                         if(RX_buff[1]==0x37&&RX_buff[2]==0x37&&RX_buff[3]==0x37)        Derection_Control(3,2,3,2);                                //左后行驶
  116.                 }
  117.                 if(RX_buff[0]==0x38)
  118.                 {
  119.                         if(RX_buff[1]==0x38&&RX_buff[2]==0x38&&RX_buff[3]==0x38)        Derection_Control(2,2,2,2);                                //向后行驶
  120.                 }
  121.                 if(RX_buff[0]==0x39)
  122.                 {
  123.                         if(RX_buff[1]==0x39&&RX_buff[2]==0x39&&RX_buff[3]==0x39)        Derection_Control(2,3,2,3);                                //右后行驶
  124.                 }
  125.                 if(RX_buff[0]==0x30)
  126.                 {
  127.                         if(RX_buff[1]==0x30&&RX_buff[2]==0x30&&RX_buff[3]==0x30)        Derection_Control(2,1,1,2);                                //逆时针旋转
  128.                 }
  129.                 if(RX_buff[0]==0x2E)
  130.                 {
  131.                         if(RX_buff[1]==0x31&&RX_buff[2]==0x32&&RX_buff[3]==0x33)        {Derection_Control(3,3,3,3);        }                //停止
  132.                 }
  133.                 if(RX_buff[0]==0x2B)
  134.                 {
  135.                         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);                //设置行驶的速度
  136.                 }                       
  137.   }
  138.   /* USER CODE END 3 */
  139. }

  140. /**
  141.   * @brief System Clock Configuration
  142.   * @retval None
  143.   */
  144. void SystemClock_Config(void)
  145. {
  146.   RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  147.   RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  148.   /** Initializes the CPU, AHB and APB busses clocks
  149.   */
  150.   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  151.   RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  152.   RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  153.   RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  154.   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  155.   RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  156.   RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  157.   if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  158.   {
  159.     Error_Handler();
  160.   }
  161.   /** Initializes the CPU, AHB and APB busses clocks
  162.   */
  163.   RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
  164.                               |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  165.   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  166.   RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  167.   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  168.   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  169.   if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  170.   {
  171.     Error_Handler();
  172.   }
  173.   /** Enables the Clock Security System
  174.   */
  175.   HAL_RCC_EnableCSS();
  176. }

  177. /* USER CODE BEGIN 4 */
  178.         uint8_t direction_A,direction_B,direction_C,direction_D;                                        //保存四个电机方向的变量
  179.         uint32_t Code_val_A=0,Code_val_B=0,Code_val_C=0,Code_val_D=0;                        //保存四个编码器计数器的的值
  180.         uint16_t last_Code_val_A=0,last_Code_val_B=0,last_Code_val_C=0,last_Code_val_D=0;//保存上一秒计数器的值,与下一秒的相比较到底计数了多少次
  181. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
  182. {                                                                        
  183.        
  184.         if(htim->Instance==TIM6)                                                                                                        //判断是不是定时器6达到更新事件
  185.         {
  186.                 if(Start_Flag==1)                                                                                                                                //判断电机的行驶标志位
  187.                 {
  188.                 direction_A=__HAL_TIM_IS_TIM_COUNTING_DOWN(&htim5);//获取电机A转动的方向
  189.                 direction_B=__HAL_TIM_IS_TIM_COUNTING_DOWN(&htim4);//获取电机B 的旋转方向
  190.                 direction_C=__HAL_TIM_IS_TIM_COUNTING_DOWN(&htim3);//获取电机C 的旋转方向
  191.                 direction_D=__HAL_TIM_IS_TIM_COUNTING_DOWN(&htim2);//获取电机D的旋转方向
  192.                 Code_val_A=__HAL_TIM_GET_COUNTER(&htim5);                                                //读取电机A的计数器的值
  193.                 Code_val_B=__HAL_TIM_GET_COUNTER(&htim4);                                                //读取电机B的计数器的值
  194.                 Code_val_C=__HAL_TIM_GET_COUNTER(&htim3);                                                //读取电机C的计数器的值
  195.                 Code_val_D=__HAL_TIM_GET_COUNTER(&htim2);                                                //读取电机D的计数器的值
  196.                 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);                                                                                                 //方向为正定时器向上计数
  197.                 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);                                                                                                        //方向为反转代表计数器是向下计数                       
  198.                 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);                                                                                                 //方向为正定时器向上计数
  199.                 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);                                                                                                        //方向为反转代表计数器是向下计数
  200.                 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);                                                                                                 //方向为正定时器向上计数
  201.                 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);                                                                                                        //方向为反转代表计数器是向下计数
  202.                 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);                                                                                                 //方向为正定时器向上计数
  203.                 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);                                                                                                        //方向为反转代表计数器是向下计数
  204.                 if(Left_Front_or_Right_rear==0)                                                        //如果小车是按照前后左右的某一个方向行驶,将ABCD四个电机进行PID控制
  205.                 {
  206.                 pwm_duth_A+=(IncPIDCalc_C(save_Ecoder_A));        //电机A的PID算法值返回
  207.                 pwm_duth_B+=(IncPIDCalc_B(save_Ecoder_B));        //电机B的PID算法值返回
  208.                 pwm_duth_C+=(IncPIDCalc_C(save_Ecoder_C));        //电机C的PID算法值返回
  209.                 pwm_duth_D+=(IncPIDCalc_D(save_Ecoder_D));        //电机D的PID算法值返回
  210.                 }
  211.                 if(Left_Front_or_Right_rear==1)                                                                        //电机向左前或者右后行驶
  212.                 {
  213.                         pwm_duth_A+=(IncPIDCalc_C(save_Ecoder_A));                //就只进行电机AC的PID算法,不进行电机BD的算法
  214.                         pwm_duth_C+=(IncPIDCalc_C(save_Ecoder_C));                //就只进行电机AC的PID算法,不进行电机BD的算法
  215.                 }                       
  216.                 if(Left_Front_or_Right_rear==2)                                                                        //电机向右前或者左后行驶
  217.                 {
  218.                         pwm_duth_B+=(IncPIDCalc_B(save_Ecoder_B));                //就只进行电机BD的PID算法,不进行电机AC的PID算法
  219.                         pwm_duth_D+=(IncPIDCalc_D(save_Ecoder_D));                //就只进行电机BD的PID算法,不进行电机AC的PID算法
  220.                 }
  221.                 if(pwm_duth_A<0) pwm_duth_A=-pwm_duth_A;                                //处理电机A,当PWM值为负时变为正
  222.                 if(pwm_duth_B<0) pwm_duth_B=-pwm_duth_B;                                //处理电机B,当PWM值为负时变为正
  223.                 if(pwm_duth_C<0) pwm_duth_C=-pwm_duth_C;                                //处理电机C,当PWM值为负时变为正       
  224.                 if(pwm_duth_D<0) pwm_duth_D=-pwm_duth_D;                                //处理电机D,当PWM值为负时变为正
  225.                 if(pwm_duth_A>=7199)        pwm_duth_A=7200*4/6;                        //限制电机A的速度为最大占空比的百分之六十六
  226.                 if(pwm_duth_B>=7199)        pwm_duth_B=7200*4/6;                        //限制电机B的速度为最大占空比的百分之六十六                               
  227.                 if(pwm_duth_C>=7199)        pwm_duth_C=7200*4/6;                        //限制电机C的速度为最大占空比的百分之六十六
  228.                 if(pwm_duth_D>=7199)        pwm_duth_D=7200*4/6;                        //限制电机D的速度为最大占空比的百分之六十六
  229.                 Set_compare(motor_A,pwm_duth_A);                                                                //将电机A经过PID算法之后得到的PWM赋给电机,让电机真正的按照目标运行起来
  230.                 Set_compare(motor_B,pwm_duth_B);                                                                //将电机B经过PID算法之后得到的PWM赋给电机,让电机真正的按照目标运行起来
  231.                 Set_compare(motor_C,pwm_duth_C);                                                                //将电机C经过PID算法之后得到的PWM赋给电机,让电机真正的按照目标运行起来
  232.                 Set_compare(motor_D,pwm_duth_D);                                                                //将电机D经过PID算法之后得到的PWM赋给电机,让电机真正的按照目标运行起来
  233.                 last_Code_val_A=Code_val_A;                                                                                        //保存电机A的编码值,便于进行脉冲值的计算
  234.                 last_Code_val_B=Code_val_B;                                                                                        //保存电机B的编码值,便于进行脉冲值的计算
  235.                 last_Code_val_C=Code_val_C;                                                                                        //保存电机C的编码值,便于进行脉冲值的计算
  236.                 last_Code_val_D=Code_val_D;                                                                                        //保存电机D的编码值,便于进行脉冲值的计算

  237.                 }
  238.         }
  239. }




  240. void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
  241. {
  242.         if(huart->Instance==USART1)                                                                                                                        //判断是不是串口1接收完成
  243.         {
  244. //                        HAL_UART_Receive_IT(&huart1,RX_buff,8);
  245.         }
  246.         if(huart->Instance==USART2)                                                                                                                        //判断是否是串口2接收完成
  247.         {

  248.                 HAL_UART_Transmit_DMA(&huart2,RX_buff,5);                                                //DMA发送数据
  249.         }
  250. }
  251. void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)                        //发送完成回调函数
  252. {
  253.         if(huart->Instance==USART2)
  254.         {
  255.                 HAL_UART_Receive_DMA(&huart2,RX_buff,5);                                                                //使能DMA接收数据
  256.         }
  257. }
  258. /* USER CODE END 4 */

  259. /**
  260.   * @brief  This function is executed in case of error occurrence.
  261.   * @retval None
  262.   */
  263. void Error_Handler(void)
  264. {
  265.   /* USER CODE BEGIN Error_Handler_Debug */
  266.   /* User can add his own implementation to report the HAL error return state */

  267.   /* USER CODE END Error_Handler_Debug */
  268. }

  269. #ifdef  USE_FULL_ASSERT
  270. /**
  271.   * @brief  Reports the name of the source file and the source line number
  272.   *         where the assert_param error has occurred.
  273.   * @param  file: pointer to the source file name
  274.   * @param  line: assert_param error line source number
  275.   * @retval None
  276.   */
  277. void assert_failed(uint8_t *file, uint32_t line)
  278. {
  279.   /* USER CODE BEGIN 6 */
  280.   /* User can add his own implementation to report the file name and line number,
  281.      tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  282.   /* USER CODE END 6 */
  283. }
  284. #endif /* USE_FULL_ASSERT */

  285. /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
复制代码

所有资料51hei提供下载:
蓝牙+PID控制的小车.7z (264.82 KB, 下载次数: 90)
回复

使用道具 举报

ID:1 发表于 2019-7-30 23:28 | 显示全部楼层
本帖需要重新编辑补全电路原理图,源码,详细说明与图片即可获得100+黑币(帖子下方有编辑按钮)
回复

使用道具 举报

ID:584531 发表于 2019-8-17 14:45 | 显示全部楼层
膜拜大佬
回复

使用道具 举报

ID:80689 发表于 2019-9-28 20:37 | 显示全部楼层
资料注释很详细!赞!!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表