步进电机驱动(ID386驱动器)

最近学习调试了利用 ID386 型号的驱动器来驱动三相电机,分享给大家,mcu是stm32f103

实现功能:

        利用 ID386 驱动器驱动三相电机

        在串口工具中输入命令来使电机按照命令转动,命令格式如下:

        $motor 0999 180 1

        $motor为帧头,0999为转速(这里单位未做转化),180为旋转角度(单位 度),1为方向

实现方式:

 1.设置主从定时器输出脉冲给驱动器

          这里感谢这个帖子提供的参考

          STM32 精确控制PWM脉冲个数_博客-CSDN博客_stm32控制pwm脉冲数量

          主要就是设置TIM4为主定时器,TIM3作为从定时器。TIM4设置为输出PWM,并通过设置参数 TIM_Prescaler和TIM_Period来设置PWM的频率,即脉冲的频率;TIM3用于计  脉冲 个数,将参数TIM_Prescaler设为零,参数TIM_Period所设置的值即为设定的脉冲数,当TIM3计数计到该值时,即产生中断。以下为定时器的配置。

上代码:

void TIM4_Master_TIM3_Slave_Config(u32 PulseFreq,u32 PulseNum)
{
	  GPIO_InitTypeDef  GPIO_InitTypeStruct;
		TIM_TimeBaseInitTypeDef TIM_TimeBaseInitTypeStruct4;
		TIM_OCInitTypeDef   TIM_OCInitTypeStruct4;
		//NVIC_InitTypeDef NVIC_InitTypeStruct4;
	
	  TIM_TimeBaseInitTypeDef TIM_TimeBaseInitTypeStruct3;
		NVIC_InitTypeDef NVIC_InitTypeStruct3;
		//TIM_OCInitTypeDef   TIM_OCInitTypeStruct;
	
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
		
		TIM_TimeBaseInitTypeStruct3.TIM_Prescaler=0;
		TIM_TimeBaseInitTypeStruct3.TIM_CounterMode=TIM_CounterMode_Up;
		TIM_TimeBaseInitTypeStruct3.TIM_Period = PulseNum;
		TIM_TimeBaseInitTypeStruct3.TIM_ClockDivision=TIM_CKD_DIV1;
		TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitTypeStruct3);
		
		TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
		
		NVIC_InitTypeStruct3.NVIC_IRQChannel=TIM3_IRQn;
		NVIC_InitTypeStruct3.NVIC_IRQChannelPreemptionPriority=2;
		NVIC_InitTypeStruct3.NVIC_IRQChannelSubPriority=2;
		NVIC_InitTypeStruct3.NVIC_IRQChannelCmd=ENABLE;
		NVIC_Init(&NVIC_InitTypeStruct3);
	 	
		TIM_SelectInputTrigger(TIM3,TIM_TS_ITR3);
		TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_External1);
		TIM_SelectMasterSlaveMode(TIM3,TIM_MasterSlaveMode_Enable);
		TIM3->CNT=0X00;
		
		RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE);
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO,ENABLE);
		
		GPIO_InitTypeStruct.GPIO_Pin=GPIO_Pin_6;
		GPIO_InitTypeStruct.GPIO_Mode=GPIO_Mode_AF_PP;
		GPIO_InitTypeStruct.GPIO_Speed=GPIO_Speed_50MHz;
		GPIO_Init(GPIOB,&GPIO_InitTypeStruct);
		
		TIM_TimeBaseInitTypeStruct4.TIM_Prescaler=71;
		TIM_TimeBaseInitTypeStruct4.TIM_CounterMode=TIM_CounterMode_Up;
		TIM_TimeBaseInitTypeStruct4.TIM_Period=PulseFreq;
		TIM_TimeBaseInitTypeStruct4.TIM_ClockDivision=TIM_CKD_DIV1;
		TIM_TimeBaseInit(TIM4,&TIM_TimeBaseInitTypeStruct4);
		
		TIM_OCInitTypeStruct4.TIM_OCMode=TIM_OCMode_PWM1;
		TIM_OCInitTypeStruct4.TIM_OutputState=TIM_OutputState_Enable;
		TIM_OCInitTypeStruct4.TIM_Pulse=0;
		TIM_OCInitTypeStruct4.TIM_OCPolarity=TIM_OCPolarity_High;
		TIM_OCInitTypeStruct4.TIM_OCIdleState=TIM_OCIdleState_Set;
		TIM_OC1Init(TIM4,&TIM_OCInitTypeStruct4);
		
		TIM_CtrlPWMOutputs(TIM4,ENABLE);
	 
		TIM_SelectOutputTrigger(TIM4,TIM_TRGOSource_OC1Ref); 
		TIM_SelectMasterSlaveMode(TIM4,TIM_MasterSlaveMode_Enable);
		
		TIM_SetCompare1(TIM4,PulseFreq/2);
		
		TIM_Cmd(TIM3,ENABLE);
		TIM_Cmd(TIM4,ENABLE);
	
}

