【STM32】实战3.2—用STM32与TB6600驱动器驱动42步进电机(二)

本文档详细介绍了使用STM32F407控制两路步进电机实现正反转、加减速的实验,参照了多个CSDN博客和论文。实验中,通过离散化处理S型加减速曲线并采用TIM8高级控制定时器配置PWM,实现了步进电机的精确控制。此外,还回顾了定时器的配置,如计数器、预分频器和自动重载寄存器,并提供了HAL库函数的应用示例。
摘要由CSDN通过智能技术生成

目录

0 参考资料出处

1 实验预期效果

2 加减速曲线

2.1 曲线离散化处理与算法实现 

2.2 举例说明

3 软件配置

3.1 定时器配置

3.1.1 TIM8 简介与主要特性

​3.1.2 PWM相关概念回顾

3.2 串口配置 

代码编写


0 参考资料出处

参考博客:
        1、CUBEMX教程—— STM32F407实现多步进电机型加减速全过程_新时代弄潮儿的博客-CSDN博客_stm32控制步进电机

        2、STM32 HAL库 实现控制步进电机 正转、反转、T型加减速_Gerhart658的博客-CSDN博客_stm32步进电机库

        3、步进电机S型加速_新时代弄潮儿的博客-CSDN博客_步进电机s加速曲线

        4、stm32输出比较PWM_小聪不想秃头的博客-CSDN博客_stm32输出pwm最大频率

        5、; 

参考论文:

        [1] 陈祖霖,黄峰,吴靖等.步进电机S曲线调速控制研究[J].福州大学学报:自然科学版,2019,47(5):640-645.

1 实验预期效果

        完成两路步进电机的正反转加减速(通过串口控制、非可移动电源供电)。

2 加减速曲线

2.1 曲线离散化处理与算法实现 

        根据论文[1]

        离散化处理: 

         算法实现:

         参数设置及计算:

2.2 举例说明

3 软件配置

3.1 定时器配置

3.1.1 TIM8 简介与主要特性

        Max timer clock:168MHz 

         TIM1 和 TIM8 简介: 

        高级控制定时器(TIM1 和 TIM8)包含一个 16 位自动重载计数器,该计数器由可编程预分 频器驱动。
        此类定时器可用于各种用途,包括测量输入信号的脉冲宽度(输入捕获),或者生成输出波形(输出比较、PWM 和带死区插入的互补 PWM)。
        使用定时器预分频器和 RCC 时钟控制器预分频器,可将脉冲宽度和波形周期从几微秒调制 到几毫秒。
        高级控制定时器(TIM1 和 TIM8)和通用 (TIMx) 定时器彼此完全独立,不共享任何资源。 

          TIM1 和 TIM8 主要特性
        TIM1 和 TIM8 定时器具有以下特性:
        ● 16 位递增、递减、递增/递减自动重载计数器。
        ● 16 位可编程预分频器,用于对计数器时钟频率进行分频(即运行时修改),分频系数
        介于 1 到 65536 之间。
        ● 多达 4 个独立通道,可用于:
                — 输入捕获
                — 输出比较
                — PWM 生成(边沿和中心对齐模式)
                — 单脉冲模式输出
        ● 带可编程死区的互补输出。
        ● 使用外部信号控制定时器且可实现多个定时器互连的同步电路。
        ● 重复计数器,用于仅在给定数目的计数器周期后更新定时器寄存器。
        ● 用于将定时器的输出信号置于复位状态或已知状态的断路输入。
        ● 发生如下事件时生成中断/DMA 请求:
                — 更新:计数器上溢/下溢、计数器初始化(通过软件或内部/外部触发)
                — 触发事件(计数器启动、停止、初始化或通过内部/外部触发计数)
                — 输入捕获
                — 输出比较
                — 断路输入
        ● 支持定位用增量(正交)编码器和霍尔传感器电路。
        ● 外部时钟触发输入或逐周期电流管理。

3.1.2 PWM相关概念回顾

【可先学习博客:stm32输出比较PWM_小聪不想秃头的博客-CSDN博客_stm32输出pwm最大频率

        (1)计数寄存器(CNT),这个寄存器存储计数器当前的计数值,可以在运行时被读取。
        (2)预分频寄存器(PSC),寄存器数值范围0至65535,对应于分频系数1至65536。 
        (3)自动重载寄存器(ARR),这个寄存器存储的是定时器计数周期。

         CubeMX参数配置:

模式描述

冻结

Frozen (used for Timing base)
CNT=CCR时,REF保持为原状态
匹配时置有效电平Active Level on matchCNT=CCR时,REF置有效电平

