OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 5473|回复: 8

STM32F4驱动步进电机,用官方例程改了驱动不起来

[复制链接]

5

主题

18

帖子

0

精华

初级会员

Rank: 2

积分
129
金钱
129
注册时间
2019-12-30
在线时间
22 小时
发表于 2020-7-19 10:50:13 | 显示全部楼层 |阅读模式
5金钱
本帖最后由 resumebb 于 2020-7-19 10:51 编辑

请问一下各位大佬,我用例程针对具体的电机驱动改了下.
原例程是
ENA+(驱动器) PE6(开发板)
DIR+(驱动器) PE5(开发板)
PUL+(驱动器) PC7(开发板)
ENA- DIR- PUL-(驱动器) GND(开发板)
用的TIM8_CH2


我用的共阳极
ENA-(驱动器) PG0(开发板)
DIR-(驱动器) PG2(开发板)
PUL-(驱动器) PC6(开发板)
ENA- DIR- PUL-(驱动器) GND(开发板)
改为TIM8_CH1

下面是我改了的驱动程序,但是电机驱动不起来,用同样的方法之前驱动57就好的,能帮我看看是什么原因吗?






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


u8 rcr_remainder;   //重复计数余数部分
u8 is_rcr_finish=1; //重复计数器是否设置完成
long rcr_integer;        //重复计数整数部分
long target_pos=0;  //有符号方向
long current_pos=0; //有符号方向
DIR_Type motor_dir=CCW;//顺时针

/************** 驱动器控制信号线初始化 ****************/
void Driver_Init(void)
{
        GPIO_InitTypeDef  GPIO_InitStructure;

        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);//使能GPIOG时钟

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_2; //DRIVER_DIR DRIVER_OE对应引脚
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100M
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
        GPIO_Init(GPIOG, &GPIO_InitStructure);
        
        GPIO_SetBits(GPIOG,GPIO_Pin_0);//PG0高使能
        GPIO_ResetBits(GPIOG,GPIO_Pin_2);//PG2低顺时针
        
}


