1.硬件环境准备
1.1.ACM32F403开发板
1.2.高精密步进电机套装(高精密步进电机、光电旋转编码器、TB6600驱动器、限位开关等)
1.3.接口板
用于连接高精密步进电机套装与ACM32F403开发板的连接
1.3.1.原理图
1.3.2.接口板3D效果图
2.硬件环境连接
ACM32F403开发板通过接口板与TB6600驱动器、光电旋转编码器、限位开关进行连接,将高精密步进电机与TB6600驱动器进行连接,接口板供12V电源。
3.TIM1定时器
高级控制定时器 TIM1 由一个 16 位的自动装载计数器组成,它由一个可编程的预分频器驱动。它适合多种用途,包含测量输入信号的脉冲宽度(输入捕获),或者产生输出波形(输出比较、 PWM、嵌入死区时间的互补 PWM 等)。使用定时器预分频器和系统时钟控制预分频器,可以实现脉冲宽度和波形周期从几个微秒到几个毫秒的调节。高级控制定时器和通用定时器是完全独立的,它们不共享任何资源,但它们可以同步操作。主要特性如下:
⚫ 16 位向上、向下、向上/下自动装载计数器
⚫ 16 位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为 1~65536 之间的任意数值
⚫ 多达 4 个独立通道
- 输入捕获
- 输出比较
- PWM 生成(边沿或中间对齐模式)
- 单脉冲模式输出
⚫ 死区时间可编程的互补输出
⚫ 使用外部信号控制定时器和定时器互联的同步电路
⚫ 允许在指定数目的计数器周期之后更新定时器寄存器的重复计数器
⚫ 刹车输入信号可以将定时器输出信号置于复位状态或者一个已知状态
⚫ 如下事件发生时产生中断/DMA:
- 更新:计数器向上溢出/向下溢出,计数器初始化(通过软件或者内部/外部触发)
- 触发事件: (计数器启动、停止、初始化或者由内部/外部触发计数)
- 输入捕获
- 输出比较
- 刹车信号输入
⚫ 支持针对定位的增量(正交)编码器和霍尔传感器电路
⚫ 触发输入作为外部时钟或者按周期的电流管理
4.实现功能
通过TIM1的通道1输出PWM作为TB6600驱动器的脉冲输入信号,控制电机转速;通过PC9控制TB6600的DIR输入,控制电机的转向;通过PC10和PC11作为限位开关的输入,当触发限位开关后,立即切换电机的运转方向。
5.程序实现
5.1.高精密电机驱动程序
#include "bsp_motor.h"
void bsp_MotorInitGPIO(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
System_Module_Enable(EN_GPIOCD);
/* Direction */
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Alternate = GPIO_FUNCTION_0;
GPIO_Init(GPIOC, &GPIO_InitStruct);
GPIO_WriteBit(GPIOC, GPIO_PIN_9, Bit_SET);
/* Limit Switch */
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_10 | GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Alternate = GPIO_FUNCTION_0;
GPIO_Init(GPIOC, &GPIO_InitStruct);
}
void bsp_MotorInitTIM1(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
TIM_Base_InitTypeDef TIM_Base_InitStruct;
TIM_OC_InitTypeDef TIM_OC_InitStruct;
uint32_t TIM_Clock;
System_Module_Enable(EN_GPIOCD);
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Alternate = GPIO_FUNCTION_2;
GPIO_Init(GPIOC, &GPIO_InitStruct);
System_Module_Enable(EN_TIM1);
if (System_Get_SystemClock() == System_Get_APBClock())
{
TIM_Clock = System_Get_APBClock();
}
else
{
TIM_Clock = System_Get_APBClock() * 2;
}
TIM_Base_InitStruct.Prescaler = (TIM_Clock / 1000000) - 1;
TIM_Base_InitStruct.Period = 1000 - 1;
TIM_Base_InitStruct.RepetitionCounter = 0;
TIM_Base_InitStruct.CounterMode = TIM_COUNTERMODE_UP;
TIM_Base_InitStruct.ClockDivision = TIM_CLOCKDIVISION_DIV1;
TIM_TimeBase_Init(TIM1, &TIM_Base_InitStruct);
TIM_OC_InitStruct.OCMode = OUTPUT_MODE_PWM1;
TIM_OC_InitStruct.Pulse = (TIM_Base_InitStruct.Period + 1) / 2;
TIM_OC_InitStruct.OCPolarity = OUTPUT_POL_ACTIVE_HIGH;
TIM_OC_InitStruct.OCNPolarity = OUTPUT_POL_ACTIVE_HIGH;
TIM_OC_InitStruct.OCFastMode = OUTPUT_FAST_MODE_DISABLE;
TIM_OC_InitStruct.OCIdleState = OUTPUT_IDLE_STATE_0;
TIM_OC_InitStruct.OCNIdleState = OUTPUT_IDLE_STATE_0;
TIM_OC1Init(TIM1, &TIM_OC_InitStruct);
TIM_CCxCmd(TIM1, TIM_CHANNEL_1, TIM_CCx_Enable);
TIM_Cmd(TIM1, ENABLE);
}
void bsp_MotorInit(void)
{
bsp_MotorInitGPIO();
bsp_MotorInitTIM1();
bsp_MotorRunning();
}
void bsp_MotorRunning(void)
{
TIM_CtrlPWMOutputs(TIM1, ENABLE);
}
void bsp_MotorSuspend(void)
{
TIM_CtrlPWMOutputs(TIM1, DISABLE);
}
void bsp_MotorSwitchDirection(void)
{
bsp_MotorSuspend();
if (GPIO_ReadOutputDataBit(GPIOC, GPIO_PIN_9) == RESET)
{
GPIO_WriteBit(GPIOC, GPIO_PIN_9, Bit_SET);
}
else
{
GPIO_WriteBit(GPIOC, GPIO_PIN_9, Bit_RESET);
}
bsp_MotorRunning();
}
uint8_t bsp_MotorReadLimitSwitchPinLevel(uint8_t Index)
{
uint8_t PinLevel = 0;
switch (Index)
{
case 1:
PinLevel = GPIO_ReadInputDataBit(GPIOC, GPIO_PIN_10);
break;
case 2:
PinLevel = GPIO_ReadInputDataBit(GPIOC, GPIO_PIN_11);
break;
default:
break;
}
return (PinLevel);
}
5.2.限位开关逻辑控制程序
#include "key.h"
#include "bsp_key.h"
#include "bsp_motor.h"
#include "multi_button.h"
struct Button keyUser;
struct Button keyMotorRight;
struct Button keyMotorLeft;
volatile uint8_t KeyRegisterFlag = 0;
void KEY_UserHandler(void *btn)
{
struct Button *handle = (struct Button *)btn;
if (handle->button_id == 0)
{
printf("\r\n%s", __FUNCTION__);
}
}
void KEY_MotorHandler(void *btn)
{
struct Button *handle = (struct Button *)btn;
if ((handle->button_id == 1) || (handle->button_id == 2))
{
bsp_MotorSwitchDirection();
}
}
void KEY_Init(void)
{
bsp_KeyInit();
button_init(&keyUser, bsp_KeyReadPinLevel, RESET, 0);
button_attach(&keyUser, PRESS_DOWN, KEY_UserHandler);
button_start(&keyUser);
button_init(&keyMotorRight, bsp_MotorReadLimitSwitchPinLevel, RESET, 1);
button_attach(&keyMotorRight, PRESS_DOWN, KEY_MotorHandler);
button_start(&keyMotorRight);
button_init(&keyMotorLeft, bsp_MotorReadLimitSwitchPinLevel, RESET, 2);
button_attach(&keyMotorLeft, PRESS_DOWN, KEY_MotorHandler);
button_start(&keyMotorLeft);
KeyRegisterFlag = 1;
}
6.运行效果
Motor Running
7.工程源码