匹配时置无效电平

Inactive Level on match

CNT=CCR时,REF置无效电平

匹配时电平翻转

Toggle on match
CNT=CCR时,REF电平翻转

强制为无效电平

Forced Active
CNT与CCR无效,REF强制为无效电平

强制为有效电平

Forced Inactive
CNT与CCR无效,REF强制为有效电平
PWM模式1向上计数: CNT<CCR时,REF置有效电平,CNT≥CCR时, REF置无效电平
向下计数: CNT>CCR时,REF置无效电平,CNT≤CCR时, REF置有效电平
PWM模式2向上计数: CNT<CCR时,REF置无效电平,CNT≥ CCR时,REF置有效电平
向下计数: CNT>CCR时,REF置有效电平,CNT≤CCR时, REF置 无效电平

【手动设置可参看博客:stm32定时器输出PWM流程讲解_Good boy-dai的博客-CSDN博客_pwm流程图

【相关HAL库函数可参看博客:4.基于STM32CubeMX使用TIM定时器_tao_sc的博客-CSDN博客_cubemx tim设置

3.2 串口配置 

代码编写

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2022 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"
#include "bsp_stepmotor.h"
#include "math.h"


uint32_t step_to_run[2]={86400,86400}; //uniform velocity      step_total = ACCELERATED_SPEED_LENGTH*2 + step_to_run  
//uint16_t step_to_run[4]={6800,6800,6800,6800};
float fre[ACCELERATED_SPEED_LENGTH]; //array_frequency 
unsigned short period[ACCELERATED_SPEED_LENGTH]; //array_ARR  


void SystemClock_Config(void);


void CalculateSModelLine(float fre[], unsigned short period[], float len, float fre_max, float fre_min, float flexible)
{
    int i = 0;
    float deno ;
    float melo ;
    float delt = fre_max - fre_min;
    for(i = 0; i < len; i++)
    {
        melo = flexible * (i-len/2) / (len/2);
        deno = 1.0f / (1 + expf(-melo));  //expf is a library function of exponential(e)
        fre[i] = fre_min + delt * deno;
        period[i] = (unsigned short)(10000000.0f / fre[i]); // 10000000 is the timer driver frequency
    }
    return ;
}