//定时器3中断服务程序
void TIM3_IRQHandler(void)   //TIM3中断
{
	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源 
		{
		  TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx的中断待处理位:TIM 中断源 
			TIM_SetCompare1(TIM4,0); //定时器4停止产生PWM,这样定时器3的时钟就停止了。如果重新开始计数只需重新设置即可
			TIM3->CNT=0X00;
			rotate_ok_flag = 1;
		}
}

2.命令接收处理部分

        从串口中断中接收上位机发送的命令,并从命令中提取所配置的速度、角度和方向,主要利于函数   sscanf(...) (这个函数是真好用><),并加上一些简单的逻辑。这里就提供一下中断服务函数,和数据处理函数。

上代码:

int speed;
int angle;
int  direct;
u8 config_success_fail;
  
char ReceiveData[30];
u8 ReceiveDataCounter=0;
	
u8 DataReceiveHandle(u8 Res)
{
	if(ReceiveDataCounter>=sizeof(ReceiveData))
	{
		ReceiveDataCounter = sizeof(ReceiveData)-1;
	}
	
	ReceiveData[ReceiveDataCounter] = Res;
	ReceiveDataCounter++;

	if( ReceiveData[0] == '$')
	{  
		;
	}
  else
	{
		 ReceiveDataCounter = 0;
	}
	
	if( ReceiveDataCounter == 17)
	{
		 sscanf(ReceiveData, "%*s%d%d%d",&speed,&angle,&direct);
		
		 printf("\n\r======== 已接收字符: %s =========\n\r", ReceiveData);
		 
		 if(speed<999||speed>9999)            //当speed为999是,速度为120度每秒
		 {
			  config_success_fail = 0;
			  ReceiveDataCounter = 0;
			 
				printf("\n\r======== SPEED_ERROR =========\n\r");
			  printf("\n\r======== SPEED must be [0999,9999] =========\n\r");
			 
			  return 0;
		 }
		 if(angle<0||angle>360)
		 {
			  config_success_fail = 0;
			  ReceiveDataCounter = 0;
			 
				printf("\n\r======== ANGLE_ERROR =========\n\r");
			  printf("\n\r======== ANGLE must be [000,360] =========\n\r");
			 
			  return 0;
		 }
		 if(direct!=0&&direct!=1)
		 {
			  config_success_fail = 0;
			  ReceiveDataCounter = 0;
			 
				printf("\n\r======== DIRECT_ERROR =========\n\r");
			  printf("\n\r======== DIRECT must be 0 or 1 =========\n\r");
			 
			  return 0;
		 }	
		 
		 printf("\n\r======== SPEED is %d =========\n\r",speed);
		 printf("\n\r======== ANGLE is %d =========\n\r",angle);
		 printf("\n\r======== DIRECT is %d =========\n\r",direct);
		 
		 config_success_fail = 1;
		 ReceiveDataCounter = 0;
	}
	
	return 1;
}	

void USART1_IRQHandler(void)                	//串口1中断服务程序
{
	u8 Res;

	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
	{
		 Res = USART_ReceiveData(USART1);	//读取接收到的数据
		 DataReceiveHandle(Res);
  } 

} 

3.主函数

        主函数直接上代码吧,没啥好说的

int main(void)
 {			
		delay_init();	    	 //延时函数初始化	  
		NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 	 //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
		uart_init(115200);	 //串口初始化为115200
    my_GPIO_Init();
	 
	  speed = 0;
	  angle = 0;
	  
		while(1)
		{
			if( rotate_ok_flag ==1 )         //等待上一次转动结束
			{
			  rotate_ok_flag = 0;            //记得及时将flag清零,以便下次使用
		 
				while(1)
				{
				  if(config_success_fail==1)     //等待参数配置成功
				  {
						config_success_fail = 0;
						
						if(direct==1)
						{
							delay_us(20);
							MotorDirect1;
							delay_us(20);
						}
						else if(direct==0)
						{
						    delay_us(20);
							MotorDirect0;
							delay_us(20);         //这里的延时是根据驱动器手册的要求
						}
						
						TIM4_Master_TIM3_Slave_Config(speed,(u32)((angle/360.0)*3000)); //这里的3000是因为驱动器的设置,即3000个脉冲转1圈
						
						break;
				  }
				}		 
			}	
		}

 }

版权声明:本文为CSDN博主「白开水_0」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_38918815/article/details/121913986

生成海报
点赞 0

白开水_0

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐

8522A+7段数码管显示实验

1、8255A简介 8255A是Intel公司生产的可编程并行I/O接口芯片,有3个8位并行I/O口。具有3个通道3种工作方式的可编程并行接口芯片(40引脚)。 其各口功能可由软件选择,

嵌入式体系结构复习笔记

寄存器表示C语言的对应关系 R0: 存储C语言函数返回值R14 : 存储C的函数返回地址R15 : 当前执行程序的代码地址 ARM的常用指令 将数据加载到寄存器:MOV/LDR子程序调用指令: BL软中断调用指