最狂的风与最静的海 · 2022年01月10日

【XR806开发板试用】跑个步进电机

来源开发板试用-跑个步进电机

从垃圾堆里翻出来个电机,今天就玩它好了,对于电机的理解已经全部还给了大学老师,所以打算先研究一番:
image.png

百度了一下,这个东西学名叫作四相五线步进电机,电机就是这个圆陀陀,板子是他的驱动器。板载芯片是ULN2003,TI出品。查了一下技术文档,就是一个集成的达令顿管放大器。

很早以前就了解过:步进电机是吃脉冲信号工作,转化信号成相应的角位移和线位移。输入一个脉冲信号,转子就转动一个角度或前进一步,其输出的角位移或线位移与输入的脉冲数成正比,转速与脉冲频率成正比。因此,步进电动机又称脉冲电动机。

步进电机相对于其它控制用途电机的最大区别是,它接收数字控制信号(电脉冲信号)并转化成与之相对应的角位移或直线位移。也就是说,它本身就可以把信号转化成运动。而且它可开环位置控制,输入一个脉冲信号就得到一个规定的位置增量,与传统的直流控制系统相比,其成本明显减低,几乎不必进行系统调整。所以他给我们带来了很大的方便。要是想要他执行起来也很简单,只要控制脉冲的数量、频率和电机绕组的相序,即可获得所需的转角、速度和方向。

从具体的硬件来看,我这里需要接六条线才能让这个电机跑起来,电源端口就不说了,IN1~IN4这四个通道口要怎么输入信号才是问题所在。

image.png

如上就是内部原理图,右侧四个开关其实就是我们的四个信号端口。右侧ABCD为定子,上面绕有线圈,为四相,与之相对应的对面四个定子上面也有线圈,相对应的两个定子之间线圈是相互连接形成一个绕组。

下面来分析一种运行模式,单四拍运行:假如说现在我闭合0对着的那个开关,则由高中学过的电能生磁原理,0对应的线圈就会产生磁力,同时他的下端,也就是对应的B线圈,也就一起导通了。接下来B断开,C导通产生磁力,1和C(这里指的是右上角那个端)就会因为两者间夹角最小而互相吸引靠近,吸引过去后C断开,D通电,继续把离他最近的2吸引过去,如此一来类推下去就形成了一个逆时针旋转的过程。

上述过程直到0被吸引到A相时,就是一个周期的完成,旋转角度为360/8=45度。

还有其他控制方法,如双拍工作、单双拍工作等等,可以根据需求调节精度速度等等···决定先放一边,适当做点容易让人有成就感的事情:用代码实现这个过程,把舵机跑起来。

了解了原理就用最简单的方法去实现好了。主要代码如下:

IoTGpioSetOutputVal(12,0);
    IoTGpioSetOutputVal(13,0);
    IoTGpioSetOutputVal(19,1);
    IoTGpioSetOutputVal(20,1);
    OS_MSleep(2);
        IoTGpioSetOutputVal(12,1);
    IoTGpioSetOutputVal(13,0);
    IoTGpioSetOutputVal(19,0);
    IoTGpioSetOutputVal(20,1);
    OS_MSleep(2);
        IoTGpioSetOutputVal(12,1);
    IoTGpioSetOutputVal(13,1);
    IoTGpioSetOutputVal(19,0);
    IoTGpioSetOutputVal(20,0);
    OS_MSleep(2);
        IoTGpioSetOutputVal(12,0);
    IoTGpioSetOutputVal(13,1);
    IoTGpioSetOutputVal(19,1);
    IoTGpioSetOutputVal(20,0);
    OS_MSleep(2);

像前面几篇一样,烧录程序,将对应IO连接上驱动板后,通上电,电机就正常工作了。

当然光转起来有些过于简单了,所以打算加一些可控元素进去,也方便后面做各种开发。于是又从垃圾堆里翻到了这个:
image.png
用翻出来的示波器研究了一下(没有万用表555),可以理解为由上下、左右两个方向的滑动变阻器和一个按键组成,总共三个信号输出口。保持在中间位置的时候测得是2.5v,移动向两边就是0跟5v,按下就是按钮。

image.png

既然是输出模拟信号最合理就是用ADC检测,无奈鸿蒙1.x.x的版本貌似都还没适配好806的接口,hal库的代码也找不到说明文档,用hal库尝试配置了一下ADC一直没成功,只能放到后面解决了。。。

