OpenEdv-开源电子网

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

求助:STM32F103通过驱动器控制两个步进电机

[复制链接]

1

主题

8

帖子

0

精华

新手上路

积分
22
金钱
22
注册时间
2016-12-10
在线时间
3 小时
发表于 2016-12-10 11:10:25 | 显示全部楼层 |阅读模式
2金钱
硬件:stm32 mini板 ,两个步进电机驱动器,两个步进电机,X-Y直角坐标丝杠螺母副 。
目的:控制X-Y两轴步进电机的单独运动,只对定位有要求,调速什么的不做要求 。(重复实现固定动作的机构)
步进电机型号:42型:42BYGH4812    57电机型号:57BYGH748
之前看了原子哥的程序,构造了相对定位和绝对定位函数,觉得挺好,但只控制一个轴。仿写多次无果,如今还是只有一轴可动。
恳求大神帮帮菜鸟小弟,使另一轴动起来,或者有完整的代码发我一份研究研究,不胜感激。
步进电机驱动器如图:
驱动器 (1).png
装置示意图如下:

装置.jpg

代码已打包附件。

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

使用道具 举报

1

主题

8

帖子

0

精华

新手上路

积分
22
金钱
22
注册时间
2016-12-10
在线时间
3 小时
 楼主| 发表于 2016-12-10 11:11:35 | 显示全部楼层
代码没上传成功,附二楼。。

MiniSTM32扩展实验18 ATK-2MD4850步进电机驱动器实验.zip

193.14 KB, 下载次数: 875

回复

使用道具 举报

1

主题

8

帖子

0

精华

新手上路

积分
22
金钱
22
注册时间
2016-12-10
在线时间
3 小时
 楼主| 发表于 2016-12-10 11:13:15 | 显示全部楼层
[mw_shl_code=applescript,true]#include "sys.h"       //声明包含sys.h头文件
#include "usart.h"           //串口调试头文件
#include "delay.h"           //延时函数头文件
#include "led.h"       //LED灯头文件
#include "key.h"       //按键头文件
#include "usmart.h"
#include "driver.h"    //驱动头文件
       
int main(void)         //主函数
{                                            
        u8 i;
        u8 keyval;
        Stm32_Clock_Init(9);        //系统时钟设置
        uart_init(72,115200);        //串口初始化为115200
        delay_init(72);                            //延时初始化
        usmart_dev.init(72);         //初始化USMART                                        
        LED_Init();                                  //初始化与LED连接的硬件接口
        KEY_Init();                                        //初始化按键
        Driver_Init();                        //驱动器初始化
        TIM8_OPM_RCR_Init(999,72-1); //1MHz计数频率  单脉冲+重复计数模式          
        while(1)
        {                           
                keyval=KEY_Scan(0);
                if(keyval==WKUP_PRES)
                {
                        Locate_Abs(0,500);//按下WKUP,回零点
                }else if(keyval==KEY0_PRES)
                {
                        Locate_Rle(200,500,CW);//按下KEY0,以500Hz的频率 顺时针发200脉冲
                }else if(keyval==KEY1_PRES)
                {
                        Locate_Rle(400,500,CCW);//按下KEY1,以500Hz的频率 逆时针发400脉冲
                }                                       
                delay_ms(10);//延时10毫秒
                i++;         //i自增加
                if(i==50)        //判断i=50,重置i数值,LED1闪烁
                {       
                        i=0;
                        LED1=!LED1;
                }       
        }
}
       








[/mw_shl_code]
回复

使用道具 举报

1

主题

8

帖子

0

精华

新手上路

积分
22
金钱
22
注册时间
2016-12-10
在线时间
3 小时
 楼主| 发表于 2016-12-10 11:14:54 | 显示全部楼层
驱动头文件[mw_shl_code=applescript,true]#ifndef __DRIVER_H
#define __DRIVER_H
#include "sys.h"
#include "stdlib.h"       


