- /*********************** 步进电机控制定时器TIM参数定义 ************************/
- #define SMOTOR1_TIMx TIM3
- #define SMOTOR1_TIM_RCC_CLK_ENABLE() __HAL_RCC_TIM3_CLK_ENABLE()
- #define SMOTOR1_TIM_RCC_CLK_DISABLE() __HAL_RCC_TIM3_CLK_DISABLE()
- #define SMOTOR1_TIM_IRQn TIM3_IRQn
- #define SMOTOR1_TIM_IRQHandler TIM3_IRQHandler
- #define TIMx_CLOCK_FREQ 72e6 //72000000 //72M定时器时钟源的最高频率
- // 定义定时器预分频,定时器实际时钟频率为:72MHz/(STEPMOTOR_TIMx_PRESCALER+1)
- #define SMOTOR1_TIM_PRESCALER 3 // 步进电机驱动器细分设置为: 32 细分
- // 定义定时器周期,当定时器开始计数到SMOTOR1_TIM_PERIOD值是更新定时器并生成对应事
- // 件和中断.定时器更新频率为:定时器频率/(SMOTOR1_TIM_PERIOD+1) Hz
- #define SMOTOR1_TIM_PERIOD 0xFFFF
- #define SMOTOR1_TIM_DEFAULT_PULSE (SMOTOR1_TIM_PERIOD>>1)
- #define SMOTOR1_COUNTER_FREQ ((float)TIMx_CLOCK_FREQ / (SMOTOR1_TIM_PRESCALER+1))
-
- /* 定义控制输出引脚 */
- #define SMOTOR1_PUL_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE();
- #define SMOTOR1_PUL_GPIO_PORT GPIOC
- #define SMOTOR1_PUL_GPIO_PIN GPIO_PIN_6
- #define SMOTOR1_PUL_PIN_AF GPIO_AF3_TIM8 // 复用功能引脚
- #define SMOTOR1_PUL_TIMx_CHANNELx TIM_CHANNEL_1
- #define SMOTOR1_ACTIVE_CHANNEL HAL_TIM_ACTIVE_CHANNEL_1
- #define SMOTOR1_DIR_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE();
- #define SMOTOR1_DIR_GPIO_PORT GPIOC
- #define SMOTOR1_DIR_GPIO_PIN GPIO_PIN_0
- #define SMOTOR1_DIR_PIN_AF 0 // default
- #define SMOTOR1_ENA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOE_CLK_ENABLE();
- #define SMOTOR1_ENA_GPIO_PORT GPIOE
- #define SMOTOR1_ENA_GPIO_PIN GPIO_PIN_0
- #define SMOTOR1_ENA_PIN_AF 0 // default
- /* 电机方向和使能控制 */
- #define SMOTOR1_DIR_FORWARE() HAL_GPIO_WritePin(\
- SMOTOR1_DIR_GPIO_PORT,\
- SMOTOR1_DIR_GPIO_PIN,\
- GPIO_PIN_SET\
- );
- #define SMOTOR1_DIR_REVERSAL() HAL_GPIO_WritePin(\
- SMOTOR1_DIR_GPIO_PORT,\
- SMOTOR1_DIR_GPIO_PIN,\
- GPIO_PIN_RESET\
- );
- #define SMOTOR1_ENABLE() HAL_GPIO_WritePin(\
- SMOTOR1_ENA_GPIO_PORT,\
- SMOTOR1_ENA_GPIO_PIN,\
- GPIO_PIN_RESET);
- #define SMOTOR1_DISABLE() HAL_GPIO_WritePin(\
- SMOTOR1_ENA_GPIO_PORT,\
- SMOTOR1_ENA_GPIO_PIN,\
- GPIO_PIN_SET)
- //#define DEFAULTSPEED 600 // 初始默认速度 600*0.1 RPM
- /************************* 步进电机与驱动器参数宏定义 *************************/
- #define SMOTOR1_STEPANGLE (1.8f) // 步距角
- #define SMOTOR1_MICORSTEP (16U) // 细分数
- #define SMOTOR1_PULSEREV (uint32_t)((SMOTOR1_MICORSTEP*360U)/SMOTOR1_STEPANGLE)// 360/(1.8/32),一转的步数
- #define SMOTOR1_RATEDSPEED (20000U) // 额定转速0.1RPM
然后定义设备运转参数
- /* 电机方向定义 */
- typedef enum
- {
- MOTOR_DIR_CW = 0,
- MOTOR_DIR_CCW
- }MotorDir_Typedef;
- /* 电机使能状态定义 */
- typedef enum
- {
- MOTOR_ENABLE = 0,
- MOTOR_DISABLE
- }MotorSta_Typedef ;
- /* 电机加减速曲线状态定义 */
- typedef enum{
- STOP = 0, // 加减速曲线状态:停止
- ACCEL, // 加减速曲线状态:加速阶段
- DECEL, // 加减速曲线状态:减速阶段
- RUN, // 加减速曲线状态:匀速阶段
- }MotorRunSta_Typedef;
- /* 电机加减速参数类型定义 */
- typedef struct {
- // 加减速控制相关
- __IO MotorRunSta_Typedef run_state ; // 电机转动状态
- int32_t decel_start;// 启动减速位置
- int32_t decel_val; // 减速阶段步数
- int32_t min_delay; // 最小脉冲周期(最大速度,即匀速段速度)
- __IO int32_t step_delay; // 下个脉冲周期(时间间隔),启动时为加速度
- __IO int32_t accel_count;// 加(减)速阶段步数计数值
- __IO uint32_t step_count; // 步数记录
-
- } SpeedRampData_Typedef;
编写驱动引脚及定时器初始化函数
- /*--------------------------- 主控制定时器 -----------------------------------*/
- /**
- * 函数功能: 定时器硬件初始化配置
- * 输入参数: 无
- * 返 回 值: 无
- * 说 明: 无
- */
- static void SMotor1_GPIO_MspInit(void)
- {
- GPIO_InitTypeDef GPIO_InitStruct={0};
-
- /* 定时器引脚时钟使能 */
- SMOTOR1_PUL_GPIO_CLK_ENABLE();
- SMOTOR1_DIR_GPIO_CLK_ENABLE();
- SMOTOR1_ENA_GPIO_CLK_ENABLE();
-
- /* 脉冲输出引脚配置 */
- GPIO_InitStruct.Pin = SMOTOR1_PUL_GPIO_PIN ;
- GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; // 复用模式
- GPIO_InitStruct.Pull = GPIO_PULLUP;
- GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
- HAL_GPIO_Init(SMOTOR1_PUL_GPIO_PORT, &GPIO_InitStruct);
-
- /* 方向控制引脚配置 */
- GPIO_InitStruct.Pin = SMOTOR1_DIR_GPIO_PIN;
- GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
- // GPIO_InitStruct.Alternate = 0;
- GPIO_InitStruct.Pull = GPIO_PULLUP;
- HAL_GPIO_Init(SMOTOR1_DIR_GPIO_PORT, &GPIO_InitStruct);
-
- /* 电机使能引脚配置 */
- GPIO_InitStruct.Pin = SMOTOR1_ENA_GPIO_PIN;
- HAL_GPIO_Init(SMOTOR1_ENA_GPIO_PORT, &GPIO_InitStruct);
-
- /* NVIC中断优先级配置 */
- HAL_NVIC_SetPriority(SMOTOR1_TIM_IRQn, 0, 0);
- HAL_NVIC_EnableIRQ(SMOTOR1_TIM_IRQn);
-
- }
- /**
- * 函数功能: 步进电机控制定时器初始化
- * 输入参数: 无
- * 返 回 值: 无
- * 说 明: 初始化PWM输出功能
- */
- void SMOTOR1_TIMx_Init(void)
- {
- TIM_ClockConfigTypeDef sClockSourceConfig={0};
- TIM_BreakDeadTimeConfigTypeDef sconfigBDTR={0};
- TIM_OC_InitTypeDef sConfigOC={0};
- TIM_MasterConfigTypeDef sMasterConfig={0};
- /* 定时器硬件配置 */
- SMotor1_GPIO_MspInit();
-
- __HAL_AFIO_REMAP_TIM3_ENABLE();//TIM3端口完全重映射
-
- /* 定时器外设配置 */
- SMOTOR1_TIM_RCC_CLK_ENABLE();
- htimx_SMotor1.Instance = SMOTOR1_TIMx;
- // htimx_SMotor1.Init.Prescaler = SMOTOR1_TIM_PRESCALER;
- htimx_SMotor1.Init.CounterMode = TIM_COUNTERMODE_UP;
- htimx_SMotor1.Init.Period = SMOTOR1_TIM_PERIOD;
- htimx_SMotor1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
- // htimx_SMotor1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
- HAL_TIM_PWM_Init(&htimx_SMotor1);
- /* 时钟源配置 */
- sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; // 内部时钟
- sClockSourceConfig.ClockPrescaler = TIM_CLOCKPRESCALER_DIV1; // 无时钟预分频
- sClockSourceConfig.ClockPolarity = TIM_CLOCKPOLARITY_INVERTED;// 无效配置
- sClockSourceConfig.ClockFilter = 0x0;
- HAL_TIM_ConfigClockSource(&htimx_SMotor1, &sClockSourceConfig);
-
- sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
- sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_ENABLE;
- // sMasterConfig.MasterOutputTrigger2= TIM_TRGO2_RESET;
- HAL_TIMEx_MasterConfigSynchronization(&htimx_SMotor1,&sMasterConfig);
-
- /* 死区时间和状态配置 */
- /** 这里主要配置高级定时器的互补通道输出控制,对于刹车功能的配置是无效的
- * 如果使用非高级定时器,可以注释掉这段代码
- */
- sconfigBDTR.OffStateRunMode = TIM_OSSR_DISABLE; // 关闭时的运行模式输出极性
- sconfigBDTR.OffStateIDLEMode = TIM_OSSI_DISABLE; // 关闭时的空闲模式输出极性
- sconfigBDTR.BreakState = TIM_BREAK_DISABLE; // 不使用刹车功能
- sconfigBDTR.BreakPolarity = TIM_BREAKPOLARITY_LOW;
- sconfigBDTR.DeadTime = 0; // Min_Data = 0x00 and Max_Data = 0xFF
- sconfigBDTR.LockLevel = TIM_LOCKLEVEL_OFF;
- // sconfigBDTR.Break2Filter = 0; // Min_Data = 0x0 and Max_Data = 0xF
- // sconfigBDTR.Break2Polarity = TIM_BREAK2POLARITY_LOW;
- // sconfigBDTR.Break2State = TIM_BREAK2_DISABLE;
- sconfigBDTR.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
- HAL_TIMEx_ConfigBreakDeadTime(&htimx_SMotor1, &sconfigBDTR);
-
- /* PWM配置,CH1 PWM Mode*/
- sConfigOC.OCMode = TIM_OCMODE_TOGGLE;
- sConfigOC.Pulse = SMOTOR1_TIM_DEFAULT_PULSE;
- sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
- sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
- sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
- sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
- sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
- HAL_TIM_OC_ConfigChannel(&htimx_SMotor1, &sConfigOC, SMOTOR1_PUL_TIMx_CHANNELx);
-
- /* 配置电机默认状态,默认禁止电机转动,并且方向是顺时针转动 */
- SMotor1_Set_Dir ( MOTOR_DIR_CW ); // 电机方向,默认顺时针转动.
- SMotor1_Set_State( MOTOR_DISABLE );// 电机状态,默认禁止
- }
- /**
- * 函数功能: 设置电机方向
- * 输入参数: ptrSMotor 步进电机控制句柄指针
- * Dir 电机方向 参数可选:
- * [url=home.php?mod=space&uid=2817080]@ARG[/url] MOTOR_DIR_CW
- * @arg MOTOR_DIR_CCW
- * 返 回 值:
- * 说 明:设置步进电机的方向.控制驱动器的DIR端口
- */
- void SMotor1_Set_Dir(MotorDir_Typedef Dir)
- {
- /* 设置对应编号的步进电机方向 */
- Motor_Dir = Dir;
- if(Dir == MOTOR_DIR_CW)
- {
- SMOTOR1_DIR_FORWARE();
- }
- else
- {
- SMOTOR1_DIR_REVERSAL();
- }
- }
- /**
- * 函数功能: 设置电机状态
- * 输入参数: ptrSMotor 步进电机控制结构体指针
- * Ena 电机状态 参数可选:
- * @arg MOTOR_ENABLE
- * @arg MOTOR_DISABLE
- * 返 回 值:
- * 说 明: 设置步进电机的状态,控制驱动器的ENA端口
- */
- void SMotor1_Set_State( MotorSta_Typedef Ena)
- {
- /* 设置对应编号的步进电机方向 */
- Motor_State = Ena;
- if(Ena == MOTOR_ENABLE)
- {
- SMOTOR1_ENABLE();
- }
- else
- {
- SMOTOR1_DISABLE();
- }
- }
编辑定时器中断处理函数
- /**
- * 函数功能: 定时器中断回调函数
- * 输入参数: 无
- * 返 回 值: 无
- * 说 明: 实现加减速过程
- */
- void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
- {
- uint32_t tmp = 0;
- // 保存新(下)一个延时周期
- uint32_t new_step_delay = 0;
- // 加速过程中最后一次延时(脉冲周期).
- __IO static uint16_t last_accel_delay = 0;
- // 总移动步数计数器
- __IO static uint32_t step_count = 0;
- // 记录new_step_delay中的余数,提高下一步计算的精度
- __IO static int32_t rest = 0;
- //定时器使用翻转模式,需要进入两次中断才输出一个完整脉冲
- __IO static uint8_t i = 0;
-
- if(htim->Channel == SMOTOR1_ACTIVE_CHANNEL)
- {
- // 设置比较值
- tmp =__HAL_TIM_GET_COMPARE(&htimx_SMotor1,SMOTOR1_PUL_TIMx_CHANNELx);
- tmp += srd.step_delay;
- __HAL_TIM_SET_COMPARE(&htimx_SMotor1,SMOTOR1_PUL_TIMx_CHANNELx,(uint16_t)tmp );
- i++; // 定时器中断次数计数值
- if( ( i & 0x01) == 0) // 偶数,输出一个完整脉冲
- {
- switch(srd.run_state) // 加减速曲线阶段
- {
- case STOP:
- step_count = 0; // 清零步数计数器
- rest = 0; // 清零余值
- last_accel_delay = 0;
- // 关闭通道
- Stop_MotorMoving();
- break;
- case ACCEL:
- step_count++; // 步数加1
- srd.accel_count++; // 加速计数值加1
-
- new_step_delay = srd.step_delay - (((2 * srd.step_delay) + rest)/(4 * srd.accel_count + 1));//计算新(下)一步脉冲周期(时间间隔)
- rest = ((2 * srd.step_delay)+rest)%(4 * srd.accel_count + 1);// 计算余数,下次计算补上余数,减少误差
-
- if(step_count >= srd.decel_start)// 检查是够应该开始减速
- {
- srd.accel_count = srd.decel_val; // 加速计数值为减速阶段计数值的初始值
- srd.run_state = DECEL; // 下个脉冲进入减速阶段
- }
- else if(new_step_delay <= srd.min_delay) // 检查是否到达期望的最大速度
- {
- last_accel_delay = new_step_delay; // 保存加速过程中最后一次延时(脉冲周期)
- new_step_delay = srd.min_delay; // 使用min_delay(对应最大速度speed)
- rest = 0; // 清零余值
- srd.run_state = RUN; // 设置为匀速运行状态
- }
- break;
- case RUN:
- step_count ++; // 步数加1
- new_step_delay = srd.min_delay; // 使用min_delay(对应最大速度speed)
- if(step_count >= srd.decel_start) // 需要开始减速
- {
- srd.accel_count = srd.decel_val; // 减速步数做为加速计数值
- new_step_delay = last_accel_delay;// 加阶段最后的延时做为减速阶段的起始延时(脉冲周期)
- srd.run_state = DECEL; // 状态改变为减速
- }
- break;
- case DECEL:
- step_count++; // 步数加1
- srd.accel_count++;
- new_step_delay = srd.step_delay - (((2 * srd.step_delay) + rest)/(4 * srd.accel_count + 1)); //计算新(下)一步脉冲周期(时间间隔)
- rest = ((2 * srd.step_delay)+rest)%(4 * srd.accel_count + 1);// 计算余数,下次计算补上余数,减少误差
-
- //检查是否为最后一步
- if(srd.accel_count >= -1)
- {
- srd.run_state = STOP;
- }
- break;
- }
- if(new_step_delay>0xFFFF)
- new_step_delay = 0xFFFF;
- srd.step_delay = new_step_delay; // 为下个(新的)延时(脉冲周期)赋值
- }
- }
- }
然后编写梯形加减速控制算法函数
- /****************************** 梯形加减速控制 ********************************/
- /**
- * 函数功能: 停止电机转动
- * 输入参数: 无
- * 返 回 值: 无
- * 说 明: 禁止输出PWM,失能电机
- */
- static void Stop_MotorMoving()
- {
- HAL_TIM_OC_Stop_IT(&htimx_SMotor1, SMOTOR1_PUL_TIMx_CHANNELx);
- LED1_OFF();
- }
- /**
- * 函数功能: 步进电机线性速度控制
- * 输入参数: StepMotor 包含了梯形加减速速度控制所需要的参数包括有:
- * @arg Step 总的步数,单位是步数,也就是脉冲数,1转的脉冲数就是SMOTOR1_PULSEREV
- * @arg Accel 加速度,单位是r/s^2
- * @arg Decel 减速度,单位是r/s^2
- * @arg Speed 最高速度,单位是r/s
- * 返 回 值: 无
- * 说 明: 计算初始速度值,和各种限制条件,启动脉冲输出
- */
- void STEPMOTOR_LSCMoveRel (float step, float accel,float decel, float speed)
- {
- /* 由于时间变化的一倍,所以速度和加速度也相应的乘上2和4 */
- accel = accel * 4; // 由于使用比较翻转模式,
- decel = decel * 4; // 计算结果是半个周期的比较值
- speed = speed * 2; // 所以时间也要做相应的调整.(t = t*2)
-
- /* 达到设定的速度时需要的步数 */
- float max_s_lim;
- /* 必须要开始减速的步数(如果加速没有达到最大速度)*/
- float accel_lim;
- /* 预分频系数 */
-
- uint32_t tmp = 0;
-
- LED1_ON();
-
- /* 计算起始速度和最大速度对应的定时器周期值 */
- // 通过计算第一个(c0) 的步进延时来设定加速度,其中accel单位为 Rev/sec^2
- // step_delay = 1/tt * sqrt(2*alpha/accel)
- // step_delay = ( tfreq*0.676 ) * sqrt( (2*alpha) / accel )
- srd.step_delay = round((SMOTOR1_COUNTER_FREQ * sqrtf(ALPHA_x2 / accel))*0.676f);//C0,初始速度的定时器值
-
- // 设置最大速度极限.
- srd.min_delay = round((ALPHA * SMOTOR1_COUNTER_FREQ ) / speed);
-
- /* 计算加减速需要的参数 */
- // 计算多少步之后达到最大速度的限制
- // max_s_lim = speed^2 / (2*alpha*accel)
- max_s_lim = speed * speed / (ALPHA_x2 * accel) ;
-
- // 计算多少步之后必须开始减速
- // n1 = (n1+n2)decel / (accel + decel)
- accel_lim = step*decel / (accel + decel) ;
-
- /* 计算加速限制条件和开始减速的位置 */
- // 使用限制条件可以计算出减速阶段步数
- if(accel_lim <= max_s_lim)
- {
- srd.decel_val = (int32_t)(accel_lim - step);
- }
- else
- {
- srd.decel_val = round (- fabs ( max_s_lim * accel / decel) );
- }
- // 计算开始减速时的步数
- srd.decel_start = (int32_t)(step + srd.decel_val);
- srd.accel_count = 0;
- srd.run_state = ACCEL;
-
- SMotor1_Set_Dir(MOTOR_DIR_CW);// 默认方向是顺时针
- SMotor1_Set_State(MOTOR_ENABLE);// 使能电机转动
-
- // 设置比较值
- tmp =__HAL_TIM_GET_COUNTER(&htimx_SMotor1);
- tmp += srd.step_delay;
- __HAL_TIM_SET_COMPARE(&htimx_SMotor1,SMOTOR1_PUL_TIMx_CHANNELx,(uint16_t)tmp);
- HAL_TIM_OC_Start_IT(&htimx_SMotor1, SMOTOR1_PUL_TIMx_CHANNELx);
- }
设置运行参数
- #define MOTORSPEED 10.0f // 单位是r/s
- #define ACCEL 5.0f // 单位是r/(s^2)
- #define DECEL 5.0f // 单位是r/(s^2)
- #define STEP (10*SMOTOR1_PULSEREV) // (100转 的脉冲数,一转是6400)
在主程序中调用初始化程序,运行控制代码就可以了
- /* 初始化配置步进电机1控制定时器 */
- SMOTOR1_TIMx_Init();
- STEPMOTOR_LSCMoveRel(STEP, ACCEL, DECEL, MOTORSPEED);