配置

单片机型号:STM32F104ZGT6

步进电机:YK28HB40-01A

驱动器:YKD2204M-Plus

接线方式:

pu+:接对应的产生PWM的引脚,这里接PF9,对应TIM14_CH1通道!

pu-:接单片机的GND;

DR+:接单片机的3.3V(电机转动的方向固定)或者单片机的控制引脚这里是PF8

DR-:接单片机的GND;

这里没有使用驱动器的电机使能引脚!!!

-V:接24V的负极

+V:接24V的正极

A+:接的步进电机的红线(需要参考对应的原理图,不同的电机接法存在差异)

A-:步进电机的蓝线

B+:步进电机的绿线

B-:步进电机的黑线

采用定时器主从模式,发送固定脉冲,控制步进电机的转动;

比如在驱动器上,将脉冲调到1600挡位,表示当有1600个脉冲到来时,电机转动一周。如果输入800个脉冲,则电机就转动半圈;

主定时器采用TIM14_CH1;

从定时器采用TIM12_ITR3;

 

 表72在407中文手册370页;  表79在464页;  图165在446页;  图166在447页

代码部分

采用标准库进行开发,先创建好工程!

再创建一个pwm.c和pwm.h文件就可以驱动了!

pwm.c

#include "PWM.h"
#include "stm32f4xx.h" 

/*
*PF9  TIM14_CH1通道
*PF8	方向引脚
*/
void TIM14_PWM_Init(void)	//主定时器	//uint32_t arr,uint32_t psc
{	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14,ENABLE);  //使能定时器 14 时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE); 	//使能PORTF时钟
	 
	GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14); //GPIOF9 复用为定时器 14
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;           //GPIOF9
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;        //复用功能
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;	//速度100MHz
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;      //推挽复用输出
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;        //上拉
	GPIO_Init(GPIOF,&GPIO_InitStructure);              //初始化PF9

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;           //GPIOF8
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;        //功能
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;	//速度100MHz
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;      //复用推挽输出
	GPIO_Init(GPIOF,&GPIO_InitStructure);              //初始化PF8
	//TIM_InternalClockConfig()
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	TIM_TimeBaseStructure.TIM_Period =100-1; //arr; //设置自动重装载值  100-1
	TIM_TimeBaseStructure.TIM_Prescaler =1050-1;//psc; //设置预分频值
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim  0=TIM_CKD_DIV1
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
	TIM_TimeBaseInit(TIM14, &TIM_TimeBaseStructure); //根据指定的参数初始化 TIMx 的
	
	TIM_OCInitTypeDef TIM_OCInitStructure;
	TIM_OCStructInit(&TIM_OCInitStructure);	//默认的初始化
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择 PWM 模式 1
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	TIM_OCInitStructure.TIM_OCPolarity =TIM_OCPolarity_High;//输出极性高 //TIM_OCPolarity_Low; //输出极性低
	TIM_OCInitStructure.TIM_Pulse=50;//CCR
	TIM_OC1Init(TIM14, &TIM_OCInitStructure); //初始化 TIM

	//TIM_SelectMasterSlaveMode();
	//TIM_SelectOutputTrigger();
	TIM_OC1PreloadConfig(TIM14,TIM_OCPreload_Enable);	//通道1的CCR可以更改
	TIM_ARRPreloadConfig(TIM14,ENABLE);	//使能ARR预装载寄存器
	TIM_Cmd(TIM14, DISABLE); //使能 TIM14

}


void TIM12_Init(void)//从定时器
{
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM12,ENABLE);  //使能定时器 12 时钟
	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	TIM_TimeBaseStructure.TIM_Period = 65535; //设置自动重装载值  100-1
	TIM_TimeBaseStructure.TIM_Prescaler =1-1; //设置预分频值
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim  0=TIM_CKD_DIV1
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
	TIM_TimeBaseInit(TIM12, &TIM_TimeBaseStructure); //根据指定的参数初始化 TIMx 的
	
	//TIM_SelectMasterSlaveMode(TIM12,);
	TIM_SelectInputTrigger(TIM12,TIM_TS_ITR3);	//TIM14主   TIM12从:ITR3
	TIM_SelectSlaveMode(TIM12,TIM_SlaveMode_External1);//从模式
	TIM_ITConfig(TIM12,TIM_IT_Update,DISABLE);
	TIM_ARRPreloadConfig(TIM12,ENABLE);	//使能ARR预装载寄存器
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel=TIM8_BRK_TIM12_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStructure);
	
	TIM_Cmd(TIM12, DISABLE); //使能 TIM12
}


