在实际工业设备中一般使用较大尺寸的步进电机,它们有更大的扭矩。根据电机外尺寸的不同,可以分为42、57、86、110步进电机;另外,同个尺寸电机可以有不同的机身长度,影响转矩大小。电机正常旋转电流都是1A以上的,一般用专用的步进电机驱动器。用得最多,最常见的是两相4线步进电机,步距角为1.8°,即旋转一圈需要200个脉冲。 (360/1.8 = 200)
57步进电机长宽都是57mm。两相四线双极性电机。A+ (黑色),A - (绿),B+(红),B-(蓝)。一般在购买电机厂家都会说明。用数字万用表测量 A+ ,A- 会发现是相通,B+,B-也是。
会发现相电流是3A,所以肯定要专门的驱动芯片。扭矩是1.2牛每米。
当频率越大电机转的也快。当时如图所示:当频率在10khz一下。力矩都是平稳的。当超过10khz力矩急剧下降。所以步进电机一般都是用在低速场合。
类似28BYJ-48这些小尺寸、低转矩的步进电机使用ULN2003这类驱动芯片并配合控制器使用是可行的,但在实际工业应用中,经常使用到42、57、86、110等等系列型号步进电机,这些步进电机需要高电压、大电流、大功率驱动电路才能使其正常运转,另外,为充分实现发挥细分驱动优势,往往需要更加复杂的驱动电路。好在,很久之前很多半导体公司已经看到了这部分商机,专门为驱动步进电机设计了驱动芯片,种类繁多,功能齐全,同时也使得我们控制步进电机运动非常简单。 当然,步进电机也可以类似之前介绍过的直流有刷电机驱动一样,直接搭建MOS桥电路驱动,根据之前的节拍控制方法实现步进电机旋转,只是如果自己搭建电路驱动,程序处理会复杂一些,特别要实现细分驱动就需要更复杂的程序实现,另外硬件成本也没有优势。现有的专用步进电机芯片种类繁多,可根据电机参数选择对应的驱动芯片,价格也非常有优势,重点是驱动起来容易很多。
TOSHIBA(东芝)公司的TB67S109A芯片是一种配备PWM斩波器的两相双极步进电机驱动芯片。内置时钟解码器。采用BiCD工艺制作,额定值为50V/4.0A。允许全步、半步、1/4、1/8、1/16、1/32步(细分)运行,即细分最高为32。TB67S109A芯片的内部逻辑电路见图。
CLK上升沿来就转一个步距角,下降沿不变。ENALE 为0H桥关闭为高正常运行。
CW/CCW
在驱动器上有拨码开关(达到上:OFF 达到下:ON)分辨率的选择。因为有三个关于分辨率的拨码开关所有有8种选择如下:
当为000时为待机模式,这里的半步有两种类型。(A与B)
MO:当完成一次整步,半步就输出一个低电平。
半步A与半步B比较就是半步B多了正负71%。
四分之一有多了正负38%。这些图都是手册上的,可以查阅相关手册。还有16,32细分。对于每一步细分可以自己列出每一步的节拍帮助更好的理解。
TB67S109A步进电机驱动器是一款专业的两相步进电机驱动器,见图。可实现正反转控制,通过3位拨码开关选择7档细分控制(1,2/A,2/B,4,8,16,32,),通过3位拨码开关选择8档电流控制(0.5A,1A,1.5A,2A,2.5A,2.8A,3.0A,3.5A)。适合驱动57、42型两相混合式步进电机。能达到低振动、小噪声、高速度的效果驱动电机。
信号输入端都有正负两个引脚。注意电压不能大于40V否则可能会烧毁驱动器。
输入信号共有三路,它们是:①步进脉冲信号PUL+,PUL-;②方向电平信号DIR+,DIR- ; ③脱机(关闭)信号EN+,EN-。输入信号接口有两种接法,用户可根据 需要采用共阳极接法或共阴极接法。 实际上,驱动器的输入信号也是用光耦芯片,所以我们驱动目的是让光耦导通与否。
共阳极接法:分别将PUL+,DIR+,EN+连接到控制系统的电源正极上,如果此电源是+5V/3.3V则可直接接入,如果此电源大于+5V,则须外部另加限流电阻R,保证给驱动器内部光藕提供8—15mA的驱动电流,一般如果是24V电压,选择2K欧的电阻。脉冲输入信号通过PUL-接入,方向信号通过DIR-接入,使能信号通过EN-接入。都接到MCU的I/o口。如下图:
共阴极接法:分别将PUL-,DIR-,EN-连接到控制系统的地线(GND)上。脉冲输入信号通过PUL+接入,方向信号通过DIR+接入,使能信号通过EN+接入。都接到MCU的I/o口。如果此控制系统信号线是+5V/3.3V 则可直接接入,如果此信号电压大于+5V,则须外部另加限流电阻R,保证给驱动器内部光藕提供8—15mA的驱动电流,一般如果是24V电压,选择2K欧的电阻。
需要用到定时器的输出翻转功能接到CLK引脚,驱动器采用共阳接法。
定时器.h
#ifndef __STEPMOTOR_TIM_H__
#define __STEPMOTOR_TIM_H__
/* 包含头文件 ----------------------------------------------------------------*/
#include "stm32f4xx_hal.h"
#define STEPMOTOR_TIMx TIM8
#define STEPMOTOR_TIM_RCC_CLK_ENABLE() __HAL_RCC_TIM8_CLK_ENABLE()
#define STEPMOTOR_TIM_RCC_CLK_DISABLE() __HAL_RCC_TIM8_CLK_DISABLE()
#define STEPMOTOR_TIMx_IRQn TIM8_CC_IRQn
#define STEPMOTOR_TIMx_IRQHandler TIM8_CC_IRQHandler
// CLK接定时器8的CH1
#define STEPMOTOR_TIM_CHANNEL_x TIM_CHANNEL_1
#define STEPMOTOR_TIM_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE()
#define STEPMOTOR_TIM_PUL_PORT GPIOI
#define STEPMOTOR_TIM_PUL_PIN GPIO_PIN_5
#define GPIO_AFx_TIMx GPIO_AF3_TIM8
// 方向控制
#define STEPMOTOR_DIR_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
#define STEPMOTOR_DIR_PORT GPIOD
#define STEPMOTOR_DIR_PIN GPIO_PIN_3
// 使能控制
#define STEPMOTOR_ENA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
#define STEPMOTOR_ENA_PORT GPIOD
#define STEPMOTOR_ENA_PIN GPIO_PIN_7
#define STEPMOTOR_DIR_FORWARD() HAL_GPIO_WritePin(STEPMOTOR_DIR_PORT,STEPMOTOR_DIR_PIN,GPIO_PIN_SET)
#define STEPMOTOR_DIR_REVERSAL() HAL_GPIO_WritePin(STEPMOTOR_DIR_PORT,STEPMOTOR_DIR_PIN,GPIO_PIN_RESET)
#define STEPMOTOR_OUTPUT_ENABLE() HAL_GPIO_WritePin(STEPMOTOR_ENA_PORT,STEPMOTOR_ENA_PIN,GPIO_PIN_RESET)
#define STEPMOTOR_OUTPUT_DISABLE() HAL_GPIO_WritePin(STEPMOTOR_ENA_PORT,STEPMOTOR_ENA_PIN,GPIO_PIN_SET)
// 定义定时器预分频,定时器实际时钟频率为:168MHz/(STEPMOTOR_TIMx_PRESCALER+1)
#define STEPMOTOR_TIM_PRESCALER 5 // 168/5+1 = 28Mhz
#define STEPMOTOR_TIM_PERIOD 0xFFFF // ARR
#define STEPMOTOR_TIM_REPETITIONCOUNTER 0 // 高级定时器重复计数寄存器值
/* 扩展变量 ------------------------------------------------------------------*/
extern TIM_HandleTypeDef htimx_STEPMOTOR;
extern __IO uint16_t Toggle_Pulse;
/* 函数声明 ------------------------------------------------------------------*/
void STEPMOTOR_TIMx_Init(void);
#endif /* __STEPMOTOR_TIM_H__ */
定时器.c
#include "StepMotor/bsp_STEPMOTOR.h"
TIM_HandleTypeDef htimx_STEPMOTOR;
__IO uint16_t Toggle_Pulse = 3000; // 比较输出周期,值越小输出频率越快 (周期小,频率大) 分频后:28Mhz / 3000+3000 = 周期
/* 扩展变量 ------------------------------------------------------------------*/
/* 私有函数原形 --------------------------------------------------------------*/
/* 函数体 --------------------------------------------------------------------*/
/**
* 函数功能: 驱动器相关GPIO初始化配置
* 输入参数: 无
* 返 回 值: 无
* 说 明: 无
*/
static void STEPMOTOR_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* 引脚端口时钟使能 */
STEPMOTOR_TIM_GPIO_CLK_ENABLE();
STEPMOTOR_DIR_GPIO_CLK_ENABLE();
STEPMOTOR_ENA_GPIO_CLK_ENABLE();
/* 驱动器脉冲控制引脚IO初始化 */
GPIO_InitStruct.Pin = STEPMOTOR_TIM_PUL_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AFx_TIMx; // GPIO引脚用做TIM复用功能
HAL_GPIO_Init(STEPMOTOR_TIM_PUL_PORT, &GPIO_InitStruct);
/* 驱动器方向控制引脚IO初始化 */
GPIO_InitStruct.Pin = STEPMOTOR_DIR_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = 0; // GPIO引脚用做系统默认功能
HAL_GPIO_Init(STEPMOTOR_DIR_PORT, &GPIO_InitStruct);
/* 驱动器脱机使能控制引脚IO初始化 */
GPIO_InitStruct.Pin = STEPMOTOR_ENA_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; // 推挽
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = 0; // GPIO引脚用做系统默认功能
HAL_GPIO_Init(STEPMOTOR_ENA_PORT, &GPIO_InitStruct);
STEPMOTOR_DIR_FORWARD(); // 正转
STEPMOTOR_OUTPUT_ENABLE(); // 电机使能
}
/**
* 函数功能: 驱动器定时器初始化
* 输入参数: 无
* 返 回 值: 无
* 说 明: 无
*/
void STEPMOTOR_TIMx_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig; // 定时器时钟
TIM_MasterConfigTypeDef sMasterConfig; // 定时器主模式配置
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);
/* 定时器比较输出配置 */
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);
}
/**
* 函数功能: 基本定时器硬件初始化配置
* 输入参数: htim_base:基本定时器句柄类型指针
* 返 回 值: 无
* 说 明: 该函数被HAL库内部调用
*/
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{
if(htim_base->Instance==STEPMOTOR_TIMx)
{
/* 基本定时器外设时钟使能 */
STEPMOTOR_TIM_RCC_CLK_ENABLE();
}
}
main.c
#include "main.h"
#include "stm32f4xx_hal.h"
#include "StepMotor/bsp_STEPMOTOR.h"
#include "key/bsp_key.h"
int main(void)
{
/* 复位所有外设,初始化Flash接口和系统滴答定时器 */
HAL_Init();
/* 配置系统时钟 */
SystemClock_Config();
/* 初始化按键配置 */
KEY_GPIO_Init();
/* 初始化定时器配置 */
STEPMOTOR_TIMx_Init();
/* 确定定时器 */
HAL_TIM_Base_Start(&htimx_STEPMOTOR);
/* 启动比较输出并使能中断 */
HAL_TIM_OC_Start_IT(&htimx_STEPMOTOR,STEPMOTOR_TIM_CHANNEL_x);
/* 禁止输出 */
TIM_CCxChannelCmd(STEPMOTOR_TIMx,STEPMOTOR_TIM_CHANNEL_x,TIM_CCx_DISABLE);
while (1)
{
if(KEY1_StateRead() == KEY_DOWN) // 电机转动
{
TIM_CCxChannelCmd(STEPMOTOR_TIMx,STEPMOTOR_TIM_CHANNEL_x,TIM_CCx_ENABLE);
}
if(KEY2_StateRead() == KEY_DOWN) // 电机停止
{
TIM_CCxChannelCmd(STEPMOTOR_TIMx,STEPMOTOR_TIM_CHANNEL_x,TIM_CCx_DISABLE);
}
HAL_Delay(100);
}
}
/**
* 函数功能: 定时器比较输出中断回调函数
* 输入参数: htim:定时器句柄指针
* 返 回 值: 无
* 说 明: 无
*/
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
{
uint32_t count;
uint32_t tmp;
count=__HAL_TIM_GET_COUNTER(&htimx_STEPMOTOR); // 获取比较寄存器的值
tmp = STEPMOTOR_TIM_PERIOD & (count+Toggle_Pulse); // STEPMOTOR_TIM_PERIOD = 0xffff
__HAL_TIM_SET_COMPARE(&htimx_STEPMOTOR,STEPMOTOR_TIM_CHANNEL_x,tmp); // 重新设置比较寄存器的值 改变频率
}
捕获比较中断的位与相当妙当捕获比较寄存器的值溢出时有重新开始。只要源源不断的脉冲输出到驱动器的CLK就可以让步进电机不停的转。
定时器.h
#ifndef __STEPMOTOR_TIM_H__
#define __STEPMOTOR_TIM_H__
#include "stm32f4xx_hal.h"
#define STEPMOTOR_TIMx TIM8
#define STEPMOTOR_TIM_RCC_CLK_ENABLE() __HAL_RCC_TIM8_CLK_ENABLE()
#define STEPMOTOR_TIM_RCC_CLK_DISABLE() __HAL_RCC_TIM8_CLK_DISABLE()
#define STEPMOTOR_TIMx_IRQn TIM8_CC_IRQn
#define STEPMOTOR_TIMx_IRQHandler TIM8_CC_IRQHandler
// CLK 接定时器8的通道1
#define STEPMOTOR_TIM_CHANNEL_x TIM_CHANNEL_1
#define STEPMOTOR_TIM_GPIO_CLK_ENABLE() __HAL_RCC_GPIOI_CLK_ENABLE()
#define STEPMOTOR_TIM_PUL_PORT GPIOI
#define STEPMOTOR_TIM_PUL_PIN GPIO_PIN_5
#define GPIO_AFx_TIMx GPIO_AF3_TIM8
// 方向控制
#define STEPMOTOR_DIR_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
#define STEPMOTOR_DIR_PORT GPIOD
#define STEPMOTOR_DIR_PIN GPIO_PIN_3
#define GPIO_PIN_AF_AS_SYS GPIO_AF0_RTC_50Hz
// 使能控制
#define STEPMOTOR_ENA_GPIO_CLK_ENABLE() __HAL_RCC_GPIOD_CLK_ENABLE()
#define STEPMOTOR_ENA_PORT GPIOD
#define STEPMOTOR_ENA_PIN GPIO_PIN_7
#define STEPMOTOR_DIR_FORWARD() // 方向 HAL_GPIO_WritePin(STEPMOTOR_DIR_PORT,STEPMOTOR_DIR_PIN,GPIO_PIN_SET)
#define STEPMOTOR_DIR_REVERSAL() HAL_GPIO_WritePin(STEPMOTOR_DIR_PORT,STEPMOTOR_DIR_PIN,GPIO_PIN_RESET)
#define STEPMOTOR_OUTPUT_ENABLE() // 使能 HAL_GPIO_WritePin(STEPMOTOR_ENA_PORT,STEPMOTOR_ENA_PIN,GPIO_PIN_RESET)
#define STEPMOTOR_OUTPUT_DISABLE() HAL_GPIO_WritePin(STEPMOTOR_ENA_PORT,STEPMOTOR_ENA_PIN,GPIO_PIN_SET)
// 定义定时器预分频,定时器实际时钟频率为:168MHz/(STEPMOTOR_TIMx_PRESCALER+1)
#define STEPMOTOR_TIM_PRESCALER 5 // 步进电机驱动器细分设置为: 32 细分
//#define STEPMOTOR_TIM_PRESCALER 9 // 步进电机驱动器细分设置为: 16 细分
//#define STEPMOTOR_TIM_PRESCALER 19 // 步进电机驱动器细分设置为: 8 细分
//#define STEPMOTOR_TIM_PRESCALER 39 // 步进电机驱动器细分设置为: 4 细分
//#define STEPMOTOR_TIM_PRESCALER 79 // 步进电机驱动器细分设置为: 2 细分
//#define STEPMOTOR_TIM_PRESCALER 159 // 步进电机驱动器细分设置为: 1 细分
// 定义定时器周期,输出比较模式周期设置为0xFFFF
#define STEPMOTOR_TIM_PERIOD 0xFFFF
// 定义高级定时器重复计数寄存器值
#define STEPMOTOR_TIM_REPETITIONCOUNTER 0
extern TIM_HandleTypeDef htimx_STEPMOTOR;
extern __IO uint16_t Toggle_Pulse;
void STEPMOTOR_TIMx_Init(void);
#endif /* __STEPMOTOR_TIM_H__ */
定时器.c
#include "StepMotor/bsp_STEPMOTOR.h"
TIM_HandleTypeDef htimx_STEPMOTOR;
__IO uint16_t Toggle_Pulse = 3000; // 比较输出周期,值越小输出频率越快
static void STEPMOTOR_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* 引脚端口时钟使能 */
STEPMOTOR_TIM_GPIO_CLK_ENABLE();
STEPMOTOR_DIR_GPIO_CLK_ENABLE();
STEPMOTOR_ENA_GPIO_CLK_ENABLE();
/* 驱动器脉冲控制引脚IO初始化 */
GPIO_InitStruct.Pin = STEPMOTOR_TIM_PUL_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AFx_TIMx; // GPIO引脚用做TIM复用功能
HAL_GPIO_Init(STEPMOTOR_TIM_PUL_PORT, &GPIO_InitStruct);
/* 驱动器方向控制引脚IO初始化 */
GPIO_InitStruct.Pin = STEPMOTOR_DIR_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF0_TRACE; // GPIO引脚用做系统默认功能
HAL_GPIO_Init(STEPMOTOR_DIR_PORT, &GPIO_InitStruct);
/* 驱动器脱机使能控制引脚IO初始化 */
GPIO_InitStruct.Pin = STEPMOTOR_ENA_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF0_TRACE; // GPIO引脚用做系统默认功能
HAL_GPIO_Init(STEPMOTOR_ENA_PORT, &GPIO_InitStruct);
STEPMOTOR_DIR_FORWARD(); // 正转
STEPMOTOR_OUTPUT_ENABLE(); // 使能
}
/**
* 函数功能: 驱动器定时器初始化
* 输入参数: 无
* 返 回 值: 无
* 说 明: 无
*/
void STEPMOTOR_TIMx_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig; // 定时器时钟
TIM_MasterConfigTypeDef sMasterConfig; // 定时器主模式配置
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);
/* 定时器比较输出配置 */
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);
}
/**
* 函数功能: 基本定时器硬件初始化配置
* 输入参数: htim_base:基本定时器句柄类型指针
* 返 回 值: 无
* 说 明: 该函数被HAL库内部调用
*/
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{
if(htim_base->Instance==STEPMOTOR_TIMx)
{
/* 基本定时器外设时钟使能 */
STEPMOTOR_TIM_RCC_CLK_ENABLE();
}
}
main.c
#include "stm32f4xx_hal.h"
#include "StepMotor/bsp_STEPMOTOR.h"
#include "key/bsp_key.h"
/* 私有类型定义 --------------------------------------------------------------*/
/* 私有宏定义 ----------------------------------------------------------------*/
#define STEPMOTOR_MICRO_STEP 32 // 步进电机驱动器细分,必须与驱动器实际设置对应
/* 私有变量 ------------------------------------------------------------------*/
uint8_t dir=0; // 0 :顺时针 1:逆时针
uint8_t ena=0; // 0 :正常运行 1:停机
/* 扩展变量 ------------------------------------------------------------------*/
extern __IO uint16_t Toggle_Pulse; /* 步进电机速度控制,可调节范围为 300 -- 3500 ,值越小速度越快 */
/*
* 当步进电机驱动器细分设置为1时,每200个脉冲步进电机旋转一周
* 为32时,每6400个脉冲步进电机旋转一周
* 下面以设置为32时为例讲解:
* pulse_count用于记录输出脉冲数量,pulse_count为脉冲数的两倍,因为一个脉冲计数2次
* 比如当pulse_count=12800时,实际输出6400个完整脉冲。
* 这样可以非常方便步进电机的实际转动圈数,就任意角度都有办法控制输出。
* 如果步进电机驱动器的细分设置为其它值,pulse_count也要做相应处理
*
*/
__IO uint32_t pulse_count = 0; /* 脉冲计数,一个完整的脉冲会增加2 */
/* 私有函数原形 --------------------------------------------------------------*/
/* 函数体 --------------------------------------------------------------------*/
/**
* 函数功能: 系统时钟配置
* 输入参数: 无
* 返 回 值: 无
* 说 明: 无
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct;
RCC_ClkInitTypeDef RCC_ClkInitStruct;
__HAL_RCC_PWR_CLK_ENABLE(); // 使能PWR时钟
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); // 设置调压器输出电压级别1
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; // 外部晶振,8MHz
RCC_OscInitStruct.HSEState = RCC_HSE_ON; // 打开HSE
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; // 打开PLL
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; // PLL时钟源选择HSE
RCC_OscInitStruct.PLL.PLLM = 8; // 8分频MHz
RCC_OscInitStruct.PLL.PLLN = 336; // 336倍频
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2; // 2分频,得到168MHz主时钟
RCC_OscInitStruct.PLL.PLLQ = 7; // USB/SDIO/随机数产生器等的主PLL分频系数
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; // 系统时钟:168MHz
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // AHB时钟: 168MHz
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; // APB1时钟:42MHz
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; // APB2时钟:84MHz
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);
HAL_RCC_EnableCSS(); // 使能CSS功能,优先使用外部晶振,内部时钟源为备用
// HAL_RCC_GetHCLKFreq()/1000 1ms中断一次
// HAL_RCC_GetHCLKFreq()/100000 10us中断一次
// HAL_RCC_GetHCLKFreq()/1000000 1us中断一次
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); // 配置并启动系统滴答定时器
/* 系统滴答定时器时钟源 */
HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);
/* 系统滴答定时器中断优先级配置 */
HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}
/**
* 函数功能: 主函数.
* 输入参数: 无
* 返 回 值: 无
* 说 明: 无
*/
int main(void)
{
/* 复位所有外设,初始化Flash接口和系统滴答定时器 */
HAL_Init();
/* 配置系统时钟 */
SystemClock_Config();
KEY_GPIO_Init();
/* 高级控制定时器初始化并配置PWM输出功能 */
STEPMOTOR_TIMx_Init();
/* 开启定时器 */
HAL_TIM_Base_Start(&htimx_STEPMOTOR);
/* 开启比较输出 并启动比较输出中断*/
HAL_TIM_OC_Start_IT(&htimx_STEPMOTOR,STEPMOTOR_TIM_CHANNEL_x);
/* 失能 */
TIM_CCxChannelCmd(STEPMOTOR_TIMx,STEPMOTOR_TIM_CHANNEL_x,TIM_CCx_DISABLE);
/* 无限循环 */
while (1)
{
if(KEY1_StateRead() == KEY_DOWN)
{
pulse_count=0;
ena=0;
TIM_CCxChannelCmd(STEPMOTOR_TIMx,STEPMOTOR_TIM_CHANNEL_x,TIM_CCx_ENABLE);
}
if(KEY2_StateRead() == KEY_DOWN) // 功能调节
{
Toggle_Pulse-=50;
if(Toggle_Pulse<50) // 最快速度限制
Toggle_Pulse=50;
}
if(KEY3_StateRead() == KEY_DOWN)
{
Toggle_Pulse+=100;
if(Toggle_Pulse>3500) // 最慢速度限制
Toggle_Pulse=3500;
}
if(KEY4_StateRead() == KEY_DOWN)
{
if(dir==0)
{
STEPMOTOR_DIR_REVERSAL(); // 反转
dir=1;
}
else
{
STEPMOTOR_DIR_FORWARD(); // 正转
dir=0;
}
}
if(KEY5_StateRead() == KEY_DOWN)
{
if(ena==1)
{
STEPMOTOR_OUTPUT_ENABLE(); // 正常运行
HAL_TIM_OC_Start_IT(&htimx_STEPMOTOR,STEPMOTOR_TIM_CHANNEL_x);
ena=0;
}
else
{
STEPMOTOR_OUTPUT_DISABLE();// 停机
HAL_TIM_OC_Stop_IT(&htimx_STEPMOTOR,STEPMOTOR_TIM_CHANNEL_x);
ena=1;
}
}
if(pulse_count >= STEPMOTOR_MICRO_STEP*200*2*10) // 转动10圈后停机 // 32 * 200 =6400 2:因为一个脉冲计数2次 10 :转10圈
{
TIM_CCxChannelCmd(STEPMOTOR_TIMx,STEPMOTOR_TIM_CHANNEL_x,TIM_CCx_DISABLE);
}
}
}
/**
* 函数功能: 定时器比较输出中断回调函数
* 输入参数: htim:定时器句柄指针
* 返 回 值: 无
* 说 明: 无
*/
void HAL_TIM_OC_DelayElapsedCallback(TIM_HandleTypeDef *htim)
{
__IO uint32_t count;
__IO uint32_t tmp;
count =__HAL_TIM_GET_COUNTER(&htimx_STEPMOTOR);
tmp = STEPMOTOR_TIM_PERIOD & (count+Toggle_Pulse);
__HAL_TIM_SET_COMPARE(&htimx_STEPMOTOR,STEPMOTOR_TIM_CHANNEL_x,tmp);
pulse_count++; // 脉冲数
}
这里脉冲数一个脉冲会加两次 (pulse_count++; // 脉冲数),因为是翻转模式一个脉冲有上下沿。所以一个脉冲会进两次输出比较中断。(注意这里是输出翻转模式不是PWM输出,只有翻转模式才可以改变频率,而PWM输出不能。PWM输出是改变占空比的)。