/********** 驱动器 端口定义 **************
//DRIVER_DIR   PC0
//DRIVER_OE    PC2
//STEP_PULSE   PC7 (TIM8_CH2,LCD_RW)
******************************************/
#define DRIVER_DIR   PCout(0) // 旋转方向
#define DRIVER_OE    PCout(2) // 使能脚 低电平有效
#define RCR_VAL    255  //每计数(RCR_VAL+1)次,中断一次,这个值(0~255)设置大一些可以降低中断频率

typedef enum
{
        CW = 1,//高电平顺时针
        CCW = 0,//低电平逆时针
}DIR_Type;//运行方向

extern long target_pos;//有符号方向
extern long current_pos;//有符号方向

void Driver_Init(void);//驱动器初始化
void TIM8_OPM_RCR_Init(u16 arr,u16 psc);//TIM8_CH2 单脉冲输出+重复计数功能初始化
void TIM8_Startup(u32 frequency);   //启动定时器8
void Locate_Rle(long num,u32 frequency,DIR_Type dir); //相对定位函数
void Locate_Abs(long num,u32 frequency);//绝对定位函数

#endif

[/mw_shl_code]
回复

使用道具 举报

1

主题

8

帖子

0

精华

新手上路

积分
22
金钱
22
注册时间
2016-12-10
在线时间
3 小时
 楼主| 发表于 2016-12-10 11:15:34 | 显示全部楼层
驱动代码[mw_shl_code=applescript,true]#include "driver.h"
#include "delay.h"
#include "usart.h"


//////////////////////////////////////////////////////////////////////////////////
/********** 驱动器 端口定义 **************
//DRIVER_DIR   PC0
//DRIVER_OE    PC2
//STEP_PULSE   PC7 (TIM8_CH2,LCD_RW)
******************************************/

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

/************** 驱动器控制信号线初始化 ****************/
void Driver_Init(void)
{
        RCC->APB2ENR|=1<<4; //GPIOC时钟使能
       
        GPIOC->CRL&=0XFFFFF0F0;        //PC0,2推挽输出
        GPIOC->CRL|=0X00000303;        //PC0,2推挽输出
        DRIVER_DIR=1;   //PC0输出高 顺时针方向
        DRIVER_OE=0;         //PC2输出低 使能输出
}

/***********************************************
//TIM8_CH2(PC7) 单脉冲输出+重复计数功能初始化
//TIM8 时钟频率 72MHz
//arr:自动重装值
//psc:时钟预分频数
************************************************/
void TIM8_OPM_RCR_Init(u16 arr,u16 psc)
{                                                          
        //此部分需手动修改IO口设置
        RCC->APB2ENR|=1<<13;         //TIM8时钟使能
        RCC->APB2ENR|=1<<4;         //GPIOC时钟使能       
        GPIOC->CRL&=0X0FFFFFFF;        //PC7清除之前的设置
        GPIOC->CRL|=0XB0000000;        //复用功能输出  
       
        TIM8->ARR=arr;                        //设定计数器自动重装值
        TIM8->PSC=psc;                        //预分频器设置       
        TIM8->CCR2=TIM8->ARR>>1;//比较值
        TIM8->CR1|=1<<2;                   //设置只有计数溢出作为更新中断
        TIM8->CR1|=1<<3;                   //单脉冲模式
        TIM8->CCMR1|=7<<12;          //CH2 PWM2模式       
        TIM8->CCMR1|=1<<11;         //CH2预装载使能                       
        TIM8->CCER|=1<<4;           //OC2 输出使能          
        TIM8->CR1|=0x0080;           //ARPE使能
        TIM8->DIER|=1<<0;           //允许更新中断
        MY_NVIC_Init(1,1,TIM8_UP_IRQn,2);//抢占1,子优先级1,组2       
        TIM8->SR=0;//清除所有标志位
        TIM8->CR1|=0x01; //使能定时器8                                                                                   
}
/******* TIM8更新中断服务程序 *********/
void TIM8_UP_IRQHandler(void)
{
        if(TIM8->SR&(1<<0))//更新中断
        {
                TIM8->SR&=~(1<<0);//清除更新中断标志位       
                if(is_rcr_finish==0)//重复计数器未设置完成
                {
                        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,直接退出                       
                        TIM8->EGR|=0x01;  //产生一个更新事件 重新初始化计数器
                        TIM8->BDTR|=1<<15;//MOE 主输出使能
                        TIM8->CR1|=0x01;  //使能定时器8                       
                        if(motor_dir==CW) //如果方向为顺时针   
                                current_pos+=(TIM8->RCR+1);//加上重复计数值
                        else          //否则方向为逆时针
                                current_pos-=(TIM8->RCR+1);//减去重复计数值                       
                }else
                {
out:                is_rcr_finish=1;//重复计数器设置完成
                        TIM8->BDTR&=~(1<<15);//MOE 关闭主输出
                        TIM8->CR1&=~(1<<0);  //关闭定时器8                                               
                        printf("当前位置=%ld\r\n",current_pos);//打印输出
                }       
        }
}
/***************** 启动TIM8 *****************/
void TIM8_Startup(u32 frequency)   //启动定时器8
{
        TIM8->ARR=1000000/frequency-1; //设定重装值       
        TIM8->CCR2=TIM8->ARR>>1;   //匹配值2等于重装值一半,是以占空比为50%       
        TIM8->CNT=0;//计数器清零
        TIM8->CR1|=1<<0;   //启动定时器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
        }
}