/**
uint16_t Num    发送的脉冲数(从定时器的ARR值)
uint8_t Dir     步进电机的旋转方向
uint16_t Speed	速度(更改主定时器的ARR值)
*/
void PWM_Output_Speed(uint16_t Num,uint8_t Dir,uint16_t Speed)
{
	if(Dir==1)
	{
		GPIO_ResetBits(GPIOF,GPIO_Pin_8);//正转
		}
	else
	{
		GPIO_SetBits(GPIOF,GPIO_Pin_8);  //反转
		}
	TIM_Cmd(TIM12, DISABLE);//关闭TIM12使能
	TIM_SetAutoreload(TIM12,Num);//从新设置ARR计数值
	TIM_GenerateEvent(TIM12,TIM_EventSource_Update);//配置由软件生成定时器事件,新修改ARR计数值后,马上软件更改一次事件
	TIM_Cmd(TIM12, ENABLE); //使能 TIM12
	TIM_ClearITPendingBit(TIM12,TIM_IT_Update);//清楚中断标志位
		
	TIM_ITConfig(TIM12,TIM_IT_Update,ENABLE);//开启定时器12的中断
	TIM_SetAutoreload(TIM14,Speed);//从新设置ARR计数值
	TIM_GenerateEvent(TIM14,TIM_EventSource_Update);//配置由软件生成定时器事件,新修改ARR计数值后,马上软件更改一次事件
	TIM_SetCompare1(TIM14,Speed/2);	//设置CCR的值为ARR的一半,占空比为50%
	TIM_GenerateEvent(TIM14,TIM_EventSource_CC1);//配置后由软件生成通道一的事件,马上生效
	TIM_Cmd(TIM14, ENABLE); //使能 TIM14	
}

void TIM8_BRK_TIM12_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM12,TIM_IT_Update) != RESET)
	{
		TIM_ClearITPendingBit(TIM12,TIM_IT_Update);
		TIM_Cmd(TIM12, DISABLE);//关闭TIM12使能
		TIM_Cmd(TIM14, DISABLE);//关闭TIM14使能
		TIM_ITConfig(TIM12,TIM_IT_Update,DISABLE);//关闭定时器12的中断
	}
}

pwm.h

#ifndef __PWM_H__
#define __PWM_H__

#include "stm32f4xx.h" 

void TIM14_PWM_Init(void);	//uint32_t arr,uint32_t psc
void TIM12_Init(void);
void PWM_Output_Speed(uint16_t Num,uint8_t Dir,uint16_t Speed);

#endif

main函数部分

#include "stm32f4xx.h"                  // Device header
#include "pwm.h"


int main()
{
	TIM14_PWM_Init();	//168M/168=1Mhz的计数频率,重装载值100,所以PWM频率为 1M/100=1Khz.
	TIM12_Init();
	
	PWM_Output_Speed(3200,0,40);//发送的脉冲数	步进电机的旋转方向	速度(更改主定时器的ARR值)
	
	while(1)
	{
	}
	
}



通过PWM_Output_Speed(3200,0,40);输入 3200个脉冲,电机逆时针转2圈。最后一位参数为速度;注意这里驱动器的挡位为1600(可以自己调整);

PWM_Output_Speed(1600,1,40);就是沿顺时针方向旋转一周;

通过修改PWM_Output_Speed();可以实现电机的角度、方向、速度控制。

其他方式的pwm简单驱动

采用定时器的翻转模式,驱动电机的转动:

#include "PWM.h"
#include "stm32f4xx.h" 

/*
*PF9  TIM14_CH1通道
*PF8 为方向引脚
*/

uint16_t CCR1=1000;

