基于STM32实现模拟脉冲对电机的控制

功能

  1. 通过模拟脉冲实现对两路电机的控制
  2. 可电机进行使能、方向、速度的调节

一、简介

整个设计的思路比较巧妙,通过一个基本定时器实现不仅可以实现对两路电机的进行控制,还能对步进电机实现加减速控制,具体的实现过程见代码。

二、具体的代码

bsp_motor.h

#ifndef _BSP_MOTOR_H
#define _BSP_MOTOR_H
/*********************************** 引入头文件 start *************************************/
#include "stm32f4xx.h"
/************************************ 引入头文件 end *************************************/

/************************************* 宏定义  start *************************************/
#define PULSE_HIGH 			GPIO_SetBits(GPIOB,GPIO_Pin_13)		//脉冲引脚置低
#define PULSE_LOW 			GPIO_ResetBits(GPIOB,GPIO_Pin_13)	//脉冲引脚置高
#define PULSE_TOGGLE 		PBout(13)									//脉冲引脚反转

#define ENA_HIGH 			GPIO_SetBits(GPIOG,GPIO_Pin_0)		//使能引脚置高 --失能
#define ENA_LOW 			GPIO_ResetBits(GPIOG,GPIO_Pin_0)	//使能引脚置低 --使能

#define DIR_HIGH 			GPIO_SetBits(GPIOF,GPIO_Pin_14)		//方向引脚 --前进
#define DIR_LOW 			GPIO_ResetBits(GPIOF,GPIO_Pin_14)	//方向引脚 --后退
/************************************* 宏定义  end **************************************/

typedef struct
{
	uint8_t 		channel;	
	
	GPIO_TypeDef* 	PULSE_GPIOx;		//脉冲端口
	uint32_t 		PULSE_GPIO_Pin;   	//脉冲引脚

	GPIO_TypeDef* 	ENA_GPIOx;			//使能端口
	uint32_t 		ENA_GPIO_Pin;   	//使能引脚
	
	GPIO_TypeDef* 	DIR_GPIOx;			//方向端口
	uint32_t 		DIR_GPIO_Pin;   	//方向引脚
	
}Motor_InitTypeDef;
/*********************************** 函数声明  start ************************************/
void Motor_InitTypeDef_Init(Motor_InitTypeDef* motor_InitTypeDef);
void motor_dir(uint8_t dir);
void motor_ena(uint8_t ena);
/************************************ 函数声明  end *************************************/
#endif

bsp_motor.c

#include "bsp_motor.h"

uint8_t motor1_flag = 1;		//脉冲标志位 	1:使能		0:失能
uint8_t motor2_flag = 1;		//脉冲标志位 	1:使能		0:失能


uint8_t channel1 = 0;			//电机1通道使能
uint8_t channel2 = 0;			//电机2通道使能

Motor_InitTypeDef* motor1_InitTypeDef;				//电机1结构体
Motor_InitTypeDef* motor2_InitTypeDef;				//电机结构体

