1.57步进电机基本介绍
大型步进电机通常用于实际工业设备中,它们有。根据电机外部尺寸的不同,可分为42、57、86、110步进电机;另外,。用得最多,最常见的是两相4线步进电机,步距角为1.8°,旋转一圈需要200个脉冲。 (360/1.8 = 200)
57步进电机长宽57mm。两相四线双极电机。A (黑色),A - (绿),B (红),B-(蓝色)。电机制造商通常会解释。用数字万用表测量 A ,A- 会发现是相通的,B ,B-也是。
相电流为3A,所以必须有一个特殊的驱动芯片。扭矩为1.2牛每米。
2.频率特性:扭矩和频率曲线
电机转得越快,频率就越大。如图所示:当频率为10时khz一下。扭矩稳定。当超过10时khz扭矩急剧下降。因此,步进电机通常用于低速。
类似28BYJ-使用这些小尺寸、低扭矩的步进电机ULN2003这种驱动芯片与控制器一起使用是可行的,但在实际工业应用中,经常使用42、57、86、110等系列步进电机,需要此外,为了充分发挥其正常运行细分驱动优点往往需要更复杂的驱动电路。好在,很久之前很多半导体公司已经看到了这部分商机,专门为驱动步进电机设计了驱动芯片,种类繁多,功能齐全,同时也使得我们控制步进电机运动非常简单。 当然,步进电机也可以直接构建,就像之前介绍的直流刷电机驱动一样MOS桥式电路驱动,根据之前的节拍控制方法实现步进电机旋转,但如果自己构建电路驱动,程序处理将更加复杂,特别是需要更复杂的程序来实现细分驱动,硬件成本没有优势。现有的专用步进电机芯片种类繁多,可根据电机参数选择对应的驱动芯片,价格也非常有优势,重点是驱动起来容易很多。
TOSHIBA(东芝)公司TB67S109A芯片是一种配备PWM斩波器的两相双极步进电机驱动芯片。内置时钟解码器。BiCD工艺制作,额定值为50V/4.0A。允许全步、半步、1/4、1/8、1/16、1/32步(细分)运行,即最高细分为32。TB67S109A芯片内部逻辑电路见图。
1.TB67S109A介绍芯片重要引脚
CLK上升沿转一个步距角,下降沿不变。ENALE 为0H桥关闭是高正常运行。
CW/CCW
2.选择分辨率
驱动器上有拨码开关()分辨率的选择。关于分辨率的拨码开关有三种选择:
当为000时为待机模式,这里的半步有两种类型。(A与B)
MO:一步完成后,半步输出低电平。
1.时序图如下:
2.半步A的时序图如下:
3.半步B时序图如下:
四分之一的时序图如下:
四分之一正负38%以上。这些图片都在手册上,可以参考相关手册。还有1632个细分。你可以列出每一步的节拍,帮助你更好地理解每一步。
3.TB67S109A芯片介绍及接线
1.TB67S109A芯片的介绍
TB67S109A步进电机驱动是一种专业的两相步进电机驱动,见图。通过3位拨码开关选择7档细分控制,可以实现正反转控制(1,2/A,2/B,通过3位拨码开关选择8档电流控制(00.5A,1A,1.5A,2A,2.5A,2.8A,3.0A,3.5A)。适用于驱动57型和42型混合步进电机。能达到低振动、低噪音、高速驱动电机的效果。
信号输入端有两个正负引脚。注意电压不能大于40V否则,驱动器可能会被烧毁。
2.TB67S109A芯片的接线
输入信号有三种方式,即:①迈进脉冲信号PUL ,PUL-;②方向电平信号DIR ,DIR- ; ③脱机(关闭)信号EN ,EN-。输入信号接口有两种连接方式,用户可以根据 需要采用 事实上,光耦芯片也用于驱动器的输入信号,因此我们的驱动目的是使光耦导通。
1.
共阳极接法:分别将PUL ,DIR ,EN 如果连接到控制系统的电源正极,则该电源为 5V/3.3V如果电源大于,可以直接接入 5V,外部必须增加限流电阻R,确保驱动器内部的莲藕提供8-15mA驱动电流一般为24V电压,选择2K欧的电阻。如下图
共阴极接法:分别将PUL-,DIR-,EN-连接到控制系统的地线(GND)上。如果控制系统信号线是这样的话 5V/3.3V 如果信号电压大于,可以直接接入 5V,外部必须增加限流电阻R,确保驱动器内部的莲藕提供8-15mA驱动电流一般为24V电压,选择2K欧的电阻。
4.分辨率对应于电流细分实物拨码开关。
5.dome的实例
1.实现基本旋转
接收定时器的输出翻转功能CLK引脚,驱动器采用共阳连接法。
#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 SEPMOTOR_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__ */
#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();
}
}
#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就可以让步进电机不停的转。
2. 旋转控制实现
#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__ */
#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();
}
}
#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++; // 脉冲数),因为是翻转模式一个脉冲有上下沿。所以一个脉冲会进两次输出比较中断。