/***********************************************
//TIM8_CH2(PC7) 单脉冲输出+重复计数功能初始化
//TIM8 时钟频率 84*2=168MHz
//arr:自动重装值
//psc:时钟预分频数
************************************************/
void TIM8_OPM_RCR_Init(u16 arr,u16 psc)
{                                                         
        GPIO_InitTypeDef GPIO_InitStructure;
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        TIM_OCInitTypeDef  TIM_OCInitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8,ENABLE);          //TIM8时钟使能   
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);         //使能PORTC时钟                                                                                    

        GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_TIM8); //GPIOC6复用为定时器8
        
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;           //GPIOC6
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;        //复用功能
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;        //速度100MHz
        GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;      //推挽复用输出
        GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;      //下拉
        GPIO_Init(GPIOC,&GPIO_InitStructure);               //初始化PC6
        
        TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
        
        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(TIM8, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
        TIM_ClearITPendingBit(TIM8,TIM_IT_Update);

        TIM_UpdateRequestConfig(TIM8,TIM_UpdateSource_Regular); /********* 设置只有计数溢出作为更新中断 ********/
        TIM_SelectOnePulseMode(TIM8,TIM_OPMode_Single);/******* 单脉冲模式 **********/

        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式2
        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出2使能
        TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable; /****** 比较输出2N失能 *******/
        TIM_OCInitStructure.TIM_Pulse = arr>>1; //设置待装入捕获比较寄存器的脉冲值,右移一位
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
        TIM_OC1Init(TIM8, &TIM_OCInitStructure);  //根据TIM_OCInitStruct中指定的参数初始化外设TIMx

        TIM_OC1PreloadConfig(TIM8, TIM_OCPreload_Enable);  //CH1预装载使能         
        TIM_ARRPreloadConfig(TIM8, ENABLE); //使能TIMx在ARR上的预装载寄存器
        
        TIM_ITConfig(TIM8, TIM_IT_Update ,ENABLE);  //TIM8   使能或者失能指定的TIM中断

        NVIC_InitStructure.NVIC_IRQChannel = TIM8_UP_TIM13_IRQn;  //TIM8中断
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  //先占优先级1级
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;  //从优先级1级
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
        NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
        
        TIM_ClearITPendingBit(TIM8, TIM_IT_Update);  //清除TIMx的中断待处理位:TIM 中断源
        TIM_Cmd(TIM8, ENABLE);  //使能TIM8                                                                                          
}
/******* TIM8更新中断服务程序 *********/
void TIM8_UP_TIM13_IRQHandler(void)
{
        if(TIM_GetITStatus(TIM8,TIM_FLAG_Update)!=RESET)//获取当前定时器状态,判断是否完成更新,更新中断
        {
                TIM_ClearITPendingBit(TIM8,TIM_FLAG_Update);//清除更新中断标志位               
                if(is_rcr_finish==0)//重复计数器未设置完成    重复计数器默认初始值为1,已完成状态
                {
                        if(rcr_integer!=0) //整数部分脉冲还未发送完成
                        {
                                TIM8->RCR=RCR_VAL;//设置重复计数值
                                rcr_integer--;//减少RCR_VAL+1个脉冲                                
                        }else if(rcr_remainder!=0)//余数部分脉冲 不为0
                        {
                                TIM8->RCR=rcr_remainder-1;//设置余数部分
                                rcr_remainder=0;//清零
                                is_rcr_finish=1;//重复计数器设置完成                                
                        }else goto out;   //rcr_remainder=0,直接退出                        
                        TIM_GenerateEvent(TIM8,TIM_EventSource_Update);//产生一个更新事件 重新初始化计数器
                        TIM_CtrlPWMOutputs(TIM8,ENABLE);        //MOE 主输出使能        
                        TIM_Cmd(TIM8, ENABLE);  //使能TIM8                        
                        if(motor_dir==CW) //如果方向为顺时针   
                                current_pos+=(TIM8->RCR+1);//加上重复计数值
                        else          //否则方向为逆时针
                                current_pos-=(TIM8->RCR+1);//减去重复计数值                        
                }else
                {
out:                is_rcr_finish=1;//重复计数器设置完成
                        TIM_CtrlPWMOutputs(TIM8,DISABLE);        //MOE 主输出关闭
                        TIM_Cmd(TIM8, DISABLE);  //关闭TIM8                                V
                        printf("当前位置=%ld\r\n",current_pos);//打印输出
                }        
        }
}
/***************** 启动TIM8 *****************/
void TIM8_Startup(u32 frequency)   //启动定时器8
{
        u16 temp_arr=1000000/frequency-1;
        TIM_SetAutoreload(TIM8,temp_arr);//设定自动重装值        
        TIM_SetCompare1(TIM8,temp_arr>>1); //匹配值2等于重装值一半,是以占空比为50%        
        TIM_SetCounter(TIM8,0);//计数器清零
        TIM_Cmd(TIM8, ENABLE);  //使能TIM8
}
/********************************************
//相对定位函数
//num 0~2147483647
//frequency: 20Hz~100KHz
//dir: CW(顺时针方向)  CCW(逆时针方向)
*********************************************/
void Locate_Rle(long num,u32 frequency,DIR_Type dir) //相对定位函数
{
        if(num<=0) //数值小等于0 则直接返回
        {
                printf("\r\nThe num should be greater than zero!!\r\n");
                return;
        }
        if(TIM8->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_dir=dir;//得到方向        
        DRIVER_DIR=motor_dir;//设置方向
        
        if(motor_dir==CW)//顺时针
                target_pos=current_pos+num;//目标位置
        else if(motor_dir==CCW)//逆时针
                target_pos=current_pos-num;//目标位置
        
        rcr_integer=num/(RCR_VAL+1);//重复计数整数部分
        rcr_remainder=num%(RCR_VAL+1);//重复计数余数部分
        is_rcr_finish=0;//重复计数器未设置完成
        TIM8_Startup(frequency);//开启TIM8
}
/********************************************
//绝对定位函数
//num   -2147483648~2147483647
//frequency: 20Hz~100KHz
*********************************************/
void Locate_Abs(long num,u32 frequency)//绝对定位函数
{
        if(TIM8->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;
        }
        target_pos=num;//设置目标位置
        if(target_pos!=current_pos)//目标和当前位置不同
        {
                if(target_pos>current_pos)
                        motor_dir=CW;//顺时针
                else
                        motor_dir=CCW;//逆时针
                DRIVER_DIR=motor_dir;//设置方向
               
                rcr_integer=abs(target_pos-current_pos)/(RCR_VAL+1);//重复计数整数部分
                rcr_remainder=abs(target_pos-current_pos)%(RCR_VAL+1);//重复计数余数部分
                is_rcr_finish=0;//重复计数器设置完成
                TIM8_Startup(frequency);//开启TIM8
        }
}





最佳答案

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

5

主题

18

帖子

0

精华

初级会员

Rank: 2

积分
129
金钱
129
注册时间
2019-12-30
在线时间
22 小时
 楼主| 发表于 2020-7-19 10:50:14 | 显示全部楼层
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165371
金钱
165371
注册时间
2010-12-1
在线时间
2110 小时
发表于 2020-7-20 01:50:04 | 显示全部楼层
帮顶
回复

使用道具 举报

3

主题

7

帖子

0

精华

新手上路

积分
42
金钱
42
注册时间
2020-7-12
在线时间
13 小时
发表于 2020-7-26 18:12:46 | 显示全部楼层
你前后矛盾啊。前面的顺时针定义是CCW,你后面写的又变成了CW了。
回复

使用道具 举报

2

主题

10

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
221
金钱
221
注册时间
2020-7-7
在线时间
41 小时
发表于 2020-7-29 09:40:42 | 显示全部楼层
本帖最后由 rioway 于 2020-7-29 09:46 编辑

#include "bjdjpwm.h"
#include "sys.h"
#include "delay.h"
int cnt = 0;

void BJDJ_Init(u16 arr,u16 psc)//IO初始化
{
        //PA4为DIR,高低电平控制方向,PA6输出PWM;  PE2,3,4为按钮控制
        GPIO_InitTypeDef GPIO_InitStructure;  
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        TIM_OCInitTypeDef  TIM_OCInitStructure;
        EXTI_InitTypeDef EXTI_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
        
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //外部中断 开启 AFIO 时钟
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);        
         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOE,ENABLE);//使能PORTA和复用时钟
        
        GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4;//PA4
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
         GPIO_Init(GPIOE, &GPIO_InitStructure);
        
        GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_4;//PA4
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
         GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA4
        GPIO_SetBits(GPIOA,GPIO_Pin_4);//正转
        
        GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_6;//PA6
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
         GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA6
               
        GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2);
        
        EXTI_InitStructure.EXTI_Line=EXTI_Line2;
        EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
        EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发
        EXTI_InitStructure.EXTI_LineCmd = ENABLE;
        EXTI_Init(&EXTI_InitStructure); //初始化中断线参数
        
        NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn; //使能按键外部中断通道
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02; //抢占优先级 2,
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02; //子优先级 2
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
        NVIC_Init(&NVIC_InitStructure);//⑤初始化 NVIC

        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(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
        

        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式:TIM脉冲宽度调制模式2
         TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
        TIM_OCInitStructure.TIM_Pulse =50;  //占空比50%
        TIM_OC1Init(TIM3, &TIM_OCInitStructure);  //根据T指定的参数初始化外设TIM3 OC1

        TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR2上的预装载寄存器

        TIM_Cmd(TIM3, ENABLE);  //使能TIM3
}