/**************************************************************************************
  * name        : void Motor_GPIO_COnfig(void)
  * Function    : 电机相关引脚的配置
  * Parameters  : void
  * Returns     : NULL
  * Author      : 那些你很冒险的梦
  * Check       :
  * Date        : 2021/3/20
**************************************************************************************/
void Motor_GPIO_Config(Motor_InitTypeDef* motor_InitTypeDef)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	//打开时钟
	//RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB|RCC_AHB1Periph_GPIOG|RCC_AHB1Periph_GPIOF, ENABLE);

	if(motor_InitTypeDef->PULSE_GPIOx == GPIOA | motor_InitTypeDef->PULSE_GPIOx == GPIOA | motor_InitTypeDef->DIR_GPIOx == GPIOA)
	{
		RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	}
	if(motor_InitTypeDef->PULSE_GPIOx == GPIOB | motor_InitTypeDef->PULSE_GPIOx == GPIOB | motor_InitTypeDef->DIR_GPIOx == GPIOB)
	{
		RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
	}
	if(motor_InitTypeDef->PULSE_GPIOx == GPIOC | motor_InitTypeDef->PULSE_GPIOx == GPIOC | motor_InitTypeDef->DIR_GPIOx == GPIOC)
	{
		RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
	}
	if(motor_InitTypeDef->PULSE_GPIOx == GPIOD | motor_InitTypeDef->PULSE_GPIOx == GPIOD | motor_InitTypeDef->DIR_GPIOx == GPIOD)
	{
		RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
	}
	if(motor_InitTypeDef->PULSE_GPIOx == GPIOE | motor_InitTypeDef->PULSE_GPIOx == GPIOE | motor_InitTypeDef->DIR_GPIOx == GPIOE)
	{
		RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);
	}
	if(motor_InitTypeDef->PULSE_GPIOx == GPIOF | motor_InitTypeDef->PULSE_GPIOx == GPIOF | motor_InitTypeDef->DIR_GPIOx == GPIOF)
	{
		RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);
	}
	if(motor_InitTypeDef->PULSE_GPIOx == GPIOG | motor_InitTypeDef->PULSE_GPIOx == GPIOG | motor_InitTypeDef->DIR_GPIOx == GPIOG)
	{
		RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);
	}
	
	/*************************************** 脉冲引脚  start **************************************/
	GPIO_InitStructure.GPIO_Pin = motor_InitTypeDef->PULSE_GPIO_Pin;				//引脚
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;									//模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;		
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Init(motor_InitTypeDef->PULSE_GPIOx, &GPIO_InitStructure);
	PULSE_LOW;
	/*************************************** 脉冲引脚  end **************************************/
	
	/************************************** 使能引脚  start  ************************************/
	GPIO_InitStructure.GPIO_Pin = motor_InitTypeDef->ENA_GPIO_Pin;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Init(motor_InitTypeDef->PULSE_GPIOx, &GPIO_InitStructure);
	/************************************** 使能引脚 end  *************************************/
	
	/**************************** 方向引脚  START**************************/   
	GPIO_InitStructure.GPIO_Pin = motor_InitTypeDef->DIR_GPIO_Pin;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Init(motor_InitTypeDef->DIR_GPIOx, &GPIO_InitStructure);
	/************************************** 方向引脚 end  *************************************/
}


/**************************************************************************************
  * name        : void Motor_InitTypeDef_Init(Motor_InitTypeDef* motor_InitTypeDef)
  * Function    : 电机初始化
  * Parameters  : motor_InitTypeDef:电机配置结构体
  * Returns     : NULL
  * Author      : 那些你很冒险的梦
  * Check       :
  * Date        : 2021/3/20
**************************************************************************************/
void Motor_InitTypeDef_Init(Motor_InitTypeDef* motor_InitTypeDef)
{
	if(motor_InitTypeDef->channel == 1)
	{
		channel1 = 1;
		motor1_InitTypeDef = motor_InitTypeDef;
	}
	if(motor_InitTypeDef->channel == 2)
	{
		channel2 = 1;
		motor2_InitTypeDef = motor_InitTypeDef;
	}
	Motor_GPIO_Config(motor_InitTypeDef);
}

/**************************************************************************************
  * name        : void Motor_GPIO_COnfig(void)
  * Function    : 方向控制
  * Parameters  : 1:使能 0:失能
  * Returns     : NULL
  * Author      : 那些你很冒险的梦
  * Check       :
  * Date        : 2021/3/20
**************************************************************************************/
void motor_dir(uint8_t dir)
{
	if(dir==1)
	{
		GPIO_ResetBits(GPIOF,GPIO_Pin_14);
	}else{
		GPIO_SetBits(GPIOF,GPIO_Pin_14);
	}
}

/**************************************************************************************
  * name        : void Motor_GPIO_COnfig(void)
  * Function    : 使能控制
  * Parameters  : start 1:顺时针 0:逆时针
  * Returns     : NULL
  * Author      : 那些你很冒险的梦
  * Check       :
  * Date        : 2021/3/20
**************************************************************************************/
void motor_ena(uint8_t ena)
{
	if(ena==1)
	{
		motor1_flag=0;
	}else{
		motor1_flag=1;
	}
}

