查看: 974|回复: 12

[经验] 使用按键通过UNO控制驱动器操作步进电机[续]

[复制链接]
  • TA的每日心情
    奋斗
    2019-3-22 22:34
  • 签到天数: 73 天

    [LV.6]常住居民II

    发表于 2019-1-9 23:22 | 显示全部楼层 |阅读模式
    本帖最后由 thsel 于 2019-1-9 23:31 编辑

    昨天经过半宿努力成功让我的步进电机转了起来,今天晚上索性加了把劲.给步进电机加了正转,反转,细分数调整,用电位器调速功能.
    现在整理一下.


    步进电机的接线请参考我发的另一篇帖子.
    地址如下:


    使用UNO通过驱动器操作步进电机
    https://www.arduino.cn/forum.php?mod=viewthread&tid=83597&fromuid=170232
    (出处: Arduino中文社区)



    这里先展示一下今天加的硬件的的接线图.


    终于也能像论坛里那些大神一样发高大上的逻辑图了.
    sc7.png


    闲话不多说了,直接上代码吧.代码里面有比较"详细"的备注!!


    原凉本人才疏学浅,部份文字写的不是很那个啥嗷!!!

    再次声明一下,本人刚接触Arduino编程不足一星期,代码中或者备注中难免有不正规的地方,还请各位将就着看或者指正,谢谢!

    主要还是在昨天发的那个让步进电机转起来的基础上升级的.

    kittenblock中小学创客名师推荐的图形化编程软件

    /**
     * Copyright(C),2019,Thsel.Com
     * FileName:步进电机测试.ino
     * Author:thsel
     * Creat:2019.1.8
     * Creat:2019.1.9
     * 
     * 这里声明一下嗷,我学Audrino刚刚不到一个星期,很多术语都不是很专业,只是按照我个人的理解来进行的解释.
     * 大神们还请飘过或指证其中的错误.
     * Arduino的路我刚刚踏进来一只脚,还希望各路神仙指导教育.再次感谢.
     */
    const int DI = 9 ; //声明变量 方向信号在9针脚
    const int PU = 8; //声明变量 脉冲信号在8针脚
    const int EN = 7; //声明变量 使能信号在7针脚
    const int KEY1 = 2; //声明变量 按钮1在2针脚 反转
    const int KEY2 = 3; //声明变量 按钮2在3针脚 正转
    const int KEY3 = 4; //声明变量 按钮3在4针脚 加细分
    const int KEY4 = 5; //声明变量 按钮4在5针脚 减细分
    int SPEED_1 = 0; //这里用来存储临时微秒数(刚接触Arduino不到一个星期,很多术语都不专业,只是按我的理解来写的.)
    int SPEED_2 = 800;//这里用来存储临时细分数
    void setup() {
      pinMode(DI, OUTPUT);
      pinMode(PU, OUTPUT);
      pinMode(EN, OUTPUT);
      pinMode(KEY1, INPUT);
      pinMode(KEY2, INPUT);
      pinMode(KEY3, INPUT);
      pinMode(KEY4, INPUT);
      Serial.begin(9600);
    }
    
    void loop() {
      SPEED();  //算是子程序吧.   这个子程序通过A0接口读电位器,用来计算步进微秒数
      XRUN();  //先叫子程序吧.    这个子程序通过3/4两个按钮调整细分数.
      //步时电机方向信号高电平转动代码---开始
      if (digitalRead(KEY2) == HIGH) {
        digitalWrite(DI, HIGH);
        RUN();
      }
      //步进电机方向信号高电平转动代码---结束
      
      //步进电机方向信号低电平转动代码---开始
      if (digitalRead(KEY1) == HIGH) {
        digitalWrite(DI, LOW);
        RUN();
      }
      //步进电机方向信号低电平转动代码---结束
    }
    
    //子程序-微秒-代码---开始  这个子程序通过A0接口读取电位器的数值,在这里,我用这个参考数值计算步进微秒数
    void SPEED() {
      int sensorValue = analogRead(A0);    //这是论坛里找到的,意思自行理解吧.
      float voltage = sensorValue * (5.0 / 1023.0);  //这也是论坛里找到的,意思自行理解吧,反正这么用,是好使.
      SPEED_1 = voltage * 200;  //由于电位器最高只能反馈到5,这里为了细化运转的微秒数,我将反馈的数值乘以200用以放大和精确微秒数
      if (SPEED_1 <= 70)  //这里用来判断微秒数是否小于70,因为我测试的时候发现,这个微秒数如果小于70的话,我的步进电机就会发出奇怪的声音,这声音在我的3D打印机上听到过.也是因为程序运行速度过快才听到的.
      {
        SPEED_1 = 70; //小于70的话,自动设置到70,不再减小.
      }
      else {
        SPEED_1 = voltage * 200;  //如果不小于70,那么就按照程序参数,放大电位器参数200倍.
        //Serial.println(SPEED_1);  //调试的时候这里输出看一下数值.
      }
    
    }
    //子程序-微秒-代码---结束
    
    //子程序-运转-代码---开始  这里让步进电机按参数转动.
    void RUN()
    {
      //下面的程序让步进电机转起来
      for (int x = 0; x < SPEED_2; x++)   //这里的SPEED_2就是通过细分代码读出的细分值(之前说过了啊,我刚学这个一周,很多术语不专业)
      {
        digitalWrite(PU, HIGH);
        delayMicroseconds(SPEED_1);  //这里的SPEED_1就是通过微秒代码取出的微秒值,应该是步进电机转动的速度的表现吧.      这里加了两次微秒,没试过加一次会怎么样,在电平高的时候加了一次微秒,在电平低的时候又加了一次微秒,两次微秒受同一个电位器控制.
        digitalWrite(PU, LOW);
        delayMicroseconds(SPEED_1);//这里的SPEED_1就是通过微秒代码取出的微秒值,应该是步进电机转动的速度的表现吧.      这里加了两次微秒,没试过加一次会怎么样,在电平高的时候加了一次微秒,在电平低的时候又加了一次微秒,两次微秒受同一个电位器控制.
        //上面的程序让步进电机转起来
      }
    }
    //子程序-运转-代码---结束
    
    //子程序-细分-代码---开始 这里通过两个按钮来控制细分,我在驱动器上设置的是800,所以,上面定义变量的默认值是800.当使用默认800的时候,我们按动按键1或者按键2一次.注意,按完要松开,速度要快,这时,电机只转一圈.
    void XRUN()
    {
      //Serial.println(SPEED_2);  //这里调试输出了一下细分的值,用来看大概的意思.
      if (digitalRead(KEY3) == HIGH) {   //按键3被按1次,细分值+1,这里发现,按住会连续加.
        SPEED_2 = SPEED_2 + 1;
      }
      if (SPEED_2 > 800) {    //如果细分值大于800,那就只到800,不再相加.
        SPEED_2 = 800;  //这个一定要和驱动器上的细分拔码匹配嗷!!
      }
      if (digitalRead(KEY4) == HIGH) {   //按键4被按1次,细分值-1,这里也是,按住会连减.
        SPEED_2 = SPEED_2 - 1;
      }
      if (SPEED_2 < 1) {//如果细分值小于1了,即为0了,那就只到1,不再相减.
        SPEED_2 = 1;
      }
    }



    具体的看上面的备注吧....我也不多说了.....上几张照片.
    先来一张万能板的,正面照,真心不舍得用跳线焊,搞了一段网线焊接,没成想是段铝包铁的网线,奇硬无比!
    sc1.png
    再给大家看一下背面的照片,焊接能力有限,大神们将就着看嗷.
    sc2.png
    由于心疼跳线和主板,中间插了块面包板作为中转站.毕竟面包板还是买得起滴!!!
    sc3.png
    上图中的驱动器请回到最顶端看前面的帖子!里面有介绍和方法.
    步进电机和将要应用到的地方.打了10几个小时.各种调整测试.
    sc4.png
    来来来,看看我的功臣们,焊接/测量!
    sc5.png
    这是一堆减扒削吸!
    sc6.png


    最后来看看乱得跟猪窝一样的操作台!!!
    sc7.png










    这么作完以后,按键自左到右分别是:正转(理论上的,我也弄不清楚哪头是正)|反转(也是理论上的,相对于左边那个理论上的正转的反面)|加细分(最大800)|减细分(最小1)|电位器(用来调整微秒的,70到1000,,,,,,,,因为刚学,还是加了两次微秒,我觉得加1次微秒也行,回头试试.)


    好了,就到这儿吧!具体的大家可以看代码里的备注嗷!!!!
  • TA的每日心情
    奋斗
    2019-3-22 22:34
  • 签到天数: 73 天

    [LV.6]常住居民II

     楼主| 发表于 2019-1-9 23:49 | 显示全部楼层
    高速转动的时候,失步严重啊!!!!!看来还得控制速度.
  • TA的每日心情
    擦汗
    2019-3-18 11:34
  • 签到天数: 9 天

    [LV.3]偶尔看看II

    发表于 2019-1-12 16:15 | 显示全部楼层
    简易楼主用定时器来驱动步进电机。
    驱动步进电机有步进电机驱动库的,比如AccelStepper这个库
  • TA的每日心情
    擦汗
    2019-3-18 11:34
  • 签到天数: 9 天

    [LV.3]偶尔看看II

    发表于 2019-1-12 16:25 | 显示全部楼层
    本帖最后由 coolbin8 于 2019-1-12 16:34 编辑

    上传一个我通过定时器库做的驱动两个步进电机的自动绞线机。改天整理一下一起发出来另外IO输入最好用下啦输入即是上面电路图红线接GND 黑色接VCC

    kittenblock中小学创客名师推荐的图形化编程软件

    //#include <AccelStepper.h>
    //#include <MultiStepper.h>
    
    #include <TimerOne.h>
    
    #define Motor_Z 1
    #define Motor_X 2
    #define Motor_Y 3
    #define Reset A0
    #define Hold A1
    #define Cycle Start A2
    #define Spindle_Direction 13
    #define Spindle_Enable 12
    #define Spindle_CoolEn A3
    #define Limit_Z_Axis 11//Z轴限位
    #define Limit_Y_Axis 10//Y轴限位 
    #define Limit_X_Axis 9  //X轴限位
    #define EN 8 //步进电机使能端,低电平有效
    #define X_DIR 5 //X轴 步进电机方向控制
    #define Y_DIR 6 //y轴 步进电机方向控制
    #define Z_DIR 7 //z轴 步进电机方向控制
    #define X_STP 2 //x轴 步进控制
    #define Y_STP 3 //y轴 步进控制
    #define Z_STP 4 //z轴 步进控制
    
    #define Speed_Max 350  // 定义电机最大速度
    
    #define Set_Rad 750//设置圈数
    #define Frist_Rad 100
    #define Set_Long_DMM  500//设置初层长度单位 丝
    #define Set_Layer_Dec_DMM  5//减少脉冲数  丝
    #define Set_Offset_DMM 6000
    //原点与中心偏置6000丝60MM
    #define Set_Start 1//开始位置判断值
    //定义开始位置,0,左边,1,中间,2,右边
    
    long int Set_Start_Pos ; //开始位置
    int X_Current_Num;//当前移动步数
    int X_Origin,Z_Origin;//X,Z原点Layer_Move_Num
    int Layer_Move_Num;//本层移动数
    
    long int Z_Current_Step ;//电机Z位置
    #define Z_Circle_Step 200  //电机Z单圈步数
    long int Z_Current_Circle;//电机当前圈数
    //int Z_Angle;  //电机当前角度
    long int Z_Target_Pos,X_Target_Pos  ;  //目标位置
    
    /*
    //Z电机参数Z_Angle=(Z_Current_Step%Z_Circle_Step)*360/Z_Circle_Step
    */
    #define X_Circle_Step 400//单圈步数
    long int X_Current_Step;//X电机位置
    int X_Angle;//电机 角度
    int X_Circle_MM;//丝杆步距
    int X_Step_MM=X_Circle_Step/X_Circle_MM;
    unsigned int Motor_CP=(unsigned long int )Z_Circle_Step*Frist_Rad/Set_Long_DMM;
    //int Motor_CP =Z_Circle_Step*Frist_Rad/Set_Long_DMM;
    
    unsigned char X_direction;//X轴大于0,正转等于0反转
    /*//Motor_CP =75000/Speed_Max*Z_Circle_Step*Frist_Rad/(Set_Long_DMM*75000/Speed_Max)
    电机X参数组
    */
    static unsigned long int Motor_FSB,Motor_Z_FSB,Motor_Z_FSB_Old;
    static unsigned long int Motor_X_FSB,Motor_X_FSB_Old;
    long int temp=1;
    
    void setup()//初始化程序
    {
       pinMode(EN,OUTPUT);
      digitalWrite(EN,LOW);//使能
      pinMode( Y_DIR,OUTPUT);
       pinMode( Z_DIR,OUTPUT);
        pinMode( Y_STP,OUTPUT);
         pinMode( Z_STP,OUTPUT);//设置驱动器引脚为输出模式
      Motor_X_FSB=0;
      Motor_X_FSB_Old=0;//X脉冲输出基准
       Motor_FSB =0;//频率基准
       Motor_Z_FSB =0;//Z频率基准
        Z_Target_Pos=(long int)Set_Rad*Z_Circle_Step;  //if(Z_Target_Pos!=Z_Current_Step) 
       Z_Current_Step=0;
       Motor_Z_FSB_Old=0;
       X_Target_Pos=0;
       Set_Start_Pos=0; //开始位置
     //   X_Target_Pos=Set_Start_Pos+1;
      Timer1.initialize(75000/Speed_Max);//设定定时器基准
      Timer1.attachInterrupt(motor_driver); ////定时器中断子程序号
    Serial.begin(9600);
    }
    
    void loop() 
    {
    //temp=(long int)X_Current_Step+(Set_Long_DMM-Layer_Move_Num*Set_Layer_Dec_DMM);
     Z_Current_Circle=Z_Current_Step/Z_Circle_Step;
      // delay(5000);
    //  Serial.print("blinkCount = ");
     //Serial.println(X_Target_Pos);
     //delay(50);
      Serial.println(Z_Current_Circle);
     // if(Z_Target_Pos!=Z_Current_Step) 
     if((Motor_FSB%Motor_CP)==0&&X_Target_Pos==X_Current_Step&&temp)  
    // if(X_Target_Pos==X_Current_Step)
    { 
      if(Layer_Move_Num%2==0)
     X_Target_Pos=(long int)X_Current_Step+(Set_Long_DMM-Layer_Move_Num*Set_Layer_Dec_DMM);
      else 
     X_Target_Pos=(long int)X_Current_Step-(Set_Long_DMM-Layer_Move_Num*Set_Layer_Dec_DMM);
     
       Layer_Move_Num++;  
         
     } 
    
      if(Z_Current_Circle==Set_Rad&&Z_Target_Pos==Z_Current_Step)
      
        X_Target_Pos=Set_Start_Pos,temp=0;
       
      
      
    }
    
    
    void motor_driver()
    {
      Motor_FSB++;
      if(Z_Target_Pos!=Z_Current_Step) //判断位置是否到达
      Motor_Z_FSB++;  //Z轴更新频率时基
     if(Motor_Z_FSB==0)  // 计数器溢出
     Motor_Z_FSB_Old=0;
          // Motor_Z_FSB=2,Motor_Z_FSB_Old=1;
     if((Motor_FSB%Motor_CP)==0&&X_Target_Pos!=X_Current_Step)  //判断X轴动作时时基及X轴是否到达目标位置
            Motor_X_FSB++;    //X轴更新频率时基
     
       
       if( Motor_Z_FSB>Motor_Z_FSB_Old)//Z轴时基出现误差更新Z轴位置
     {
       Motor_Z_FSB_Old=Motor_Z_FSB;//已更新标注
      if(Motor_Z_FSB%2)
      { digitalWrite(Z_STP,LOW);
       if(Z_Target_Pos>Z_Current_Step)//低电平时判断Z轴输出反向
        digitalWrite(Z_DIR,LOW),Z_Current_Step++;
       else
       digitalWrite(Z_DIR,HIGH), Z_Current_Step--;
      }
       else
       digitalWrite(Z_STP,HIGH);
     
     }    
     if( Motor_X_FSB>Motor_X_FSB_Old)     //X轴时基出现误差更新Z轴位置
     {
       Motor_X_FSB_Old=Motor_X_FSB;
      if(Motor_X_FSB%2)
      { digitalWrite(Y_STP,LOW);
       if(X_Target_Pos>X_Current_Step)   //低电平时判断Z轴输出反向
        digitalWrite(Y_DIR,LOW),X_Current_Step++;
       else
       digitalWrite(Y_DIR,HIGH), X_Current_Step--;
      }
       else
       digitalWrite(Y_STP,HIGH);
     
     }   
     }
      
    
    

  • TA的每日心情
    奋斗
    2019-3-22 22:34
  • 签到天数: 73 天

    [LV.6]常住居民II

     楼主| 发表于 2019-1-12 20:08 | 显示全部楼层
    coolbin8 发表于 2019-1-12 16:25
    上传一个我通过定时器库做的驱动两个步进电机的自动绞线机。改天整理一下一起发出来另外IO输入最好用下啦输 ...

    好的好的,我去研究研究.还没接触到库这一块儿!
  • TA的每日心情
    奋斗
    2019-3-22 22:34
  • 签到天数: 73 天

    [LV.6]常住居民II

     楼主| 发表于 2019-1-12 20:11 | 显示全部楼层
    coolbin8 发表于 2019-1-12 16:25
    上传一个我通过定时器库做的驱动两个步进电机的自动绞线机。改天整理一下一起发出来另外IO输入最好用下啦输 ...

    您这是一个大三轴的绞盘啊?

    好高深.今天研究研究.
  • TA的每日心情
    擦汗
    2019-3-18 11:34
  • 签到天数: 9 天

    [LV.3]偶尔看看II

    发表于 2019-1-12 21:39 | 显示全部楼层
    要下载TimerOne库。头文件加载一下
    #include <TimerOne.h>
    程序只控制两个电机的。
  • TA的每日心情
    奋斗
    2019-3-22 22:34
  • 签到天数: 73 天

    [LV.6]常住居民II

     楼主| 发表于 2019-1-13 00:01 | 显示全部楼层
    coolbin8 发表于 2019-1-12 21:39
    要下载TimerOne库。头文件加载一下
    #include
    程序只控制两个电机的。

    哦哦,好哒.感谢大牛.

    该用户从未签到

    发表于 2019-1-20 22:59 | 显示全部楼层
    coolbin8 发表于 2019-1-12 16:25
    上传一个我通过定时器库做的驱动两个步进电机的自动绞线机。改天整理一下一起发出来另外IO输入最好用下啦输 ...

    这学写程序真的需要学习英文了
  • TA的每日心情

    2019-2-6 11:34
  • 签到天数: 3 天

    [LV.2]偶尔看看I

    发表于 2019-2-3 16:11 | 显示全部楼层
    各位大神,回原点怎么搞啊,小白好苦恼,苦恼,苦恼,苦苦恼
    您需要登录后才可以回帖 登录 | 立即注册  

    本版积分规则

    热门推荐

    BLE胸带+GPS墨水屏运动心率表
    BLE胸带+GPS墨水屏运动心
    参赛项目: BLE胸带+GPS墨水屏运动心率表 参赛组员: 沧海笑1122 项目简介: 我喜欢
    基于树莓派的水滴摄影控制器(更新中)
    基于树莓派的水滴摄影控制
    【项目名称】基于树莓派的水滴摄影控制器(更新中) 状态:已完成 资料正在整理更
    如何实现避障小车和机械臂的组合
    如何实现避障小车和机械臂
    学校有科创杯比赛,想出了一个题目,但是一直无法实现,想请教大神指点指点 想达成的
    arduino nano 上传出错保这个错怎么办呀
    arduino nano 上传出错保
    基于Esp8266的点阵时钟
    基于Esp8266的点阵时钟
    芯片是ESP8266 12F 配合点阵单元板(64*32,单色),实现自动对时,天气预报,农历,
    Copyright   ©2015-2016  Arduino中文社区  Powered by©Discuz!   ( 蜀ICP备14017632号-3 )
    快速回复 返回顶部 返回列表