u8 KEY_Scan(u8 mode)
{         
        static u8 key_up=1;//按键按松开标志
        if(mode)key_up=1;  //支持连按                  
        if(key_up&&(KEY0==0||KEY1==0||KEY2==0))
        {
                delay_ms(10);//去抖动
                key_up=0;
                if(KEY0==0)return KEY0_PRES;
                else if(KEY1==0)return KEY1_PRES;
                else if(KEY2==0)return KEY2_PRES;
        }else if(KEY0==1&&KEY1==1&&KEY2==1)key_up=1;            
         return 0;// 无按键按下
}

void EXTI2_IRQHandler(void)
{
        delay_ms(10);
        if(KEY2 == 0)
        cnt++;
        if(cnt%2==1)
                TIM_Cmd(TIM3, DISABLE);
        else
                TIM_Cmd(TIM3, ENABLE);
               
        EXTI_ClearITPendingBit(EXTI_Line2); //清除 LINE2 上的中断标志位
}
这是用PA6输出PWM,PA4控制方向;可以实现正反转。

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

//功能:key2按下一次电机会停止,再按一次会启动;
int main(void)
{
        int i = 0;

        delay_init();                     //延时函数初始化         
         BJDJ_Init(499,71);         //不分频。PWM周期=(499+1)(71+1)/72M
        while(1)
        {//电机正反转
                        DIR=0;        
                        delay_ms(3000);               
                        DIR=1;
                        delay_ms(3000);

}        
DIR是PA4.
刚学习PWM,使用定时器TIM3_CH1,对应接口是PA6,高级定时器还没学习

回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165371
金钱
165371
注册时间
2010-12-1
在线时间
2110 小时
发表于 2020-7-30 03:10:14 | 显示全部楼层
帮顶
回复

使用道具 举报

0

主题

6

帖子

0

精华

新手上路

积分
30
金钱
30
注册时间
2019-5-22
在线时间
14 小时
发表于 2020-9-25 21:00:06 | 显示全部楼层
楼主,用的是哪里的例程?
回复

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
14
金钱
14
注册时间
2021-11-13
在线时间
2 小时
发表于 2021-11-13 11:21:58 | 显示全部楼层

楼主解决办法是什么啊
回复

使用道具 举报

1

主题

11

帖子

0

精华

新手上路

积分
46
金钱
46
注册时间
2021-11-12
在线时间
12 小时
发表于 2022-1-11 09:00:03 | 显示全部楼层
怎么解决的,我也遇到同样问题,看你代码没发现有什么错误,能否分享一下经验?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-2-26 06:14

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表