[/mw_shl_code]
回复

使用道具 举报

1

主题

8

帖子

0

精华

新手上路

积分
22
金钱
22
注册时间
2016-12-10
在线时间
3 小时
 楼主| 发表于 2016-12-10 11:24:48 | 显示全部楼层
函数说明: 111.jpg
回复

使用道具 举报

1

主题

8

帖子

0

精华

新手上路

积分
22
金钱
22
注册时间
2016-12-10
在线时间
3 小时
 楼主| 发表于 2016-12-10 15:28:33 | 显示全部楼层
有木有人(=@__@=)。。
回复

使用道具 举报

3

主题

2170

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
5779
金钱
5779
注册时间
2013-11-22
在线时间
1211 小时
发表于 2016-12-10 21:37:51 | 显示全部楼层
按照同样的方法再搞一个 定时器。
回复

使用道具 举报

1

主题

8

帖子

0

精华

新手上路

积分
22
金钱
22
注册时间
2016-12-10
在线时间
3 小时
 楼主| 发表于 2016-12-11 09:55:11 | 显示全部楼层
lycreturn 发表于 2016-12-10 21:37
按照同样的方法再搞一个 定时器。

我模仿着用TIM1又写了一遍,结果没反应。仿着又写了一个驱动.c和.h引用进去还是没用。编译也没报错,不知道是什么原因,希望有经验的可以提点提点。。会是哪里的问题?我只修改了 driver.c和driver.h以及main.c文件。
回复

使用道具 举报

3

主题

2170

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
5779
金钱
5779
注册时间
2013-11-22
在线时间
1211 小时
发表于 2016-12-11 17:27:40 | 显示全部楼层
GregJoy 发表于 2016-12-11 09:55
我模仿着用TIM1又写了一遍,结果没反应。仿着又写了一个驱动.c和.h引用进去还是没用。编译也没报错,不知 ...

说明可能某些地方没改对,仔细检查下
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165524
金钱
165524
注册时间
2010-12-1
在线时间
2116 小时
发表于 2016-12-12 21:05:50 | 显示全部楼层
依葫芦画瓢,再写一个类似的函数就行了啊。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

0

主题

2

帖子

0

精华

新手入门

积分
10
金钱
10
注册时间
2017-8-10
在线时间
3 小时
发表于 2017-8-10 17:51:35 | 显示全部楼层
GregJoy 发表于 2016-12-11 09:55
我模仿着用TIM1又写了一遍,结果没反应。仿着又写了一个驱动.c和.h引用进去还是没用。编译也没报错,不知 ...

我也用定时器1写了个类似的函数。定时器1的函数也能单独控制电机定位。但是与原子哥的例程结合,就只能控制一个电机运动了
回复

