本帖最后由 大连好人 于 2013-2-6 17:20 编辑
更新提示:为 EasyStepper 增加了加速度功能,详情请见: http://www.geek-workshop.com/thread-3366-1-1.html
最近买了两个 42 步进电机和基于 TB6560 的步进电机驱动板,想学习一下步进电机到底是个什么东西。
研究了几天,发现现有库(如 Arduino 自带的 Stepper、Playground 里的 CustomeStepper、EasyDriver 推荐的 AccelStepper)都不是很好用,于是下决心自己写一个,顺便学习一下C++的代码。
先介绍一下这个步进电机驱动板(这个算广告吗? http://item.taobao.com/item.htm?id=12484846976 ):
最大支持 3A 输出,最多 16 细分,可设置静止电流和衰减。
之所以选择这个驱动板,是因为看到有很多二手的 TB6560 芯片出售,和汽车一样,保有量多的必定是好东西,呵呵。
输出就不说了,都一样。
输入端有3个:CLK、CW、EN,分表代表:
CLK:即 step 端口,给一个脉冲(HIGH-LOW)步进电机动一步;
CW:即 direction 端口,该板子定义为 LOW 为顺时针,HIGH 为逆时针;
EN:即 enable 端口,该板子定义为 LOW 为工作,HIGH 为脱机。
这样类型的接口,好像 Stepper 和 CustomeStepper 都不支持。
AccelStepper 可以用,但我发现由于它引入了加速度的概念(而且不能关闭),导致在多圈旋转时会出现不同步,具体问题懒得看,有兴趣的同学可以看看: http://www.open.com.au/mikem/arduino/AccelStepper/index.html 。
其实,从原理上分析,让这个 TB6560 工作起来很简单,只要给脉冲就行了,如:
- void loop()
- {
- digitalWrite(STEP_PIN, HIGH);
- delay(1);
- digitalWrite(STEP_PIN, LOW);
- delay(10); // 修改这个参数可以控制速度
- }
复制代码
但问题是:如果使用 delay 方式,将导致不能同时使用多个步进电机,而且,对系统的其他代码也会有影响。
阅读了 CustomeStepper 的代码后,我的 EasyStepper 就来了。。。。
先看 EasyStepper.h 文件:
- #ifndef EasyStepper_h
- #define EasyStepper_h
- #include <stdlib.h>
- #if ARDUINO >= 100
- #include <Arduino.h>
- #else
- #include <WProgram.h>
- #include <wiring.h>
- #endif
- // These defs cause trouble on some versions of Arduino
- #undef round
- /**
- * author [email][email protected][/email]
- */
- class EasyStepper
- {
- public:
-
- /**
- * to create the EasyStepper
- * parameters:
- * stepPin the step pin
- * directionPin the direction pin
- * enablePin the enable pin
- * directionPinsInverted if the value is true then invert HIGH/LOW value for direction pin
- * enablePinsInverted if the value is true then invert HIGH/LOW value for enable pin
- */
- EasyStepper(byte stepPin, byte directionPin, byte enablePin, bool directionPinsInverted, bool enablePinsInverted);
-
- /**
- * to startup the EasyStepper
- */
- void startup();
-
- /**
- * to shutdown the EasyStepper, will release the enable pin to save power
- */
- void shutdown();
-
- /**
- * to rotate steps from current position with speed
- * speed the speed for rotation, the unit is steps per second
- */
- void rotate(float speed, int steps);
-
- /**
- * to stop the stepper, the motor will stay at current position
- */
- void stop();
-
- /**
- * run, you must call this as frequently as possible, but at least once per minimum step interval,
- * preferably in your main loop.
- */
- void run();
-
- /**
- * if return true means the action is done
- */
- boolean isDone();
-
- /**
- * enable the debug mode?
- */
- void debugMode(boolean enabled);
-
- protected:
-
- //
-
- private:
-
- boolean debugModeFlag;
-
- byte stepPin;
- byte directionPin;
- byte enablePin;
-
- bool directionPinsInverted;
- bool enablePinsInverted;
-
- int stepsToGo;
- int stepsGone;
-
- float stepTime;
- unsigned long nextTimestamp;
-
- boolean done;
-
- void step();
-
- };
- #endif
复制代码
再来看 EasyStepper.cpp,代码里面有注释,应该容易理解的:
- #include "EasyStepper.h"
- EasyStepper::EasyStepper(byte stepPin, byte directionPin, byte enablePin, bool directionPinsInverted, bool enablePinsInverted)
- {
- // save the parameters
- this->stepPin = stepPin;
- this->directionPin = directionPin;
- this->enablePin = enablePin;
- this->directionPinsInverted = directionPinsInverted;
- this->enablePinsInverted = enablePinsInverted;
- }
- void EasyStepper::startup()
- {
- // set the pin mode
- pinMode(this->stepPin, OUTPUT);
- pinMode(this->directionPin, OUTPUT);
- pinMode(this->enablePin, OUTPUT);
- // enable the stepper
- digitalWrite(enablePin, HIGH ^ this->enablePinsInverted);
- // initialize the done to true
- this->done = true;
- }
- void EasyStepper::shutdown()
- {
- // disable the stepper
- digitalWrite(enablePin, LOW ^ this->enablePinsInverted);
- }
- void EasyStepper::debugMode(boolean enabled)
- {
- this->debugModeFlag = enabled;
- }
- void EasyStepper::rotate(float speed, int steps)
- {
- // ignore the zero value
- if (speed != 0 && steps != 0)
- {
- if (steps > 0)
- {
- // CW
- digitalWrite(directionPin, HIGH ^ this->directionPinsInverted);
- if (this->debugModeFlag)
- {
- Serial.println("CW");
- }
- }
- else if (steps < 0)
- {
- // CCW
- digitalWrite(directionPin, LOW ^ this->directionPinsInverted);
- if (this->debugModeFlag)
- {
- Serial.println("CCW");
- }
- }
- this->done = false;
- // the steps to go
- this->stepsToGo = abs(steps);
- // the steps gone
- this->stepsGone = 0;
- // change the speed to stepTime, micro seconds per step
- this->stepTime = 1000.0 * 1000.0 / abs(speed);
- // current timestamp
- unsigned long time = micros();
- this->nextTimestamp = time + this->stepTime;
- if (this->debugModeFlag)
- {
- Serial.print("stepsToGo=");
- Serial.print(this->stepsToGo);
- Serial.print(", stepTime=");
- Serial.print(this->stepTime);
- Serial.print(", currentTimestamp=");
- Serial.print(time);
- Serial.print(", nextTimestamp=");
- Serial.println(this->nextTimestamp);
- }
- // call the step method to rotate the motor
- this->step();
- }
- }
- void EasyStepper::stop()
- {
- this->stepsToGo = 0;
- this->done = true;
- }
- void EasyStepper::run()
- {
- // the current timestamp
- unsigned long time = micros();
- if (time >= this->nextTimestamp && !this->done)
- {
- this->step();
- }
- if (this->debugModeFlag)
- {
- Serial.print("currentTimestamp=");
- Serial.println(time);
- }
- }
- void EasyStepper::step()
- {
- // are there some steps to rotate?
- if (this->stepsToGo > this->stepsGone)
- {
- // HIGH value
- digitalWrite(stepPin, HIGH);
- // delay
- delayMicroseconds(2);
- // LOW value
- digitalWrite(stepPin, LOW);
- // increase the stepsGone
- this->stepsGone++;
- // current timestamp
- unsigned long time = micros();
- this->nextTimestamp = time + this->stepTime;
- if (this->debugModeFlag)
- {
- Serial.print("stepsGone=");
- Serial.print(stepsGone);
- Serial.print(", currentTimestamp=");
- Serial.print(time);
- Serial.print(", nextTimestamp=");
- Serial.println(this->nextTimestamp);
- }
- }
- else
- {
- this->done = true;
- }
- }
-
- boolean EasyStepper::isDone()
- {
- return this->done;
- }
复制代码
最后来看一个测试程序,逻辑很简单,来回转 10 次,然后停:
- #include <EasyStepper.h>
- // define the pins
- #define STEP_PIN 34
- #define DIR_PIN 35
- #define EN_PIN 36
- // define the inverted
- #define DIR_PIN_INVERTED true
- #define EN_PIN_INVERTED true
- // the EasyStepper instance
- EasyStepper stepper1(STEP_PIN, DIR_PIN, EN_PIN, DIR_PIN_INVERTED, EN_PIN_INVERTED);
- // the stepps to rotate
- int stepps = 200;
- // run times
- int times = 0;
- void setup()
- {
- Serial.begin(9600);
- stepper1.debugMode(false);
- stepper1.startup();
- stepper1.rotate(400.0, stepps);
- }
- void loop()
- {
- if (times < 10)
- {
- stepper1.run();
- if (stepper1.isDone())
- {
- // go back
- stepps *= -1;
- stepper1.rotate(400.0, stepps);
- times++;
- }
- }
- }
复制代码
好人是个 Java 程序员,写 C++ 太吃力了,程序里面应该有 bug 或可以优化的地方,还请大家来指导,谢谢。。。。
|