使用STM32的通用定时器定时,控制步进电机正反转和启停。
学习目的:学习步进电机和步进电机驱动器的基本使用方法。
串口(TTL-USB TO USART):
CH340的收发引脚与STM32的发收引脚相连。
?? ?RX<--->PA9
?? ?TX<--->PA10
步进电机驱动器:
?? ?ENA+ <---> 3V3
?? ?ENA- <---> PB12
?? ?DIR+ <---> 3V3
?? ?DIR- <---> PB14
?? ?PUL+ <---> 3V3
?? ?PUL- <---> PC6
头文件
#ifndef __BSP_STEP_MOTOR_INIT_H
#define __BSP_STEP_MOTOR_INIT_H
#include "stm32f1xx.h"
#include "stm32f1xx_hal.h"
#define MOTOR_PUL_TIM TIM2
#define MOTOR_PUL_CLK_ENABLE() __HAL_RCC_TIM2_CLK_ENABLE()
#define MOTOR_PUL_IRQn TIM2_IRQn
#define MOTOR_PUL_IRQHandler TIM2_IRQHandler
//引脚定义
//Motor 使能
#define MOTOR_EN_PIN GPIO_PIN_12
#define MOTOR_EN_GPIO_PORT GPIOB
#define MOTOR_EN_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
//Motor 方向
#define MOTOR_DIR_PIN GPIO_PIN_14
#define MOTOR_DIR_GPIO_PORT GPIOB
#define MOTOR_DIR_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
//Motor 脉冲
#define MOTOR_PUL_PIN GPIO_PIN_6
#define MOTOR_PUL_GPIO_PORT GPIOC
#define MOTOR_PUL_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()
/************************************************************/
#define HIGH GPIO_PIN_SET //高电平
#define LOW GPIO_PIN_RESET //低电平
#define ON LOW //开
#define OFF HIGH //关
#define CW HIGH //顺时针
#define CCW LOW //逆时针
//控制使能引脚
/* 带参宏,可以像内联函数一样使用 */
#define MOTOR_EN(x) HAL_GPIO_WritePin(MOTOR_EN_GPIO_PORT,MOTOR_EN_PIN,x)
#define MOTOR_PUL(x) HAL_GPIO_WritePin(MOTOR_PUL_GPIO_PORT,MOTOR_PUL_PIN,x)
#define MOTOR_DIR(x) HAL_GPIO_WritePin(MOTOR_DIR_GPIO_PORT,MOTOR_DIR_PIN,x)
#define MOTOR_PUL_T() HAL_GPIO_TogglePin(MOTOR_PUL_GPIO_PORT,MOTOR_PUL_PIN);
extern TIM_HandleTypeDef TIM_TimeBaseStructure;
void TIMx_Configuration(void);
extern void stepper_Init(void);
extern void stepper_turn(int tim,float angle,float subdivide,uint8_t dir);
#endif /* __STEP_MOTOR_INIT_H */
#include "./stepper/bsp_stepper_init.h"
#include "./led/bsp_led.h"
#include "stm32f1xx.h"
TIM_HandleTypeDef TIM_TimeBaseStructure;
/**
* @brief 通用定时器 TIMx,x[6,7]中断优先级配置
* @param 无
* @retval 无
*/
static void TIMx_NVIC_Configuration(void)
{
/* 外设中断配置 */
HAL_NVIC_SetPriority(MOTOR_PUL_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(MOTOR_PUL_IRQn);
}
/*
* 注意:TIM_TimeBaseInitTypeDef结构体里面有5个成员,TIM6和TIM7的寄存器里面只有
* TIM_Prescaler和TIM_Period,所以使用TIM6和TIM7的时候只需初始化这两个成员即可,
* 另外三个成员是通用定时器和高级定时器才有.
*-----------------------------------------------------------------------------
* TIM_Prescaler 都有
* TIM_CounterMode TIMx,x[6,7]没有,其他都有(通用定时器)
* TIM_Period 都有
* TIM_ClockDivision TIMx,x[6,7]没有,其他都有(通用定时器)
* TIM_RepetitionCounter TIMx,x[1,8]才有(高级定时器)
*-----------------------------------------------------------------------------
*/
static void TIM_Mode_Config(void)
{
MOTOR_PUL_CLK_ENABLE();
TIM_TimeBaseStructure.Instance = MOTOR_PUL_TIM;
/* 累计 TIM_Period个后产生一个更新或者中断*/
//当定时器从0计数到4999,即为5000次,为一个定时周期
TIM_TimeBaseStructure.Init.Period = 300-1;
// 通用控制定时器时钟源TIMxCLK = HCLK/2=84MHz
// 设定定时器频率为=TIMxCLK/(TIM_Prescaler+1)=1MHz
TIM_TimeBaseStructure.Init.Prescaler = 84-1;
// 计数方式
TIM_TimeBaseStructure.Init.CounterMode=TIM_COUNTERMODE_UP;
// 采样时钟分频
TIM_TimeBaseStructure.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
// 初始化定时器TIMx, x[2,5] [9,14]
HAL_TIM_Base_Init(&TIM_TimeBaseStructure);
// 开启定时器更新中断
HAL_TIM_Base_Start_IT(&TIM_TimeBaseStructure);
}
/**
* @brief 初始化通用定时器定时
* @param 无
* @retval 无
*/
void TIMx_Configuration(void)
{
TIMx_NVIC_Configuration();
TIM_Mode_Config();
}
/**
* @brief 引脚初始化
* @retval 无
*/
void stepper_Init()
{
/*定义一个GPIO_InitTypeDef类型的结构体*/
GPIO_InitTypeDef GPIO_InitStruct;
/*开启Motor相关的GPIO外设时钟*/
MOTOR_DIR_GPIO_CLK_ENABLE();
MOTOR_PUL_GPIO_CLK_ENABLE();
MOTOR_EN_GPIO_CLK_ENABLE();
/*选择要控制的GPIO引脚*/
GPIO_InitStruct.Pin = MOTOR_DIR_PIN;
/*设置引脚的输出类型为推挽输出*/
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull =GPIO_PULLUP;
/*设置引脚速率为高速 */
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
/*Motor 方向引脚 初始化*/
HAL_GPIO_Init(MOTOR_DIR_GPIO_PORT, &GPIO_InitStruct);
/*Motor 脉冲引脚 初始化*/
GPIO_InitStruct.Pin = MOTOR_PUL_PIN;
HAL_GPIO_Init(MOTOR_PUL_GPIO_PORT, &GPIO_InitStruct);
/*Motor 使能引脚 初始化*/
GPIO_InitStruct.Pin = MOTOR_EN_PIN;
HAL_GPIO_Init(MOTOR_EN_GPIO_PORT, &GPIO_InitStruct);
/*关掉使能*/
MOTOR_EN(LOW);
/*初始化定时器*/
TIMx_Configuration();
}
/**
* @brief 定时器中断函数
* @note 无
* @retval 无
*/
void MOTOR_PUL_IRQHandler (void)
{
HAL_TIM_IRQHandler(&TIM_TimeBaseStructure);
}
/**
* @brief 回调函数
* @note 无
* @retval 无
*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim==(&TIM_TimeBaseStructure))
{
MOTOR_PUL_T();//翻转IO口达到脉冲的效果
}
}
主函数?
?
#include "main.h"
#include <stdlib.h>
#include "./stepper/bsp_stepper_init.h"
#include "./usart/bsp_debug_usart.h"
#include "./led/bsp_led.h"
#include "./key/bsp_key.h"
/**
* @brief 主函数
* @param 无
* @retval 无
*/
int main(void)
{
int i=0,j=0;
int dir_val=0;
int en_val=0;
/* 初始化系统时钟为72MHz */
SystemClock_Config();
/*初始化USART 配置模式为 115200 8-N-1,中断接收*/
DEBUG_USART_Config();
printf("按下按键1可修改旋转方向,按下按键2可修改使能\r\n");
/*LED初始化*/
LED_GPIO_Config();
/*按键初始化*/
Key_GPIO_Config();
/*步进电机初始化*/
stepper_Init();
MOTOR_EN(HIGH);
while(1)
{
if( Key_Scan(KEY1_GPIO_PORT,KEY1_PIN) == KEY_ON )
{
// LED1 取反
LED1_TOGGLE;
/*改变方向*/
dir_val=(++i % 2) ? CW : CCW;
MOTOR_DIR(dir_val);
}
if( Key_Scan(KEY2_GPIO_PORT,KEY2_PIN) == KEY_ON )
{
// LED2 取反
LED2_TOGGLE;
/*改变使能*/
en_val=(++j % 2) ? CW : CCW;
MOTOR_EN(en_val);
}
}
}
/**
* @brief System Clock Configuration
* The system Clock is configured as follow :
* System Clock source = PLL (HSE)
* SYSCLK(Hz) = 72000000
* HCLK(Hz) = 72000000
* AHB Prescaler = 1
* APB1 Prescaler = 2
* APB2 Prescaler = 1
* HSE Frequency(Hz) = 8000000
* HSE PREDIV1 = 2
* PLLMUL = 9
* Flash Latency(WS) = 0
* @param None
* @retval None
*/
void SystemClock_Config(void)
{
RCC_ClkInitTypeDef clkinitstruct = {0};
RCC_OscInitTypeDef oscinitstruct = {0};
/* Enable HSE Oscillator and activate PLL with HSE as source */
oscinitstruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
oscinitstruct.HSEState = RCC_HSE_ON;
oscinitstruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
oscinitstruct.PLL.PLLState = RCC_PLL_ON;
oscinitstruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
oscinitstruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&oscinitstruct)!= HAL_OK)
{
/* Initialization Error */
while(1);
}
/* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
clocks dividers */
clkinitstruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
clkinitstruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
clkinitstruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
clkinitstruct.APB2CLKDivider = RCC_HCLK_DIV1;
clkinitstruct.APB1CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&clkinitstruct, FLASH_LATENCY_2)!= HAL_OK)
{
/* Initialization Error */
while(1);
}
}