timer.c

#include "timer.h"
#include "led.h"
#include "bsp_motor.h"								  



extern uint8_t motor1_flag;		//产生脉冲标志位    1:表示产生脉冲    0表示不产生脉冲
extern uint8_t motor2_flag;		//产生脉冲标志位    1:表示产生脉冲    0表示不产生脉冲

extern uint8_t channel1;
extern uint8_t channel2;

extern Motor_InitTypeDef* motor1_InitTypeDef;		//电机控制结构体1
extern Motor_InitTypeDef* motor2_InitTypeDef;		//电机控制结构体2

int speed1=0;					//速度控制变量1
int speed2=0;					//速度控制变量2
/**************************************************************************************
  * name        : TIM3_Int_Init(u16 arr,u16 psc)
  * Function    : 定时器3配置函数
  * Parameters  : arr:自动重装载值    psc:预分频系数
  * Returns     : NULL
  * Note        :
  * Author      : 那些你很冒险的梦
  * Check       :
**************************************************************************************/

void TIM3_Int_Init(u16 arr,u16 psc)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	/********************************* 定时器配置  start *********************************/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); 			//开启定时器3的时钟
	TIM_TimeBaseInitStructure.TIM_Period = arr; 					//重装载寄存器的值
	TIM_TimeBaseInitStructure.TIM_Prescaler=psc;  					//预分频系数
	TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; 	//设置向上计数
	TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1; 
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);
	TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); 						//中断使能
	TIM_Cmd(TIM3,ENABLE); 											//定时器使能
	/********************************* 定时器配置  end *********************************/
	
	/*************************** 中断优先级结构体配置  start ***************************/
	NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn; 					//配置中断源
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01; 		//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x03; 			//子优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;					//使能
	NVIC_Init(&NVIC_InitStructure);
	/**************************** 中断优先级结构体配置  end ***************************/
}

/**************************************************************************************
  * name        : TIM3_IRQHandler(void)
  * Function    : 定时器3中断服务函数
  * Parameters  : void
  * Returns     : NULL
  * Note        :
  * Author      :那些你很冒险的梦
  * Check       :
**************************************************************************************/

int temp1=0;
int temp2=0;
void TIM3_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) 
	{
		//判定通道1是否开启
		if(channel1==1)
		{
			//将脉冲进行反转
			if(motor1_flag==1)
			{
				
				if(temp1<speed1)
				{
					temp1++;
				}else if(temp1==speed1 && speed1 != 0)
				{
					motor1_InitTypeDef->PULSE_GPIOx->ODR ^= motor1_InitTypeDef->PULSE_GPIO_Pin;//脉冲引脚电平反转
					temp1=0;
				
				}else if(temp1>speed1)
				{
					temp1=0;
				}
				

			}
		}
		
		//判定通道2是否开启
		if(channel2==1)
		{
			//将脉冲进行反转
			if(motor2_flag==1)
			{
				
				if(temp2<speed2)
				{
					temp2++;
				}else if(temp2==speed1 && speed2 != 0)
				{
					motor2_InitTypeDef->PULSE_GPIOx->ODR ^= motor2_InitTypeDef->PULSE_GPIO_Pin;//脉冲引脚电平反转
					temp2=0;
				}else if(temp2>speed2)
				{
					temp2=0;
				}
			}
		}
	}
	TIM_ClearITPendingBit(TIM3,TIM_IT_Update); 
}

main.c

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "timer.h"
#include "bsp_motor.h"
#include "bsp_hmi.h"
 
