简单驱动步进电机:使用stm32f103zet6的定时器和pwm

驱动步进电机

文章目录

  • 驱动步进电机
  • 前言
  • 一、两种方式的对比
  • 二、第一种方式定时器设置对某个IO进行自动翻转
  • 1.定时器TIM3初始话
  • 2.输出PWM来驱动步进电机
  • 总结

  • 前言

    提示:正如所说简单驱动步进电机,这里使用的定时器方式是很简单的,用一个设置一个确定的定时器周期,在一个周期里面进行对步进电机的IO电平的自动翻转,这里的自动翻转是类似于LED的翻转,比如:LED1=!LED1 ,而PWM驱动步进电机也跟我们驱动直流电机一样简单的。

  • 至于步进电机的驱动方式,大家可以这样简单理解,就是首先我们要区分两种接线方法,一种是共阳接法,按我的接法,就是PUL+和DIR+都是接5V,而PUL-就是你要输出脉冲的IO口,而DIR-就是接控制控制步进电机的正反转的IO,也就是说我的DIR,给高电平的话就正转;然后如果是共阴极的接法就是,相反而已,PUL-和DIR-都是接GND,而PUL+和DIR+分别接输出脉冲IO和控制正反转IO,然后我只要给一个完整的脉冲给电机驱动器,然后如果你设置的细分数是800的话,也就是说360°除以800等于0.45°,也就是接到上面所说的,一个完整的脉冲,步进电机就会转过0.45°,至于电机是里面是怎么动的话,去参考其他大佬的文章肯定比我写得好,我主要就是介绍步进电机的驱动代码

  • 一、两种方式的对比

    这两种方式去驱动步进电机无疑就是我不能改变输出PWM的频率,也就是说我们的步进电机的速度就是一开始就是固定死的,后面还会继续写使用定时器的电平翻转来进行输出脉冲,并且完成步进电机的定位,还有一个简易后的步进电机梯形加减速算法进行控制步进电机的控制。

    二、第一种方式定时器设置对某个IO进行自动翻转

    1.定时器TIM3初始话

    代码如下(示例):

    
    void TIM3_Int_Init(u16 arr,u16 psc)
    {
      	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    	NVIC_InitTypeDef NVIC_InitStructure;
    
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能
    
    	TIM_TimeBaseStructure.TIM_Period = arr;
    	TIM_TimeBaseStructure.TIM_Prescaler =psc;
    	TIM_TimeBaseStructure.TIM_ClockDivision = 0;
    	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
    	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //初始化TIMx的时间基数单位
     
    	TIM_ITConfig(TIM3,TIM_IT_Update ,ENABLE);
    	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3中断
    	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //先占优先级0级
    	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级
    	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
    	NVIC_Init(&NVIC_InitStructure);  //初始化外设NVIC寄存器
    
    	TIM_Cmd(TIM3, ENABLE);  //使能TIMx外设
    							 
    }
    
    

    因为我们只需确定我的定时器的周期,所以我们无需对定时器的IO也进行初始化,然后初始化一个周期为0.001秒的定时器

    TIM3_Int_Init(100-1,719);
    

    这样我们就得到了一个0.001秒的中断函数,然后我们就可以在这一个中断函数里面去进行对IO的电平翻转

    u16 i=0;
    u16 pulse_num=0;
    void TIM3_IRQHandler(void)
    {
    	if(TIM_GetITStatus(TIM3,TIM_IT_Update)!=RESET)//是否发生中断
    	{		
    		i++;
    		moter=1;//
    		Pul=!Pul;
    		if(i%2==0)
    		{
    			pulse_num++;
    			printf("脉冲数为:%d\r\n",pulse_num);
    		}
    		Crtl();
    	}
    	TIM_ClearITPendingBit(TIM3,TIM_IT_Update);  //清除TIMx的中断待处理位:TIM 中断源 
    }
    
    

    定义一个记录进入中断函数的变量来记录我们的脉冲数,每两次进入中断就视为一次完整的脉冲,并且进行对此时刻的脉冲进行打印。这样就能够让我们的步进电机以恒定的速度进行运转,第一种的思路就是这样驱动步进电机。至于函数里面的moter,和PUL都是普通IO都是正常的推挽输出;

    2.输出PWM来驱动步进电机

    代码如下(示例):

    void Driver_Init(void){//初始话PC1
    	GPIO_InitTypeDef  GPIO_InitStructure;
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);	//使能C端口时钟
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 			//推挽输出
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;			//IO口速度为50MHz
    	GPIO_Init(GPIOC, &GPIO_InitStructure);
    	GPIO_ResetBits(GPIOC,GPIO_Pin_1);//拉低io输出
    }
    

    这部分就是初始化c1,作为我们控制步进电机的方向IO

    
    void TIM2_PWM_Init(u16 arr,u16 psc)
    {  
    	GPIO_InitTypeDef 		GPIO_InitStructure;
    	TIM_TimeBaseInitTypeDef  	TIM_TimeBaseStructure;
    	TIM_OCInitTypeDef  	        TIM_OCInitStructure;
    	
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE);//使能定时器B、AFIO时钟 
    	GPIO_AFIODeInit(); 	//重映射必加,以免出现不正常现象。 只需初始一次 避免把原先的重映射给取消了	
    	
    	GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); // 关闭jtag 开启sw   ps:重映射必须使能AFIO时钟  
    	GPIO_PinRemapConfig(GPIO_FullRemap_TIM2,ENABLE);//开启 TIM2完全重映射:4通道重映射==>PB3
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);	 //使能定时器2时钟
    	
     
            //引脚功能配置
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //TIM2_CH1 TIM2_CH2
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;          //复用推挽输出!!
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOB, &GPIO_InitStructure);
     
            //初始化TIM2
    	TIM_TimeBaseStructure.TIM_Period = arr;                     //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
    	TIM_TimeBaseStructure.TIM_Prescaler =psc;                   //设置用来作为TIMx时钟频率除数的预分频值 
    	TIM_TimeBaseStructure.TIM_ClockDivision = 0;                //设置时钟分割:TDTS = Tck_tim
    	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
    	TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);             //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
    	
    	//初始化TIM2 Channel1、Channel2 PWM模式	 
    	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;           //选择定时器模式:TIM脉冲宽度调制模式2
     	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
    	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;   //输出极性:TIM输出比较极性高
    	TIM_OC2Init(TIM2, &TIM_OCInitStructure);                    //根据T指定的参数初始化外设TIM2 OC2
     
    	TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);  //使能TIM2在CCR2上的预装载寄存器
     
    	TIM_Cmd(TIM2, ENABLE);  //使能TIM2
    }
    

    初始化定时器二的PB3,这里的PB3是特殊IO而且还需要对IO进行完全重映射才能使用

    TIM2_PWM_Init(100-1,720-1);
    

    输出频率为1000hz,然后

    void ctrl(void){
    	SET_MOTOR=1;
    	TIM_SetCompare2(TIM2,50);
    }
    

    然后这也是电机正转,然后因为我们设置的装载值为100,也就是设置为50,我们就能得到一半高电平一半低电平的脉冲。然后这样就是pwm的驱动步进电机方法。

    总结

    这两种驱动步进电机的方法很简单,也就只是为了驱动步进电机,知道步进电机应该怎么动,我给一个脉冲,步进电机就会走一个你设置好的细分数下的步距角,其实写这也是主要是为了一些刚刚接触步进电机的同学来玩玩步进电机简单驱动,大佬勿喷,下次更新用步进电机的定时器TIM_OCMode_Toggle这个输出比较模式来进行对脉冲的输出,还有定位函数,各位下次见,以上有错误,感谢指出。

    物联沃分享整理
    物联沃-IOTWORD物联网 » 简单驱动步进电机:使用stm32f103zet6的定时器和pwm

    发表评论