基于STM32之控制步进电机,学到即赚到!(含主代码)

目录

前言

一、关于步进电机那点事

二、接线问题

三、主要代码

四、总结


前言

最近发现电机类的步进电机挺有趣的,于是趁快开学了有空再码一篇,分享一下自己的学习心得,有哪里写的不好欢迎随时指正。

一、关于步进电机那点事

这次使用的是二相步进电机,博客上也有许多关于步进电机的博文啊,质量也是参差不齐,今天就给大家仔细的介绍一下该电机,我主要还是继承以往的风格,资料方面我也讲的少,主要还是侧重实操方向,希望能够带给大家帮助

下面是图: 

首先要认识一下步进电机上的几条线:

四条线(红、蓝、绿、黑)

正常来说对应A+、A-、B+、B-,在电机上基本上也都会标明代表含义,其实步进电机的原理其实都差不多,主要就是学会使用和了解原理就基本上达到我们的目的了,如果想要深入学习,那可以再继续研究······

那么怎么使用呢?首先就要搭配一款步进电机的驱动器了,网上随便都可以买到,如图:

 这里我们很明显可以看到它有12个接口,这里再详细介绍一下如何使用接口:

V+:连接电源正极(注意电压在9V~32V之间即可,过大的话你懂得)

GND:连接电源负极

A+:连接电机绕组A+相

A- : 连接电机绕组A-相

B+:连接电机绕组B+相

B- : 连接电机绕组B-相

CP+:脉冲信号输入正 ( PUL+ )(取决于共阴、共阳接法再来接线,共阴的话CP-接地,CP+接脉冲信号即定时器PWM输出)

CP-:脉冲信号输入负  ( PUL-)

DIR+:电机正、反转控制正(同样取决于共阴共阳接法)

DIR-:电机正、反转控制负

EN+:电机脱机控制正(可以不接)

EN-:电机脱机控制负

二、接线问题

上面到这可能对它的接线有了一个想法了,那么具体如何接线呢?嘿嘿,这里有共阴和共阳的常见的两种接法,具体参照下图:

 这里我采用了共阴极的接法

那么我的接线:

DIR+:PA8(随便一个端口即可)

DIR-:GND

CP+:PA1(TIM2通道2)

CP-:GND

ENA不接

三、主要代码

这里的代码搬运后修改一些的,即可上手即可用

主函数

#include "stm32f10x.h"
#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "key.h"
#include "led.h"	 
#include "usmart.h"	
#include "driver.h"

//共阴
/*
CP+->PA.1   CP-接GND
DIR+->PA.8  DIR-接GND
*/

int main(void)
{	 
	delay_init();	    	 	  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 	
	uart_init(115200);	     
	KEY_Init();			
	Driver_Init();			
	TIM2_Init(999,72-1);       
	while(1) 
	{	
			Locate_Rle2(500,CW);
			delay_ms(5000);
			delay_ms(5000);
			delay_ms(5000);
			Locate_Rle2(500,CCW);
			delay_ms(5000);
			delay_ms(5000);
			delay_ms(5000);
		}

}	

 定时器函数:

#include "stm32f10x.h"
#include "driver.h"
#include "delay.h"
#include "usart.h"

long current_pos[2]={0,0}; 
int motor_dir2=0;
u8 count[2]={0,0};

void Driver_Init(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	
	GPIO_Init(GPIOA, &GPIO_InitStructure);					
	GPIO_SetBits(GPIOA,GPIO_Pin_8);						
}


void TIM2_Init(u16 arr,u16 psc)
{		 					 
	GPIO_InitTypeDef GPIO_InitStructure;
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); 	
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);                                                                      	

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;				//TIM2_CH2
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;			
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
	
	TIM_TimeBaseStructure.TIM_Period = arr;					 
	TIM_TimeBaseStructure.TIM_Prescaler =psc;				
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; 			
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 
	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); 		
	TIM_ClearITPendingBit(TIM2,TIM_IT_Update);				

	TIM_UpdateRequestConfig(TIM2,TIM_UpdateSource_Regular); 
	TIM_SelectOnePulseMode(TIM2,TIM_OPMode_Single);			
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;		
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; 
	TIM_OCInitStructure.TIM_Pulse = arr>>1; 				
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; 
	TIM_OC2Init(TIM2, &TIM_OCInitStructure); 				

	TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);  		
	TIM_ARRPreloadConfig(TIM2, ENABLE); 					
	
	TIM_ITConfig(TIM2, TIM_IT_Update ,ENABLE);  			
 
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;  		
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; 		
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 	
	NVIC_Init(&NVIC_InitStructure);  						
	
	TIM_ClearITPendingBit(TIM2, TIM_IT_Update);  			
	TIM_Cmd(TIM2, DISABLE);  															  
}
/******* TIM2*********/
void TIM2_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM2,TIM_FLAG_Update)!=RESET)
	{
		TIM_ClearITPendingBit(TIM2,TIM_FLAG_Update);	
		count[0]++; 
		TIM_GenerateEvent(TIM2,TIM_EventSource_Update);
	
		TIM_Cmd(TIM2, ENABLE);  					  

		if(count[0]==200)
		{
			if(motor_dir2==CW) 						  
				current_pos[0]+=count[0];
			else          							  
				current_pos[0]-=count[0];
			TIM_Cmd(TIM2, DISABLE);  				  		
			printf("motor2µ±Ç°Î»ÖÃ=%ld\r\n",current_pos[0]);
			count[0]=0;
		}
	
	}
}

void TIM2_Startup(u32 frequency)   
{
	u16 temp_arr=1000000/frequency-1; 
	TIM_SetAutoreload(TIM2,temp_arr);
	TIM_SetCompare2(TIM2,temp_arr>>1); 
	
	TIM_SetCounter(TIM2,0);
	TIM_Cmd(TIM2, ENABLE);  
}