void TIM14_PWM_Init(uint32_t arr,uint32_t psc)
{
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14,ENABLE);  //使能定时器 14 时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE); 	//使能PORTF时钟
	 
	GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14); //GPIOF9 复用为定时器 14
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;           //GPIOF9
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;        //复用功能
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;	//速度100MHz
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;      //推挽复用输出
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;        //上拉
	GPIO_Init(GPIOF,&GPIO_InitStructure);              //初始化PF9
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;           //GPIOF8
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;        //功能
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;	//速度100MHz
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;      //复用推挽输出
	GPIO_Init(GPIOF,&GPIO_InitStructure);              //初始化PF8

	
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	TIM_TimeBaseStructure.TIM_Period = arr-1; //设置自动重装载值  输出频率
	TIM_TimeBaseStructure.TIM_Prescaler =psc-1; //设置预分频值 
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim  0=TIM_CKD_DIV1
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
	TIM_TimeBaseInit(TIM14, &TIM_TimeBaseStructure); //根据指定的参数初始化 TIMx 的
	
	TIM_OCInitTypeDef TIM_OCInitStructure;
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Toggle; //翻转模式 //TIM_OCMode_PWM1; //选择 PWM 模式 1
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	TIM_OCInitStructure.TIM_OCPolarity =TIM_OCPolarity_High;//输出极性高 //TIM_OCPolarity_Low; //输出极性低
	TIM_OCInitStructure.TIM_Pulse=CCR1; //CCR
	TIM_OC1Init(TIM14, &TIM_OCInitStructure); //初始化 TIM

	TIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Disable);//失能  //使能TIM14在CCR1上的预装载寄存器  TIM_OCPreload_Enable
//	TIM_ARRPreloadConfig(TIM14,ENABLE);//ARPE使能 

	TIM_ClearFlag(TIM14,TIM_FLAG_CC1);	//清除定时器中断标志位
	TIM_ITConfig(TIM14,TIM_FLAG_CC1,ENABLE);    //开启定时器比较中断

	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	NVIC_InitTypeDef NVIC_InitStructure;
	NVIC_InitStructure.NVIC_IRQChannel=TIM8_TRG_COM_TIM14_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
	NVIC_Init(&NVIC_InitStructure);
	
	TIM_Cmd(TIM14, ENABLE); //使能 TIM14
}


void TIM8_TRG_COM_TIM14_IRQHandler(void)
{
	uint16_t num = 0;
	if(TIM_GetITStatus(TIM14,TIM_FLAG_CC1)==SET)
	{
		
		TIM_ClearITPendingBit(TIM14,TIM_FLAG_CC1);
		num=TIM_GetCapture1(TIM14);
		TIM_SetCompare1(TIM14,num+CCR1);
	}
}


 在main函数中调用TIM14_PWM_Init(65536,1);

运行结果就是使电机沿单一方向转动,通过修改ARR值可以调速;

通过在main函数调用下面函数,可控制电机的旋转方向;(引脚接线注意接对)

GPIO_SetBits(GPIOF,GPIO_Pin_8);  //反转
GPIO_ResetBits(GPIOF,GPIO_Pin_8); //正转

直接输出pwm波形的驱动

pwm.c

#include "PWM.h"
#include "stm32f4xx.h" 
//#include "uart.h"

/*
*PF9  TIM14_CH1通道
*
*/
void TIM14_PWM_Init(uint32_t arr,uint32_t psc)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure;
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14,ENABLE);  //使能定时器 14 时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE); 	//使能PORTF时钟
	 
	GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14); //GPIOF9 复用为定时器 14
	
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;           //GPIOF9
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;        //复用功能
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;	//速度100MHz
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;      //推挽复用输出
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;        //上拉
	GPIO_Init(GPIOF,&GPIO_InitStructure);              //初始化PF9

	
	TIM_TimeBaseStructure.TIM_Period = arr; //设置自动重装载值  100-1
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置预分频值
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim  0=TIM_CKD_DIV1
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
	TIM_TimeBaseInit(TIM14, &TIM_TimeBaseStructure); //根据指定的参数初始化 TIMx 的
	
	
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择 PWM 模式 1
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	TIM_OCInitStructure.TIM_OCPolarity =TIM_OCPolarity_High; //TIM_OCPolarity_Low; //输出极性低
	TIM_OCInitStructure.TIM_Pulse=50;//CCR
	TIM_OC1Init(TIM14, &TIM_OCInitStructure); //初始化 TIM
	
	TIM_Cmd(TIM14, ENABLE); //使能 TIM14

}


在main函数中调用TIM14_PWM_Init(100-1,1680-1);

运行结果就是使电机沿单一方向转动,通过修改ARR值可以调速;

使用cubemx配置H7主从定时器

 250421补充!

芯片:STM32H723ZGTx

主定时器是TM13

从定时器是TM12

可以看到TIM12作为TIM13的从定时器,内部触发选择ITR2,原理和上文的F407相似,不在过多解释!