所以最终决定还是用GPIO接口去读电平高低,具体代码如下:

BUILD.gn

#Create by Randolph.


import("//device/xradio/xr806/liteos_m/config.gni")

static_library("app_Stepper") 
{
   configs = []

   sources = ["main.c",]

   cflags = board_cflags

   include_dirs = board_include_dirs
   include_dirs += [
      "//kernel/liteos_m/kernel/arch/include",
      "//base/iot_hardware/peripheral/interfaces/kits",
            "//device/xradio/xr806/xr_skylark/src/rom/rom_bin/src/driver",
   ]
}

main.c

//Create by Randolph

#include <stdio.h>
#include "kernel/os/os.h"
#include "ohos_init.h"
#include "iot_gpio.h"


static OS_Thread_t g_main_thread;

unsigned char mode;

static void gpio_init(void)
{
    IoTGpioInit(11);
    IoTGpioInit(12);
    IoTGpioInit(13);
    IoTGpioInit(19);
    IoTGpioInit(20);
    IotGpioDir dir;
            IoTGpioSetDir(11, IOT_GPIO_DIR_IN);
    IoTGpioGetDir(11, &dir);
        IoTGpioSetDir(12, IOT_GPIO_DIR_OUT);
        IoTGpioSetDir(13, IOT_GPIO_DIR_OUT);
        IoTGpioSetDir(19, IOT_GPIO_DIR_OUT);
        IoTGpioSetDir(20, IOT_GPIO_DIR_OUT);
}

static void Servo_mode(unsigned char mode)
{
    if (mode == 1)
    {
            IoTGpioSetOutputVal(12,0);
    IoTGpioSetOutputVal(13,0);
    IoTGpioSetOutputVal(19,1);
    IoTGpioSetOutputVal(20,1);
    OS_MSleep(2);
        IoTGpioSetOutputVal(12,1);
    IoTGpioSetOutputVal(13,0);
    IoTGpioSetOutputVal(19,0);
    IoTGpioSetOutputVal(20,1);
    OS_MSleep(2);
        IoTGpioSetOutputVal(12,1);
    IoTGpioSetOutputVal(13,1);
    IoTGpioSetOutputVal(19,0);
    IoTGpioSetOutputVal(20,0);
    OS_MSleep(2);
        IoTGpioSetOutputVal(12,0);
    IoTGpioSetOutputVal(13,1);
    IoTGpioSetOutputVal(19,1);
    IoTGpioSetOutputVal(20,0);
    OS_MSleep(2);
    }
    else if (mode == 0)
    {
        IoTGpioSetOutputVal(12,0);
    IoTGpioSetOutputVal(13,1);
    IoTGpioSetOutputVal(19,1);
    IoTGpioSetOutputVal(20,0);
    OS_MSleep(2);    
        IoTGpioSetOutputVal(12,1);
    IoTGpioSetOutputVal(13,1);
    IoTGpioSetOutputVal(19,0);
    IoTGpioSetOutputVal(20,0);
    OS_MSleep(2);
        IoTGpioSetOutputVal(12,1);
    IoTGpioSetOutputVal(13,0);
    IoTGpioSetOutputVal(19,0);
    IoTGpioSetOutputVal(20,1);
    OS_MSleep(2);    
            IoTGpioSetOutputVal(12,0);
    IoTGpioSetOutputVal(13,0);
    IoTGpioSetOutputVal(19,1);
    IoTGpioSetOutputVal(20,1);
    OS_MSleep(2);
    }
}

static void MainThread(void *arg)
{   
    while (1) {
        IoTGpioGetInputVal(11,&mode);
        Servo_mode(mode);
    }
}

void Stepper_TestMain(void)
{
    printf("Test Start\n");
    gpio_init();

    if (OS_ThreadCreate(&g_main_thread,"MainThread",MainThread, NULL, OS_THREAD_PRIO_APP, 4096) != OS_OK) 
    {
        printf("[ERR] Create HelloWorld_Task Failed\n");
    }
}

SYS_RUN(Stepper_TestMain);

点击看看效果
image.png

至于为什么要顶个风扇叶呢,一方面是方便观察转动,另一方面也算是致敬一张大部分程序员应该都见过的图:
image.png

推荐阅读
关注数
13820
内容数
140
全志XR806开发板相关的知识介绍以及应用专栏。
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息