来源开发板试用-跑个步进电机
从垃圾堆里翻出来个电机,今天就玩它好了,对于电机的理解已经全部还给了大学老师,所以打算先研究一番:
百度了一下,这个东西学名叫作四相五线步进电机,电机就是这个圆陀陀,板子是他的驱动器。板载芯片是ULN2003,TI出品。查了一下技术文档,就是一个集成的达令顿管放大器。
很早以前就了解过:步进电机是吃脉冲信号工作,转化信号成相应的角位移和线位移。输入一个脉冲信号,转子就转动一个角度或前进一步,其输出的角位移或线位移与输入的脉冲数成正比,转速与脉冲频率成正比。因此,步进电动机又称脉冲电动机。
步进电机相对于其它控制用途电机的最大区别是,它接收数字控制信号(电脉冲信号)并转化成与之相对应的角位移或直线位移。也就是说,它本身就可以把信号转化成运动。而且它可开环位置控制,输入一个脉冲信号就得到一个规定的位置增量,与传统的直流控制系统相比,其成本明显减低,几乎不必进行系统调整。所以他给我们带来了很大的方便。要是想要他执行起来也很简单,只要控制脉冲的数量、频率和电机绕组的相序,即可获得所需的转角、速度和方向。
从具体的硬件来看,我这里需要接六条线才能让这个电机跑起来,电源端口就不说了,IN1~IN4这四个通道口要怎么输入信号才是问题所在。
如上就是内部原理图,右侧四个开关其实就是我们的四个信号端口。右侧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连接上驱动板后,通上电,电机就正常工作了。
当然光转起来有些过于简单了,所以打算加一些可控元素进去,也方便后面做各种开发。于是又从垃圾堆里翻到了这个:
用翻出来的示波器研究了一下(没有万用表555),可以理解为由上下、左右两个方向的滑动变阻器和一个按键组成,总共三个信号输出口。保持在中间位置的时候测得是2.5v,移动向两边就是0跟5v,按下就是按钮。
既然是输出模拟信号最合理就是用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);
点击看看效果
至于为什么要顶个风扇叶呢,一方面是方便观察转动,另一方面也算是致敬一张大部分程序员应该都见过的图: