STM32驱动TB6600精准控制步进电机

(一)硬件信息

        STM32C8T6,42步进电机,TB660电机驱动

(二)参考博客

1.【STM32】实战3.1—用STM32与TB6600驱动器驱动42步进电机(一)_白白与瓜的博客-CSDN博客

2.利用STM32F103精确控制步进电机_stm32控制步进电机_jl_mlh的博客-CSDN博客

(三)前言

        42步进电机的详细原理和运行方式都可以从上面的文章中学习到,本章是站在前人的肩膀上重新改写的代码,更基础,更简单,便于二次改写用于不同的场合。

(四)工作原理

        1.本驱动代码利用定时器TIM2和定时器TIM3构造一个主从定时器,TIM2作为主定时器控制电机的转速,TIM3作为从定时器控制电机的转动角度。
        2.电机的转速和转角还与驱动器自身的细分数有关,但是驱动器细分数是通过影响电机的步距角来影响转速和转角,而TIM2和TIM3是控制步进电机的频率和脉冲数来控制转速转角。
        定时器二进行输出,通过计算可以得出旋转速度,通过配置合适的装载值可以实现对步进电机的速度控制(参考博客二),定时器作为从定时器可以在内部计算定时器二的脉冲数,通过计算可以得到目标角度所需要的脉冲数,通过向定时器三中写入装载值,让定时器三开始计数,中断。

        中从定时器目的就是实现对内部定时器发出的脉冲进行计数。

        STM32单片机每个通用定时器可以独立产生4路PWM信号,每个通道的PWM信号频率由预分频器PSC和重装载寄存器ARR决定,脉宽由预分频器PSC和比较/捕获寄存器CCRx决定,但对于一些特殊使用场景,如可控硅控制,步进电机控制,或基带信号PPM调制等,需要对PWM输出信号的位时(类似于正弦信号的相位)进行调节,普通PWM输出模式无法满足这种需求,本文所述主从定时器结合定时器单脉冲模式实现输出频率、脉宽、位时均可自由调节的PWM信号。且相对于传统PWM输出方式来说,可以最大限度的提高脉宽调节精度,72M主频下可实现13.89ns的调节精度。而缺点正是多耗费一个定时器。

        话不多说上代码。

(五)代码部分

timer.c

#include "timer.h"
#include "stm32f10x.h"


 /****************************************************
 * 函数名:GPIO_Config
 * 描述  :无
 * 输入  :无 
 * 输出  :无
 * 调用  :主函数
 * 返回值:无
******************************************************/
void GPIO_Config(void)
{ 
		GPIO_InitTypeDef GPIO_InitStructure; 

		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE); 											//使能GPIOA
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 | RCC_APB1Periph_TIM3, ENABLE);  //使能TIM2,TIM3的时钟

    /* Timer2 Channel 1, PA0 */ 
    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_0; 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 														//复用输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
    GPIO_Init(GPIOA, &GPIO_InitStructure);
	 
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2; 												//初始化引脚用于控制方向(GPIOA1)和使能(GPIOA2)
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;        										//通用推挽输出模式
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;       									  //指定GPIO引脚可输出的最高频率为50MHZ
		GPIO_Init(GPIOA, &GPIO_InitStructure);                 										  
	
	  GPIO_ResetBits(GPIOA, GPIO_Pin_1);																					//指定引脚输出低电平,此时灯全灭,方向
		GPIO_ResetBits(GPIOA, GPIO_Pin_2);																					//指定引脚输出低电平,此时灯全灭	使能	
	
}


