查看: 2080|回复: 0

[经验] 如何通过树莓派的GPIO接口控制步进电机

[复制链接]
  • TA的每日心情
    开心
    2019-11-4 13:48
  • 签到天数: 14 天

    连续签到: 1 天

    [LV.3]偶尔看看II

    发表于 2020-6-24 10:42:02 | 显示全部楼层 |阅读模式
    分享到:
    如何通过树莓派的GPIO接口控制步进电机

    1、实验目的
    在树莓派上编写一个C程序,通过其GPIO口控制步进电机的转动方向以及速度。

    2、为什么要用树莓派来控制步进电机
    在我的概念中,无论是控制接在树莓派上的摄像头来拍照,还是通过树莓派控制LED发光,我都还是在“虚拟世界”中折腾树莓派,因为它没有向外界输出任何动作。而在构建一个稍微复杂的系统时,这种能力可能是很重要的,于是,用树莓派来控制步进电机是我必须要做的事情。

    3、实现方案
    怎样通过Raspberry Pi的GPIO口来控制步进电机?已经有很多人这样做了。由于步进电机通常需要一块驱动板,而这样的产品已经很容易买到并且极其廉价(肯定比你自己做要便宜),因此,我们没有必要自己去做。我在淘宝上不断地查啊查,终于找到了白菜价的步进电机和配套驱动板,加起来才一共8块多钱。

    下面来看看我买的步进电机和驱动板的样子:
    1.jpg


    步进电机和驱动板的接线:
    2.jpg


    该驱动板配有一个原理图,根据它我们可以知道如何把整个系统连接起来:
    3.jpg


    可见,驱动板上有4个输入口:IN1~IN4,这4个口用来接树莓派的4个GPIO口。同时,我们需要为驱动板提供5V的供电,这从哪里来?当然是从树莓派引出来。从下面的GPIO口分布图可以得知,“2”口就是+5V,正好就利用它。
    4.jpg


    我将树莓派上的GPIO 17、18、21、22口(用树莓派的命名方式就是0、1、2、3口)分别接到步进电机驱动板上的IN1、IN2、IN3、IN4口,最后接好线的效果如下:
    5.jpg


    4、编写程序
    在参考了这款步进电机配套的51单片机的示例代码后,我知道了依次把驱动板的IN1~IN4置为高电平,就可以驱动步进电机,也就是说,要把树莓派的4个GPIO输出口依次置为高电平。例如,假设用0代表低电平,1代表高电平的话,GPIO 17、18、21、22口的电平第一次被置为1、0、0、0,第二次被置为0、1、0、0,第三次被置为0、0、1、0,第四次被置为0、0、0、1。

    于是我写出了下面的代码(仍然使用WiringPi这个库来操作GPIO):
    • /* moto.c
    • * A program to control a stepper motor through the GPIO on Raspberry Pi.
    • *
    • * Author: Darran Zhang (http://www.codelast.com)
    • */
    • #include <wiringPi.h>
    • #include <stdio.h>
    • #include <unistd.h>
    • #include <stdlib.h>
    • #define clockWISE 1
    • #define COUNTER_CLOCKWISE 2
    • void delayMS(int x);
    • void rotate(int* pins, int direction);
    • int main(int argc,char* argv[]) {
    •   IF (argc < 4) {
    •     printf("Usage example: ./motor 0 1 2 3 \n");
    •     return 1;
    •   }
    •   /* number of the pins which connected to the stepper motor driver board */
    •   int pinA = atoi(argv[1]);
    •   int pinB = atoi(argv[2]);
    •   int pinC = atoi(argv[3]);
    •   int pinD = atoi(argv[4]);
    •   int pins[4] = {pinA, pinB, pinC, pinD};
    •   if (-1 == wiringPiSetup()) {
    •     printf("Setup wiringPi failed!");
    •     return 1;
    •   }
    •   /* set mode to output */
    •   pinMode(pinA, OUTPUT);
    •   pinMode(pinB, OUTPUT);
    •   pinMode(pinC, OUTPUT);
    •   pinMode(pinD, OUTPUT);
    •   delayMS(50);    // wait for a stable status
    •   for (int i = 0; i < 500; i++) {
    •     rotate(pins, CLOCKWISE);
    •   }
    •   return 0;
    • }
    • /* Suspend execution for x milliseconds intervals.
    • *  @param ms Milliseconds to sleep.
    • */
    • void delayMS(int x) {
    •   usleep(x * 1000);
    • }
    • /* Rotate the motor.
    • *  @param pins     A pointer which points to the pins number array.
    • *  @param direction  CLOCKWISE for clockwise rotation, COUNTER_CLOCKWISE for counter clockwise rotation.
    • */
    • void rotate(int* pins, int direction) {
    •   for (int i = 0; i < 4; i++) {
    •     if (CLOCKWISE == direction) {
    •       for (int j = 0; j < 4; j++) {
    •         if (j == i) {
    •           digitalWrite(pins[3 - j], 1); // output a high level
    •         } else {
    •           digitalWrite(pins[3 - j], 0); // output a low level
    •         }
    •       }
    •     } else if (COUNTER_CLOCKWISE == direction) {
    •       for (int j = 0; j < 4; j++) {
    •         if (j == i) {
    •           digitalWrite(pins[j], 1); // output a high level
    •         } else {
    •           digitalWrite(pins[j], 0); // output a low level
    •         }
    •       }
    •     }
    •     delayMS(4);
    •   }
    • }

    [color=rgb(51, 102, 153) !important]复制代码


    编译程序:
    • Compile the code:

    [color=rgb(51, 102, 153) !important]复制代码

    • g++ motor.c -o motor -lwiringPi

    [color=rgb(51, 102, 153) !important]复制代码



    运行程序:
    • ./motor 0 1 2 3

    [color=rgb(51, 102, 153) !important]复制代码



    这里向程序传入了4个参数,它们分别代表要控制的树莓派的GPIO口。切记,由于使用了WiringPi库,所以要参考上面的GPIO分布图的左边那部分来确定这些数字。
    可以看到步进电机已经转动了(如下面的Youku视频所示)。如果你发现转动方向(顺/逆时针)反了,你可以把传入的参数顺序调整一下,就可以让它转对方向。
    从前面的代码可见,如果要改变步进电机的转速,只需要改变rotate()函数中每次delay的时间即可。因此,如果我们把delay的时间逐渐由大变小,就会导致步进电机呈加速状态。让步进电机周期性加速的完整代码如下:
    • /* motor_speed_up.c
    • * A program to control a stepper motor(speed up) through the GPIO on Raspberry Pi.
    • *
    • * Author: Darran Zhang (http://www.codelast.com)
    • */
    • #include <wiringPi.h>
    • #include <stdio.h>
    • #include <unistd.h>
    • #include <stdlib.h>
    • #define CLOCKWISE 1
    • #define COUNTER_CLOCKWISE 2
    • void delayMS(int x);
    • void rotate(int* pins, int direction, int delay);
    • void stop(int* pins);
    • int main(int argc,char* argv[]) {
    •   if (argc < 4) {
    •     printf("Usage example: ./motor 0 1 2 3 \n");
    •     return 1;
    •   }
    •   /* number of the pins which connected to the stepper motor driver board */
    •   int pinA = atoi(argv[1]);
    •   int pinB = atoi(argv[2]);
    •   int pinC = atoi(argv[3]);
    •   int pinD = atoi(argv[4]);
    •   int pins[4] = {pinA, pinB, pinC, pinD};
    •   if (-1 == wiringPiSetup()) {
    •     printf("Setup wiringPi failed!");
    •     return 1;
    •   }
    •   /* set mode to output */
    •   pinMode(pinA, OUTPUT);
    •   pinMode(pinB, OUTPUT);
    •   pinMode(pinC, OUTPUT);
    •   pinMode(pinD, OUTPUT);
    •   delayMS(50);    // wait for a stable status
    •   int delay = 25;
    •   while (true) {
    •     for (int i = 0; i < 10; i++) {
    •       rotate(pins, CLOCKWISE, delay);
    •     }
    •     delay--;
    •     if (delay < 4) {
    •       delay = 25;
    •       stop(pins);
    •       delayMS(500);
    •     }
    •   }
    •   return 0;
    • }
    • /* Suspend execution for x milliseconds intervals.
    • *  @param ms Milliseconds to sleep.
    • */
    • void delayMS(int x) {
    •   usleep(x * 1000);
    • }
    • /* Rotate the motor.
    • *  @param pins     A pointer which points to the pins number array.
    • *  @param direction  CLOCKWISE for clockwise rotation, COUNTER_CLOCKWISE for counter clockwise rotation.
    • *  @param delay    The time intervals(in ms) to delay, and if the value is smaller, the motor rotates faster.
    • */
    • void rotate(int* pins, int direction, int delay) {
    •   for (int i = 0; i < 4; i++) {
    •     if (CLOCKWISE == direction) {
    •       for (int j = 0; j < 4; j++) {
    •         if (j == i) {
    •           digitalWrite(pins[3 - j], 1); // output a high level
    •         } else {
    •           digitalWrite(pins[3 - j], 0); // output a low level
    •         }
    •       }
    •     } else if (COUNTER_CLOCKWISE == direction) {
    •       for (int j = 0; j < 4; j++) {
    •         if (j == i) {
    •           digitalWrite(pins[j], 1); // output a high level
    •         } else {
    •           digitalWrite(pins[j], 0); // output a low level
    •         }
    •       }
    •     }
    •     delayMS(delay);
    •   }
    • }
    • /* Stop the motor.
    • *  @param pins     A pointer which points to the pins number array.
    • */
    • void stop(int* pins) {
    •   for (int i = 0; i < 4; i++) {
    •     digitalWrite(pins, 0); // output a low level
    •   }
    • }

    [color=rgb(51, 102, 153) !important]复制代码












    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条



    手机版|小黑屋|与非网

    GMT+8, 2024-4-24 21:45 , Processed in 0.118239 second(s), 16 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.