使用道具 举报

0

主题

3

帖子

0

精华

新手上路

积分
21
金钱
21
注册时间
2018-1-23
在线时间
8 小时
发表于 2018-1-24 09:37:57 | 显示全部楼层

请问现在楼主的问题解决了吗,我现在 也是想通过这个例程改成可以同时控制两个步进电机,不过和楼主一样,并没有成功,如果楼主解决了,能不能和我分享一下经验,不胜感激。
回复

使用道具 举报

4

主题

17

帖子

0

精华

新手上路

积分
30
金钱
30
注册时间
2019-1-10
在线时间
16 小时
发表于 2019-4-14 16:49:41 | 显示全部楼层
请问现在楼主的问题解决了吗,我现在 也是想通过这个例程改成可以同时控制两个步进电机,不过和楼主一样,并没有成功,如果楼主解决了,能不能和我分享一下经验,不胜感激。
回复

使用道具 举报

0

主题

7

帖子

0

精华

新手入门

积分
17
金钱
17
注册时间
2019-7-18
在线时间
3 小时
发表于 2019-7-28 10:50:56 | 显示全部楼层
我也在做控制两个步进电机的程序,请问解决了吗
回复

使用道具 举报

0

主题

3

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2019-7-1
在线时间
9 小时
发表于 2019-8-27 11:36:42 | 显示全部楼层
马天宇 发表于 2018-1-24 09:37
**** 作者被禁止或删除 内容自动屏蔽 ****

求问老哥这个问题解决了吗?我也改了半天没有成功,如果老哥解决了,可以分享一下吗,感激不尽!
回复

使用道具 举报

0

主题

3

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2019-7-1
在线时间
9 小时
发表于 2019-8-27 11:38:38 | 显示全部楼层
376127631 发表于 2019-4-14 16:49
请问现在楼主的问题解决了吗,我现在 也是想通过这个例程改成可以同时控制两个步进电机,不过和楼主一样, ...

求问老哥两个高级定时器驱动两个步进电机驱动器的问题解决了吗?我也改了半天没有成功,如果老哥解决了,可以分享一下吗,感激不尽!
回复

使用道具 举报

0

主题

3

帖子

0

精华

新手上路

积分
32
金钱
32
注册时间
2019-7-1
在线时间
9 小时
发表于 2019-8-27 11:39:01 | 显示全部楼层
DC斗川 发表于 2019-7-28 10:50
我也在做控制两个步进电机的程序,请问解决了吗

求问老哥两个高级定时器驱动两个步进电机驱动器的问题解决了吗?我也改了半天没有成功,如果老哥解决了,可以分享一下吗,感激不尽!
回复

使用道具 举报

1

主题

15

帖子

0

精华

初级会员

Rank: 2

积分
98
金钱
98
注册时间
2019-8-6
在线时间
22 小时
发表于 2019-9-9 16:15:05 | 显示全部楼层
老哥  解决了吗?  我刚刚调到这个问题
回复

使用道具 举报

0

主题

10

帖子

0

精华

新手上路

积分
42
金钱
42
注册时间
2019-11-8
在线时间
15 小时
发表于 2020-3-30 18:03:53 | 显示全部楼层
lycreturn 发表于 2016-12-10 21:37
按照同样的方法再搞一个 定时器。

对于F767,不能用其他通道吗?? 非要换一个定时器
回复

使用道具 举报

1

主题

100

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
279
金钱
279
注册时间
2019-8-29
在线时间
31 小时
发表于 2020-4-5 11:18:22 | 显示全部楼层
继续加油
回复

使用道具 举报

0

主题

5

帖子

0

精华

新手入门

积分
15
金钱
15
注册时间
2020-4-7
在线时间
4 小时
发表于 2020-4-8 13:26:57 | 显示全部楼层
TOP TOP TOP
回复

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
7
金钱
7
注册时间
2020-4-1
在线时间
2 小时
发表于 2020-5-8 17:51:07 | 显示全部楼层
老哥解决了么?我也遇到了这个问题
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-5-29 06:27

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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