//================================================================================
 /****************************************************
 * 函数名:TIM2_Master__TIM3_Slave_Configuration
 * 描述  :主从定时器配置
 * 输入  :电机转速speed,转角angle 
 * 输出  :无
 * 调用  :主函数
 * 返回值:无
******************************************************/
void TIM2_Master__TIM3_Slave_Configuration(u32 PulseFrequency, u32 pulse) 
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; 
	TIM_OCInitTypeDef TIM_OCInitStructure; 
	NVIC_InitTypeDef NVIC_InitStructure; 
	
	u16 nPDTemp ; 
	u16 pulse_number;
	float p=PulseFrequency;
	TIM_Cmd(TIM2, DISABLE); 
	nPDTemp = (11.25/p); 			   																	//TIM2重装值是11.25时1s转一圈(电机32细分下)   控制速度
	pulse_number = (17.7778*pulse);																//TIM3重装值是17.7778时转1°(电机32细分下)。TIM_Period不要超过0xFFFF   控制旋转角度
	
	// 时基配置:配置PWM输出定时器——TIM2 
	/* Time base configuration */ 
	TIM_TimeBaseStructure.TIM_Period = nPDTemp; 									//定时周期为nPDTemp
	TIM_TimeBaseStructure.TIM_Prescaler = 999; 										//预分频值1000,即f=72khz
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; 									//时钟分频因子,会影响滤波器采样频率,与本实验无影响
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 	//向上计数模式
	TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; 							//指定重复计数器值
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); 
	
	// 输出配置:配置PWM输出定时器——TIM2 
	/* PWM1 Mode configuration: Channel1 */    
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;				 			  //TIM 脉冲宽度调制模式 1
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 			//高电平有效
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; 	//使能输出
	TIM_OCInitStructure.TIM_Pulse = nPDTemp>>1;											//50% //比较tim_ccr的值,输出脉冲发生跳变
	TIM_OC1Init(TIM2, &TIM_OCInitStructure); 												//初始化
	TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable); 							//使能 TIMx 在 CCR1 上的预装载寄存器
	TIM_ARRPreloadConfig(TIM2, ENABLE); 														//使能或者失能 TIMx 在 ARR 上的预装载寄存器

	
	// 时基配置:配置脉冲计数寄存器——TIM3 
	TIM_TimeBaseStructure.TIM_Period = pulse_number;      							//0x1900是360°;//改变给电机的脉冲个数		     
	TIM_TimeBaseStructure.TIM_Prescaler = 0; 
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; 
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 
	TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; 
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); 
	
	
	// 输出配置:配置输出比较非主动模式定时器——TIM3
	// Output Compare Active Mode configuration: Channel1 
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Inactive; 							//输出比较非主动模式,(匹配时设置输出引脚为无效电平,当计数值为比较/捕获寄存器值相同时,强制输出为低电平)      
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; 
	TIM_OCInitStructure.TIM_Pulse = 0xFFFF;														 // 这里的配置值意义不大   
	TIM_OC1Init(TIM3, &TIM_OCInitStructure); 
	

	// 配置TIM2为主定时器 
	// Select the Master Slave Mode 
	TIM_SelectMasterSlaveMode(TIM2, TIM_MasterSlaveMode_Enable);	 //设置 TIM2 主/从模式并使能
	// Master Mode selection  
	TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update); 				//使用更新事件作为触发输出
	
	
	// 配置TIM3为从定时器 
	// Slave Mode selection: TIM3 
	TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Gated); 					//选择 TIM3为从模式   TIM_SlaveMode_Gated-当触发信号(TRGI)为高电平时计数器时钟使能
	TIM_SelectInputTrigger(TIM3, TIM_TS_ITR1); 								//选择 TIM3 输入触发源    TIM_TS_ITR1-TIM 内部触发 1
	TIM_ITRxExternalClockConfig(TIM3, TIM_TS_ITR1);						//设置 TIM3 内部触发为外部时钟模式   TIM_TS_ITR1-TIM 内部触发 1
	TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE); 									//使能TIM3     TIM 捕获/比较 1 中断源 	 
	
	
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;				
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
	
	TIM_Cmd(TIM2, ENABLE); 
	TIM_Cmd(TIM3, ENABLE); 
} 

 /****************************************************
 * 函数名:Frequence_Setting
 * 描述  :无
 * 输入  :无 
 * 输出  :无
 * 调用  :主函数
 * 返回值:无
******************************************************/
void Frequence_Setting(u32 PulseFrequency) 
{
	u16 nPDTemp ; 

	TIM_Cmd(TIM2, DISABLE);                       //关闭定时器二
	nPDTemp = 72000UL/PulseFrequency;             //计算装载数

	TIM_SetAutoreload(TIM2,nPDTemp);
	TIM_GenerateEvent(TIM2,TIM_EventSource_Update);
	TIM_SetCompare1(TIM2,nPDTemp/2);
}

 /****************************************************
 * 函数名:Output_Pulse
 * 描述  :无
 * 输入  :无 
 * 输出  :无
 * 返回值:无
******************************************************/
void Output_Pulse(u16 Num)
{
		GPIO_ResetBits(GPIOA, GPIO_Pin_2);				//指定引脚输出低电平,使能
		TIM3->CCR1 = Num;                					//把脉冲数写入定时器三的寄存器里
		TIM3->CNT = 0; 														//把定时器三的计数归零
		TIM_Cmd(TIM3, ENABLE); 										//使能定时器三
		TIM_ITConfig(TIM3, TIM_IT_CC1, ENABLE);   //使能定时器三的中断
		TIM_Cmd(TIM2, ENABLE);                    //使能定时器二
}

 /****************************************************
 * 函数名:angle_set
 * 描述  :无
 * 输入  :无 
 * 输出  :无
 * 返回值:无
******************************************************/
void angle_set(u8 dir,u8 angle)
{
	if(dir==0)
				GPIO_ResetBits(GPIOA, GPIO_Pin_1);//指定引脚输出低电平,方向
	else
				GPIO_SetBits(GPIOA, GPIO_Pin_1);//指定引脚输出低电平,方向
	
	Output_Pulse(angle*6400);
}


void TIM3_IRQHandler(void) 
{
	if (TIM_GetITStatus(TIM3, TIM_IT_CC1) != RESET) 	   // TIM_IT_CC1
	{ 
		TIM_ClearITPendingBit(TIM3, TIM_IT_CC1); // 清除中断标志位 
		TIM_Cmd(TIM2, DISABLE); // 关闭定时器 
		TIM_Cmd(TIM3, DISABLE); // 关闭定时器 
		TIM_ITConfig(TIM3, TIM_IT_CC1, DISABLE); 
	
	} 
} 

timer.h


#ifndef __TIMER_H
#define	__TIMER_H
#include "stm32f10x.h"


extern unsigned char Flag;
extern unsigned char TIM2_Pulse_TIM3_Counter_OK;
void GPIO_Config(void);
void TIM2_Master__TIM3_Slave_Configuration(u32 PulseFrequency,u32 pulse);
void Frequence_Setting(u32 PulseFrequency);
void Output_Pulse(u16 Num);
void angle_set(u8 dir,u8 angle);

#endif /* __USART1_H */

main.c

#include "stm32f10x.h"
#include "delay.h"
#include "timer.h"
#include "sys.h"


int main()
{

	delay_init(); 																 //延时初始化
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断初始化
	
	GPIO_Config();																	//引脚初始化
	
	u8 flag=1;
	u8 angle=90;
	while(1)
	{
		if(flag==1)
		{
			TIM2_Master__TIM3_Slave_Configuration(1,angle);
			delay_ms(40000);
			angle=0;
			flag=0;
		}
	}
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值