不步进电机编码器测速
本例我们选用了THB6064MQ集成步进电机驱动模块使用很简单,仅有3个输入端口分别是使能端口、方向控制端口和脉冲输入端口,在不细分的模式下每输入一个脉冲步进电机就转动一个步进角,本例使用的是32细分所以就是每32个脉冲步进电机转动一个步进角。
THB6064MQ集成驱动
步进电机驱动板接线图
步进电机电流设置
驱动板细分选择列表
驱动步进电机的方法有很多,不同的驱动器可能使用的方法不一样,使用同一种驱动器控制的方法也可能不一样,这里我们使用的是利用STM32定时器的输出比较反转模式产生驱动电机所需的脉冲。
/**
* 函数功能: 驱动器定时器初始化
* 输入参数: 无
* 返 回 值: 无
* 说 明: 无
*/
void STEPMOTOR_TIMx_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig; // 定时器时钟
TIM_MasterConfigTypeDef sMasterConfig; // 定时器主模式配置
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig; // 刹车和死区时间配置
TIM_OC_InitTypeDef sConfigOC; // 定时器通道比较输出
/* 定时器基本环境配置 */
htimx_STEPMOTOR.Instance = STEPMOTOR_TIMx; // 定时器编号
htimx_STEPMOTOR.Init.Prescaler = STEPMOTOR_TIM_PRESCALER; // 定时器预分频器
htimx_STEPMOTOR.Init.CounterMode = TIM_COUNTERMODE_UP; // 计数方向:向上计数
htimx_STEPMOTOR.Init.Period = STEPMOTOR_TIM_PERIOD; // 定时器周期
htimx_STEPMOTOR.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1; // 时钟分频
htimx_STEPMOTOR.Init.RepetitionCounter = STEPMOTOR_TIM_REPETITIONCOUNTER; // 重复计数器
HAL_TIM_Base_Init(&htimx_STEPMOTOR);
/* 定时器时钟源配置 */
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; // 使用内部时钟源
HAL_TIM_ConfigClockSource(&htimx_STEPMOTOR, &sClockSourceConfig);
/* 初始化定时器比较输出环境 */
HAL_TIM_OC_Init(&htimx_STEPMOTOR);
/* 定时器主输出模式 */
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htimx_STEPMOTOR, &sMasterConfig);
/* 刹车和死区时间配置 */
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE;
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_OFF;
sBreakDeadTimeConfig.DeadTime = 0;
sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_DISABLE;
HAL_TIMEx_ConfigBreakDeadTime(&htimx_STEPMOTOR, &sBreakDeadTimeConfig);
/* 定时器比较输出配置 */
sConfigOC.OCMode = TIM_OCMODE_TOGGLE; // 比较输出模式:反转输出
sConfigOC.Pulse = Toggle_Pulse; // 脉冲数
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; // 输出极性
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_LOW; // 互补通道输出极性
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; // 快速模式
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET; // 空闲电平
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET; // 互补通道空闲电平
HAL_TIM_OC_ConfigChannel(&htimx_STEPMOTOR, &sConfigOC, STEPMOTOR_TIM_CHANNEL_x);
/* STEPMOTOR相关GPIO初始化配置 */
STEPMOTOR_GPIO_Init();
/* 配置定时器中断优先级并使能 */
HAL_NVIC_SetPriority(STEPMOTOR_TIMx_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(STEPMOTOR_TIMx_IRQn);
}
/**
* 函数功能: 步进电机运动控制
* 输入参数: Dir:步进电机运动方向 0:反转 1正转
* Speed:步进电机速度
* 返 回 值: void
* 说 明: 无
*/
void STEPMOTOR_Motion_Ctrl(uint8_t Dir , uint16_t Speed)
{
uint16_t Step_Delay; //步进延时
if(Speed == 0)
STEPMOTOR_OUTPUT_DISABLE();
else
{
if(Dir==CCW)
{
STEPMOTOR_DIR_REVERSAL();
}
else STEPMOTOR_DIR_FORWARD();//方向控制
//步进电机在丝杠上的单步距离
//x = (MPR*α)/2π; MPR:单圈距离 α:步距角
//单步距离的周期
//T = C/Ft; C:定时器计数周期 Ft:定时器频率
//∴ V = x/T =(MPR*α*Ft)/(2π*C);
//得 C = (MPR*α*Ft)/(2π*V);
//其中 α = (2π)/spr; spr:步进电机旋转一圈需要的脉冲数
//∴ C= (MPR*Ft)/(spr*V);
//Step_Delay = C/2; 步进电机脉宽
Step_Delay = (uint16_t)((MPR_FREQ_SPR_X_10/Speed)>>1);
STEPMOTOR_OUTPUT_ENABLE();
Toggle_Pulse = Step_Delay;
}
}
编码器硬件接口连接
一般都是使用编码器读取在转动时产生的脉冲值根据采集时间计算电机轴的运转速度,本例使用的是STM32定时器模式来做编码器AB脉冲的读取。
/**
* 函数功能: 基本定时器硬件初始化配置
* 输入参数: htim_base:基本定时器句柄类型指针
* 返 回 值: 无
* 说 明: 该函数被HAL库内部调用
*/
void HAL_TIM_Encoder_MspInit(TIM_HandleTypeDef* htim_base)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(htim_base->Instance==ENCODER_TIMx)
{
/* 基本定时器外设时钟使能 */
ENCODER_TIM_RCC_CLK_ENABLE();
ENCODER_TIM_GPIO_CLK_ENABLE();
/* 定时器通道1功能引脚IO初始化 */
GPIO_InitStruct.Pin = ENCODER_TIM_CH1_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull=GPIO_PULLUP;
GPIO_InitStruct.Alternate = GPIO_CH1_AFx_TIMx;
HAL_GPIO_Init(ENCODER_TIM_CH1_GPIO, &GPIO_InitStruct);
/* 定时器通道2功能引脚IO初始化 */
GPIO_InitStruct.Pin = ENCODER_TIM_CH2_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Alternate = GPIO_CH2_AFx_TIMx;
HAL_GPIO_Init(ENCODER_TIM_CH2_GPIO, &GPIO_InitStruct);
}
}
// 采样和控制周期为20ms
if(Time_Flag & SAMPLING)
{
// 获得编码器的脉冲值
CaptureNumber = OverflowCount*65535 + __HAL_TIM_GET_COUNTER(&htimx_Encoder);
// M法 测速度 M法是测量单位时间内的脉数,然后换算成频率,这里不算频率
MSF = CaptureNumber - Last_CaptureNumber;
Last_CaptureNumber = CaptureNumber;
// 对速度进行累计,得到1s内的脉冲数
MSF = abs(MSF);
SUM_Pulse += MSF;
MMPS = MSF*SPEED_CONSTANT;// 由脉冲数转换为 mm/s, MMPS = (MSF*(TXDCYCLE/SAMPLING_PERIOD))/PSPM;
if(Speed >= MAX_SPEED) // 限制最大速度
Speed = MAX_SPEED;
if(Speed <= MIN_SPEED)
Speed = MIN_SPEED;
STEPMOTOR_Motion_Ctrl(CW,Speed);
Time_Flag &= ~SAMPLING;
}
// 数据发送周期为1s
if(Time_Flag & TXD)
{
//printf("OverflowCount:%d \n",OverflowCount);
sprintf((char *)aTxBuffer,"捕获值: %d -- 速度: %.2f mm/s\n",CaptureNumber,(float)MMPS);
sprintf((char *)aTxBuffer+strlen((const char*)aTxBuffer),"1s内编码器计数值: %5d \n",SUM_Pulse);
HAL_USART_Transmit_DMA(&husartx,aTxBuffer,strlen((const char*)aTxBuffer));
SUM_Pulse = 0;
Time_Flag &= ~TXD;
}