extern uint8_t isFinish;		//1:数据接收完成   0:表示数据接收未完成
extern HMI_Struct hmi_Struct;
extern int speed1;
int main(void)
{ 
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	//中断配置
	delay_init(168); 								//延时配置
	LED_Init();										//LED配置
 	TIM3_Int_Init(10,6400-1);						//打开定时器配置
	uart_init(115200);								//打开串口配置

	//配置电机结构体
	Motor_InitTypeDef motor_InitTypeDef;
	motor_InitTypeDef.channel = 1;					//使能通道
	motor_InitTypeDef.PULSE_GPIOx = GPIOF;
	motor_InitTypeDef.PULSE_GPIO_Pin = GPIO_Pin_3;
	
	motor_InitTypeDef.ENA_GPIOx = GPIOG;
	motor_InitTypeDef.ENA_GPIO_Pin = GPIO_Pin_0; 
	
	motor_InitTypeDef.DIR_GPIOx = GPIOF;
	motor_InitTypeDef.DIR_GPIO_Pin = GPIO_Pin_14;
	
	Motor_InitTypeDef_Init(&motor_InitTypeDef);
	
	hmi_Struct.com = USART1;
	
//	speed1 = 1;
	
//	HMI_WriteBuf(&hmi_Struct,01);
//	HMI_WriteBuf(&hmi_Struct,02);
//	HMI_SendCode(&hmi_Struct);
//	Set_Motor_Speed(16);
//	ENA_LOW;		//使能
//	speed1 = 1;
	while(1)
	{
		//HMI_Decode(&hmi_Struct,isFinish);
	}
}