void Locate_Rle2(u32 frequency,DIR_Type dir) 
{
	
	if(TIM2->CR1&0x01)
	{
		printf("\r\nThe last time pulses is not send finished,wait please!\r\n");
		return;
	}
	if((frequency<20)||(frequency>100000))
	{
		printf("\r\nThe frequency is out of range! please reset it!!(range:20Hz~100KHz)\r\n");
		return;
	}
	motor_dir2=dir;
	
	DRIVER_DIR2=motor_dir2;				
	TIM2_Startup(frequency);			
}

 到这里你就会发现其实原理还是相当简单的,剩下的也不再深入了,希望能够对大家帮助哈哈

实现目的:

该程序就是实现正转后隔一会再反转,大家可以根据自己需求设置到自己想要的转动情况,同时要让他停下来,只需要在自己需要的地方设置一个TIM_SetCompare2(TIM2,0)即可停下,可以自由设置。

四、总结

今天关于步进电机就暂且介绍到这里,后面有需要会再特别介绍一下,文章写得还是比较简单,相信对于你还是可以很轻松入手的,到这里别忘了给点个赞,收藏一波,顺道关注一下,厚着脸皮求三连哈哈。

有需要代码可以随时评论留下邮箱即可,看到即回,其他博文也一样,有需要即可评论带上邮箱,同时欢迎交流学习

 

题外话:

挺喜欢彭于晏说的一句话:“我就是没有才华,所以才用命去拼!”

学习32之路固然辛苦,但要是坚持下来了,那不是很酷?哈哈哈

以下是基于STM32控制步进电机代码示例: ```c #include "stm32f4xx.h" // 定义IO口 #define STEP_GPIO_PORT GPIOA #define DIR_GPIO_PORT GPIOB #define STEP_GPIO_PIN GPIO_Pin_8 #define DIR_GPIO_PIN GPIO_Pin_10 // 定义步距角 #define STEP_ANGLE 1.8f // 定义步进电机控制参数 #define STEPS_PER_REV 200 // 每转步数 #define SPEED 5000 // 转速,单位为step/s #define ACCELERATION 5000 // 加速度,单位为step/s^2 // 定义计数器 volatile uint32_t step_count = 0; volatile uint32_t step_goal = 0; volatile uint32_t accel_count = 0; // 定时器中断处理函数 void TIM2_IRQHandler(void) { if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) { // 清除中断标志 TIM_ClearITPendingBit(TIM2, TIM_IT_Update); // 判断是否加速 if(step_count < accel_count) { // 计算加速度 uint32_t speed_new = (uint32_t)(sqrtf(2.0f * ACCELERATION * step_count * STEP_ANGLE / 360.0f) * STEPS_PER_REV); // 更新定时器计数值 TIM2->ARR = (uint16_t)(SystemCoreClock / speed_new / 2); } else if(step_count >= step_goal - accel_count) { // 计算减速度 uint32_t speed_new = (uint32_t)(sqrtf(2.0f * ACCELERATION * (step_goal - step_count) * STEP_ANGLE / 360.0f) * STEPS_PER_REV); // 更新定时器计数值 TIM2->ARR = (uint16_t)(SystemCoreClock / speed_new / 2); } // 更新步进电机控制口状态 if(step_count < step_goal) { // 输出脉冲信号 GPIO_SetBits(STEP_GPIO_PORT, STEP_GPIO_PIN); GPIO_ResetBits(STEP_GPIO_PORT, STEP_GPIO_PIN); // 更新计数器 step_count++; } } } // 初始化GPIO口和定时器 void Init_StepMotor(void) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; NVIC_InitTypeDef NVIC_InitStructure; // 使能GPIO时钟和定时器时钟 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOB, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // 初始化GPIO口 GPIO_InitStructure.GPIO_Pin = STEP_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(STEP_GPIO_PORT, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = DIR_GPIO_PIN; GPIO_Init(DIR_GPIO_PORT, &GPIO_InitStructure); // 初始化定时器 TIM_TimeBaseStructure.TIM_Period = SystemCoreClock / SPEED / 2 - 1; // 定时器周期,单位为us TIM_TimeBaseStructure.TIM_Prescaler = 0; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); // 配置定时器中断 NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); // 启动定时器 TIM_Cmd(TIM2, ENABLE); } // 控制步进电机转动 void StepMotor_Run(int32_t steps) { if(steps > 0) { // 向正方向旋转 GPIO_SetBits(DIR_GPIO_PORT, DIR_GPIO_PIN); } else { // 向负方向旋转 GPIO_ResetBits(DIR_GPIO_PORT, DIR_GPIO_PIN); steps = -steps; } // 计算目标步数和加速时间 step_count = 0; step_goal = (uint32_t)(steps * STEP_PER_REV / 360.0f / STEP_ANGLE); accel_count = (uint32_t)(sqrtf(2.0f * step_goal * ACCELERATION * STEP_ANGLE / 360.0f) * STEPS_PER_REV); // 等待步进电机停止 while(step_count < step_goal); } int main(void) { // 初始化步进电机控制口和定时器 Init_StepMotor(); // 控制步进电机旋转1000步 StepMotor_Run(1000); while(1); return 0; } ``` 这段代码使用TIM2定时器来控制脉冲信号的输出和步进电机的旋转方向。在定时器中断处理函数中,根据加速度和减速度的公式计算定时器的计数周期,并且输出脉冲信号来驱动步进电机。在控制步进电机旋转时,先计算目标步数和加速时间,然后等待步进电机旋转到目标位置。
评论 265
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不说二话的自家人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值