讲一下cubemx的配置!

先配好一些基本的初始化,如debug口,RCC,时钟树,主要还是配置定时器12和定时器13!

创建工程

 选择H7芯片生成工程

 选择RCC

 选择debug接口

值得注意的是STM32H723的主频为550MHZ,定时器最大频率为275MHZ,我使用的是外部8MHZ的晶振进行倍频!输入550后软件会自动匹配!

标题

 定时器13的配置

TIM13配置

TIM12的配置

TIM12配置

开启定时器12的中断

TIM12的中断
TIM12的中断​

 再配置一下TIM的GPIO引脚(这里用于控制方向的引脚忘记配置了)

配置完成后生成工程,打开!

新建一个hardware文件夹

打开工程,添加路径!

 新建pwm.c和pwm.h文件,并添加到Hardware文件夹路径下!

修改代码,将定时器tim.c中的初始化HAL_TIM_MspPostInit中添加__HAL_TIM_DISABLE()函数先关闭使能!

添加的pwm.c内容如下!

#include "pwm.h"

extern uint16_t Motor_En;
/**
uint16_t Num    发送的脉冲数(从定时器的ARR值)
uint8_t Dir     步进电机的旋转方向
uint16_t Speed	速度(更改主定时器的ARR值)
*/
void PWM_Output_Speed(uint16_t Num,uint8_t Dir,uint16_t Speed)
{
	uint16_t DutyCycle=Speed/2;
	//HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, ((Dir == 1) ? GPIO_PIN_RESET : GPIO_PIN_SET));
	
	__HAL_TIM_DISABLE(&htim12);		//关闭TIM12使能
	__HAL_TIM_SET_AUTORELOAD(&htim12, Num);						//从新设置ARR计数值
	HAL_TIM_GenerateEvent(&htim12, TIM_EVENTSOURCE_UPDATE);		//配置由软件生成定时器事件,新修改ARR计数值后,马上软件更改一次事件
	__HAL_TIM_ENABLE(&htim12);									 	//使能 TIM12
	__HAL_TIM_CLEAR_IT(&htim12, TIM_IT_UPDATE);					//清楚中断标志位
	__HAL_TIM_ENABLE_IT(&htim12, TIM_IT_UPDATE);					//开启定时器12的中断
	
	__HAL_TIM_DISABLE(&htim13);	
	__HAL_TIM_SET_AUTORELOAD(&htim13, Speed);						//从新设置ARR计数值
	HAL_TIM_GenerateEvent(&htim13, TIM_EVENTSOURCE_UPDATE);		//配置由软件生成定时器事件,新修改ARR计数值后,马上软件更改一次事件	
	(&htim13)->Instance->CCR1 = DutyCycle;//设置CCR的值为ARR的一半,占空比为50%
	HAL_TIM_GenerateEvent(&htim13, TIM_EVENTSOURCE_CC1);			//配置后由软件生成通道一的事件,马上生效
	__HAL_TIM_ENABLE(&htim13);									//TIM_Cmd(TIM14, ENABLE); //使能 TIM14	

	HAL_TIM_PWM_Start(&htim13,TIM_CHANNEL_1);
}


void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM12)
  {
	  if(__HAL_TIM_GET_IT_SOURCE(&htim12,TIM_IT_UPDATE) != RESET)
	{
		//__HAL_TIM_CLEAR_IT(&htim12, TIM_IT_UPDATE);
		__HAL_TIM_DISABLE(&htim12);	//关闭TIM12使能
		__HAL_TIM_DISABLE(&htim13);	//关闭TIM14使能
		HAL_TIM_PWM_Stop(&htim13,TIM_CHANNEL_1);
		Motor_En=0;
		//__HAL_TIM_DISABLE_IT(&htim12, TIM_IT_UPDATE);		//关闭定时器12的中断
	}
  }
}

 HAL_TIM_PeriodElapsedCallback函数是TIM中断TIM8_BRK_TIM12_IRQHandler的回调函数,进入中断后会进入此函数!在此函数中进行处理!

pwm.h

#ifndef _PWM_H_
#define _PWM_H_
#include "main.h"
#include "tim.h"
#include "gpio.h"

void PWM_Output_Speed(uint16_t Num,uint8_t Dir,uint16_t Speed);

#endif

在main中调用

编译仿真运行!PF8引脚输出PWM,验证一下!可以!

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