欢迎一起讨论技术问题,求关注!

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
《《《《《 PLC指令说明 》》》》》 代码类产品由于具备可复制性,一经销售,买家不得以任何理由退款 、退货,请亲们理解,谢谢! 编译环境:Keil MDK 4.7以上的版本,亲可以去百度或者官网直接下载; CPU需要:STM32F103--RAM内存不小于64K Flash程序空间不小于128K 串口使用:USART1-(PA9\PA10) 我们提供的是项目工程文件,所以主要你的MDK版本兼容直接编译就可以了; C语言单片机开发PLC-基于三菱FX2N,里面包括通讯,以及监控功能,指令执行,在线写入功能,店铺保证程序可以在MDK上编译通过,同时下载进控制器,可以在硬件上运行梯形图程序,如果需要其他的功能,需要亲自己修改代码,我们不提供代码修改服务和技术支持服务,所以拍的话亲需要一定的基础; 支持三菱GX-Develoer/GX-WORKS2 支持人机界面连接,FX2N(不完全支持所有梯形图指令,其他指令亲可以自己添加) 支持梯形图编程、下载、监控. 编程口为程序上下载及与人机界面通信之端口.下面有我们测试维纶的触摸屏与控制器的人机通信; ================================= 基本指令: LD LDI AND ANI OR ORI LDP LDF ANDP ANDF ORP ORF SET RST MPS MPP MRD ANB ORB OUT INV PLS PLF MC MCR NOP END CALL CJ FEND SRET STL RET (基本指令29条全包含) ======================================== 功能指令: ALT MOV ZRST ZCP INC DEC ADD CMP SUB MUL DIV BCD BIN WAND WOR WXOR DECO ENCO REF DHSCS DHSCR PWM RAMP PLSV DRVI DRVA PLSY ZRN PLSR TCMP TZCP TADD TSUB HOUR TRD TWR LD= = AND= = OR= = SFTR SFTL SPD 支持32位D指令,支持上升沿P指令 ======================================= 软件件范围 X0-X77 Y0-Y77 M0-M1535 M8000-M8255 S0-S999 C0-C255 T0-T255 D0-D5999 D8000-D8255 V0-V7 Z0-Z7 软元件掉电保持范围与三菱FX1N兼容 X0-X5高速脉冲捕捉功能与三菱FX1N兼容 Y0 Y1高速脉冲输出功能与三菱FX1N兼容,最高可发两路独立100K脉 冲。
### 回答1: STM32脉冲控制伺服是指通过使用STM32微控制器来控制伺服马达的运动。伺服马达的运动是由脉冲信号控制的,通过改变脉冲信号的特性来实现不同的运动要求。 首先,STM32微控制器具有高性能和丰富的外设资源,可以灵活地生成和控制脉冲信号。通过配置和控制定时器,可以生成不同频率和占空比的脉冲信号。 其次,STM32微控制器可以与伺服驱动器进行通信,将生成的脉冲信号传递给伺服驱动器。伺服驱动器根据接收到的脉冲信号来控制伺服马达的旋转角度和速度。 此外,STM32还具有丰富的通信接口,如UART、SPI和I2C等,可以与外部设备进行交互。可以通过这些接口来接收来自传感器的反馈信号,实现闭环控制。 最后,使用STM32微控制器进行脉冲控制伺服具有很高的可编程性和灵活性。通过编写相关的代码和算法,可以实现更复杂的运动控制,如位置控制、速度控制和力控制等。同时,STM32的强大的计算能力和丰富的存储资源,也为算法的实现提供了充足的支持。 综上所述,STM32脉冲控制伺服是一种使用STM32微控制器来生成和控制脉冲信号,进而控制伺服马达运动的技术。它通过灵活的配置、通信和编程能力,实现了对伺服马达的高效、精准控制,适用于各种应用场景,如机器人、自动化设备和CNC机床等。 ### 回答2: STM32脉冲控制伺服是一种基于STM32微控制器的伺服控制系统。伺服控制是一种将输入信号转换为运动的控制方法,通过控制电机的转动来实现对输出机械运动的精确控制。 在STM32脉冲控制伺服系统中,通过编程STM32微控制器的定时器模块来生成脉冲信号,控制伺服电机的转动。通过定时器的计数和频率设定,可以精确控制脉冲信号的频率和占空比,从而实现对伺服电机的转速和位置的控制。 在伺服系统中,通常会使用反馈装置(例如编码器)来获取电机实际转动的位置信息,通过与预期位置进行比较,反馈控制系统可以实时调整脉冲信号的输出,从而实现电机转动位置的精确控制STM32脉冲控制伺服系统具有高精度、高可靠性、灵活性强等优点。它可以广泛应用于机械、自动化设备、机器人等领域,实现对运动控制的精确调节和控制。 同时,STM32脉冲控制伺服系统还可以通过与其他传感器、采集装置等硬件模块的联动,实现更复杂的控制功能,例如力矩控制、速度控制等。通过编程和配置,我们可以根据具体的需求和应用场景,灵活地定制和优化伺服系统的控制算法和参数,从而实现更高级的控制策略和更精确的控制效果。 总之,STM32脉冲控制伺服系统是一种功能强大、控制精确的伺服控制系统,广泛应用于各种机械和自动化装置中,为实现高效、精确的运动控制提供了有效的解决方案。 ### 回答3: STM32是一款微控制器,其具有丰富的功能和灵活性,可以用来控制伺服系统的脉冲信号。通过STM32的GPIO引脚和定时器,可以非常方便地生成频率和占空比可调的PWM信号。 伺服系统是一种通过控制电机实现位置、速度或力控制的系统。为了控制伺服电机,需要向其提供一定频率和占空比的脉冲信号。脉冲的频率决定了电机的转速,脉冲的占空比则决定了电机的位置。因此,通过控制STM32的PWM信号的频率和占空比,可以实现对伺服电机控制。 在STM32上实现脉冲控制伺服的步骤如下: 1. 配置GPIO引脚为输出模式,将其连接到伺服电机控制信号端口。 2. 初始化定时器,并设置其工作模式为PWM输出模式。 3. 根据伺服电机的要求,配置PWM的周期和重载值。周期决定了PWM波形的频率,而重载值决定了PWM波形的占空比。 4. 启动定时器,使其开始生成PWM信号。 5. 根据控制需要,不断调整PWM的周期和重载值,以达到所需的控制效果。 通过上述步骤,我们可以利用STM32的脉冲控制功能来控制伺服系统。同时,STM32还支持使用编码器来实现闭环控制,进一步提高伺服系统的精确度和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

一杯苦 Coffee

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

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

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

打赏作者

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

抵扣说明:

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

余额充值