void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
{
	static uint32_t count[2]={0,0};
	//static uint32_t count[4]={0,0,0,0};
	
	static uint32_t num_callback[2]={0,0};
	//static uint32_t num_callback[4]={0,0,0,0};
	
	static uint8_t status[2]={1,1};
	//static uint8_t status[4]={1,1,1,1};
	
	if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
	{
        
		num_callback[0]++;
		if(num_callback[0]%2==0)
		{
			switch(status[0])
	          {
	              case ACCEL://Acceleration
                        __HAL_TIM_SetAutoreload(&htim8,period[count[0]]);
	                    __HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_1,period[count[0]]/2);
	                    count[0]++;
	                    if(count[0]>=ACCELERATED_SPEED_LENGTH)
	                    {
	                        status[0]=3;
	                    }                        
	                  break;
	              case RUN://Uniform Velocity
	                     step_to_run[0]--;
	                     if(step_to_run[0]<1)
	                       status[0]=2;     
	                   break;
	              case DECEL://Deceleration
	                     count[0]--;
                        __HAL_TIM_SetAutoreload(&htim8,period[count[0]]);
	                    __HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_1,period[count[0]]/2);
	                    if(count[0]<1)
	                        status[0]=0;
	                   break;
	              case STOP://STOP
	                   //Close the channel
	                  TIM_CCxChannelCmd(TIM8, TIM_CHANNEL_1, TIM_CCx_DISABLE);        
	                  __HAL_TIM_CLEAR_FLAG(&htim8, TIM_FLAG_CC1);
	                   break;
	          
	          }
		}
 
	}
	else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
	{
        num_callback[1]++;
		if(num_callback[1]%2==0)
		{
              switch(status[1])
	          {
	              case ACCEL://Acceleration
                        __HAL_TIM_SetAutoreload(&htim8,period[count[1]]);
	                    __HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_2,period[count[1]]/2);
	                    count[1]++;
	                    if(count[1]>=ACCELERATED_SPEED_LENGTH)
	                    {
	                        status[1]=3;
	                    }                        
	                  break;
	              case RUN://Uniform Velocity
	                     step_to_run[1]--;
	                     if(step_to_run[1]<1)
	                       status[1]=2;     
	                   break;
	              case DECEL://Deceleration
	                     count[1]--;
                        __HAL_TIM_SetAutoreload(&htim8,period[count[1]]);
	                    __HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_2,period[count[1]]/2);
	                    if(count[1]<1)
	                        status[1]=0;
	                   break;
	              case STOP://STOP
	                   //Close the channel
	                  TIM_CCxChannelCmd(TIM8, TIM_CHANNEL_2, TIM_CCx_DISABLE);        
	                  __HAL_TIM_CLEAR_FLAG(&htim8, TIM_FLAG_CC2);
	                   break;
	          
	          }
        }
		
 
	}
	/*
	else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_3)
	{
		num_callback[2]++;
		if(num_callback[2]%2==0)
		{
               switch(status[2])
	          {
	              case ACCEL://??
                        __HAL_TIM_SetAutoreload(&htim8,period[count[2]]);
	                    __HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_3,period[count[2]]/2);
	                    count[2]++;
	                    if(count[2]>=ACCELERATED_SPEED_LENGTH)
	                    {
	                        status[2]=3;
	                    }                        
	                  break;
	              case RUN://??
	                     step_to_run[2]--;
	                     if(step_to_run[2]<1)
	                       status[2]=2;     
	                   break;
	              case DECEL://??
	                     count[2]--;
                        __HAL_TIM_SetAutoreload(&htim8,period[count[2]]);
	                    __HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_3,period[count[2]]/2);
	                    if(count[2]<1)
	                        status[2]=0;
	                   break;
	              case STOP://??
	                   // ????
	                  TIM_CCxChannelCmd(TIM8, TIM_CHANNEL_3, TIM_CCx_DISABLE);        
	                  __HAL_TIM_CLEAR_FLAG(&htim8, TIM_FLAG_CC3);
	                   break;
	          
	          }
        }
	}
	else if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_4)
	{
		num_callback[3]++;
		if(num_callback[3]%2==0)
		{
              switch(status[3])
	          {
	              case ACCEL://??
                        __HAL_TIM_SetAutoreload(&htim8,period[count[3]]);
	                    __HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_4,period[count[3]]/2);
	                    count[3]++;
	                    if(count[3]>=ACCELERATED_SPEED_LENGTH)
	                    {
	                        status[3]=3;
	                    }                        
	                  break;
	              case RUN://??
	                     step_to_run[3]--;
	                     if(step_to_run[3]<1)
	                       status[3]=2;     
	                   break;
	              case DECEL://??
	                     count[3]--;
                        __HAL_TIM_SetAutoreload(&htim8,period[count[3]]);
	                    __HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_4,period[count[3]]/2);
	                    if(count[3]<1)
	                        status[1]=0;
	                   break;
	              case STOP://??
	                   // ????
	                  TIM_CCxChannelCmd(TIM8, TIM_CHANNEL_4, TIM_CCx_DISABLE);        
	                  __HAL_TIM_CLEAR_FLAG(&htim8, TIM_FLAG_CC4);
	                   break;
	          
	          }
        }
	}
*/
}



/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();
  MX_TIM8_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */

	CalculateSModelLine(fre,period,ACCELERATED_SPEED_LENGTH,FRE_MAX,FRE_MIN,4);		//len = ACCELERATED_SPEED_LENGTH		flexible = 4(flexible:4~6) 
	HAL_TIM_Base_Start(&htim8);
	HAL_TIM_OC_Start_IT(&htim8, TIM_CHANNEL_1);
	HAL_TIM_OC_Start_IT(&htim8, TIM_CHANNEL_2);
	/*
	HAL_TIM_OC_Start_IT(&htim8, TIM_CHANNEL_3);
	HAL_TIM_OC_Start_IT(&htim8, TIM_CHANNEL_4);
  */
	/* USER CODE END 2 */

  while (1)
  {

  }

}
/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = 8;
  RCC_OscInitStruct.PLL.PLLN = 168;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  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_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* 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 */
  __disable_irq();
  while (1)
  {
  }
  /* 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,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
#ifndef __bsp_stepmotor_H
#define __bsp_stepmotor_H
#include "tim.h"
#ifdef __cplusplus
 extern "C" {
#endif
     
#define S_ACCEL 1    
#define T_ACCEL 0
     
/* S????? */
#define ACCELERATED_SPEED_LENGTH 3000
#define FRE_MIN 500
#define FRE_MAX 100000
 
     
#define STOP		0 
#define ACCEL		1 
#define DECEL		2 
#define RUN			3  
 
#endif
 
 
 
 
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值