03-24-2013 03:05 PM
Hi, my name is Wilson Leong and currently I have the problem upload LIFA_Base.ino code to my own Arduino before I want to write the labview programming. The problem is when I want to upload the LIFA_Base.ino to my arduino, it failed to upload LIFA_Base.ino to my arduino. I uninstall and reinstall the Labview for Arduino using the VI Package Manager and also restart my computer for many times, but I failed solve it.
The error message prompted below at here:
Error compiling
IRremote\IRremote.cpp.o: In function `IRrecv':
C:\arduino-1.0\libraries\IRremote/IRremote.cpp:268: multiple definition of `IRrecv::IRrecv(int)'
IRremote.cpp.o:C:\Users\WILSON~1\AppData\Local\Temp\build3937145811672605449.tmp/IRremote.cpp:217: first defined here
IRremote\IRremote.cpp.o: In function `MATCH(int, int)':
/IRremoteInt.h:180: multiple definition of `irparams'
IRremote.cpp.o:C:\Users\WILSON~1\AppData\Local\Temp\build3937145811672605449.tmp/IRremote.cpp:217: first defined here
c:/arduino-1.0/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../../avr/bin/ld.exe: Warning: size of symbol `irparams' changed from 158 in IRremote.cpp.o to 206 in IRremote\IRremote.cpp.o
IRremote\IRremote.cpp.o: In function `IRrecv':
C:\arduino-1.0\libraries\IRremote/IRremote.cpp:268: multiple definition of `IRrecv::IRrecv(int)'
IRremote.cpp.o:C:\Users\WILSON~1\AppData\Local\Temp\build3937145811672605449.tmp/IRremote.cpp:217: first defined here
IRremote\IRremote.cpp.o: In function `IRrecv::resume()':
C:\arduino-1.0\libraries\IRremote/IRremote.cpp:379: multiple definition of `IRrecv::resume()'
IRremote.cpp.o:C:\Users\WILSON~1\AppData\Local\Temp\build3937145811672605449.tmp/IRremote.cpp:332: first defined here
IRremote\IRremote.cpp.o: In function `IRrecv::decodeNEC(decode_results*)':
C:\arduino-1.0\libraries\IRremote/IRremote.cpp:454: multiple definition of `IRrecv::decodeNEC(decode_results*)'
IRremote.cpp.o:C:\Users\WILSON~1\AppData\Local\Temp\build3937145811672605449.tmp/IRremote.cpp:383: first defined here
IRremote\IRremote.cpp.o: In function `IRrecv::decodeSony(decode_results*)':
C:\arduino-1.0\libraries\IRremote/IRremote.cpp:502: multiple definition of `IRrecv::decodeSony(decode_results*)'
IRremote.cpp.o:C:\Users\WILSON~1\AppData\Local\Temp\build3937145811672605449.tmp/IRremote.cpp:431: first defined here
IRremote\IRremote.cpp.o: In function `IRrecv::getRClevel(decode_results*, int*, int*, int)':
C:\arduino-1.0\libraries\IRremote/IRremote.cpp:690: multiple definition of `IRrecv::getRClevel(decode_results*, int*, int*, int)'
IRremote.cpp.o:C:\Users\WILSON~1\AppData\Local\Temp\build3937145811672605449.tmp/IRremote.cpp:478: first defined here
IRremote\IRremote.cpp.o: In function `IRrecv::decodeRC5(decode_results*)':
C:\arduino-1.0\libraries\IRremote/IRremote.cpp:729: multiple definition of `IRrecv::decodeRC5(decode_results*)'
IRremote.cpp.o:C:\Users\WILSON~1\AppData\Local\Temp\build3937145811672605449.tmp/IRremote.cpp:517: first defined here
IRremote\IRremote.cpp.o: In function `IRrecv::decodeRC6(decode_results*)':
C:\arduino-1.0\libraries\IRremote/IRremote.cpp:764: multiple definition of `IRrecv::decodeRC6(decode_results*)'
IRremote.cpp.o:C:\Users\WILSON~1\AppData\Local\Temp\build3937145811672605449.tmp/IRremote.cpp:552: first defined here
IRremote\IRremote.cpp.o: In function `IRrecv::decode(decode_results*)':
C:\arduino-1.0\libraries\IRremote/IRremote.cpp:388: multiple definition of `IRrecv::decode(decode_results*)'
IRremote.cpp.o:C:\Users\WILSON~1\AppData\Local\Temp\build3937145811672605449.tmp/IRremote.cpp:341: first defined here
IRremote\IRremote.cpp.o: In function `IRrecv::blink13(int)':
C:\arduino-1.0\libraries\IRremote/IRremote.cpp:299: multiple definition of `IRrecv::blink13(int)'
IRremote.cpp.o:C:\Users\WILSON~1\AppData\Local\Temp\build3937145811672605449.tmp/IRremote.cpp:252: first defined here
IRremote\IRremote.cpp.o: In function `IRrecv::enableIRIn()':
C:\arduino-1.0\libraries\IRremote/IRremote.cpp:274: multiple definition of `IRrecv::enableIRIn()'
IRremote.cpp.o:C:\Users\WILSON~1\AppData\Local\Temp\build3937145811672605449.tmp/IRremote.cpp:224: first defined here
IRremote\IRremote.cpp.o: In function `IRsend::enableIROut(int)':
C:\arduino-1.0\libraries\IRremote/IRremote.cpp:239: multiple definition of `IRsend::enableIROut(int)'
IRremote.cpp.o:C:\Users\WILSON~1\AppData\Local\Temp\build3937145811672605449.tmp/IRremote.cpp:184: first defined here
IRremote\IRremote.cpp.o: In function `IRsend::space(int)':
C:\arduino-1.0\libraries\IRremote/IRremote.cpp:235: multiple definition of `IRsend::space(int)'
IRremote.cpp.o:C:\Users\WILSON~1\AppData\Local\Temp\build3937145811672605449.tmp/IRremote.cpp:177: first defined here
IRremote\IRremote.cpp.o: In function `IRsend::mark(int)':
C:\arduino-1.0\libraries\IRremote/IRremote.cpp:227: multiple definition of `IRsend::mark(int)'
IRremote.cpp.o:C:\Users\WILSON~1\AppData\Local\Temp\build3937145811672605449.tmp/IRremote.cpp:169: first defined here
IRremote\IRremote.cpp.o: In function `IRsend::sendRC6(unsigned long, int)':
C:\arduino-1.0\libraries\IRremote/IRremote.cpp:145: multiple definition of `IRsend::sendRC6(unsigned long, int)'
IRremote.cpp.o:C:\Users\WILSON~1\AppData\Local\Temp\build3937145811672605449.tmp/IRremote.cpp:138: first defined here
IRremote\IRremote.cpp.o: In function `IRsend::sendRC5(unsigned long, int)':
C:\arduino-1.0\libraries\IRremote/IRremote.cpp:123: multiple definition of `IRsend::sendRC5(unsigned long, int)'
IRremote.cpp.o:C:\Users\WILSON~1\AppData\Local\Temp\build3937145811672605449.tmp/IRremote.cpp:116: first defined here
IRremote\IRremote.cpp.o: In function `IRsend::sendRaw(unsigned int*, int, int)':
C:\arduino-1.0\libraries\IRremote/IRremote.cpp:108: multiple definition of `IRsend::sendRaw(unsigned int*, int, int)'
IRremote.cpp.o:C:\Users\WILSON~1\AppData\Local\Temp\build3937145811672605449.tmp/IRremote.cpp:101: first defined here
IRremote\IRremote.cpp.o: In function `IRsend::sendSony(unsigned long, int)':
C:\arduino-1.0\libraries\IRremote/IRremote.cpp:90: multiple definition of `IRsend::sendSony(unsigned long, int)'
IRremote.cpp.o:C:\Users\WILSON~1\AppData\Local\Temp\build3937145811672605449.tmp/IRremote.cpp:83: first defined here
IRremote\IRremote.cpp.o: In function `IRsend::sendNEC(unsigned long, int)':
C:\arduino-1.0\libraries\IRremote/IRremote.cpp:70: multiple definition of `IRsend::sendNEC(unsigned long, int)'
IRremote.cpp.o:C:\Users\WILSON~1\AppData\Local\Temp\build3937145811672605449.tmp/IRremote.cpp:63: first defined here
core.a(Tone.cpp.o): In function `__vector_7':
C:\arduino-1.0\hardware\arduino\cores\arduino/Tone.cpp:523: multiple definition of `__vector_7'
IRremote\IRremote.cpp.o:C:\arduino-1.0\libraries\IRremote/IRremote.cpp:311: first defined here
May I know that how can I solved this problem so I have the idea to solve the problem that I faced. Thank you and appreciate for your help.
Regards,
Wilson Leong
03-24-2013 04:08 PM
It looks like you might have multiple instances of the same file open in the Arduino IDE. Make sure that this is not the case before compiling the code.
03-25-2013 02:14 PM
As Nathan mentioned the problem looks like a double decliration where one file defines a variable and then another file tries to define the same variable name. Can you post a screenshot of the Arduino IDE with this error? Have you modified the firmware at all?
Thanks,
-Sam K
-LIFA Developer
03-25-2013 03:47 PM
Thanks for your time to reply back my answer. Actually I use the VIPM software to download LabVIEW Interface for Arduino and I have no idea how to modify the firmware as I downloaded from VIPM software. I open the LIFA_Base.ino file using the Arduino IDE software, the entire file are open together. I just upload the LIFA_Base.ino file to my arduino. When I upload the LIFA_Base.ino file to my Arduino, the error is displayed. The further error message is displayed as I mentioned before.
The source code I downloaded from VIPM software will upload
/*********************************************************************************
**
** LVFA_Firmware - Provides Basic Arduino Sketch For Interfacing With LabVIEW.
**
** Written By: Sam Kristoff - National Instruments
** Written On: November 2010
** Last Updated: Dec 2011 - Kevin Fort - National Instruments
**
** This File May Be Modified And Re-Distributed Freely. Original File Content
** Written By Sam Kristoff And Available At www.ni.com/arduino.
**
*********************************************************************************/
/*********************************************************************************
**
** Includes.
**
********************************************************************************/
// Standard includes. These should always be included.
#include <Wire.h>
#include <SPI.h>
#include <Servo.h>
#include "LabVIEWInterface.h"
/*********************************************************************************
** setup()
**
** Initialize the Arduino and setup serial communication.
**
** Input: None
** Output: None
*********************************************************************************/
void setup()
{
// Initialize Serial Port With The Default Baud Rate
syncLV();
// Place your custom setup code here
}
/*********************************************************************************
** loop()
**
** The main loop. This loop runs continuously on the Arduino. It
** receives and processes serial commands from LabVIEW.
**
** Input: None
** Output: None
*********************************************************************************/
void loop()
{
// Check for commands from LabVIEW and process them.
checkForCommand();
// Place your custom loop code here (this may slow down communication with LabVIEW)
if(acqMode==1)
{
sampleContinously();
}
}
// Adafruit Motor shield library
// copyright Adafruit Industries LLC, 2009
// this code is public domain, enjoy!
#include <avr/io.h>
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include "AFMotor.h"
static uint8_t latch_state;
#if (MICROSTEPS == 😎
uint8_t microstepcurve[] = {0, 50, 98, 142, 180, 212, 236, 250, 255};
#elif (MICROSTEPS == 16)
uint8_t microstepcurve[] = {0, 25, 50, 74, 98, 120, 141, 162, 180, 197, 212, 225, 236, 244, 250, 253, 255};
#endif
AFMotorController::AFMotorController(void) {
}
void AFMotorController::enable(void) {
// setup the latch
/*
LATCH_DDR |= _BV(LATCH);
ENABLE_DDR |= _BV(ENABLE);
CLK_DDR |= _BV(CLK);
SER_DDR |= _BV(SER);
*/
pinMode(MOTORLATCH, OUTPUT);
pinMode(MOTORENABLE, OUTPUT);
pinMode(MOTORDATA, OUTPUT);
pinMode(MOTORCLK, OUTPUT);
latch_state = 0;
latch_tx(); // "reset"
//ENABLE_PORT &= ~_BV(ENABLE); // enable the chip outputs!
digitalWrite(MOTORENABLE, LOW);
}
void AFMotorController::latch_tx(void) {
uint8_t i;
//LATCH_PORT &= ~_BV(LATCH);
digitalWrite(MOTORLATCH, LOW);
//SER_PORT &= ~_BV(SER);
digitalWrite(MOTORDATA, LOW);
for (i=0; i<8; i++) {
//CLK_PORT &= ~_BV(CLK);
digitalWrite(MOTORCLK, LOW);
if (latch_state & _BV(7-i)) {
//SER_PORT |= _BV(SER);
digitalWrite(MOTORDATA, HIGH);
} else {
//SER_PORT &= ~_BV(SER);
digitalWrite(MOTORDATA, LOW);
}
//CLK_PORT |= _BV(CLK);
digitalWrite(MOTORCLK, HIGH);
}
//LATCH_PORT |= _BV(LATCH);
digitalWrite(MOTORLATCH, HIGH);
}
static AFMotorController MC;
/******************************************
MOTORS
******************************************/
inline void initPWM1(uint8_t freq) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer2A on PB3 (Arduino pin #11)
TCCR2A |= _BV(COM2A1) | _BV(WGM20) | _BV(WGM21); // fast PWM, turn on oc2a
TCCR2B = freq & 0x7;
OCR2A = 0;
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// on arduino mega, pin 11 is now PB5 (OC1A)
TCCR1A |= _BV(COM1A1) | _BV(WGM10); // fast PWM, turn on oc1a
TCCR1B = (freq & 0x7) | _BV(WGM12);
OCR1A = 0;
#else
#error "This chip is not supported!"
#endif
pinMode(11, OUTPUT);
}
inline void setPWM1(uint8_t s) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer2A on PB3 (Arduino pin #11)
OCR2A = s;
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// on arduino mega, pin 11 is now PB5 (OC1A)
OCR1A = s;
#else
#error "This chip is not supported!"
#endif
}
inline void initPWM2(uint8_t freq) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer2B (pin 3)
TCCR2A |= _BV(COM2B1) | _BV(WGM20) | _BV(WGM21); // fast PWM, turn on oc2b
TCCR2B = freq & 0x7;
OCR2B = 0;
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// on arduino mega, pin 3 is now PE5 (OC3C)
TCCR3A |= _BV(COM1C1) | _BV(WGM10); // fast PWM, turn on oc3c
TCCR3B = (freq & 0x7) | _BV(WGM12);
OCR3C = 0;
#else
#error "This chip is not supported!"
#endif
pinMode(3, OUTPUT);
}
inline void setPWM2(uint8_t s) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer2A on PB3 (Arduino pin #11)
OCR2B = s;
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// on arduino mega, pin 11 is now PB5 (OC1A)
OCR3C = s;
#else
#error "This chip is not supported!"
#endif
}
inline void initPWM3(uint8_t freq) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer0A / PD6 (pin 6)
TCCR0A |= _BV(COM0A1) | _BV(WGM00) | _BV(WGM01); // fast PWM, turn on OC0A
//TCCR0B = freq & 0x7;
OCR0A = 0;
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// on arduino mega, pin 6 is now PH3 (OC4A)
TCCR4A |= _BV(COM1A1) | _BV(WGM10); // fast PWM, turn on oc4a
TCCR4B = (freq & 0x7) | _BV(WGM12);
//TCCR4B = 1 | _BV(WGM12);
OCR4A = 0;
#else
#error "This chip is not supported!"
#endif
pinMode(6, OUTPUT);
}
inline void setPWM3(uint8_t s) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer0A on PB3 (Arduino pin #6)
OCR0A = s;
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// on arduino mega, pin 6 is now PH3 (OC4A)
OCR4A = s;
#else
#error "This chip is not supported!"
#endif
}
inline void initPWM4(uint8_t freq) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer0B / PD5 (pin 5)
TCCR0A |= _BV(COM0B1) | _BV(WGM00) | _BV(WGM01); // fast PWM, turn on oc0a
//TCCR0B = freq & 0x7;
OCR0B = 0;
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// on arduino mega, pin 5 is now PE3 (OC3A)
TCCR3A |= _BV(COM1A1) | _BV(WGM10); // fast PWM, turn on oc3a
TCCR3B = (freq & 0x7) | _BV(WGM12);
//TCCR4B = 1 | _BV(WGM12);
OCR3A = 0;
#else
#error "This chip is not supported!"
#endif
pinMode(5, OUTPUT);
}
inline void setPWM4(uint8_t s) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer0A on PB3 (Arduino pin #6)
OCR0B = s;
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// on arduino mega, pin 6 is now PH3 (OC4A)
OCR3A = s;
#else
#error "This chip is not supported!"
#endif
}
AF_DCMotor::AF_DCMotor(uint8_t num, uint8_t freq) {
motornum = num;
pwmfreq = freq;
MC.enable();
switch (num) {
case 1:
latch_state &= ~_BV(MOTOR1_A) & ~_BV(MOTOR1_B); // set both motor pins to 0
MC.latch_tx();
initPWM1(freq);
break;
case 2:
latch_state &= ~_BV(MOTOR2_A) & ~_BV(MOTOR2_B); // set both motor pins to 0
MC.latch_tx();
initPWM2(freq);
break;
case 3:
latch_state &= ~_BV(MOTOR3_A) & ~_BV(MOTOR3_B); // set both motor pins to 0
MC.latch_tx();
initPWM3(freq);
break;
case 4:
latch_state &= ~_BV(MOTOR4_A) & ~_BV(MOTOR4_B); // set both motor pins to 0
MC.latch_tx();
initPWM4(freq);
break;
}
}
void AF_DCMotor::run(uint8_t cmd) {
uint8_t a, b;
switch (motornum) {
case 1:
a = MOTOR1_A; b = MOTOR1_B; break;
case 2:
a = MOTOR2_A; b = MOTOR2_B; break;
case 3:
a = MOTOR3_A; b = MOTOR3_B; break;
case 4:
a = MOTOR4_A; b = MOTOR4_B; break;
default:
return;
}
switch (cmd) {
case FORWARD:
latch_state |= _BV(a);
latch_state &= ~_BV(b);
MC.latch_tx();
break;
case BACKWARD:
latch_state &= ~_BV(a);
latch_state |= _BV(b);
MC.latch_tx();
break;
case RELEASE:
latch_state &= ~_BV(a);
latch_state &= ~_BV(b);
MC.latch_tx();
break;
}
}
void AF_DCMotor::setSpeed(uint8_t speed) {
switch (motornum) {
case 1:
setPWM1(speed); break;
case 2:
setPWM2(speed); break;
case 3:
setPWM3(speed); break;
case 4:
setPWM4(speed); break;
}
}
/******************************************
STEPPERS
******************************************/
AF_Stepper::AF_Stepper(uint16_t steps, uint8_t num) {
MC.enable();
revsteps = steps;
steppernum = num;
currentstep = 0;
if (steppernum == 1) {
latch_state &= ~_BV(MOTOR1_A) & ~_BV(MOTOR1_B) &
~_BV(MOTOR2_A) & ~_BV(MOTOR2_B); // all motor pins to 0
MC.latch_tx();
// enable both H bridges
pinMode(11, OUTPUT);
pinMode(3, OUTPUT);
digitalWrite(11, HIGH);
digitalWrite(3, HIGH);
// use PWM for microstepping support
initPWM1(MOTOR12_64KHZ);
initPWM2(MOTOR12_64KHZ);
setPWM1(255);
setPWM2(255);
} else if (steppernum == 2) {
latch_state &= ~_BV(MOTOR3_A) & ~_BV(MOTOR3_B) &
~_BV(MOTOR4_A) & ~_BV(MOTOR4_B); // all motor pins to 0
MC.latch_tx();
// enable both H bridges
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
digitalWrite(5, HIGH);
digitalWrite(6, HIGH);
// use PWM for microstepping support
// use PWM for microstepping support
initPWM3(1);
initPWM4(1);
setPWM3(255);
setPWM4(255);
}
}
void AF_Stepper::setSpeed(uint16_t rpm) {
usperstep = 60000000 / ((uint32_t)revsteps * (uint32_t)rpm);
steppingcounter = 0;
}
void AF_Stepper::release(void) {
if (steppernum == 1) {
latch_state &= ~_BV(MOTOR1_A) & ~_BV(MOTOR1_B) &
~_BV(MOTOR2_A) & ~_BV(MOTOR2_B); // all motor pins to 0
MC.latch_tx();
} else if (steppernum == 2) {
latch_state &= ~_BV(MOTOR3_A) & ~_BV(MOTOR3_B) &
~_BV(MOTOR4_A) & ~_BV(MOTOR4_B); // all motor pins to 0
MC.latch_tx();
}
}
void AF_Stepper::step(uint16_t steps, uint8_t dir, uint8_t style) {
uint32_t uspers = usperstep;
uint8_t ret = 0;
if (style == INTERLEAVE) {
uspers /= 2;
}
else if (style == MICROSTEP) {
uspers /= MICROSTEPS;
steps *= MICROSTEPS;
#ifdef MOTORDEBUG
Serial.print("steps = "); Serial.println(steps, DEC);
#endif
}
while (steps--) {
ret = onestep(dir, style);
delay(uspers/1000); // in ms
steppingcounter += (uspers % 1000);
if (steppingcounter >= 1000) {
delay(1);
steppingcounter -= 1000;
}
}
if (style == MICROSTEP) {
while ((ret != 0) && (ret != MICROSTEPS)) {
ret = onestep(dir, style);
delay(uspers/1000); // in ms
steppingcounter += (uspers % 1000);
if (steppingcounter >= 1000) {
delay(1);
steppingcounter -= 1000;
}
}
}
}
uint8_t AF_Stepper::onestep(uint8_t dir, uint8_t style) {
uint8_t a, b, c, d;
uint8_t ocrb, ocra;
ocra = ocrb = 255;
if (steppernum == 1) {
a = _BV(MOTOR1_A);
b = _BV(MOTOR2_A);
c = _BV(MOTOR1_B);
d = _BV(MOTOR2_B);
} else if (steppernum == 2) {
a = _BV(MOTOR3_A);
b = _BV(MOTOR4_A);
c = _BV(MOTOR3_B);
d = _BV(MOTOR4_B);
} else {
return 0;
}
// next determine what sort of stepping procedure we're up to
if (style == SINGLE) {
if ((currentstep/(MICROSTEPS/2)) % 2) { // we're at an odd step, weird
if (dir == FORWARD) {
currentstep += MICROSTEPS/2;
}
else {
currentstep -= MICROSTEPS/2;
}
} else { // go to the next even step
if (dir == FORWARD) {
currentstep += MICROSTEPS;
}
else {
currentstep -= MICROSTEPS;
}
}
} else if (style == DOUBLE) {
if (! (currentstep/(MICROSTEPS/2) % 2)) { // we're at an even step, weird
if (dir == FORWARD) {
currentstep += MICROSTEPS/2;
} else {
currentstep -= MICROSTEPS/2;
}
} else { // go to the next odd step
if (dir == FORWARD) {
currentstep += MICROSTEPS;
} else {
currentstep -= MICROSTEPS;
}
}
} else if (style == INTERLEAVE) {
if (dir == FORWARD) {
currentstep += MICROSTEPS/2;
} else {
currentstep -= MICROSTEPS/2;
}
}
if (style == MICROSTEP) {
if (dir == FORWARD) {
currentstep++;
} else {
// BACKWARDS
currentstep--;
}
currentstep += MICROSTEPS*4;
currentstep %= MICROSTEPS*4;
ocra = ocrb = 0;
if ( (currentstep >= 0) && (currentstep < MICROSTEPS)) {
ocra = microstepcurve[MICROSTEPS - currentstep];
ocrb = microstepcurve[currentstep];
} else if ( (currentstep >= MICROSTEPS) && (currentstep < MICROSTEPS*2)) {
ocra = microstepcurve[currentstep - MICROSTEPS];
ocrb = microstepcurve[MICROSTEPS*2 - currentstep];
} else if ( (currentstep >= MICROSTEPS*2) && (currentstep < MICROSTEPS*3)) {
ocra = microstepcurve[MICROSTEPS*3 - currentstep];
ocrb = microstepcurve[currentstep - MICROSTEPS*2];
} else if ( (currentstep >= MICROSTEPS*3) && (currentstep < MICROSTEPS*4)) {
ocra = microstepcurve[currentstep - MICROSTEPS*3];
ocrb = microstepcurve[MICROSTEPS*4 - currentstep];
}
}
currentstep += MICROSTEPS*4;
currentstep %= MICROSTEPS*4;
#ifdef MOTORDEBUG
Serial.print("current step: "); Serial.println(currentstep, DEC);
Serial.print(" pwmA = "); Serial.print(ocra, DEC);
Serial.print(" pwmB = "); Serial.println(ocrb, DEC);
#endif
if (steppernum == 1) {
setPWM1(ocra);
setPWM2(ocrb);
} else if (steppernum == 2) {
setPWM3(ocra);
setPWM4(ocrb);
}
// release all
latch_state &= ~a & ~b & ~c & ~d; // all motor pins to 0
//Serial.println(step, DEC);
if (style == MICROSTEP) {
if ((currentstep >= 0) && (currentstep < MICROSTEPS))
latch_state |= a | b;
if ((currentstep >= MICROSTEPS) && (currentstep < MICROSTEPS*2))
latch_state |= b | c;
if ((currentstep >= MICROSTEPS*2) && (currentstep < MICROSTEPS*3))
latch_state |= c | d;
if ((currentstep >= MICROSTEPS*3) && (currentstep < MICROSTEPS*4))
latch_state |= d | a;
} else {
switch (currentstep/(MICROSTEPS/2)) {
case 0:
latch_state |= a; // energize coil 1 only
break;
case 1:
latch_state |= a | b; // energize coil 1+2
break;
case 2:
latch_state |= b; // energize coil 2 only
break;
case 3:
latch_state |= b | c; // energize coil 2+3
break;
case 4:
latch_state |= c; // energize coil 3 only
break;
case 5:
latch_state |= c | d; // energize coil 3+4
break;
case 6:
latch_state |= d; // energize coil 4 only
break;
case 7:
latch_state |= d | a; // energize coil 1+4
break;
}
}
MC.latch_tx();
return currentstep;
}
// Adafruit Motor shield library
// copyright Adafruit Industries LLC, 2009
// this code is public domain, enjoy!
#ifndef _AFMotor_h_
#define _AFMotor_h_
#include <inttypes.h>
#include <avr/io.h>
//#define MOTORDEBUG 1
#define MICROSTEPS 16 // 8 or 16
#define MOTOR12_64KHZ _BV(CS20) // no prescale
#define MOTOR12_8KHZ _BV(CS21) // divide by 8
#define MOTOR12_2KHZ _BV(CS21) | _BV(CS20) // divide by 32
#define MOTOR12_1KHZ _BV(CS22) // divide by 64
#define MOTOR34_64KHZ _BV(CS00) // no prescale
#define MOTOR34_8KHZ _BV(CS01) // divide by 8
#define MOTOR34_1KHZ _BV(CS01) | _BV(CS00) // divide by 64
#define MOTOR1_A 2
#define MOTOR1_B 3
#define MOTOR2_A 1
#define MOTOR2_B 4
#define MOTOR4_A 0
#define MOTOR4_B 6
#define MOTOR3_A 5
#define MOTOR3_B 7
#define FORWARD 1
#define BACKWARD 2
#define BRAKE 3
#define RELEASE 4
#define SINGLE 1
#define DOUBLE 2
#define INTERLEAVE 3
#define MICROSTEP 4
/*
#define LATCH 4
#define LATCH_DDR DDRB
#define LATCH_PORT PORTB
#define CLK_PORT PORTD
#define CLK_DDR DDRD
#define CLK 4
#define ENABLE_PORT PORTD
#define ENABLE_DDR DDRD
#define ENABLE 7
#define SER 0
#define SER_DDR DDRB
#define SER_PORT PORTB
*/
// Arduino pin names
#define MOTORLATCH 12
#define MOTORCLK 4
#define MOTORENABLE 7
#define MOTORDATA 8
class AFMotorController
{
public:
AFMotorController(void);
void enable(void);
friend class AF_DCMotor;
void latch_tx(void);
};
class AF_DCMotor
{
public:
AF_DCMotor(uint8_t motornum, uint8_t freq = MOTOR34_8KHZ);
void run(uint8_t);
void setSpeed(uint8_t);
private:
uint8_t motornum, pwmfreq;
};
class AF_Stepper {
public:
AF_Stepper(uint16_t, uint8_t);
void step(uint16_t steps, uint8_t dir, uint8_t style = SINGLE);
void setSpeed(uint16_t);
uint8_t onestep(uint8_t dir, uint8_t style);
void release(void);
uint16_t revsteps; // # steps per revolution
uint8_t steppernum;
uint32_t usperstep, steppingcounter;
private:
uint8_t currentstep;
};
uint8_t getlatchstate(void);
#endif
// AccelStepper.cpp
//
// Copyright (C) 2009 Mike McCauley
// $Id: AccelStepper.cpp,v 1.4 2011/01/05 01:51:01 mikem Exp $
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include "AccelStepper.h"
void AccelStepper::moveTo(long absolute)
{
_targetPos = absolute;
computeNewSpeed();
}
void AccelStepper::move(long relative)
{
moveTo(_currentPos + relative);
}
// Implements steps according to the current speed
// You must call this at least once per step
// returns true if a step occurred
boolean AccelStepper::runSpeed()
{
unsigned long time = micros();
// if ( (time >= (_lastStepTime + _stepInterval)) // okay if both current time and next step time wrap
// || ((time < _lastRunTime) && (time > (0xFFFFFFFF-(_lastStepTime+_stepInterval)))) ) // check if only current time has wrapped
// unsigned long nextStepTime = _lastStepTime + _stepInterval;
// if ( ((nextStepTime < _lastStepTime) && (time < _lastStepTime) && (time >= nextStepTime))
// || ((nextStepTime >= _lastStepTime) && (time >= nextStepTime)))
// TESTING:
//time += (0xffffffff - 10000000);
// Gymnastics to detect wrapping of either the nextStepTime and/or the current time
unsigned long nextStepTime = _lastStepTime + _stepInterval;
if ( ((nextStepTime >= _lastStepTime) && ((time >= nextStepTime) || (time < _lastStepTime)))
|| ((nextStepTime < _lastStepTime) && ((time >= nextStepTime) && (time < _lastStepTime))))
{
if (_speed > 0.0f)
{
// Clockwise
_currentPos += 1;
}
else if (_speed < 0.0f)
{
// Anticlockwise
_currentPos -= 1;
}
step(_currentPos & 0x7); // Bottom 3 bits (same as mod 8, but works with + and - numbers)
// _lastRunTime = time;
_lastStepTime = time;
return true;
}
else
{
// _lastRunTime = time;
return false;
}
}
long AccelStepper::distanceToGo()
{
return _targetPos - _currentPos;
}
long AccelStepper::targetPosition()
{
return _targetPos;
}
long AccelStepper::currentPosition()
{
return _currentPos;
}
// Useful during initialisations or after initial positioning
void AccelStepper::setCurrentPosition(long position)
{
_targetPos = _currentPos = position;
computeNewSpeed(); // Expect speed of 0
}
void AccelStepper::computeNewSpeed()
{
setSpeed(desiredSpeed());
}
// Work out and return a new speed.
// Subclasses can override if they want
// Implement acceleration, deceleration and max speed
// Negative speed is anticlockwise
// This is called:
// after each step
// after user changes:
// maxSpeed
// acceleration
// target position (relative or absolute)
float AccelStepper::desiredSpeed()
{
float requiredSpeed;
long distanceTo = distanceToGo();
// Max possible speed that can still decelerate in the available distance
// Use speed squared to avoid using sqrt
if (distanceTo == 0)
return 0.0f; // We're there
else if (distanceTo > 0) // Clockwise
requiredSpeed = (2.0f * distanceTo * _acceleration);
else // Anticlockwise
requiredSpeed = -(2.0f * -distanceTo * _acceleration);
float sqrSpeed = (_speed * _speed) * ((_speed > 0.0f) ? 1.0f : -1.0f);
if (requiredSpeed > sqrSpeed)
{
if (_speed == _maxSpeed) // Reduces processor load by avoiding extra calculations below
{
// Maintain max speed
requiredSpeed = _maxSpeed;
}
else
{
// Need to accelerate in clockwise direction
if (_speed == 0.0f)
requiredSpeed = sqrt(2.0f * _acceleration);
else
requiredSpeed = _speed + abs(_acceleration / _speed);
if (requiredSpeed > _maxSpeed)
requiredSpeed = _maxSpeed;
}
}
else if (requiredSpeed < sqrSpeed)
{
if (_speed == -_maxSpeed) // Reduces processor load by avoiding extra calculations below
{
// Maintain max speed
requiredSpeed = -_maxSpeed;
}
else
{
// Need to accelerate in clockwise direction
if (_speed == 0.0f)
requiredSpeed = -sqrt(2.0f * _acceleration);
else
requiredSpeed = _speed - abs(_acceleration / _speed);
if (requiredSpeed < -_maxSpeed)
requiredSpeed = -_maxSpeed;
}
}
else // if (requiredSpeed == sqrSpeed)
requiredSpeed = _speed;
// Serial.println(requiredSpeed);
return requiredSpeed;
}
// Run the motor to implement speed and acceleration in order to proceed to the target position
// You must call this at least once per step, preferably in your main loop
// If the motor is in the desired position, the cost is very small
// returns true if we are still running to position
boolean AccelStepper::run()
{
if (_targetPos == _currentPos)
return false;
if (runSpeed())
computeNewSpeed();
return true;
}
AccelStepper::AccelStepper(uint8_t pins, uint8_t pin1, uint8_t pin2, uint8_t pin3, uint8_t pin4)
{
_pins = pins;
_currentPos = 0;
_targetPos = 0;
_speed = 0.0;
_maxSpeed = 1.0;
_acceleration = 1.0;
_stepInterval = 0;
// _lastRunTime = 0;
_minPulseWidth = 1;
_lastStepTime = 0;
_pin1 = pin1;
_pin2 = pin2;
_pin3 = pin3;
_pin4 = pin4;
//_stepInterval = 20000;
//_speed = 50.0;
//_lastRunTime = 0xffffffff - 20000;
//_lastStepTime = 0xffffffff - 20000 - 10000;
enableOutputs();
}
AccelStepper::AccelStepper(void (*forward)(), void (*backward)())
{
_pins = 0;
_currentPos = 0;
_targetPos = 0;
_speed = 0.0;
_maxSpeed = 1.0;
_acceleration = 1.0;
_stepInterval = 0;
// _lastRunTime = 0;
_minPulseWidth = 1;
_lastStepTime = 0;
_pin1 = 0;
_pin2 = 0;
_pin3 = 0;
_pin4 = 0;
_forward = forward;
_backward = backward;
}
void AccelStepper::setMaxSpeed(float speed)
{
_maxSpeed = speed;
computeNewSpeed();
}
void AccelStepper::setAcceleration(float acceleration)
{
_acceleration = acceleration;
computeNewSpeed();
}
void AccelStepper::setSpeed(float speed)
{
if (speed == _speed)
return;
if ((speed > 0.0f) && (speed > _maxSpeed))
_speed = _maxSpeed;
else if ((speed < 0.0f) && (speed < -_maxSpeed))
_speed = -_maxSpeed;
else
_speed = speed;
_stepInterval = abs(1000000.0 / _speed);
}
float AccelStepper::speed()
{
return _speed;
}
// Subclasses can override
void AccelStepper::step(uint8_t step)
{
switch (_pins)
{
case 0:
step0();
break;
case 1:
step1(step);
break;
case 2:
step2(step);
break;
case 4:
step4(step);
break;
case 8:
step8(step);
break;
}
}
// 0 pin step function (ie for functional usage)
void AccelStepper::step0()
{
if (_speed > 0) {
_forward();
} else {
_backward();
}
}
// 1 pin step function (ie for stepper drivers)
// This is passed the current step number (0 to 7)
// Subclasses can override
void AccelStepper::step1(uint8_t step)
{
digitalWrite(_pin2, _speed > 0); // Direction
// Caution 200ns setup time
digitalWrite(_pin1, HIGH);
// Delay the minimum allowed pulse width
delayMicroseconds(_minPulseWidth);
digitalWrite(_pin1, LOW);
}
// 2 pin step function
// This is passed the current step number (0 to 7)
// Subclasses can override
void AccelStepper::step2(uint8_t step)
{
switch (step & 0x3)
{
case 0: /* 01 */
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, HIGH);
break;
case 1: /* 11 */
digitalWrite(_pin1, HIGH);
digitalWrite(_pin2, HIGH);
break;
case 2: /* 10 */
digitalWrite(_pin1, HIGH);
digitalWrite(_pin2, LOW);
break;
case 3: /* 00 */
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, LOW);
break;
}
}
// 4 pin step function for half stepper
// This is passed the current step number (0 to 7)
// Subclasses can override
void AccelStepper::step4(uint8_t step)
{
switch (step & 0x3)
{
case 0: // 1010
digitalWrite(_pin1, HIGH);
digitalWrite(_pin2, LOW);
digitalWrite(_pin3, HIGH);
digitalWrite(_pin4, LOW);
break;
case 1: // 0110
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, HIGH);
digitalWrite(_pin3, HIGH);
digitalWrite(_pin4, LOW);
break;
case 2: //0101
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, HIGH);
digitalWrite(_pin3, LOW);
digitalWrite(_pin4, HIGH);
break;
case 3: //1001
digitalWrite(_pin1, HIGH);
digitalWrite(_pin2, LOW);
digitalWrite(_pin3, LOW);
digitalWrite(_pin4, HIGH);
break;
}
}
// 4 pin step function
// This is passed the current step number (0 to 3)
// Subclasses can override
void AccelStepper::step8(uint8_t step)
{
switch (step & 0x7)
{
case 0: // 1000
digitalWrite(_pin1, HIGH);
digitalWrite(_pin2, LOW);
digitalWrite(_pin3, LOW);
digitalWrite(_pin4, LOW);
break;
case 1: // 1010
digitalWrite(_pin1, HIGH);
digitalWrite(_pin2, LOW);
digitalWrite(_pin3, HIGH);
digitalWrite(_pin4, LOW);
break;
case 2: // 0010
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, LOW);
digitalWrite(_pin3, HIGH);
digitalWrite(_pin4, LOW);
break;
case 3: // 0110
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, HIGH);
digitalWrite(_pin3, HIGH);
digitalWrite(_pin4, LOW);
break;
case 4: // 0100
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, HIGH);
digitalWrite(_pin3, LOW);
digitalWrite(_pin4, LOW);
break;
case 5: //0101
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, HIGH);
digitalWrite(_pin3, LOW);
digitalWrite(_pin4, HIGH);
break;
case 6: // 0001
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, LOW);
digitalWrite(_pin3, LOW);
digitalWrite(_pin4, HIGH);
break;
case 7: //1001
digitalWrite(_pin1, HIGH);
digitalWrite(_pin2, LOW);
digitalWrite(_pin3, LOW);
digitalWrite(_pin4, HIGH);
break;
}
}
// Prevents power consumption on the outputs
void AccelStepper::disableOutputs()
{
if (! _pins) return;
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, LOW);
if (_pins == 4 || _pins == 😎
{
digitalWrite(_pin3, LOW);
digitalWrite(_pin4, LOW);
}
}
void AccelStepper::enableOutputs()
{
if (! _pins) return;
pinMode(_pin1, OUTPUT);
pinMode(_pin2, OUTPUT);
if (_pins == 4 || _pins == 😎
{
pinMode(_pin3, OUTPUT);
pinMode(_pin4, OUTPUT);
}
}
void AccelStepper::setMinPulseWidth(unsigned int minWidth)
{
_minPulseWidth = minWidth;
}
// Blocks until the target position is reached
void AccelStepper::runToPosition()
{
while (run())
;
}
boolean AccelStepper::runSpeedToPosition()
{
return _targetPos!=_currentPos ? runSpeed() : false;
}
// Blocks until the new target position is reached
void AccelStepper::runToNewPosition(long position)
{
moveTo(position);
runToPosition();
}
// AccelStepper.h
//
/// \mainpage AccelStepper library for Arduino
///
/// This is the Arduino AccelStepper library.
/// It provides an object-oriented interface for 2 or 4 pin stepper motors.
///
/// The standard Arduino IDE includes the Stepper library
/// (http://arduino.cc/en/Reference/Stepper) for stepper motors. It is
/// perfectly adequate for simple, single motor applications.
///
/// AccelStepper significantly improves on the standard Arduino Stepper library in several ways:
/// \li Supports acceleration and deceleration
/// \li Supports multiple simultaneous steppers, with independent concurrent stepping on each stepper
/// \li API functions never delay() or block
/// \li Supports 2 and 4 wire steppers, plus 4 wire half steppers.
/// \li Supports alternate stepping functions to enable support of AFMotor (https://github.com/adafruit/Adafruit-Motor-Shield-library)
/// \li Supports stepper drivers such as the Sparkfun EasyDriver (based on 3967 driver chip)
/// \li Very slow speeds are supported
/// \li Extensive API
/// \li Subclass support
///
/// The latest version of this documentation can be downloaded from
/// http://www.open.com.au/mikem/arduino/AccelStepper
///
/// Example Arduino programs are included to show the main modes of use.
///
/// The version of the package that this documentation refers to can be downloaded
/// from http://www.open.com.au/mikem/arduino/AccelStepper/AccelStepper-1.9.zip
/// You can find the latest version at http://www.open.com.au/mikem/arduino/AccelStepper
///
/// Tested on Arduino Diecimila and Mega with arduino-0018 & arduino-0021
/// on OpenSuSE 11.1 and avr-libc-1.6.1-1.15,
/// cross-avr-binutils-2.19-9.1, cross-avr-gcc-4.1.3_20080612-26.5.
///
/// \par Installation
/// Install in the usual way: unzip the distribution zip file to the libraries
/// sub-folder of your sketchbook.
///
/// This software is Copyright (C) 2010 Mike McCauley. Use is subject to license
/// conditions. The main licensing options available are GPL V2 or Commercial:
///
/// \par Open Source Licensing GPL V2
/// This is the appropriate option if you want to share the source code of your
/// application with everyone you distribute it to, and you also want to give them
/// the right to share who uses it. If you wish to use this software under Open
/// Source Licensing, you must contribute all your source code to the open source
/// community in accordance with the GPL Version 2 when your application is
/// distributed. See http://www.gnu.org/copyleft/gpl.html
///
/// \par Commercial Licensing
/// This is the appropriate option if you are creating proprietary applications
/// and you are not prepared to distribute and share the source code of your
/// application. Contact info@open.com.au for details.
///
/// \par Revision History
/// \version 1.0 Initial release
///
/// \version 1.1 Added speed() function to get the current speed.
/// \version 1.2 Added runSpeedToPosition() submitted by Gunnar Arndt.
/// \version 1.3 Added support for stepper drivers (ie with Step and Direction inputs) with _pins == 1
/// \version 1.4 Added functional contructor to support AFMotor, contributed by Limor, with example sketches.
/// \version 1.5 Improvements contributed by Peter Mousley: Use of microsecond steps and other speed improvements
/// to increase max stepping speed to about 4kHz. New option for user to set the min allowed pulse width.
/// Added checks for already running at max speed and skip further calcs if so.
/// \version 1.6 Fixed a problem with wrapping of microsecond stepping that could cause stepping to hang.
/// Reported by Sandy Noble.
/// Removed redundant _lastRunTime member.
/// \version 1.7 Fixed a bug where setCurrentPosition() did always work as expected. Reported by Peter Linhart.
/// Reported by Sandy Noble.
/// Removed redundant _lastRunTime member.
/// \version 1.8 Added support for 4 pin half-steppers, requested by Harvey Moon
/// \version 1.9 setCurrentPosition() now also sets motor speed to 0.
///
///
/// \author Mike McCauley (mikem@open.com.au)
// Copyright (C) 2009 Mike McCauley
// $Id: AccelStepper.h,v 1.5 2011/03/21 00:42:15 mikem Exp mikem $
#ifndef AccelStepper_h
#define AccelStepper_h
#include <stdlib.h>
#if defined(ARDUINO) && ARDUINO >= 100
#include <pins_arduino.h>
#else
#include <wiring.h>
#endif
// These defs cause trouble on some versions of Arduino
#undef round
/////////////////////////////////////////////////////////////////////
/// \class AccelStepper AccelStepper.h <AccelStepper.h>
/// \brief Support for stepper motors with acceleration etc.
///
/// This defines a single 2 or 4 pin stepper motor, or stepper moter with fdriver chip, with optional
/// acceleration, deceleration, absolute positioning commands etc. Multiple
/// simultaneous steppers are supported, all moving
/// at different speeds and accelerations.
///
/// \par Operation
/// This module operates by computing a step time in microseconds. The step
/// time is recomputed after each step and after speed and acceleration
/// parameters are changed by the caller. The time of each step is recorded in
/// microseconds. The run() function steps the motor if a new step is due.
/// The run() function must be called frequently until the motor is in the
/// desired position, after which time run() will do nothing.
///
/// \par Positioning
/// Positions are specified by a signed long integer. At
/// construction time, the current position of the motor is consider to be 0. Positive
/// positions are clockwise from the initial position; negative positions are
/// anticlockwise. The curent position can be altered for instance after
/// initialization positioning.
///
/// \par Caveats
/// This is an open loop controller: If the motor stalls or is oversped,
/// AccelStepper will not have a correct
/// idea of where the motor really is (since there is no feedback of the motor's
/// real position. We only know where we _think_ it is, relative to the
/// initial starting point).
///
/// The fastest motor speed that can be reliably supported is 4000 steps per
/// second (4 kHz) at a clock frequency of 16 MHz. However, any speed less than that
/// down to very slow speeds (much less than one per second) are also supported,
/// provided the run() function is called frequently enough to step the motor
/// whenever required for the speed set.
class AccelStepper
{
public:
/// Constructor. You can have multiple simultaneous steppers, all moving
/// at different speeds and accelerations, provided you call their run()
/// functions at frequent enough intervals. Current Position is set to 0, target
/// position is set to 0. MaxSpeed and Acceleration default to 1.0.
/// The motor pins will be initialised to OUTPUT mode during the
/// constructor by a call to enableOutputs().
/// \param[in] pins Number of pins to interface to. 1, 2 or 4 are
/// supported. 1 means a stepper driver (with Step and Direction pins)
/// 2 means a 2 wire stepper. 4 means a 4 wire stepper. 8 means a 4 wire half stepper
/// Defaults to 4 pins.
/// \param[in] pin1 Arduino digital pin number for motor pin 1. Defaults
/// to pin 2. For a driver (pins==1), this is the Step input to the driver. Low to high transition means to step)
/// \param[in] pin2 Arduino digital pin number for motor pin 2. Defaults
/// to pin 3. For a driver (pins==1), this is the Direction input the driver. High means forward.
/// \param[in] pin3 Arduino digital pin number for motor pin 3. Defaults
/// to pin 4.
/// \param[in] pin4 Arduino digital pin number for motor pin 4. Defaults
/// to pin 5.
AccelStepper(uint8_t pins = 4, uint8_t pin1 = 2, uint8_t pin2 = 3, uint8_t pin3 = 4, uint8_t pin4 = 5);
/// Alternate Constructor which will call your own functions for forward and backward steps.
/// You can have multiple simultaneous steppers, all moving
/// at different speeds and accelerations, provided you call their run()
/// functions at frequent enough intervals. Current Position is set to 0, target
/// position is set to 0. MaxSpeed and Acceleration default to 1.0.
/// Any motor initialization should happen before hand, no pins are used or initialized.
/// \param[in] forward void-returning procedure that will make a forward step
/// \param[in] backward void-returning procedure that will make a backward step
AccelStepper(void (*forward)(), void (*backward)());
/// Set the target position. The run() function will try to move the motor
/// from the current position to the target position set by the most
/// recent call to this function.
/// \param[in] absolute The desired absolute position. Negative is
/// anticlockwise from the 0 position.
void moveTo(long absolute);
/// Set the target position relative to the current position
/// \param[in] relative The desired position relative to the current position. Negative is
/// anticlockwise from the current position.
void move(long relative);
/// Poll the motor and step it if a step is due, implementing
/// accelerations and decelerations to achive the ratget position. You must call this as
/// fequently as possible, but at least once per minimum step interval,
/// preferably in your main loop.
/// \return true if the motor is at the target position.
boolean run();
/// Poll the motor and step it if a step is due, implmenting a constant
/// speed as set by the most recent call to setSpeed().
/// \return true if the motor was stepped.
boolean runSpeed();
/// Sets the maximum permitted speed. the run() function will accelerate
/// up to the speed set by this function.
/// \param[in] speed The desired maximum speed in steps per second. Must
/// be > 0. Speeds of more than 1000 steps per second are unreliable.
void setMaxSpeed(float speed);
/// Sets the acceleration and deceleration parameter.
/// \param[in] acceleration The desired acceleration in steps per second
/// per second. Must be > 0.
void setAcceleration(float acceleration);
/// Sets the desired constant speed for use with runSpeed().
/// \param[in] speed The desired constant speed in steps per
/// second. Positive is clockwise. Speeds of more than 1000 steps per
/// second are unreliable. Very slow speeds may be set (eg 0.00027777 for
/// once per hour, approximately. Speed accuracy depends on the Arduino
/// crystal. Jitter depends on how frequently you call the runSpeed() function.
void setSpeed(float speed);
/// The most recently set speed
/// \return the most recent speed in steps per second
float speed();
/// The distance from the current position to the target position.
/// \return the distance from the current position to the target position
/// in steps. Positive is clockwise from the current position.
long distanceToGo();
/// The most recently set target position.
/// \return the target position
/// in steps. Positive is clockwise from the 0 position.
long targetPosition();
/// The currently motor position.
/// \return the current motor position
/// in steps. Positive is clockwise from the 0 position.
long currentPosition();
/// Resets the current position of the motor, so that wherever the motor
/// happens to be right now is considered to be the new 0 position. Useful
/// for setting a zero position on a stepper after an initial hardware
/// positioning move.
/// Has the side effect of setting the current motor speed to 0.
/// \param[in] position The position in steps of wherever the motor
/// happens to be right now.
void setCurrentPosition(long position);
/// Moves the motor to the target position and blocks until it is at
/// position. Dont use this in event loops, since it blocks.
void runToPosition();
/// Runs at the currently selected speed until the target position is reached
/// Does not implement accelerations.
boolean runSpeedToPosition();
/// Moves the motor to the new target position and blocks until it is at
/// position. Dont use this in event loops, since it blocks.
/// \param[in] position The new target position.
void runToNewPosition(long position);
/// Disable motor pin outputs by setting them all LOW
/// Depending on the design of your electronics this may turn off
/// the power to the motor coils, saving power.
/// This is useful to support Arduino low power modes: disable the outputs
/// during sleep and then reenable with enableOutputs() before stepping
/// again.
void disableOutputs();
/// Enable motor pin outputs by setting the motor pins to OUTPUT
/// mode. Called automatically by the constructor.
void enableOutputs();
/// Sets the minimum pulse width allowed by the stepper driver.
/// \param[in] minWidth The minimum pulse width in microseconds.
void setMinPulseWidth(unsigned int minWidth);
protected:
/// Forces the library to compute a new instantaneous speed and set that as
/// the current speed. Calls
/// desiredSpeed(), which can be overridden by subclasses. It is called by
/// the library:
/// \li after each step
/// \li after change to maxSpeed through setMaxSpeed()
/// \li after change to acceleration through setAcceleration()
/// \li after change to target position (relative or absolute) through
/// move() or moveTo()
void computeNewSpeed();
/// Called to execute a step. Only called when a new step is
/// required. Subclasses may override to implement new stepping
/// interfaces. The default calls step1(), step2(), step4() or step8() depending on the
/// number of pins defined for the stepper.
/// \param[in] step The current step phase number (0 to 7)
virtual void step(uint8_t step);
/// Called to execute a step using stepper functions (pins = 0) Only called when a new step is
/// required. Calls _forward() or _backward() to perform the step
virtual void step0(void);
/// Called to execute a step on a stepper drover (ie where pins == 1). Only called when a new step is
/// required. Subclasses may override to implement new stepping
/// interfaces. The default sets or clears the outputs of Step pin1 to step,
/// and sets the output of _pin2 to the desired direction. The Step pin (_pin1) is pulsed for 1 microsecond
/// which is the minimum STEP pulse width for the 3967 driver.
/// \param[in] step The current step phase number (0 to 7)
virtual void step1(uint8_t step);
/// Called to execute a step on a 2 pin motor. Only called when a new step is
/// required. Subclasses may override to implement new stepping
/// interfaces. The default sets or clears the outputs of pin1 and pin2
/// \param[in] step The current step phase number (0 to 7)
virtual void step2(uint8_t step);
/// Called to execute a step on a 4 pin motor. Only called when a new step is
/// required. Subclasses may override to implement new stepping
/// interfaces. The default sets or clears the outputs of pin1, pin2,
/// pin3, pin4.
/// \param[in] step The current step phase number (0 to 7)
virtual void step4(uint8_t step);
/// Called to execute a step on a 4 pin half-steper motor. Only called when a new step is
/// required. Subclasses may override to implement new stepping
/// interfaces. The default sets or clears the outputs of pin1, pin2,
/// pin3, pin4.
/// \param[in] step The current step phase number (0 to 7)
virtual void step8(uint8_t step);
/// Compute and return the desired speed. The default algorithm uses
/// maxSpeed, acceleration and the current speed to set a new speed to
/// move the motor from teh current position to the target
/// position. Subclasses may override this to provide an alternate
/// algorithm (but do not block). Called by computeNewSpeed whenever a new speed neds to be
/// computed.
virtual float desiredSpeed();
private:
/// Number of pins on the stepper motor. Permits 2 or 4. 2 pins is a
/// bipolar, and 4 pins is a unipolar.
uint8_t _pins; // 2 or 4
/// Arduino pin number for the 2 or 4 pins required to interface to the
/// stepper motor.
uint8_t _pin1, _pin2, _pin3, _pin4;
/// The current absolution position in steps.
long _currentPos; // Steps
/// The target position in steps. The AccelStepper library will move the
/// motor from teh _currentPos to the _targetPos, taking into account the
/// max speed, acceleration and deceleration
long _targetPos; // Steps
/// The current motos speed in steps per second
/// Positive is clockwise
float _speed; // Steps per second
/// The maximum permitted speed in steps per second. Must be > 0.
float _maxSpeed;
/// The acceleration to use to accelerate or decelerate the motor in steps
/// per second per second. Must be > 0
float _acceleration;
/// The current interval between steps in microseconds
unsigned long _stepInterval;
/// The last run time (when runSpeed() was last called) in microseconds
// unsigned long _lastRunTime;
/// The last step time in microseconds
unsigned long _lastStepTime;
/// The minimum allowed pulse width in microseconds
unsigned int _minPulseWidth;
// The pointer to a forward-step procedure
void (*_forward)();
// The pointer to a backward-step procedure
void (*_backward)();
};
#endif
/*
* IRremote
* Version 0.11 August, 2009
* Copyright 2009 Ken Shirriff
* For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html
*
* Interrupt code based on NECIRrcv by Joe Knapp
* http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556
* Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/
*/
#include "IRremote.h"
#include "IRremoteInt.h"
// Provides ISR
#include <avr/interrupt.h>
volatile irparams_t irparams;
// These versions of MATCH, MATCH_MARK, and MATCH_SPACE are only for debugging.
// To use them, set DEBUG in IRremoteInt.h
// Normally macros are used for efficiency
#ifdef DEBUG
int MATCH(int measured, int desired) {
Serial.print("Testing: ");
Serial.print(TICKS_LOW(desired), DEC);
Serial.print(" <= ");
Serial.print(measured, DEC);
Serial.print(" <= ");
Serial.println(TICKS_HIGH(desired), DEC);
return measured >= TICKS_LOW(desired) && measured <= TICKS_HIGH(desired);
}
int MATCH_MARK(int measured_ticks, int desired_us) {
Serial.print("Testing mark ");
Serial.print(measured_ticks * USECPERTICK, DEC);
Serial.print(" vs ");
Serial.print(desired_us, DEC);
Serial.print(": ");
Serial.print(TICKS_LOW(desired_us + MARK_EXCESS), DEC);
Serial.print(" <= ");
Serial.print(measured_ticks, DEC);
Serial.print(" <= ");
Serial.println(TICKS_HIGH(desired_us + MARK_EXCESS), DEC);
return measured_ticks >= TICKS_LOW(desired_us + MARK_EXCESS) && measured_ticks <= TICKS_HIGH(desired_us + MARK_EXCESS);
}
int MATCH_SPACE(int measured_ticks, int desired_us) {
Serial.print("Testing space ");
Serial.print(measured_ticks * USECPERTICK, DEC);
Serial.print(" vs ");
Serial.print(desired_us, DEC);
Serial.print(": ");
Serial.print(TICKS_LOW(desired_us - MARK_EXCESS), DEC);
Serial.print(" <= ");
Serial.print(measured_ticks, DEC);
Serial.print(" <= ");
Serial.println(TICKS_HIGH(desired_us - MARK_EXCESS), DEC);
return measured_ticks >= TICKS_LOW(desired_us - MARK_EXCESS) && measured_ticks <= TICKS_HIGH(desired_us - MARK_EXCESS);
}
#endif
void IRsend::sendNEC(unsigned long data, int nbits)
{
enableIROut(38);
mark(NEC_HDR_MARK);
space(NEC_HDR_SPACE);
for (int i = 0; i < nbits; i++) {
if (data & TOPBIT) {
mark(NEC_BIT_MARK);
space(NEC_ONE_SPACE);
}
else {
mark(NEC_BIT_MARK);
space(NEC_ZERO_SPACE);
}
data <<= 1;
}
mark(NEC_BIT_MARK);
space(0);
}
void IRsend::sendSony(unsigned long data, int nbits) {
enableIROut(40);
mark(SONY_HDR_MARK);
space(SONY_HDR_SPACE);
data = data << (32 - nbits);
for (int i = 0; i < nbits; i++) {
if (data & TOPBIT) {
mark(SONY_ONE_MARK);
space(SONY_HDR_SPACE);
}
else {
mark(SONY_ZERO_MARK);
space(SONY_HDR_SPACE);
}
data <<= 1;
}
}
void IRsend::sendRaw(unsigned int buf[], int len, int hz)
{
enableIROut(hz);
for (int i = 0; i < len; i++) {
if (i & 1) {
space(buf);
}
else {
mark(buf);
}
}
space(0); // Just to be sure
}
// Note: first bit must be a one (start bit)
void IRsend::sendRC5(unsigned long data, int nbits)
{
enableIROut(36);
data = data << (32 - nbits);
mark(RC5_T1); // First start bit
space(RC5_T1); // Second start bit
mark(RC5_T1); // Second start bit
for (int i = 0; i < nbits; i++) {
if (data & TOPBIT) {
space(RC5_T1); // 1 is space, then mark
mark(RC5_T1);
}
else {
mark(RC5_T1);
space(RC5_T1);
}
data <<= 1;
}
space(0); // Turn off at end
}
// Caller needs to take care of flipping the toggle bit
void IRsend::sendRC6(unsigned long data, int nbits)
{
enableIROut(36);
data = data << (32 - nbits);
mark(RC6_HDR_MARK);
space(RC6_HDR_SPACE);
mark(RC6_T1); // start bit
space(RC6_T1);
int t;
for (int i = 0; i < nbits; i++) {
if (i == 3) {
// double-wide trailer bit
t = 2 * RC6_T1;
}
else {
t = RC6_T1;
}
if (data & TOPBIT) {
mark(t);
space(t);
}
else {
space(t);
mark(t);
}
data <<= 1;
}
space(0); // Turn off at end
}
void IRsend::mark(int time) {
// Sends an IR mark for the specified number of microseconds.
// The mark output is modulated at the PWM frequency.
TCCR2A |= _BV(COM2B1); // Enable pin 3 PWM output
delayMicroseconds(time);
}
/* Leave pin off for time (given in microseconds) */
void IRsend::space(int time) {
// Sends an IR space for the specified number of microseconds.
// A space is no output, so the PWM output is disabled.
TCCR2A &= ~(_BV(COM2B1)); // Disable pin 3 PWM output
delayMicroseconds(time);
}
void IRsend::enableIROut(int khz) {
// Enables IR output. The khz value controls the modulation frequency in kilohertz.
// The IR output will be on pin 3 (OC2B).
// This routine is designed for 36-40KHz; if you use it for other values, it's up to you
// to make sure it gives reasonable results. (Watch out for overflow / underflow / rounding.)
// TIMER2 is used in phase-correct PWM mode, with OCR2A controlling the frequency and OCR2B
// controlling the duty cycle.
// There is no prescaling, so the output frequency is 16MHz / (2 * OCR2A)
// To turn the output on and off, we leave the PWM running, but connect and disconnect the output pin.
// A few hours staring at the ATmega documentation and this will all make sense.
// See my Secrets of Arduino PWM at http://arcfn.com/2009/07/secrets-of-arduino-pwm.html for details.
// Disable the Timer2 Interrupt (which is used for receiving IR)
TIMSK2 &= ~_BV(TOIE2); //Timer2 Overflow Interrupt
pinMode(3, OUTPUT);
digitalWrite(3, LOW); // When not sending PWM, we want it low
// COM2A = 00: disconnect OC2A
// COM2B = 00: disconnect OC2B; to send signal set to 10: OC2B non-inverted
// WGM2 = 101: phase-correct PWM with OCRA as top
// CS2 = 000: no prescaling
TCCR2A = _BV(WGM20);
TCCR2B = _BV(WGM22) | _BV(CS20);
// The top value for the timer. The modulation frequency will be SYSCLOCK / 2 / OCR2A.
OCR2A = SYSCLOCK / 2 / khz / 1000;
OCR2B = OCR2A / 3; // 33% duty cycle
}
IRrecv::IRrecv(int recvpin)
{
irparams.recvpin = recvpin;
irparams.blinkflag = 0;
}
// initialization
void IRrecv::enableIRIn() {
// setup pulse clock timer interrupt
TCCR2A = 0; // normal mode
//Prescale /8 (16M/8 = 0.5 microseconds per tick)
// Therefore, the timer interval can range from 0.5 to 128 microseconds
// depending on the reset value (255 to 0)
cbi(TCCR2B,CS22);
sbi(TCCR2B,CS21);
cbi(TCCR2B,CS20);
//Timer2 Overflow Interrupt Enable
sbi(TIMSK2,TOIE2);
RESET_TIMER2;
sei(); // enable interrupts
// initialize state machine variables
irparams.rcvstate = STATE_IDLE;
irparams.rawlen = 0;
// set pin modes
pinMode(irparams.recvpin, INPUT);
}
// enable/disable blinking of pin 13 on IR processing
void IRrecv::blink13(int blinkflag)
{
irparams.blinkflag = blinkflag;
if (blinkflag)
pinMode(BLINKLED, OUTPUT);
}
// TIMER2 interrupt code to collect raw data.
// Widths of alternating SPACE, MARK are recorded in rawbuf.
// Recorded in ticks of 50 microseconds.
// rawlen counts the number of entries recorded so far.
// First entry is the SPACE between transmissions.
// As soon as a SPACE gets long, ready is set, state switches to IDLE, timing of SPACE continues.
// As soon as first MARK arrives, gap width is recorded, ready is cleared, and new logging starts
ISR(TIMER2_OVF_vect)
{
RESET_TIMER2;
uint8_t irdata = (uint8_t)digitalRead(irparams.recvpin);
irparams.timer++; // One more 50us tick
if (irparams.rawlen >= RAWBUF) {
// Buffer overflow
irparams.rcvstate = STATE_STOP;
}
switch(irparams.rcvstate) {
case STATE_IDLE: // In the middle of a gap
if (irdata == MARK) {
if (irparams.timer < GAP_TICKS) {
// Not big enough to be a gap.
irparams.timer = 0;
}
else {
// gap just ended, record duration and start recording transmission
irparams.rawlen = 0;
irparams.rawbuf[irparams.rawlen++] = irparams.timer;
irparams.timer = 0;
irparams.rcvstate = STATE_MARK;
}
}
break;
case STATE_MARK: // timing MARK
if (irdata == SPACE) { // MARK ended, record time
irparams.rawbuf[irparams.rawlen++] = irparams.timer;
irparams.timer = 0;
irparams.rcvstate = STATE_SPACE;
}
break;
case STATE_SPACE: // timing SPACE
if (irdata == MARK) { // SPACE just ended, record it
irparams.rawbuf[irparams.rawlen++] = irparams.timer;
irparams.timer = 0;
irparams.rcvstate = STATE_MARK;
}
else { // SPACE
if (irparams.timer > GAP_TICKS) {
// big SPACE, indicates gap between codes
// Mark current code as ready for processing
// Switch to STOP
// Don't reset timer; keep counting space width
irparams.rcvstate = STATE_STOP;
}
}
break;
case STATE_STOP: // waiting, measuring gap
if (irdata == MARK) { // reset gap timer
irparams.timer = 0;
}
break;
}
if (irparams.blinkflag) {
if (irdata == MARK) {
PORTB |= B00100000; // turn pin 13 LED on
}
else {
PORTB &= B11011111; // turn pin 13 LED off
}
}
}
void IRrecv::resume() {
irparams.rcvstate = STATE_IDLE;
irparams.rawlen = 0;
}
// Decodes the received IR message
// Returns 0 if no data ready, 1 if data ready.
// Results of decoding are stored in results
int IRrecv::decode(decode_results *results) {
results->rawbuf = irparams.rawbuf;
results->rawlen = irparams.rawlen;
if (irparams.rcvstate != STATE_STOP) {
return ERR;
}
#ifdef DEBUG
Serial.println("Attempting NEC decode");
#endif
if (decodeNEC(results)) {
return DECODED;
}
#ifdef DEBUG
Serial.println("Attempting Sony decode");
#endif
if (decodeSony(results)) {
return DECODED;
}
#ifdef DEBUG
Serial.println("Attempting RC5 decode");
#endif
if (decodeRC5(results)) {
return DECODED;
}
#ifdef DEBUG
Serial.println("Attempting RC6 decode");
#endif
if (decodeRC6(results)) {
return DECODED;
}
if (results->rawlen >= 6) {
// Only return raw buffer if at least 6 bits
results->decode_type = UNKNOWN;
results->bits = 0;
results->value = 0;
return DECODED;
}
// Throw away and start over
resume();
return ERR;
}
long IRrecv::decodeNEC(decode_results *results) {
long data = 0;
int offset = 1; // Skip first space
// Initial mark
if (!MATCH_MARK(results->rawbuf[offset], NEC_HDR_MARK)) {
return ERR;
}
offset++;
// Check for repeat
if (irparams.rawlen == 4 &&
MATCH_SPACE(results->rawbuf[offset], NEC_RPT_SPACE) &&
MATCH_MARK(results->rawbuf[offset+1], NEC_BIT_MARK)) {
results->bits = 0;
results->value = REPEAT;
results->decode_type = NEC;
return DECODED;
}
if (irparams.rawlen < 2 * NEC_BITS + 4) {
return ERR;
}
// Initial space
if (!MATCH_SPACE(results->rawbuf[offset], NEC_HDR_SPACE)) {
return ERR;
}
offset++;
for (int i = 0; i < NEC_BITS; i++) {
if (!MATCH_MARK(results->rawbuf[offset], NEC_BIT_MARK)) {
return ERR;
}
offset++;
if (MATCH_SPACE(results->rawbuf[offset], NEC_ONE_SPACE)) {
data = (data << 1) | 1;
}
else if (MATCH_SPACE(results->rawbuf[offset], NEC_ZERO_SPACE)) {
data <<= 1;
}
else {
return ERR;
}
offset++;
}
// Success
results->bits = NEC_BITS;
results->value = data;
results->decode_type = NEC;
return DECODED;
}
long IRrecv::decodeSony(decode_results *results) {
long data = 0;
if (irparams.rawlen < 2 * SONY_BITS + 2) {
return ERR;
}
int offset = 1; // Skip first space
// Initial mark
if (!MATCH_MARK(results->rawbuf[offset], SONY_HDR_MARK)) {
return ERR;
}
offset++;
while (offset + 1 < irparams.rawlen) {
if (!MATCH_SPACE(results->rawbuf[offset], SONY_HDR_SPACE)) {
break;
}
offset++;
if (MATCH_MARK(results->rawbuf[offset], SONY_ONE_MARK)) {
data = (data << 1) | 1;
}
else if (MATCH_MARK(results->rawbuf[offset], SONY_ZERO_MARK)) {
data <<= 1;
}
else {
return ERR;
}
offset++;
}
// Success
results->bits = (offset - 1) / 2;
if (results->bits < 12) {
results->bits = 0;
return ERR;
}
results->value = data;
results->decode_type = SONY;
return DECODED;
}
// Gets one undecoded level at a time from the raw buffer.
// The RC5/6 decoding is easier if the data is broken into time intervals.
// E.g. if the buffer has MARK for 2 time intervals and SPACE for 1,
// successive calls to getRClevel will return MARK, MARK, SPACE.
// offset and used are updated to keep track of the current position.
// t1 is the time interval for a single bit in microseconds.
// Returns -1 for error (measured time interval is not a multiple of t1).
int IRrecv::getRClevel(decode_results *results, int *offset, int *used, int t1) {
if (*offset >= results->rawlen) {
// After end of recorded buffer, assume SPACE.
return SPACE;
}
int width = results->rawbuf[*offset];
int val = ((*offset) % 2) ? MARK : SPACE;
int correction = (val == MARK) ? MARK_EXCESS : - MARK_EXCESS;
int avail;
if (MATCH(width, t1 + correction)) {
avail = 1;
}
else if (MATCH(width, 2*t1 + correction)) {
avail = 2;
}
else if (MATCH(width, 3*t1 + correction)) {
avail = 3;
}
else {
return -1;
}
(*used)++;
if (*used >= avail) {
*used = 0;
(*offset)++;
}
#ifdef DEBUG
if (val == MARK) {
Serial.println("MARK");
}
else {
Serial.println("SPACE");
}
#endif
return val;
}
long IRrecv::decodeRC5(decode_results *results) {
if (irparams.rawlen < MIN_RC5_SAMPLES + 2) {
return ERR;
}
int offset = 1; // Skip gap space
long data = 0;
int used = 0;
// Get start bits
if (getRClevel(results, &offset, &used, RC5_T1) != MARK) return ERR;
if (getRClevel(results, &offset, &used, RC5_T1) != SPACE) return ERR;
if (getRClevel(results, &offset, &used, RC5_T1) != MARK) return ERR;
int nbits;
for (nbits = 0; offset < irparams.rawlen; nbits++) {
int levelA = getRClevel(results, &offset, &used, RC5_T1);
int levelB = getRClevel(results, &offset, &used, RC5_T1);
if (levelA == SPACE && levelB == MARK) {
// 1 bit
data = (data << 1) | 1;
}
else if (levelA == MARK && levelB == SPACE) {
// zero bit
data <<= 1;
}
else {
return ERR;
}
}
// Success
results->bits = nbits;
results->value = data;
results->decode_type = RC5;
return DECODED;
}
long IRrecv::decodeRC6(decode_results *results) {
if (results->rawlen < MIN_RC6_SAMPLES) {
return ERR;
}
int offset = 1; // Skip first space
// Initial mark
if (!MATCH_MARK(results->rawbuf[offset], RC6_HDR_MARK)) {
return ERR;
}
offset++;
if (!MATCH_SPACE(results->rawbuf[offset], RC6_HDR_SPACE)) {
return ERR;
}
offset++;
long data = 0;
int used = 0;
// Get start bit (1)
if (getRClevel(results, &offset, &used, RC6_T1) != MARK) return ERR;
if (getRClevel(results, &offset, &used, RC6_T1) != SPACE) return ERR;
int nbits;
for (nbits = 0; offset < results->rawlen; nbits++) {
int levelA, levelB; // Next two levels
levelA = getRClevel(results, &offset, &used, RC6_T1);
if (nbits == 3) {
// T bit is double wide; make sure second half matches
if (levelA != getRClevel(results, &offset, &used, RC6_T1)) return ERR;
}
levelB = getRClevel(results, &offset, &used, RC6_T1);
if (nbits == 3) {
// T bit is double wide; make sure second half matches
if (levelB != getRClevel(results, &offset, &used, RC6_T1)) return ERR;
}
if (levelA == MARK && levelB == SPACE) { // reversed compared to RC5
// 1 bit
data = (data << 1) | 1;
}
else if (levelA == SPACE && levelB == MARK) {
// zero bit
data <<= 1;
}
else {
return ERR; // Error
}
}
// Success
results->bits = nbits;
results->value = data;
results->decode_type = RC6;
return DECODED;
}
/*
* IRremote
* Version 0.1 July, 2009
* Copyright 2009 Ken Shirriff
* For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.htm http://arcfn.com
*
* Interrupt code based on NECIRrcv by Joe Knapp
* http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556
* Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/
*/
#ifndef IRremote_h
#define IRremote_h
// The following are compile-time library options.
// If you change them, recompile the library.
// If DEBUG is defined, a lot of debugging output will be printed during decoding.
// TEST must be defined for the IRtest unittests to work. It will make some
// methods virtual, which will be slightly slower, which is why it is optional.
// #define DEBUG
// #define TEST
// Results returned from the decoder
class decode_results {
public:
int decode_type; // NEC, SONY, RC5, UNKNOWN
unsigned long value; // Decoded value
int bits; // Number of bits in decoded value
volatile unsigned int *rawbuf; // Raw intervals in .5 us ticks
int rawlen; // Number of records in rawbuf.
};
// Values for decode_type
#define NEC 1
#define SONY 2
#define RC5 3
#define RC6 4
#define UNKNOWN -1
// Decoded value for NEC when a repeat code is received
#define REPEAT 0xffffffff
// main class for receiving IR
class IRrecv
{
public:
IRrecv(int recvpin);
void blink13(int blinkflag);
int decode(decode_results *results);
void enableIRIn();
void resume();
private:
// These are called by decode
int getRClevel(decode_results *results, int *offset, int *used, int t1);
long decodeNEC(decode_results *results);
long decodeSony(decode_results *results);
long decodeRC5(decode_results *results);
long decodeRC6(decode_results *results);
}
;
// Only used for testing; can remove virtual for shorter code
#ifdef TEST
#define VIRTUAL virtual
#else
#define VIRTUAL
#endif
class IRsend
{
public:
IRsend() {}
void sendNEC(unsigned long data, int nbits);
void sendSony(unsigned long data, int nbits);
void sendRaw(unsigned int buf[], int len, int hz);
void sendRC5(unsigned long data, int nbits);
void sendRC6(unsigned long data, int nbits);
// private:
void enableIROut(int khz);
VIRTUAL void mark(int usec);
VIRTUAL void space(int usec);
}
;
// Some useful constants
#define USECPERTICK 50 // microseconds per clock interrupt tick
#define RAWBUF 76 // Length of raw duration buffer
// Marks tend to be 100us too long, and spaces 100us too short
// when received due to sensor lag.
#define MARK_EXCESS 100
#endif
/*
* IRremote
* Version 0.1 July, 2009
* Copyright 2009 Ken Shirriff
* For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html
*
* Interrupt code based on NECIRrcv by Joe Knapp
* http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556
* Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/
*/
#include <Arduino.h>
#ifndef IRremoteint_h
#define IRremoteint_h
#ifndef IRremote_h
#include "IRremote.h"
#endif
#define CLKFUDGE 5 // fudge factor for clock interrupt overhead
#define CLK 256 // max value for clock (timer 2)
#define PRESCALE 8 // timer2 clock prescale
#define SYSCLOCK 16000000 // main Arduino clock
#define CLKSPERUSEC (SYSCLOCK/PRESCALE/1000000) // timer clocks per microsecond
#define ERR 0
#define DECODED 1
#define BLINKLED 13
// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
// clock timer reset value
#define INIT_TIMER_COUNT2 (CLK - USECPERTICK*CLKSPERUSEC + CLKFUDGE)
#define RESET_TIMER2 TCNT2 = INIT_TIMER_COUNT2
// pulse parameters in usec
#define NEC_HDR_MARK 9000
#define NEC_HDR_SPACE 4500
#define NEC_BIT_MARK 560
#define NEC_ONE_SPACE 1600
#define NEC_ZERO_SPACE 560
#define NEC_RPT_SPACE 2250
#define SONY_HDR_MARK 2400
#define SONY_HDR_SPACE 600
#define SONY_ONE_MARK 1200
#define SONY_ZERO_MARK 600
#define SONY_RPT_LENGTH 45000
#define RC5_T1 889
#define RC5_RPT_LENGTH 46000
#define RC6_HDR_MARK 2666
#define RC6_HDR_SPACE 889
#define RC6_T1 444
#define RC6_RPT_LENGTH 46000
#define TOLERANCE 25 // percent tolerance in measurements
#define LTOL (1.0 - TOLERANCE/100.)
#define UTOL (1.0 + TOLERANCE/100.)
#define _GAP 5000 // Minimum map between transmissions
#define GAP_TICKS (_GAP/USECPERTICK)
#define TICKS_LOW(us) (int) (((us)*LTOL/USECPERTICK))
#define TICKS_HIGH(us) (int) (((us)*UTOL/USECPERTICK + 1))
#ifndef DEBUG
#define MATCH(measured_ticks, desired_us) ((measured_ticks) >= TICKS_LOW(desired_us) && (measured_ticks) <= TICKS_HIGH(desired_us))
#define MATCH_MARK(measured_ticks, desired_us) MATCH(measured_ticks, (desired_us) + MARK_EXCESS)
#define MATCH_SPACE(measured_ticks, desired_us) MATCH((measured_ticks), (desired_us) - MARK_EXCESS)
// Debugging versions are in IRremote.cpp
#endif
// receiver states
#define STATE_IDLE 2
#define STATE_MARK 3
#define STATE_SPACE 4
#define STATE_STOP 5
// information for the interrupt handler
typedef struct {
uint8_t recvpin; // pin for IR data from detector
uint8_t rcvstate; // state machine
uint8_t blinkflag; // TRUE to enable blinking of pin 13 on IR processing
unsigned int timer; // state timer, counts 50uS ticks.
unsigned int rawbuf[RAWBUF]; // raw data
uint8_t rawlen; // counter of entries in rawbuf
}
irparams_t;
// Defined in IRremote.cpp
extern volatile irparams_t irparams;
// IR detector output is active low
#define MARK 0
#define SPACE 1
#define TOPBIT 0x80000000
#define NEC_BITS 32
#define SONY_BITS 12
#define MIN_RC5_SAMPLES 11
#define MIN_RC6_SAMPLES 1
#endif
/*********************************************************************************
**
**
** LVFA_Firmware - Provides Functions For Interfacing With The Arduino Uno
**
** Written By: Sam Kristoff - National Instruments
** Written On: November 2010
** Last Updated: Dec 2011 - Kevin Fort - National Instruments
**
** This File May Be Modified And Re-Distributed Freely. Original File Content
** Written By Sam Kristoff And Available At www.ni.com/arduino.
**
*********************************************************************************/
/*********************************************************************************
** Define Constants
**
** Define directives providing meaningful names for constant values.
*********************************************************************************/
#define FIRMWARE_MAJOR 02
#define FIRMWARE_MINOR 00
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define DEFAULTBAUDRATE 9600 // Defines The Default Serial Baud Rate (This must match the baud rate specifid in LabVIEW)
#else
#define DEFAULTBAUDRATE 115200
#endif
#define MODE_DEFAULT 0 // Defines Arduino Modes (Currently Not Used)
#define COMMANDLENGTH 15 // Defines The Number Of Bytes In A Single LabVIEW Command (This must match the packet size specifid in LabVIEW)
#define STEPPER_SUPPORT 1 // Defines Whether The Stepper Library Is Included - Comment This Line To Exclude Stepper Support
// Declare Variables
unsigned char currentCommand[COMMANDLENGTH]; // The Current Command For The Arduino To Process
//Globals for continuous aquisition
unsigned char acqMode;
unsigned char contAcqPin;
float contAcqSpeed;
float acquisitionPeriod;
float iterationsFlt;
int iterations;
float delayTime;
/*********************************************************************************
** syncLV
**
** Synchronizes with LabVIEW and sends info about the board and firmware (Unimplemented)
**
** Input: None
** Output: None
*********************************************************************************/
void syncLV();
/*********************************************************************************
** setMode
**
** Sets the mode of the Arduino (Reserved For Future Use)
**
** Input: Int - Mode
** Output: None
*********************************************************************************/
void setMode(int mode);
/*********************************************************************************
** checkForCommand
**
** Checks for new commands from LabVIEW and processes them if any exists.
**
** Input: None
** Output: 1 - Command received and processed
** 0 - No new command
*********************************************************************************/
int checkForCommand(void);
/*********************************************************************************
** processCommand
**
** Processes a given command
**
** Input: command of COMMANDLENGTH bytes
** Output: 1 - Command received and processed
** 0 - No new command
*********************************************************************************/
void processCommand(unsigned char command[]);
/*********************************************************************************
** writeDigitalPort
**
** Write values to DIO pins 0 - 13. Pins must first be configured as outputs.
**
** Input: Command containing digital port data
** Output: None
*********************************************************************************/
void writeDigitalPort(unsigned char command[]);
/*********************************************************************************
** analogReadPort
**
** Reads all 6 analog input ports, builds 8 byte packet, send via RS232.
**
** Input: None
** Output: None
*********************************************************************************/
void analogReadPort();
/*********************************************************************************
** sevenSegment_Config
**
** Configure digital I/O pins to use for seven segment display. Pins are stored in sevenSegmentPins array.
**
** Input: Pins to use for seven segment LED [A, B, C, D, E, F, G, DP]
** Output: None
*********************************************************************************/
void sevenSegment_Config(unsigned char command[]);
/*********************************************************************************
** sevenSegment_Write
**
** Write values to sevenSegment display. Must first use sevenSegment_Configure
**
** Input: Eight values to write to seven segment display
** Output: None
*********************************************************************************/
void sevenSegment_Write(unsigned char command[]);
/*********************************************************************************
** spi_setClockDivider
**
** Set the SPI Clock Divisor
**
** Input: SPI Clock Divider 2, 4, 8, 16, 32, 64, 128
** Output: None
*********************************************************************************/
void spi_setClockDivider(unsigned char divider);
/*********************************************************************************
** spi_sendReceive
**
** Sens / Receive SPI Data
**
** Input: Command Packet
** Output: None (This command sends one serail byte back to LV for each data byte.
*********************************************************************************/
void spi_sendReceive(unsigned char command[]);
/*********************************************************************************
** checksum_Compute
**
** Compute Packet Checksum
**
** Input: Command Packet
** Output: Char Checksum Value
*********************************************************************************/
unsigned char checksum_Compute(unsigned char command[]);
/*********************************************************************************
** checksum_Test
**
** Compute Packet Checksum And Test Against Included Checksum
**
** Input: Command Packet
** Output: 0 If Checksums Are Equal, Else 1
*********************************************************************************/
int checksum_Test(unsigned char command[]);
/*********************************************************************************
** AccelStepper_Write
**
** Parse command packet and write speed, direction, and number of steps to travel
**
** Input: Command Packet
** Output: None
*********************************************************************************/
void AccelStepper_Write(unsigned char command[]);
/*********************************************************************************
** SampleContinuosly
**
** Returns several analog input points at once.
**
** Input: void
** Output: void
*********************************************************************************/
void sampleContinously(void);
/*********************************************************************************
** finiteAcquisition
**
** Returns the number of samples specified at the rate specified.
**
** Input: pin to sampe on, speed to sample at, number of samples
** Output: void
*********************************************************************************/
void finiteAcquisition(int analogPin, float acquisitionSpeed, int numberOfSamples );
/*********************************************************************************
** lcd_print
**
** Prints Data to the LCD With The Given Base
**
** Input: Command Packet
** Output: None
*********************************************************************************/
void lcd_print(unsigned char command[]);
/*********************************************************************************
**
** LVIFA_Firmware - Provides Functions For Interfacing With The Arduino Uno
**
** Written By: Sam Kristoff - National Instruments
** Written On: November 2010
** Last Updated: Dec 2011 - Kevin Fort - National Instruments
**
** This File May Be Modified And Re-Distributed Freely. Original File Content
** Written By Sam Kristoff And Available At www.ni.com/arduino.
**
*********************************************************************************/
#include <Wire.h>
#include <SPI.h>
#include <LiquidCrystal.h>
//Includes for IR Remote
#ifndef IRremoteInt_h
#include "IRremoteInt.h"
#endif
#ifndef IRremote_h
#include "IRremote.h"
#endif
/*********************************************************************************
** Optionally Include And Configure Stepper Support
*********************************************************************************/
#ifdef STEPPER_SUPPORT
// Stepper Modifications
#include "AFMotor.h"
#include "AccelStepper.h"
// Adafruit shield
AF_Stepper motor1(200, 1);
AF_Stepper motor2(200, 2);
// you can change these to DOUBLE or INTERLEAVE or MICROSTEP
// wrappers for the first motor
void forwardstep1() {
motor1.onestep(FORWARD, SINGLE);
}
void backwardstep1() {
motor1.onestep(BACKWARD, SINGLE);
}
// wrappers for the second motor
void forwardstep2() {
motor2.onestep(FORWARD, SINGLE);
}
void backwardstep2() {
motor2.onestep(BACKWARD, SINGLE);
}
AccelStepper steppers[8]; //Create array of 8 stepper objects
#endif
// Variables
unsigned int retVal;
int sevenSegmentPins[8];
int currentMode;
unsigned int freq;
unsigned long duration;
int i2cReadTimeouts = 0;
char spiBytesToSend = 0;
char spiBytesSent = 0;
char spiCSPin = 0;
char spiWordSize = 0;
Servo *servos;
byte customChar[8];
LiquidCrystal lcd(0,0,0,0,0,0,0);
unsigned long IRdata;
IRsend irsend;
// Sets the mode of the Arduino (Reserved For Future Use)
void setMode(int mode)
{
currentMode = mode;
}
// Checks for new commands from LabVIEW and processes them if any exists.
int checkForCommand(void)
{
#ifdef STEPPER_SUPPORT
// Call run function as fast as possible to keep motors turning
for (int i=0; i<8; i++){
steppers.run();
}
#endif
int bufferBytes = Serial.available();
if(bufferBytes >= COMMANDLENGTH)
{
// New Command Ready, Process It
// Build Command From Serial Buffer
for(int i=0; i<COMMANDLENGTH; i++)
{
currentCommand = Serial.read();
}
processCommand(currentCommand);
return 1;
}
else
{
return 0;
}
}
// Processes a given command
void processCommand(unsigned char command[])
{
// Determine Command
if(command[0] == 0xFF && checksum_Test(command) == 0)
{
switch(command[1])
{
/*********************************************************************************
** LIFA Maintenance Commands
*********************************************************************************/
case 0x00: // Sync Packet
Serial.print("sync");
Serial.flush();
break;
case 0x01: // Flush Serial Buffer
Serial.flush();
break;
/*********************************************************************************
** Low Level - Digital I/O Commands
*********************************************************************************/
case 0x02: // Set Pin As Input Or Output
pinMode(command[2], command[3]);
Serial.write('0');
break;
case 0x03: // Write Digital Pin
digitalWrite(command[2], command[3]);
Serial.write('0');
break;
case 0x04: // Write Digital Port 0
writeDigitalPort(command);
Serial.write('0');
break;
case 0x05: //Tone
freq = ( (command[3]<<8) + command[4]);
duration=(command[8]+ (command[7]<<8)+ (command[6]<<16)+(command[5]<<24));
if(freq > 0)
{
tone(command[2], freq, duration);
}
else
{
noTone(command[2]);
}
Serial.write('0');
break;
case 0x06: // Read Digital Pin
retVal = digitalRead(command[2]);
Serial.write(retVal);
break;
case 0x07: // Digital Read Port
retVal = 0x0000;
for(int i=0; i <=13; i++)
{
if(digitalRead(i))
{
retVal += (1<<i);
}
}
Serial.write( (retVal & 0xFF));
Serial.write( (retVal >> 8));
break;
/*********************************************************************************
** Low Level - Analog Commands
*********************************************************************************/
case 0x08: // Read Analog Pin
retVal = analogRead(command[2]);
Serial.write( (retVal >> 8));
Serial.write( (retVal & 0xFF));
break;
case 0x09: // Analog Read Port
analogReadPort();
break;
/*********************************************************************************
** Low Level - PWM Commands
*********************************************************************************/
case 0x0A: // PWM Write Pin
analogWrite(command[2], command[3]);
Serial.write('0');
break;
case 0x0B: // PWM Write 3 Pins
analogWrite(command[2], command[5]);
analogWrite(command[3], command[6]);
analogWrite(command[4], command[7]);
Serial.write('0');
break;
/*********************************************************************************
** Sensor Specific Commands
*********************************************************************************/
case 0x0C: // Configure Seven Segment Display
sevenSegment_Config(command);
Serial.write('0');
break;
case 0x0D: // Write To Seven Segment Display
sevenSegment_Write(command);
Serial.write('0');
break;
/*********************************************************************************
** I2C
*********************************************************************************/
case 0x0E: // Initialize I2C
Wire.begin();
Serial.write('0');
break;
case 0x0F: // Send I2C Data
Wire.beginTransmission(command[3]);
for(int i=0; i<command[2]; i++)
{
#if defined(ARDUINO) && ARDUINO >= 100
Wire.write(command[i+4]);
#else
Wire.send(command[i+4]);
#endif
}
Wire.endTransmission();
Serial.write('0');
break;
case 0x10: // I2C Read
i2cReadTimeouts = 0;
Wire.requestFrom(command[3], command[2]);
while(Wire.available() < command[2])
{
i2cReadTimeouts++;
if(i2cReadTimeouts > 100)
{
return;
}
else
{
delay(1);
}
}
for(int i=0; i<command[2]; i++)
{
#if defined(ARDUINO) && ARDUINO >= 100
Serial.write(Wire.read());
#else
Serial.write(Wire.receive());
#endif
}
break;
/*********************************************************************************
** SPI
*********************************************************************************/
case 0x11: // SPI Init
SPI.begin();
Serial.write('0');
break;
case 0x12: // SPI Set Bit Order (MSB LSB)
if(command[2] == 0)
{
SPI.setBitOrder(LSBFIRST);
}
else
{
SPI.setBitOrder(MSBFIRST);
}
Serial.write('0');
break;
case 0x13: // SPI Set Clock Divider
spi_setClockDivider(command[2]);
Serial.write('0');
break;
case 0x14: // SPI Set Data Mode
switch(command[2])
{
case 0:
SPI.setDataMode(SPI_MODE0);
break;
case 1:
SPI.setDataMode(SPI_MODE1);
break;
case 2:
SPI.setDataMode(SPI_MODE2);
break;
case 3:
SPI.setDataMode(SPI_MODE3);
break;
default:
break;
}
Serial.write('0');
break;
case 0x15: // SPI Send / Receive
spi_sendReceive(command);
break;
case 0x16: // SPI Close
SPI.end();
Serial.write('0');
break;
/*********************************************************************************
** Servos
*********************************************************************************/
case 0x17: // Set Num Servos
free(servos);
servos = (Servo*) malloc(command[2]*sizeof(Servo));
for(int i=0; i<command[2]; i++)
{
servos = Servo();
}
if(servos == 0)
{
Serial.write('1');
}
else
{
Serial.write('0');
}
break;
case 0x18: // Configure Servo
servos[command[2]].attach(command[3]);
Serial.write('0');
break;
case 0x19: // Servo Write
servos[command[2]].write(command[3]);
Serial.write('0');
break;
case 0x1A: // Servo Read Angle
Serial.write(servos[command[2]].read());
break;
case 0x1B: // Servo Write uS Pulse
servos[command[2]].writeMicroseconds( (command[3] + (command[4]<<8)) );
Serial.write('0');
break;
case 0x1C: // Servo Read uS Pulse
retVal = servos[command[2]].readMicroseconds();
Serial.write ((retVal & 0xFF));
Serial.write( (retVal >> 8));
break;
case 0x1D: // Servo Detach
servos[command[2]].detach();
Serial.write('0');
break;
/*********************************************************************************
** LCD
*********************************************************************************/
case 0x1E: // LCD Init
lcd.init(command[2], command[3], command[4], command[5], command[6], command[7], command[8], command[9], command[10], command[11], command[12], command[13]);
Serial.write('0');
break;
case 0x1F: // LCD Set Size
lcd.begin(command[2], command[3]);
Serial.write('0');
break;
case 0x20: // LCD Set Cursor Mode
if(command[2] == 0)
{
lcd.noCursor();
}
else
{
lcd.cursor();
}
if(command[3] == 0)
{
lcd.noBlink();
}
else
{
lcd.blink();
}
Serial.write('0');
break;
case 0x21: // LCD Clear
lcd.clear();
Serial.write('0');
break;
case 0x22: // LCD Set Cursor Position
lcd.setCursor(command[2], command[3]);
Serial.write('0');
break;
case 0x23: // LCD Print
lcd_print(command);
break;
case 0x24: // LCD Display Power
if(command[2] == 0)
{
lcd.noDisplay();
}
else
{
lcd.display();
}
Serial.write('0');
break;
case 0x25: // LCD Scroll
if(command[2] == 0)
{
lcd.scrollDisplayLeft();
}
else
{
lcd.scrollDisplayRight();
}
Serial.write('0');
break;
case 0x26: // LCD Autoscroll
if(command[2] == 0)
{
lcd.noAutoscroll();
}
else
{
lcd.autoscroll();
}
Serial.write('0');
break;
case 0x27: // LCD Print Direction
if(command[2] == 0)
{
lcd.rightToLeft();
}
else
{
lcd.leftToRight();
}
Serial.write('0');
break;
case 0x28: // LCD Create Custom Char
for(int i=0; i<8; i++)
{
customChar = command[i+3];
}
lcd.createChar(command[2], customChar);
Serial.write('0');
break;
case 0x29: // LCD Print Custom Char
lcd.write(command[2]);
Serial.write('0');
break;
/*********************************************************************************
** Continuous Aquisition
*********************************************************************************/
case 0x2A: // Continuous Aquisition Mode On
acqMode=1;
contAcqPin=command[2];
contAcqSpeed=(command[3])+(command[4]<<8);
acquisitionPeriod=1/contAcqSpeed;
iterationsFlt =.08/acquisitionPeriod;
iterations=(int)iterationsFlt;
if(iterations<1)
{
iterations=1;
}
delayTime= acquisitionPeriod;
if(delayTime<0)
{
delayTime=0;
}
break;
case 0x2B: // Continuous Aquisition Mode Off
acqMode=0;
break;
case 0x2C: // Return Firmware Revision
Serial.write(byte(FIRMWARE_MAJOR));
Serial.write(byte(FIRMWARE_MINOR));
break;
case 0x2D: // Perform Finite Aquisition
Serial.write('0');
finiteAcquisition(command[2],(command[3])+(command[4]<<8),command[5]+(command[6]<<8));
break;
/*********************************************************************************
** Stepper
*********************************************************************************/
#ifdef STEPPER_SUPPORT
case 0x30: // Configure Stepper
if (command[2] == 5){ // Support AFMotor Shield
switch (command[3]){
case 0:
steppers[command[3]] = AccelStepper(forwardstep1, backwardstep1);
break;
case 1:
steppers[command[3]] = AccelStepper(forwardstep2, backwardstep2);
break;
default:
break;
}
}
else if(command[2]==6) { // All other stepper configurations
steppers[command[3]] = AccelStepper(1, command[4],command[5],command[6],command[7]);
}
else{
steppers[command[3]] = AccelStepper(command[2], command[4],command[5],command[6],command[7]);
}
Serial.write('0');
break;
case 0x31: // Stepper Write
AccelStepper_Write(command);
Serial.write('0');
break;
case 0x32: // Stepper Detach
steppers[command[2]].disableOutputs();
Serial.write('0');
break;
case 0x33: // Stepper steps to go
retVal = 0;
for(int i=0; i<8; i++){
retVal += steppers.distanceToGo();
}
Serial.write( (retVal & 0xFF) );
Serial.write( (retVal >> 😎 );
break;
#endif
/*********************************************************************************
** IR Transmit
*********************************************************************************/
case 0x34: // IR Transmit
IRdata = ((unsigned long)command [4] << 24) | ((unsigned long)command [5] << 16) | ((unsigned long)command [6] << 😎 | ((unsigned long)command [7]);
switch(command[2])
{
case 0x00: // NEC
irsend.sendNEC(IRdata, command[3]);
break;
case 0x01: //Sony
irsend.sendSony(IRdata, command[3]);
break;
case 0x02: //RC5
irsend.sendRC5(IRdata, command[3]);
break;
case 0x03: //RC6
irsend.sendRC6(IRdata, command[3]);
break;
}
Serial.write((IRdata>>16) & 0xFF);
break;
/*********************************************************************************
** Unknown Packet
*********************************************************************************/
default: // Default Case
Serial.flush();
break;
}
}
else{
// Checksum Failed, Flush Serial Buffer
Serial.flush();
}
}
/*********************************************************************************
** Functions
*********************************************************************************/
// Writes Values To Digital Port (DIO 0-13). Pins Must Be Configured As Outputs Before Being Written To
void writeDigitalPort(unsigned char command[])
{
digitalWrite(13, (( command[2] >> 5) & 0x01) );
digitalWrite(12, (( command[2] >> 4) & 0x01) );
digitalWrite(11, (( command[2] >> 3) & 0x01) );
digitalWrite(10, (( command[2] >> 2) & 0x01) );
digitalWrite(9, (( command[2] >> 1) & 0x01) );
digitalWrite(8, (command[2] & 0x01) );
digitalWrite(7, (( command[3] >> 7) & 0x01) );
digitalWrite(6, (( command[3] >> 6) & 0x01) );
digitalWrite(5, (( command[3] >> 5) & 0x01) );
digitalWrite(4, (( command[3] >> 4) & 0x01) );
digitalWrite(3, (( command[3] >> 3) & 0x01) );
digitalWrite(2, (( command[3] >> 2) & 0x01) );
digitalWrite(1, (( command[3] >> 1) & 0x01) );
digitalWrite(0, (command[3] & 0x01) );
}
// Reads all 6 analog input ports, builds 8 byte packet, send via RS232.
void analogReadPort()
{
// Read Each Analog Pin
int pin0 = analogRead(0);
int pin1 = analogRead(1);
int pin2 = analogRead(2);
int pin3 = analogRead(3);
int pin4 = analogRead(4);
int pin5 = analogRead(5);
//Build 8-Byte Packet From 60 Bits of Data Read
char output0 = (pin0 & 0xFF);
char output1 = ( ((pin1 << 2) & 0xFC) | ( (pin0 >> 😎 & 0x03) );
char output2 = ( ((pin2 << 4) & 0xF0) | ( (pin1 >> 6) & 0x0F) );
char output3 = ( ((pin3 << 6) & 0xC0) | ( (pin2 >> 4) & 0x3F) );
char output4 = ( (pin3 >> 2) & 0xFF);
char output5 = (pin4 & 0xFF);
char output6 = ( ((pin5 << 2) & 0xFC) | ( (pin4 >> 😎 & 0x03) );
char output7 = ( (pin5 >> 6) & 0x0F );
// Write Bytes To Serial Port
Serial.print(output0);
Serial.print(output1);
Serial.print(output2);
Serial.print(output3);
Serial.print(output4);
Serial.print(output5);
Serial.print(output6);
Serial.print(output7);
}
// Configure digital I/O pins to use for seven segment display
void sevenSegment_Config(unsigned char command[])
{
// Configure pins as outputs and store in sevenSegmentPins array for use in sevenSegment_Write
for(int i=2; i<10; i++)
{
pinMode(command, OUTPUT);
sevenSegmentPins[(i-1)] = command;
}
}
// Write values to sevenSegment display. Must first use sevenSegment_Configure
void sevenSegment_Write(unsigned char command[])
{
for(int i=1; i<9; i++)
{
digitalWrite(sevenSegmentPins[(i-1)], command);
}
}
// Set the SPI Clock Divisor
void spi_setClockDivider(unsigned char divider)
{
switch(divider)
{
case 0:
SPI.setClockDivider(SPI_CLOCK_DIV2);
break;
case 1:
SPI.setClockDivider(SPI_CLOCK_DIV4);
break;
case 2:
SPI.setClockDivider(SPI_CLOCK_DIV8);
break;
case 3:
SPI.setClockDivider(SPI_CLOCK_DIV16);
break;
case 4:
SPI.setClockDivider(SPI_CLOCK_DIV32);
break;
case 5:
SPI.setClockDivider(SPI_CLOCK_DIV64);
break;
case 6:
SPI.setClockDivider(SPI_CLOCK_DIV128);
break;
default:
SPI.setClockDivider(SPI_CLOCK_DIV4);
break;
}
}
void spi_sendReceive(unsigned char command[])
{
if(command[2] == 1) //Check to see if this is the first of a series of SPI packets
{
spiBytesSent = 0;
spiCSPin = command[3];
spiWordSize = command[4];
// Send First Packet's 8 Data Bytes
for(int i=0; i<command[5]; i++)
{
// If this is the start of a new word toggle CS LOW
if( (spiBytesSent == 0) || (spiBytesSent % spiWordSize == 0) )
{
digitalWrite(spiCSPin, LOW);
}
// Send SPI Byte
Serial.print(SPI.transfer(command[i+6]));
spiBytesSent++;
// If word is complete set CS High
if(spiBytesSent % spiWordSize == 0)
{
digitalWrite(spiCSPin, HIGH);
}
}
}
else
{
// SPI Data Packet - Send SPI Bytes
for(int i=0; i<command[3]; i++)
{
// If this is the start of a new word toggle CS LOW
if( (spiBytesSent == 0) || (spiBytesSent % spiWordSize == 0) )
{
digitalWrite(spiCSPin, LOW);
}
// Send SPI Byte
Serial.write(SPI.transfer(command[i+4]));
spiBytesSent++;
// If word is complete set CS High
if(spiBytesSent % spiWordSize == 0)
{
digitalWrite(spiCSPin, HIGH);
}
}
}
}
// Synchronizes with LabVIEW and sends info about the board and firmware (Unimplemented)
void syncLV()
{
Serial.begin(DEFAULTBAUDRATE);
i2cReadTimeouts = 0;
spiBytesSent = 0;
spiBytesToSend = 0;
Serial.flush();
}
// Compute Packet Checksum
unsigned char checksum_Compute(unsigned char command[])
{
unsigned char checksum;
for (int i=0; i<(COMMANDLENGTH-1); i++)
{
checksum += command;
}
return checksum;
}
// Compute Packet Checksum And Test Against Included Checksum
int checksum_Test(unsigned char command[])
{
unsigned char checksum = checksum_Compute(command);
if(checksum == command[COMMANDLENGTH-1])
{
return 0;
}
else
{
return 1;
}
}
// Stepper Functions
#ifdef STEPPER_SUPPORT
void AccelStepper_Write(unsigned char command[]){
int steps = 0;
int step_speed = 0;
int acceleration = 0;
//Number of steps & speed are a 16 bit values, split for data transfer. Reassemble 2 bytes to an int 16
steps = (int)(command[5] << 😎 + command[6];
step_speed = (int)(command[2] << 😎 + command[3];
acceleration = (int)(command[7] << 😎 + command[8];
steppers[command[4]].setMaxSpeed(step_speed);
if (acceleration == 0){
//Workaround AccelStepper bug that requires negative speed for negative step direction
if (steps < 0) step_speed = -step_speed;
steppers[command[4]].setSpeed(step_speed);
steppers[command[4]].move(steps);
}
else {
steppers[command[4]].setAcceleration(acceleration);
steppers[command[4]].move(steps);
}
}
#endif
void sampleContinously()
{
for(int i=0; i<iterations; i++)
{
retVal = analogRead(contAcqPin);
if(contAcqSpeed>1000) //delay Microseconds is only accurate for values less that 16383
{
Serial.write( (retVal >> 2));
delayMicroseconds(delayTime*1000000); //Delay for neccesary amount of time to achieve desired sample rate
}
else
{
Serial.write( (retVal & 0xFF) );
Serial.write( (retVal >> 8));
delay(delayTime*1000);
}
}
}
void finiteAcquisition(int analogPin, float acquisitionSpeed, int numberOfSamples)
{
//want to exit this loop every 8ms
acquisitionPeriod=1/acquisitionSpeed;
for(int i=0; i<numberOfSamples; i++)
{
retVal = analogRead(analogPin);
if(acquisitionSpeed>1000)
{
Serial.write( (retVal >> 2));
delayMicroseconds(acquisitionPeriod*1000000);
}
else
{
Serial.write( (retVal & 0xFF) );
Serial.write( (retVal >> 8));
delay(acquisitionPeriod*1000);
}
}
}
void lcd_print(unsigned char command[])
{
if(command[2] != 0)
{
// Base Specified By User
int base = 0;
switch(command[2])
{
case 0x01: // BIN
base = BIN;
break;
case 0x02: // DEC
base = DEC;
break;
case 0x03: // OCT
base = OCT;
break;
case 0x04: // HEX
base = HEX;
break;
default:
break;
}
for(int i=0; i<command[3]; i++)
{
lcd.print(command[i+4], base);
}
}
else
{
for(int i=0; i<command[3]; i++)
{
lcd.print((char)command[i+4]);
}
}
Serial.write('0');
}
May I know that is there any problem regarding the source code since I have no idea how to modified the code is default? Thanks for your time to help me to resolve the problem.
Regards,
Wilson Leong
03-25-2013 04:13 PM
Thanks for your time to reply back my answer. Actually I use the VIPM software to download LabVIEW Interface for Arduino and I have no idea how to modify the firmware as I downloaded from VIPM software. I open the LIFA_Base.ino file using the Arduino IDE software, the entire file are open together. I just upload the LIFA_Base.ino file to my arduino. When I upload the LIFA_Base.ino file to my Arduino, the error is displayed. The further error message is displayed as I mentioned before.
The source code I downloaded from VIPM software will upload
/*********************************************************************************
**
** LVFA_Firmware - Provides Basic Arduino Sketch For Interfacing With LabVIEW.
**
** Written By: Sam Kristoff - National Instruments
** Written On: November 2010
** Last Updated: Dec 2011 - Kevin Fort - National Instruments
**
** This File May Be Modified And Re-Distributed Freely. Original File Content
** Written By Sam Kristoff And Available At www.ni.com/arduino.
**
*********************************************************************************/
/*********************************************************************************
**
** Includes.
**
********************************************************************************/
// Standard includes. These should always be included.
#include <Wire.h>
#include <SPI.h>
#include <Servo.h>
#include "LabVIEWInterface.h"
/*********************************************************************************
** setup()
**
** Initialize the Arduino and setup serial communication.
**
** Input: None
** Output: None
*********************************************************************************/
void setup()
{
// Initialize Serial Port With The Default Baud Rate
syncLV();
// Place your custom setup code here
}
/*********************************************************************************
** loop()
**
** The main loop. This loop runs continuously on the Arduino. It
** receives and processes serial commands from LabVIEW.
**
** Input: None
** Output: None
*********************************************************************************/
void loop()
{
// Check for commands from LabVIEW and process them.
checkForCommand();
// Place your custom loop code here (this may slow down communication with LabVIEW)
if(acqMode==1)
{
sampleContinously();
}
}
// Adafruit Motor shield library
// copyright Adafruit Industries LLC, 2009
// this code is public domain, enjoy!
#include <avr/io.h>
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include "AFMotor.h"
static uint8_t latch_state;
#if (MICROSTEPS == 😎
uint8_t microstepcurve[] = {0, 50, 98, 142, 180, 212, 236, 250, 255};
#elif (MICROSTEPS == 16)
uint8_t microstepcurve[] = {0, 25, 50, 74, 98, 120, 141, 162, 180, 197, 212, 225, 236, 244, 250, 253, 255};
#endif
AFMotorController::AFMotorController(void) {
}
void AFMotorController::enable(void) {
// setup the latch
/*
LATCH_DDR |= _BV(LATCH);
ENABLE_DDR |= _BV(ENABLE);
CLK_DDR |= _BV(CLK);
SER_DDR |= _BV(SER);
*/
pinMode(MOTORLATCH, OUTPUT);
pinMode(MOTORENABLE, OUTPUT);
pinMode(MOTORDATA, OUTPUT);
pinMode(MOTORCLK, OUTPUT);
latch_state = 0;
latch_tx(); // "reset"
//ENABLE_PORT &= ~_BV(ENABLE); // enable the chip outputs!
digitalWrite(MOTORENABLE, LOW);
}
void AFMotorController::latch_tx(void) {
uint8_t i;
//LATCH_PORT &= ~_BV(LATCH);
digitalWrite(MOTORLATCH, LOW);
//SER_PORT &= ~_BV(SER);
digitalWrite(MOTORDATA, LOW);
for (i=0; i<8; i++) {
//CLK_PORT &= ~_BV(CLK);
digitalWrite(MOTORCLK, LOW);
if (latch_state & _BV(7-i)) {
//SER_PORT |= _BV(SER);
digitalWrite(MOTORDATA, HIGH);
} else {
//SER_PORT &= ~_BV(SER);
digitalWrite(MOTORDATA, LOW);
}
//CLK_PORT |= _BV(CLK);
digitalWrite(MOTORCLK, HIGH);
}
//LATCH_PORT |= _BV(LATCH);
digitalWrite(MOTORLATCH, HIGH);
}
static AFMotorController MC;
/******************************************
MOTORS
******************************************/
inline void initPWM1(uint8_t freq) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer2A on PB3 (Arduino pin #11)
TCCR2A |= _BV(COM2A1) | _BV(WGM20) | _BV(WGM21); // fast PWM, turn on oc2a
TCCR2B = freq & 0x7;
OCR2A = 0;
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// on arduino mega, pin 11 is now PB5 (OC1A)
TCCR1A |= _BV(COM1A1) | _BV(WGM10); // fast PWM, turn on oc1a
TCCR1B = (freq & 0x7) | _BV(WGM12);
OCR1A = 0;
#else
#error "This chip is not supported!"
#endif
pinMode(11, OUTPUT);
}
inline void setPWM1(uint8_t s) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer2A on PB3 (Arduino pin #11)
OCR2A = s;
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// on arduino mega, pin 11 is now PB5 (OC1A)
OCR1A = s;
#else
#error "This chip is not supported!"
#endif
}
inline void initPWM2(uint8_t freq) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer2B (pin 3)
TCCR2A |= _BV(COM2B1) | _BV(WGM20) | _BV(WGM21); // fast PWM, turn on oc2b
TCCR2B = freq & 0x7;
OCR2B = 0;
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// on arduino mega, pin 3 is now PE5 (OC3C)
TCCR3A |= _BV(COM1C1) | _BV(WGM10); // fast PWM, turn on oc3c
TCCR3B = (freq & 0x7) | _BV(WGM12);
OCR3C = 0;
#else
#error "This chip is not supported!"
#endif
pinMode(3, OUTPUT);
}
inline void setPWM2(uint8_t s) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer2A on PB3 (Arduino pin #11)
OCR2B = s;
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// on arduino mega, pin 11 is now PB5 (OC1A)
OCR3C = s;
#else
#error "This chip is not supported!"
#endif
}
inline void initPWM3(uint8_t freq) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer0A / PD6 (pin 6)
TCCR0A |= _BV(COM0A1) | _BV(WGM00) | _BV(WGM01); // fast PWM, turn on OC0A
//TCCR0B = freq & 0x7;
OCR0A = 0;
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// on arduino mega, pin 6 is now PH3 (OC4A)
TCCR4A |= _BV(COM1A1) | _BV(WGM10); // fast PWM, turn on oc4a
TCCR4B = (freq & 0x7) | _BV(WGM12);
//TCCR4B = 1 | _BV(WGM12);
OCR4A = 0;
#else
#error "This chip is not supported!"
#endif
pinMode(6, OUTPUT);
}
inline void setPWM3(uint8_t s) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer0A on PB3 (Arduino pin #6)
OCR0A = s;
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// on arduino mega, pin 6 is now PH3 (OC4A)
OCR4A = s;
#else
#error "This chip is not supported!"
#endif
}
inline void initPWM4(uint8_t freq) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer0B / PD5 (pin 5)
TCCR0A |= _BV(COM0B1) | _BV(WGM00) | _BV(WGM01); // fast PWM, turn on oc0a
//TCCR0B = freq & 0x7;
OCR0B = 0;
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// on arduino mega, pin 5 is now PE3 (OC3A)
TCCR3A |= _BV(COM1A1) | _BV(WGM10); // fast PWM, turn on oc3a
TCCR3B = (freq & 0x7) | _BV(WGM12);
//TCCR4B = 1 | _BV(WGM12);
OCR3A = 0;
#else
#error "This chip is not supported!"
#endif
pinMode(5, OUTPUT);
}
inline void setPWM4(uint8_t s) {
#if defined(__AVR_ATmega8__) || \
defined(__AVR_ATmega48__) || \
defined(__AVR_ATmega88__) || \
defined(__AVR_ATmega168__) || \
defined(__AVR_ATmega328P__)
// use PWM from timer0A on PB3 (Arduino pin #6)
OCR0B = s;
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
// on arduino mega, pin 6 is now PH3 (OC4A)
OCR3A = s;
#else
#error "This chip is not supported!"
#endif
}
AF_DCMotor::AF_DCMotor(uint8_t num, uint8_t freq) {
motornum = num;
pwmfreq = freq;
MC.enable();
switch (num) {
case 1:
latch_state &= ~_BV(MOTOR1_A) & ~_BV(MOTOR1_B); // set both motor pins to 0
MC.latch_tx();
initPWM1(freq);
break;
case 2:
latch_state &= ~_BV(MOTOR2_A) & ~_BV(MOTOR2_B); // set both motor pins to 0
MC.latch_tx();
initPWM2(freq);
break;
case 3:
latch_state &= ~_BV(MOTOR3_A) & ~_BV(MOTOR3_B); // set both motor pins to 0
MC.latch_tx();
initPWM3(freq);
break;
case 4:
latch_state &= ~_BV(MOTOR4_A) & ~_BV(MOTOR4_B); // set both motor pins to 0
MC.latch_tx();
initPWM4(freq);
break;
}
}
void AF_DCMotor::run(uint8_t cmd) {
uint8_t a, b;
switch (motornum) {
case 1:
a = MOTOR1_A; b = MOTOR1_B; break;
case 2:
a = MOTOR2_A; b = MOTOR2_B; break;
case 3:
a = MOTOR3_A; b = MOTOR3_B; break;
case 4:
a = MOTOR4_A; b = MOTOR4_B; break;
default:
return;
}
switch (cmd) {
case FORWARD:
latch_state |= _BV(a);
latch_state &= ~_BV(b);
MC.latch_tx();
break;
case BACKWARD:
latch_state &= ~_BV(a);
latch_state |= _BV(b);
MC.latch_tx();
break;
case RELEASE:
latch_state &= ~_BV(a);
latch_state &= ~_BV(b);
MC.latch_tx();
break;
}
}
void AF_DCMotor::setSpeed(uint8_t speed) {
switch (motornum) {
case 1:
setPWM1(speed); break;
case 2:
setPWM2(speed); break;
case 3:
setPWM3(speed); break;
case 4:
setPWM4(speed); break;
}
}
/******************************************
STEPPERS
******************************************/
AF_Stepper::AF_Stepper(uint16_t steps, uint8_t num) {
MC.enable();
revsteps = steps;
steppernum = num;
currentstep = 0;
if (steppernum == 1) {
latch_state &= ~_BV(MOTOR1_A) & ~_BV(MOTOR1_B) &
~_BV(MOTOR2_A) & ~_BV(MOTOR2_B); // all motor pins to 0
MC.latch_tx();
// enable both H bridges
pinMode(11, OUTPUT);
pinMode(3, OUTPUT);
digitalWrite(11, HIGH);
digitalWrite(3, HIGH);
// use PWM for microstepping support
initPWM1(MOTOR12_64KHZ);
initPWM2(MOTOR12_64KHZ);
setPWM1(255);
setPWM2(255);
} else if (steppernum == 2) {
latch_state &= ~_BV(MOTOR3_A) & ~_BV(MOTOR3_B) &
~_BV(MOTOR4_A) & ~_BV(MOTOR4_B); // all motor pins to 0
MC.latch_tx();
// enable both H bridges
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
digitalWrite(5, HIGH);
digitalWrite(6, HIGH);
// use PWM for microstepping support
// use PWM for microstepping support
initPWM3(1);
initPWM4(1);
setPWM3(255);
setPWM4(255);
}
}
void AF_Stepper::setSpeed(uint16_t rpm) {
usperstep = 60000000 / ((uint32_t)revsteps * (uint32_t)rpm);
steppingcounter = 0;
}
void AF_Stepper::release(void) {
if (steppernum == 1) {
latch_state &= ~_BV(MOTOR1_A) & ~_BV(MOTOR1_B) &
~_BV(MOTOR2_A) & ~_BV(MOTOR2_B); // all motor pins to 0
MC.latch_tx();
} else if (steppernum == 2) {
latch_state &= ~_BV(MOTOR3_A) & ~_BV(MOTOR3_B) &
~_BV(MOTOR4_A) & ~_BV(MOTOR4_B); // all motor pins to 0
MC.latch_tx();
}
}
void AF_Stepper::step(uint16_t steps, uint8_t dir, uint8_t style) {
uint32_t uspers = usperstep;
uint8_t ret = 0;
if (style == INTERLEAVE) {
uspers /= 2;
}
else if (style == MICROSTEP) {
uspers /= MICROSTEPS;
steps *= MICROSTEPS;
#ifdef MOTORDEBUG
Serial.print("steps = "); Serial.println(steps, DEC);
#endif
}
while (steps--) {
ret = onestep(dir, style);
delay(uspers/1000); // in ms
steppingcounter += (uspers % 1000);
if (steppingcounter >= 1000) {
delay(1);
steppingcounter -= 1000;
}
}
if (style == MICROSTEP) {
while ((ret != 0) && (ret != MICROSTEPS)) {
ret = onestep(dir, style);
delay(uspers/1000); // in ms
steppingcounter += (uspers % 1000);
if (steppingcounter >= 1000) {
delay(1);
steppingcounter -= 1000;
}
}
}
}
uint8_t AF_Stepper::onestep(uint8_t dir, uint8_t style) {
uint8_t a, b, c, d;
uint8_t ocrb, ocra;
ocra = ocrb = 255;
if (steppernum == 1) {
a = _BV(MOTOR1_A);
b = _BV(MOTOR2_A);
c = _BV(MOTOR1_B);
d = _BV(MOTOR2_B);
} else if (steppernum == 2) {
a = _BV(MOTOR3_A);
b = _BV(MOTOR4_A);
c = _BV(MOTOR3_B);
d = _BV(MOTOR4_B);
} else {
return 0;
}
// next determine what sort of stepping procedure we're up to
if (style == SINGLE) {
if ((currentstep/(MICROSTEPS/2)) % 2) { // we're at an odd step, weird
if (dir == FORWARD) {
currentstep += MICROSTEPS/2;
}
else {
currentstep -= MICROSTEPS/2;
}
} else { // go to the next even step
if (dir == FORWARD) {
currentstep += MICROSTEPS;
}
else {
currentstep -= MICROSTEPS;
}
}
} else if (style == DOUBLE) {
if (! (currentstep/(MICROSTEPS/2) % 2)) { // we're at an even step, weird
if (dir == FORWARD) {
currentstep += MICROSTEPS/2;
} else {
currentstep -= MICROSTEPS/2;
}
} else { // go to the next odd step
if (dir == FORWARD) {
currentstep += MICROSTEPS;
} else {
currentstep -= MICROSTEPS;
}
}
} else if (style == INTERLEAVE) {
if (dir == FORWARD) {
currentstep += MICROSTEPS/2;
} else {
currentstep -= MICROSTEPS/2;
}
}
if (style == MICROSTEP) {
if (dir == FORWARD) {
currentstep++;
} else {
// BACKWARDS
currentstep--;
}
currentstep += MICROSTEPS*4;
currentstep %= MICROSTEPS*4;
ocra = ocrb = 0;
if ( (currentstep >= 0) && (currentstep < MICROSTEPS)) {
ocra = microstepcurve[MICROSTEPS - currentstep];
ocrb = microstepcurve[currentstep];
} else if ( (currentstep >= MICROSTEPS) && (currentstep < MICROSTEPS*2)) {
ocra = microstepcurve[currentstep - MICROSTEPS];
ocrb = microstepcurve[MICROSTEPS*2 - currentstep];
} else if ( (currentstep >= MICROSTEPS*2) && (currentstep < MICROSTEPS*3)) {
ocra = microstepcurve[MICROSTEPS*3 - currentstep];
ocrb = microstepcurve[currentstep - MICROSTEPS*2];
} else if ( (currentstep >= MICROSTEPS*3) && (currentstep < MICROSTEPS*4)) {
ocra = microstepcurve[currentstep - MICROSTEPS*3];
ocrb = microstepcurve[MICROSTEPS*4 - currentstep];
}
}
currentstep += MICROSTEPS*4;
currentstep %= MICROSTEPS*4;
#ifdef MOTORDEBUG
Serial.print("current step: "); Serial.println(currentstep, DEC);
Serial.print(" pwmA = "); Serial.print(ocra, DEC);
Serial.print(" pwmB = "); Serial.println(ocrb, DEC);
#endif
if (steppernum == 1) {
setPWM1(ocra);
setPWM2(ocrb);
} else if (steppernum == 2) {
setPWM3(ocra);
setPWM4(ocrb);
}
// release all
latch_state &= ~a & ~b & ~c & ~d; // all motor pins to 0
//Serial.println(step, DEC);
if (style == MICROSTEP) {
if ((currentstep >= 0) && (currentstep < MICROSTEPS))
latch_state |= a | b;
if ((currentstep >= MICROSTEPS) && (currentstep < MICROSTEPS*2))
latch_state |= b | c;
if ((currentstep >= MICROSTEPS*2) && (currentstep < MICROSTEPS*3))
latch_state |= c | d;
if ((currentstep >= MICROSTEPS*3) && (currentstep < MICROSTEPS*4))
latch_state |= d | a;
} else {
switch (currentstep/(MICROSTEPS/2)) {
case 0:
latch_state |= a; // energize coil 1 only
break;
case 1:
latch_state |= a | b; // energize coil 1+2
break;
case 2:
latch_state |= b; // energize coil 2 only
break;
case 3:
latch_state |= b | c; // energize coil 2+3
break;
case 4:
latch_state |= c; // energize coil 3 only
break;
case 5:
latch_state |= c | d; // energize coil 3+4
break;
case 6:
latch_state |= d; // energize coil 4 only
break;
case 7:
latch_state |= d | a; // energize coil 1+4
break;
}
}
MC.latch_tx();
return currentstep;
}
// Adafruit Motor shield library
// copyright Adafruit Industries LLC, 2009
// this code is public domain, enjoy!
#ifndef _AFMotor_h_
#define _AFMotor_h_
#include <inttypes.h>
#include <avr/io.h>
//#define MOTORDEBUG 1
#define MICROSTEPS 16 // 8 or 16
#define MOTOR12_64KHZ _BV(CS20) // no prescale
#define MOTOR12_8KHZ _BV(CS21) // divide by 8
#define MOTOR12_2KHZ _BV(CS21) | _BV(CS20) // divide by 32
#define MOTOR12_1KHZ _BV(CS22) // divide by 64
#define MOTOR34_64KHZ _BV(CS00) // no prescale
#define MOTOR34_8KHZ _BV(CS01) // divide by 8
#define MOTOR34_1KHZ _BV(CS01) | _BV(CS00) // divide by 64
#define MOTOR1_A 2
#define MOTOR1_B 3
#define MOTOR2_A 1
#define MOTOR2_B 4
#define MOTOR4_A 0
#define MOTOR4_B 6
#define MOTOR3_A 5
#define MOTOR3_B 7
#define FORWARD 1
#define BACKWARD 2
#define BRAKE 3
#define RELEASE 4
#define SINGLE 1
#define DOUBLE 2
#define INTERLEAVE 3
#define MICROSTEP 4
/*
#define LATCH 4
#define LATCH_DDR DDRB
#define LATCH_PORT PORTB
#define CLK_PORT PORTD
#define CLK_DDR DDRD
#define CLK 4
#define ENABLE_PORT PORTD
#define ENABLE_DDR DDRD
#define ENABLE 7
#define SER 0
#define SER_DDR DDRB
#define SER_PORT PORTB
*/
// Arduino pin names
#define MOTORLATCH 12
#define MOTORCLK 4
#define MOTORENABLE 7
#define MOTORDATA 8
class AFMotorController
{
public:
AFMotorController(void);
void enable(void);
friend class AF_DCMotor;
void latch_tx(void);
};
class AF_DCMotor
{
public:
AF_DCMotor(uint8_t motornum, uint8_t freq = MOTOR34_8KHZ);
void run(uint8_t);
void setSpeed(uint8_t);
private:
uint8_t motornum, pwmfreq;
};
class AF_Stepper {
public:
AF_Stepper(uint16_t, uint8_t);
void step(uint16_t steps, uint8_t dir, uint8_t style = SINGLE);
void setSpeed(uint16_t);
uint8_t onestep(uint8_t dir, uint8_t style);
void release(void);
uint16_t revsteps; // # steps per revolution
uint8_t steppernum;
uint32_t usperstep, steppingcounter;
private:
uint8_t currentstep;
};
uint8_t getlatchstate(void);
#endif
// AccelStepper.cpp
//
// Copyright (C) 2009 Mike McCauley
// $Id: AccelStepper.cpp,v 1.4 2011/01/05 01:51:01 mikem Exp $
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include "AccelStepper.h"
void AccelStepper::moveTo(long absolute)
{
_targetPos = absolute;
computeNewSpeed();
}
void AccelStepper::move(long relative)
{
moveTo(_currentPos + relative);
}
// Implements steps according to the current speed
// You must call this at least once per step
// returns true if a step occurred
boolean AccelStepper::runSpeed()
{
unsigned long time = micros();
// if ( (time >= (_lastStepTime + _stepInterval)) // okay if both current time and next step time wrap
// || ((time < _lastRunTime) && (time > (0xFFFFFFFF-(_lastStepTime+_stepInterval)))) ) // check if only current time has wrapped
// unsigned long nextStepTime = _lastStepTime + _stepInterval;
// if ( ((nextStepTime < _lastStepTime) && (time < _lastStepTime) && (time >= nextStepTime))
// || ((nextStepTime >= _lastStepTime) && (time >= nextStepTime)))
// TESTING:
//time += (0xffffffff - 10000000);
// Gymnastics to detect wrapping of either the nextStepTime and/or the current time
unsigned long nextStepTime = _lastStepTime + _stepInterval;
if ( ((nextStepTime >= _lastStepTime) && ((time >= nextStepTime) || (time < _lastStepTime)))
|| ((nextStepTime < _lastStepTime) && ((time >= nextStepTime) && (time < _lastStepTime))))
{
if (_speed > 0.0f)
{
// Clockwise
_currentPos += 1;
}
else if (_speed < 0.0f)
{
// Anticlockwise
_currentPos -= 1;
}
step(_currentPos & 0x7); // Bottom 3 bits (same as mod 8, but works with + and - numbers)
// _lastRunTime = time;
_lastStepTime = time;
return true;
}
else
{
// _lastRunTime = time;
return false;
}
}
long AccelStepper::distanceToGo()
{
return _targetPos - _currentPos;
}
long AccelStepper::targetPosition()
{
return _targetPos;
}
long AccelStepper::currentPosition()
{
return _currentPos;
}
// Useful during initialisations or after initial positioning
void AccelStepper::setCurrentPosition(long position)
{
_targetPos = _currentPos = position;
computeNewSpeed(); // Expect speed of 0
}
void AccelStepper::computeNewSpeed()
{
setSpeed(desiredSpeed());
}
// Work out and return a new speed.
// Subclasses can override if they want
// Implement acceleration, deceleration and max speed
// Negative speed is anticlockwise
// This is called:
// after each step
// after user changes:
// maxSpeed
// acceleration
// target position (relative or absolute)
float AccelStepper::desiredSpeed()
{
float requiredSpeed;
long distanceTo = distanceToGo();
// Max possible speed that can still decelerate in the available distance
// Use speed squared to avoid using sqrt
if (distanceTo == 0)
return 0.0f; // We're there
else if (distanceTo > 0) // Clockwise
requiredSpeed = (2.0f * distanceTo * _acceleration);
else // Anticlockwise
requiredSpeed = -(2.0f * -distanceTo * _acceleration);
float sqrSpeed = (_speed * _speed) * ((_speed > 0.0f) ? 1.0f : -1.0f);
if (requiredSpeed > sqrSpeed)
{
if (_speed == _maxSpeed) // Reduces processor load by avoiding extra calculations below
{
// Maintain max speed
requiredSpeed = _maxSpeed;
}
else
{
// Need to accelerate in clockwise direction
if (_speed == 0.0f)
requiredSpeed = sqrt(2.0f * _acceleration);
else
requiredSpeed = _speed + abs(_acceleration / _speed);
if (requiredSpeed > _maxSpeed)
requiredSpeed = _maxSpeed;
}
}
else if (requiredSpeed < sqrSpeed)
{
if (_speed == -_maxSpeed) // Reduces processor load by avoiding extra calculations below
{
// Maintain max speed
requiredSpeed = -_maxSpeed;
}
else
{
// Need to accelerate in clockwise direction
if (_speed == 0.0f)
requiredSpeed = -sqrt(2.0f * _acceleration);
else
requiredSpeed = _speed - abs(_acceleration / _speed);
if (requiredSpeed < -_maxSpeed)
requiredSpeed = -_maxSpeed;
}
}
else // if (requiredSpeed == sqrSpeed)
requiredSpeed = _speed;
// Serial.println(requiredSpeed);
return requiredSpeed;
}
// Run the motor to implement speed and acceleration in order to proceed to the target position
// You must call this at least once per step, preferably in your main loop
// If the motor is in the desired position, the cost is very small
// returns true if we are still running to position
boolean AccelStepper::run()
{
if (_targetPos == _currentPos)
return false;
if (runSpeed())
computeNewSpeed();
return true;
}
AccelStepper::AccelStepper(uint8_t pins, uint8_t pin1, uint8_t pin2, uint8_t pin3, uint8_t pin4)
{
_pins = pins;
_currentPos = 0;
_targetPos = 0;
_speed = 0.0;
_maxSpeed = 1.0;
_acceleration = 1.0;
_stepInterval = 0;
// _lastRunTime = 0;
_minPulseWidth = 1;
_lastStepTime = 0;
_pin1 = pin1;
_pin2 = pin2;
_pin3 = pin3;
_pin4 = pin4;
//_stepInterval = 20000;
//_speed = 50.0;
//_lastRunTime = 0xffffffff - 20000;
//_lastStepTime = 0xffffffff - 20000 - 10000;
enableOutputs();
}
AccelStepper::AccelStepper(void (*forward)(), void (*backward)())
{
_pins = 0;
_currentPos = 0;
_targetPos = 0;
_speed = 0.0;
_maxSpeed = 1.0;
_acceleration = 1.0;
_stepInterval = 0;
// _lastRunTime = 0;
_minPulseWidth = 1;
_lastStepTime = 0;
_pin1 = 0;
_pin2 = 0;
_pin3 = 0;
_pin4 = 0;
_forward = forward;
_backward = backward;
}
void AccelStepper::setMaxSpeed(float speed)
{
_maxSpeed = speed;
computeNewSpeed();
}
void AccelStepper::setAcceleration(float acceleration)
{
_acceleration = acceleration;
computeNewSpeed();
}
void AccelStepper::setSpeed(float speed)
{
if (speed == _speed)
return;
if ((speed > 0.0f) && (speed > _maxSpeed))
_speed = _maxSpeed;
else if ((speed < 0.0f) && (speed < -_maxSpeed))
_speed = -_maxSpeed;
else
_speed = speed;
_stepInterval = abs(1000000.0 / _speed);
}
float AccelStepper::speed()
{
return _speed;
}
// Subclasses can override
void AccelStepper::step(uint8_t step)
{
switch (_pins)
{
case 0:
step0();
break;
case 1:
step1(step);
break;
case 2:
step2(step);
break;
case 4:
step4(step);
break;
case 8:
step8(step);
break;
}
}
// 0 pin step function (ie for functional usage)
void AccelStepper::step0()
{
if (_speed > 0) {
_forward();
} else {
_backward();
}
}
// 1 pin step function (ie for stepper drivers)
// This is passed the current step number (0 to 7)
// Subclasses can override
void AccelStepper::step1(uint8_t step)
{
digitalWrite(_pin2, _speed > 0); // Direction
// Caution 200ns setup time
digitalWrite(_pin1, HIGH);
// Delay the minimum allowed pulse width
delayMicroseconds(_minPulseWidth);
digitalWrite(_pin1, LOW);
}
// 2 pin step function
// This is passed the current step number (0 to 7)
// Subclasses can override
void AccelStepper::step2(uint8_t step)
{
switch (step & 0x3)
{
case 0: /* 01 */
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, HIGH);
break;
case 1: /* 11 */
digitalWrite(_pin1, HIGH);
digitalWrite(_pin2, HIGH);
break;
case 2: /* 10 */
digitalWrite(_pin1, HIGH);
digitalWrite(_pin2, LOW);
break;
case 3: /* 00 */
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, LOW);
break;
}
}
// 4 pin step function for half stepper
// This is passed the current step number (0 to 7)
// Subclasses can override
void AccelStepper::step4(uint8_t step)
{
switch (step & 0x3)
{
case 0: // 1010
digitalWrite(_pin1, HIGH);
digitalWrite(_pin2, LOW);
digitalWrite(_pin3, HIGH);
digitalWrite(_pin4, LOW);
break;
case 1: // 0110
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, HIGH);
digitalWrite(_pin3, HIGH);
digitalWrite(_pin4, LOW);
break;
case 2: //0101
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, HIGH);
digitalWrite(_pin3, LOW);
digitalWrite(_pin4, HIGH);
break;
case 3: //1001
digitalWrite(_pin1, HIGH);
digitalWrite(_pin2, LOW);
digitalWrite(_pin3, LOW);
digitalWrite(_pin4, HIGH);
break;
}
}
// 4 pin step function
// This is passed the current step number (0 to 3)
// Subclasses can override
void AccelStepper::step8(uint8_t step)
{
switch (step & 0x7)
{
case 0: // 1000
digitalWrite(_pin1, HIGH);
digitalWrite(_pin2, LOW);
digitalWrite(_pin3, LOW);
digitalWrite(_pin4, LOW);
break;
case 1: // 1010
digitalWrite(_pin1, HIGH);
digitalWrite(_pin2, LOW);
digitalWrite(_pin3, HIGH);
digitalWrite(_pin4, LOW);
break;
case 2: // 0010
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, LOW);
digitalWrite(_pin3, HIGH);
digitalWrite(_pin4, LOW);
break;
case 3: // 0110
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, HIGH);
digitalWrite(_pin3, HIGH);
digitalWrite(_pin4, LOW);
break;
case 4: // 0100
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, HIGH);
digitalWrite(_pin3, LOW);
digitalWrite(_pin4, LOW);
break;
case 5: //0101
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, HIGH);
digitalWrite(_pin3, LOW);
digitalWrite(_pin4, HIGH);
break;
case 6: // 0001
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, LOW);
digitalWrite(_pin3, LOW);
digitalWrite(_pin4, HIGH);
break;
case 7: //1001
digitalWrite(_pin1, HIGH);
digitalWrite(_pin2, LOW);
digitalWrite(_pin3, LOW);
digitalWrite(_pin4, HIGH);
break;
}
}
// Prevents power consumption on the outputs
void AccelStepper::disableOutputs()
{
if (! _pins) return;
digitalWrite(_pin1, LOW);
digitalWrite(_pin2, LOW);
if (_pins == 4 || _pins == 😎
{
digitalWrite(_pin3, LOW);
digitalWrite(_pin4, LOW);
}
}
void AccelStepper::enableOutputs()
{
if (! _pins) return;
pinMode(_pin1, OUTPUT);
pinMode(_pin2, OUTPUT);
if (_pins == 4 || _pins == 😎
{
pinMode(_pin3, OUTPUT);
pinMode(_pin4, OUTPUT);
}
}
void AccelStepper::setMinPulseWidth(unsigned int minWidth)
{
_minPulseWidth = minWidth;
}
// Blocks until the target position is reached
void AccelStepper::runToPosition()
{
while (run())
;
}
boolean AccelStepper::runSpeedToPosition()
{
return _targetPos!=_currentPos ? runSpeed() : false;
}
// Blocks until the new target position is reached
void AccelStepper::runToNewPosition(long position)
{
moveTo(position);
runToPosition();
}
// AccelStepper.h
//
/// \mainpage AccelStepper library for Arduino
///
/// This is the Arduino AccelStepper library.
/// It provides an object-oriented interface for 2 or 4 pin stepper motors.
///
/// The standard Arduino IDE includes the Stepper library
/// (http://arduino.cc/en/Reference/Stepper) for stepper motors. It is
/// perfectly adequate for simple, single motor applications.
///
/// AccelStepper significantly improves on the standard Arduino Stepper library in several ways:
/// \li Supports acceleration and deceleration
/// \li Supports multiple simultaneous steppers, with independent concurrent stepping on each stepper
/// \li API functions never delay() or block
/// \li Supports 2 and 4 wire steppers, plus 4 wire half steppers.
/// \li Supports alternate stepping functions to enable support of AFMotor (https://github.com/adafruit/Adafruit-Motor-Shield-library)
/// \li Supports stepper drivers such as the Sparkfun EasyDriver (based on 3967 driver chip)
/// \li Very slow speeds are supported
/// \li Extensive API
/// \li Subclass support
///
/// The latest version of this documentation can be downloaded from
/// http://www.open.com.au/mikem/arduino/AccelStepper
///
/// Example Arduino programs are included to show the main modes of use.
///
/// The version of the package that this documentation refers to can be downloaded
/// from http://www.open.com.au/mikem/arduino/AccelStepper/AccelStepper-1.9.zip
/// You can find the latest version at http://www.open.com.au/mikem/arduino/AccelStepper
///
/// Tested on Arduino Diecimila and Mega with arduino-0018 & arduino-0021
/// on OpenSuSE 11.1 and avr-libc-1.6.1-1.15,
/// cross-avr-binutils-2.19-9.1, cross-avr-gcc-4.1.3_20080612-26.5.
///
/// \par Installation
/// Install in the usual way: unzip the distribution zip file to the libraries
/// sub-folder of your sketchbook.
///
/// This software is Copyright (C) 2010 Mike McCauley. Use is subject to license
/// conditions. The main licensing options available are GPL V2 or Commercial:
///
/// \par Open Source Licensing GPL V2
/// This is the appropriate option if you want to share the source code of your
/// application with everyone you distribute it to, and you also want to give them
/// the right to share who uses it. If you wish to use this software under Open
/// Source Licensing, you must contribute all your source code to the open source
/// community in accordance with the GPL Version 2 when your application is
/// distributed. See http://www.gnu.org/copyleft/gpl.html
///
/// \par Commercial Licensing
/// This is the appropriate option if you are creating proprietary applications
/// and you are not prepared to distribute and share the source code of your
/// application. Contact info@open.com.au for details.
///
/// \par Revision History
/// \version 1.0 Initial release
///
/// \version 1.1 Added speed() function to get the current speed.
/// \version 1.2 Added runSpeedToPosition() submitted by Gunnar Arndt.
/// \version 1.3 Added support for stepper drivers (ie with Step and Direction inputs) with _pins == 1
/// \version 1.4 Added functional contructor to support AFMotor, contributed by Limor, with example sketches.
/// \version 1.5 Improvements contributed by Peter Mousley: Use of microsecond steps and other speed improvements
/// to increase max stepping speed to about 4kHz. New option for user to set the min allowed pulse width.
/// Added checks for already running at max speed and skip further calcs if so.
/// \version 1.6 Fixed a problem with wrapping of microsecond stepping that could cause stepping to hang.
/// Reported by Sandy Noble.
/// Removed redundant _lastRunTime member.
/// \version 1.7 Fixed a bug where setCurrentPosition() did always work as expected. Reported by Peter Linhart.
/// Reported by Sandy Noble.
/// Removed redundant _lastRunTime member.
/// \version 1.8 Added support for 4 pin half-steppers, requested by Harvey Moon
/// \version 1.9 setCurrentPosition() now also sets motor speed to 0.
///
///
/// \author Mike McCauley (mikem@open.com.au)
// Copyright (C) 2009 Mike McCauley
// $Id: AccelStepper.h,v 1.5 2011/03/21 00:42:15 mikem Exp mikem $
#ifndef AccelStepper_h
#define AccelStepper_h
#include <stdlib.h>
#if defined(ARDUINO) && ARDUINO >= 100
#include <pins_arduino.h>
#else
#include <wiring.h>
#endif
// These defs cause trouble on some versions of Arduino
#undef round
/////////////////////////////////////////////////////////////////////
/// \class AccelStepper AccelStepper.h <AccelStepper.h>
/// \brief Support for stepper motors with acceleration etc.
///
/// This defines a single 2 or 4 pin stepper motor, or stepper moter with fdriver chip, with optional
/// acceleration, deceleration, absolute positioning commands etc. Multiple
/// simultaneous steppers are supported, all moving
/// at different speeds and accelerations.
///
/// \par Operation
/// This module operates by computing a step time in microseconds. The step
/// time is recomputed after each step and after speed and acceleration
/// parameters are changed by the caller. The time of each step is recorded in
/// microseconds. The run() function steps the motor if a new step is due.
/// The run() function must be called frequently until the motor is in the
/// desired position, after which time run() will do nothing.
///
/// \par Positioning
/// Positions are specified by a signed long integer. At
/// construction time, the current position of the motor is consider to be 0. Positive
/// positions are clockwise from the initial position; negative positions are
/// anticlockwise. The curent position can be altered for instance after
/// initialization positioning.
///
/// \par Caveats
/// This is an open loop controller: If the motor stalls or is oversped,
/// AccelStepper will not have a correct
/// idea of where the motor really is (since there is no feedback of the motor's
/// real position. We only know where we _think_ it is, relative to the
/// initial starting point).
///
/// The fastest motor speed that can be reliably supported is 4000 steps per
/// second (4 kHz) at a clock frequency of 16 MHz. However, any speed less than that
/// down to very slow speeds (much less than one per second) are also supported,
/// provided the run() function is called frequently enough to step the motor
/// whenever required for the speed set.
class AccelStepper
{
public:
/// Constructor. You can have multiple simultaneous steppers, all moving
/// at different speeds and accelerations, provided you call their run()
/// functions at frequent enough intervals. Current Position is set to 0, target
/// position is set to 0. MaxSpeed and Acceleration default to 1.0.
/// The motor pins will be initialised to OUTPUT mode during the
/// constructor by a call to enableOutputs().
/// \param[in] pins Number of pins to interface to. 1, 2 or 4 are
/// supported. 1 means a stepper driver (with Step and Direction pins)
/// 2 means a 2 wire stepper. 4 means a 4 wire stepper. 8 means a 4 wire half stepper
/// Defaults to 4 pins.
/// \param[in] pin1 Arduino digital pin number for motor pin 1. Defaults
/// to pin 2. For a driver (pins==1), this is the Step input to the driver. Low to high transition means to step)
/// \param[in] pin2 Arduino digital pin number for motor pin 2. Defaults
/// to pin 3. For a driver (pins==1), this is the Direction input the driver. High means forward.
/// \param[in] pin3 Arduino digital pin number for motor pin 3. Defaults
/// to pin 4.
/// \param[in] pin4 Arduino digital pin number for motor pin 4. Defaults
/// to pin 5.
AccelStepper(uint8_t pins = 4, uint8_t pin1 = 2, uint8_t pin2 = 3, uint8_t pin3 = 4, uint8_t pin4 = 5);
/// Alternate Constructor which will call your own functions for forward and backward steps.
/// You can have multiple simultaneous steppers, all moving
/// at different speeds and accelerations, provided you call their run()
/// functions at frequent enough intervals. Current Position is set to 0, target
/// position is set to 0. MaxSpeed and Acceleration default to 1.0.
/// Any motor initialization should happen before hand, no pins are used or initialized.
/// \param[in] forward void-returning procedure that will make a forward step
/// \param[in] backward void-returning procedure that will make a backward step
AccelStepper(void (*forward)(), void (*backward)());
/// Set the target position. The run() function will try to move the motor
/// from the current position to the target position set by the most
/// recent call to this function.
/// \param[in] absolute The desired absolute position. Negative is
/// anticlockwise from the 0 position.
void moveTo(long absolute);
/// Set the target position relative to the current position
/// \param[in] relative The desired position relative to the current position. Negative is
/// anticlockwise from the current position.
void move(long relative);
/// Poll the motor and step it if a step is due, implementing
/// accelerations and decelerations to achive the ratget position. You must call this as
/// fequently as possible, but at least once per minimum step interval,
/// preferably in your main loop.
/// \return true if the motor is at the target position.
boolean run();
/// Poll the motor and step it if a step is due, implmenting a constant
/// speed as set by the most recent call to setSpeed().
/// \return true if the motor was stepped.
boolean runSpeed();
/// Sets the maximum permitted speed. the run() function will accelerate
/// up to the speed set by this function.
/// \param[in] speed The desired maximum speed in steps per second. Must
/// be > 0. Speeds of more than 1000 steps per second are unreliable.
void setMaxSpeed(float speed);
/// Sets the acceleration and deceleration parameter.
/// \param[in] acceleration The desired acceleration in steps per second
/// per second. Must be > 0.
void setAcceleration(float acceleration);
/// Sets the desired constant speed for use with runSpeed().
/// \param[in] speed The desired constant speed in steps per
/// second. Positive is clockwise. Speeds of more than 1000 steps per
/// second are unreliable. Very slow speeds may be set (eg 0.00027777 for
/// once per hour, approximately. Speed accuracy depends on the Arduino
/// crystal. Jitter depends on how frequently you call the runSpeed() function.
void setSpeed(float speed);
/// The most recently set speed
/// \return the most recent speed in steps per second
float speed();
/// The distance from the current position to the target position.
/// \return the distance from the current position to the target position
/// in steps. Positive is clockwise from the current position.
long distanceToGo();
/// The most recently set target position.
/// \return the target position
/// in steps. Positive is clockwise from the 0 position.
long targetPosition();
/// The currently motor position.
/// \return the current motor position
/// in steps. Positive is clockwise from the 0 position.
long currentPosition();
/// Resets the current position of the motor, so that wherever the motor
/// happens to be right now is considered to be the new 0 position. Useful
/// for setting a zero position on a stepper after an initial hardware
/// positioning move.
/// Has the side effect of setting the current motor speed to 0.
/// \param[in] position The position in steps of wherever the motor
/// happens to be right now.
void setCurrentPosition(long position);
/// Moves the motor to the target position and blocks until it is at
/// position. Dont use this in event loops, since it blocks.
void runToPosition();
/// Runs at the currently selected speed until the target position is reached
/// Does not implement accelerations.
boolean runSpeedToPosition();
/// Moves the motor to the new target position and blocks until it is at
/// position. Dont use this in event loops, since it blocks.
/// \param[in] position The new target position.
void runToNewPosition(long position);
/// Disable motor pin outputs by setting them all LOW
/// Depending on the design of your electronics this may turn off
/// the power to the motor coils, saving power.
/// This is useful to support Arduino low power modes: disable the outputs
/// during sleep and then reenable with enableOutputs() before stepping
/// again.
void disableOutputs();
/// Enable motor pin outputs by setting the motor pins to OUTPUT
/// mode. Called automatically by the constructor.
void enableOutputs();
/// Sets the minimum pulse width allowed by the stepper driver.
/// \param[in] minWidth The minimum pulse width in microseconds.
void setMinPulseWidth(unsigned int minWidth);
protected:
/// Forces the library to compute a new instantaneous speed and set that as
/// the current speed. Calls
/// desiredSpeed(), which can be overridden by subclasses. It is called by
/// the library:
/// \li after each step
/// \li after change to maxSpeed through setMaxSpeed()
/// \li after change to acceleration through setAcceleration()
/// \li after change to target position (relative or absolute) through
/// move() or moveTo()
void computeNewSpeed();
/// Called to execute a step. Only called when a new step is
/// required. Subclasses may override to implement new stepping
/// interfaces. The default calls step1(), step2(), step4() or step8() depending on the
/// number of pins defined for the stepper.
/// \param[in] step The current step phase number (0 to 7)
virtual void step(uint8_t step);
/// Called to execute a step using stepper functions (pins = 0) Only called when a new step is
/// required. Calls _forward() or _backward() to perform the step
virtual void step0(void);
/// Called to execute a step on a stepper drover (ie where pins == 1). Only called when a new step is
/// required. Subclasses may override to implement new stepping
/// interfaces. The default sets or clears the outputs of Step pin1 to step,
/// and sets the output of _pin2 to the desired direction. The Step pin (_pin1) is pulsed for 1 microsecond
/// which is the minimum STEP pulse width for the 3967 driver.
/// \param[in] step The current step phase number (0 to 7)
virtual void step1(uint8_t step);
/// Called to execute a step on a 2 pin motor. Only called when a new step is
/// required. Subclasses may override to implement new stepping
/// interfaces. The default sets or clears the outputs of pin1 and pin2
/// \param[in] step The current step phase number (0 to 7)
virtual void step2(uint8_t step);
/// Called to execute a step on a 4 pin motor. Only called when a new step is
/// required. Subclasses may override to implement new stepping
/// interfaces. The default sets or clears the outputs of pin1, pin2,
/// pin3, pin4.
/// \param[in] step The current step phase number (0 to 7)
virtual void step4(uint8_t step);
/// Called to execute a step on a 4 pin half-steper motor. Only called when a new step is
/// required. Subclasses may override to implement new stepping
/// interfaces. The default sets or clears the outputs of pin1, pin2,
/// pin3, pin4.
/// \param[in] step The current step phase number (0 to 7)
virtual void step8(uint8_t step);
/// Compute and return the desired speed. The default algorithm uses
/// maxSpeed, acceleration and the current speed to set a new speed to
/// move the motor from teh current position to the target
/// position. Subclasses may override this to provide an alternate
/// algorithm (but do not block). Called by computeNewSpeed whenever a new speed neds to be
/// computed.
virtual float desiredSpeed();
private:
/// Number of pins on the stepper motor. Permits 2 or 4. 2 pins is a
/// bipolar, and 4 pins is a unipolar.
uint8_t _pins; // 2 or 4
/// Arduino pin number for the 2 or 4 pins required to interface to the
/// stepper motor.
uint8_t _pin1, _pin2, _pin3, _pin4;
/// The current absolution position in steps.
long _currentPos; // Steps
/// The target position in steps. The AccelStepper library will move the
/// motor from teh _currentPos to the _targetPos, taking into account the
/// max speed, acceleration and deceleration
long _targetPos; // Steps
/// The current motos speed in steps per second
/// Positive is clockwise
float _speed; // Steps per second
/// The maximum permitted speed in steps per second. Must be > 0.
float _maxSpeed;
/// The acceleration to use to accelerate or decelerate the motor in steps
/// per second per second. Must be > 0
float _acceleration;
/// The current interval between steps in microseconds
unsigned long _stepInterval;
/// The last run time (when runSpeed() was last called) in microseconds
// unsigned long _lastRunTime;
/// The last step time in microseconds
unsigned long _lastStepTime;
/// The minimum allowed pulse width in microseconds
unsigned int _minPulseWidth;
// The pointer to a forward-step procedure
void (*_forward)();
// The pointer to a backward-step procedure
void (*_backward)();
};
#endif
/*
* IRremote
* Version 0.11 August, 2009
* Copyright 2009 Ken Shirriff
* For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html
*
* Interrupt code based on NECIRrcv by Joe Knapp
* http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556
* Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/
*/
#include "IRremote.h"
#include "IRremoteInt.h"
// Provides ISR
#include <avr/interrupt.h>
volatile irparams_t irparams;
// These versions of MATCH, MATCH_MARK, and MATCH_SPACE are only for debugging.
// To use them, set DEBUG in IRremoteInt.h
// Normally macros are used for efficiency
#ifdef DEBUG
int MATCH(int measured, int desired) {
Serial.print("Testing: ");
Serial.print(TICKS_LOW(desired), DEC);
Serial.print(" <= ");
Serial.print(measured, DEC);
Serial.print(" <= ");
Serial.println(TICKS_HIGH(desired), DEC);
return measured >= TICKS_LOW(desired) && measured <= TICKS_HIGH(desired);
}
int MATCH_MARK(int measured_ticks, int desired_us) {
Serial.print("Testing mark ");
Serial.print(measured_ticks * USECPERTICK, DEC);
Serial.print(" vs ");
Serial.print(desired_us, DEC);
Serial.print(": ");
Serial.print(TICKS_LOW(desired_us + MARK_EXCESS), DEC);
Serial.print(" <= ");
Serial.print(measured_ticks, DEC);
Serial.print(" <= ");
Serial.println(TICKS_HIGH(desired_us + MARK_EXCESS), DEC);
return measured_ticks >= TICKS_LOW(desired_us + MARK_EXCESS) && measured_ticks <= TICKS_HIGH(desired_us + MARK_EXCESS);
}
int MATCH_SPACE(int measured_ticks, int desired_us) {
Serial.print("Testing space ");
Serial.print(measured_ticks * USECPERTICK, DEC);
Serial.print(" vs ");
Serial.print(desired_us, DEC);
Serial.print(": ");
Serial.print(TICKS_LOW(desired_us - MARK_EXCESS), DEC);
Serial.print(" <= ");
Serial.print(measured_ticks, DEC);
Serial.print(" <= ");
Serial.println(TICKS_HIGH(desired_us - MARK_EXCESS), DEC);
return measured_ticks >= TICKS_LOW(desired_us - MARK_EXCESS) && measured_ticks <= TICKS_HIGH(desired_us - MARK_EXCESS);
}
#endif
void IRsend::sendNEC(unsigned long data, int nbits)
{
enableIROut(38);
mark(NEC_HDR_MARK);
space(NEC_HDR_SPACE);
for (int i = 0; i < nbits; i++) {
if (data & TOPBIT) {
mark(NEC_BIT_MARK);
space(NEC_ONE_SPACE);
}
else {
mark(NEC_BIT_MARK);
space(NEC_ZERO_SPACE);
}
data <<= 1;
}
mark(NEC_BIT_MARK);
space(0);
}
void IRsend::sendSony(unsigned long data, int nbits) {
enableIROut(40);
mark(SONY_HDR_MARK);
space(SONY_HDR_SPACE);
data = data << (32 - nbits);
for (int i = 0; i < nbits; i++) {
if (data & TOPBIT) {
mark(SONY_ONE_MARK);
space(SONY_HDR_SPACE);
}
else {
mark(SONY_ZERO_MARK);
space(SONY_HDR_SPACE);
}
data <<= 1;
}
}
void IRsend::sendRaw(unsigned int buf[], int len, int hz)
{
enableIROut(hz);
for (int i = 0; i < len; i++) {
if (i & 1) {
space(buf);
}
else {
mark(buf);
}
}
space(0); // Just to be sure
}
// Note: first bit must be a one (start bit)
void IRsend::sendRC5(unsigned long data, int nbits)
{
enableIROut(36);
data = data << (32 - nbits);
mark(RC5_T1); // First start bit
space(RC5_T1); // Second start bit
mark(RC5_T1); // Second start bit
for (int i = 0; i < nbits; i++) {
if (data & TOPBIT) {
space(RC5_T1); // 1 is space, then mark
mark(RC5_T1);
}
else {
mark(RC5_T1);
space(RC5_T1);
}
data <<= 1;
}
space(0); // Turn off at end
}
// Caller needs to take care of flipping the toggle bit
void IRsend::sendRC6(unsigned long data, int nbits)
{
enableIROut(36);
data = data << (32 - nbits);
mark(RC6_HDR_MARK);
space(RC6_HDR_SPACE);
mark(RC6_T1); // start bit
space(RC6_T1);
int t;
for (int i = 0; i < nbits; i++) {
if (i == 3) {
// double-wide trailer bit
t = 2 * RC6_T1;
}
else {
t = RC6_T1;
}
if (data & TOPBIT) {
mark(t);
space(t);
}
else {
space(t);
mark(t);
}
data <<= 1;
}
space(0); // Turn off at end
}
void IRsend::mark(int time) {
// Sends an IR mark for the specified number of microseconds.
// The mark output is modulated at the PWM frequency.
TCCR2A |= _BV(COM2B1); // Enable pin 3 PWM output
delayMicroseconds(time);
}
/* Leave pin off for time (given in microseconds) */
void IRsend::space(int time) {
// Sends an IR space for the specified number of microseconds.
// A space is no output, so the PWM output is disabled.
TCCR2A &= ~(_BV(COM2B1)); // Disable pin 3 PWM output
delayMicroseconds(time);
}
void IRsend::enableIROut(int khz) {
// Enables IR output. The khz value controls the modulation frequency in kilohertz.
// The IR output will be on pin 3 (OC2B).
// This routine is designed for 36-40KHz; if you use it for other values, it's up to you
// to make sure it gives reasonable results. (Watch out for overflow / underflow / rounding.)
// TIMER2 is used in phase-correct PWM mode, with OCR2A controlling the frequency and OCR2B
// controlling the duty cycle.
// There is no prescaling, so the output frequency is 16MHz / (2 * OCR2A)
// To turn the output on and off, we leave the PWM running, but connect and disconnect the output pin.
// A few hours staring at the ATmega documentation and this will all make sense.
// See my Secrets of Arduino PWM at http://arcfn.com/2009/07/secrets-of-arduino-pwm.html for details.
// Disable the Timer2 Interrupt (which is used for receiving IR)
TIMSK2 &= ~_BV(TOIE2); //Timer2 Overflow Interrupt
pinMode(3, OUTPUT);
digitalWrite(3, LOW); // When not sending PWM, we want it low
// COM2A = 00: disconnect OC2A
// COM2B = 00: disconnect OC2B; to send signal set to 10: OC2B non-inverted
// WGM2 = 101: phase-correct PWM with OCRA as top
// CS2 = 000: no prescaling
TCCR2A = _BV(WGM20);
TCCR2B = _BV(WGM22) | _BV(CS20);
// The top value for the timer. The modulation frequency will be SYSCLOCK / 2 / OCR2A.
OCR2A = SYSCLOCK / 2 / khz / 1000;
OCR2B = OCR2A / 3; // 33% duty cycle
}
IRrecv::IRrecv(int recvpin)
{
irparams.recvpin = recvpin;
irparams.blinkflag = 0;
}
// initialization
void IRrecv::enableIRIn() {
// setup pulse clock timer interrupt
TCCR2A = 0; // normal mode
//Prescale /8 (16M/8 = 0.5 microseconds per tick)
// Therefore, the timer interval can range from 0.5 to 128 microseconds
// depending on the reset value (255 to 0)
cbi(TCCR2B,CS22);
sbi(TCCR2B,CS21);
cbi(TCCR2B,CS20);
//Timer2 Overflow Interrupt Enable
sbi(TIMSK2,TOIE2);
RESET_TIMER2;
sei(); // enable interrupts
// initialize state machine variables
irparams.rcvstate = STATE_IDLE;
irparams.rawlen = 0;
// set pin modes
pinMode(irparams.recvpin, INPUT);
}
// enable/disable blinking of pin 13 on IR processing
void IRrecv::blink13(int blinkflag)
{
irparams.blinkflag = blinkflag;
if (blinkflag)
pinMode(BLINKLED, OUTPUT);
}
// TIMER2 interrupt code to collect raw data.
// Widths of alternating SPACE, MARK are recorded in rawbuf.
// Recorded in ticks of 50 microseconds.
// rawlen counts the number of entries recorded so far.
// First entry is the SPACE between transmissions.
// As soon as a SPACE gets long, ready is set, state switches to IDLE, timing of SPACE continues.
// As soon as first MARK arrives, gap width is recorded, ready is cleared, and new logging starts
ISR(TIMER2_OVF_vect)
{
RESET_TIMER2;
uint8_t irdata = (uint8_t)digitalRead(irparams.recvpin);
irparams.timer++; // One more 50us tick
if (irparams.rawlen >= RAWBUF) {
// Buffer overflow
irparams.rcvstate = STATE_STOP;
}
switch(irparams.rcvstate) {
case STATE_IDLE: // In the middle of a gap
if (irdata == MARK) {
if (irparams.timer < GAP_TICKS) {
// Not big enough to be a gap.
irparams.timer = 0;
}
else {
// gap just ended, record duration and start recording transmission
irparams.rawlen = 0;
irparams.rawbuf[irparams.rawlen++] = irparams.timer;
irparams.timer = 0;
irparams.rcvstate = STATE_MARK;
}
}
break;
case STATE_MARK: // timing MARK
if (irdata == SPACE) { // MARK ended, record time
irparams.rawbuf[irparams.rawlen++] = irparams.timer;
irparams.timer = 0;
irparams.rcvstate = STATE_SPACE;
}
break;
case STATE_SPACE: // timing SPACE
if (irdata == MARK) { // SPACE just ended, record it
irparams.rawbuf[irparams.rawlen++] = irparams.timer;
irparams.timer = 0;
irparams.rcvstate = STATE_MARK;
}
else { // SPACE
if (irparams.timer > GAP_TICKS) {
// big SPACE, indicates gap between codes
// Mark current code as ready for processing
// Switch to STOP
// Don't reset timer; keep counting space width
irparams.rcvstate = STATE_STOP;
}
}
break;
case STATE_STOP: // waiting, measuring gap
if (irdata == MARK) { // reset gap timer
irparams.timer = 0;
}
break;
}
if (irparams.blinkflag) {
if (irdata == MARK) {
PORTB |= B00100000; // turn pin 13 LED on
}
else {
PORTB &= B11011111; // turn pin 13 LED off
}
}
}
void IRrecv::resume() {
irparams.rcvstate = STATE_IDLE;
irparams.rawlen = 0;
}
// Decodes the received IR message
// Returns 0 if no data ready, 1 if data ready.
// Results of decoding are stored in results
int IRrecv::decode(decode_results *results) {
results->rawbuf = irparams.rawbuf;
results->rawlen = irparams.rawlen;
if (irparams.rcvstate != STATE_STOP) {
return ERR;
}
#ifdef DEBUG
Serial.println("Attempting NEC decode");
#endif
if (decodeNEC(results)) {
return DECODED;
}
#ifdef DEBUG
Serial.println("Attempting Sony decode");
#endif
if (decodeSony(results)) {
return DECODED;
}
#ifdef DEBUG
Serial.println("Attempting RC5 decode");
#endif
if (decodeRC5(results)) {
return DECODED;
}
#ifdef DEBUG
Serial.println("Attempting RC6 decode");
#endif
if (decodeRC6(results)) {
return DECODED;
}
if (results->rawlen >= 6) {
// Only return raw buffer if at least 6 bits
results->decode_type = UNKNOWN;
results->bits = 0;
results->value = 0;
return DECODED;
}
// Throw away and start over
resume();
return ERR;
}
long IRrecv::decodeNEC(decode_results *results) {
long data = 0;
int offset = 1; // Skip first space
// Initial mark
if (!MATCH_MARK(results->rawbuf[offset], NEC_HDR_MARK)) {
return ERR;
}
offset++;
// Check for repeat
if (irparams.rawlen == 4 &&
MATCH_SPACE(results->rawbuf[offset], NEC_RPT_SPACE) &&
MATCH_MARK(results->rawbuf[offset+1], NEC_BIT_MARK)) {
results->bits = 0;
results->value = REPEAT;
results->decode_type = NEC;
return DECODED;
}
if (irparams.rawlen < 2 * NEC_BITS + 4) {
return ERR;
}
// Initial space
if (!MATCH_SPACE(results->rawbuf[offset], NEC_HDR_SPACE)) {
return ERR;
}
offset++;
for (int i = 0; i < NEC_BITS; i++) {
if (!MATCH_MARK(results->rawbuf[offset], NEC_BIT_MARK)) {
return ERR;
}
offset++;
if (MATCH_SPACE(results->rawbuf[offset], NEC_ONE_SPACE)) {
data = (data << 1) | 1;
}
else if (MATCH_SPACE(results->rawbuf[offset], NEC_ZERO_SPACE)) {
data <<= 1;
}
else {
return ERR;
}
offset++;
}
// Success
results->bits = NEC_BITS;
results->value = data;
results->decode_type = NEC;
return DECODED;
}
long IRrecv::decodeSony(decode_results *results) {
long data = 0;
if (irparams.rawlen < 2 * SONY_BITS + 2) {
return ERR;
}
int offset = 1; // Skip first space
// Initial mark
if (!MATCH_MARK(results->rawbuf[offset], SONY_HDR_MARK)) {
return ERR;
}
offset++;
while (offset + 1 < irparams.rawlen) {
if (!MATCH_SPACE(results->rawbuf[offset], SONY_HDR_SPACE)) {
break;
}
offset++;
if (MATCH_MARK(results->rawbuf[offset], SONY_ONE_MARK)) {
data = (data << 1) | 1;
}
else if (MATCH_MARK(results->rawbuf[offset], SONY_ZERO_MARK)) {
data <<= 1;
}
else {
return ERR;
}
offset++;
}
// Success
results->bits = (offset - 1) / 2;
if (results->bits < 12) {
results->bits = 0;
return ERR;
}
results->value = data;
results->decode_type = SONY;
return DECODED;
}
// Gets one undecoded level at a time from the raw buffer.
// The RC5/6 decoding is easier if the data is broken into time intervals.
// E.g. if the buffer has MARK for 2 time intervals and SPACE for 1,
// successive calls to getRClevel will return MARK, MARK, SPACE.
// offset and used are updated to keep track of the current position.
// t1 is the time interval for a single bit in microseconds.
// Returns -1 for error (measured time interval is not a multiple of t1).
int IRrecv::getRClevel(decode_results *results, int *offset, int *used, int t1) {
if (*offset >= results->rawlen) {
// After end of recorded buffer, assume SPACE.
return SPACE;
}
int width = results->rawbuf[*offset];
int val = ((*offset) % 2) ? MARK : SPACE;
int correction = (val == MARK) ? MARK_EXCESS : - MARK_EXCESS;
int avail;
if (MATCH(width, t1 + correction)) {
avail = 1;
}
else if (MATCH(width, 2*t1 + correction)) {
avail = 2;
}
else if (MATCH(width, 3*t1 + correction)) {
avail = 3;
}
else {
return -1;
}
(*used)++;
if (*used >= avail) {
*used = 0;
(*offset)++;
}
#ifdef DEBUG
if (val == MARK) {
Serial.println("MARK");
}
else {
Serial.println("SPACE");
}
#endif
return val;
}
long IRrecv::decodeRC5(decode_results *results) {
if (irparams.rawlen < MIN_RC5_SAMPLES + 2) {
return ERR;
}
int offset = 1; // Skip gap space
long data = 0;
int used = 0;
// Get start bits
if (getRClevel(results, &offset, &used, RC5_T1) != MARK) return ERR;
if (getRClevel(results, &offset, &used, RC5_T1) != SPACE) return ERR;
if (getRClevel(results, &offset, &used, RC5_T1) != MARK) return ERR;
int nbits;
for (nbits = 0; offset < irparams.rawlen; nbits++) {
int levelA = getRClevel(results, &offset, &used, RC5_T1);
int levelB = getRClevel(results, &offset, &used, RC5_T1);
if (levelA == SPACE && levelB == MARK) {
// 1 bit
data = (data << 1) | 1;
}
else if (levelA == MARK && levelB == SPACE) {
// zero bit
data <<= 1;
}
else {
return ERR;
}
}
// Success
results->bits = nbits;
results->value = data;
results->decode_type = RC5;
return DECODED;
}
long IRrecv::decodeRC6(decode_results *results) {
if (results->rawlen < MIN_RC6_SAMPLES) {
return ERR;
}
int offset = 1; // Skip first space
// Initial mark
if (!MATCH_MARK(results->rawbuf[offset], RC6_HDR_MARK)) {
return ERR;
}
offset++;
if (!MATCH_SPACE(results->rawbuf[offset], RC6_HDR_SPACE)) {
return ERR;
}
offset++;
long data = 0;
int used = 0;
// Get start bit (1)
if (getRClevel(results, &offset, &used, RC6_T1) != MARK) return ERR;
if (getRClevel(results, &offset, &used, RC6_T1) != SPACE) return ERR;
int nbits;
for (nbits = 0; offset < results->rawlen; nbits++) {
int levelA, levelB; // Next two levels
levelA = getRClevel(results, &offset, &used, RC6_T1);
if (nbits == 3) {
// T bit is double wide; make sure second half matches
if (levelA != getRClevel(results, &offset, &used, RC6_T1)) return ERR;
}
levelB = getRClevel(results, &offset, &used, RC6_T1);
if (nbits == 3) {
// T bit is double wide; make sure second half matches
if (levelB != getRClevel(results, &offset, &used, RC6_T1)) return ERR;
}
if (levelA == MARK && levelB == SPACE) { // reversed compared to RC5
// 1 bit
data = (data << 1) | 1;
}
else if (levelA == SPACE && levelB == MARK) {
// zero bit
data <<= 1;
}
else {
return ERR; // Error
}
}
// Success
results->bits = nbits;
results->value = data;
results->decode_type = RC6;
return DECODED;
}
/*
* IRremote
* Version 0.1 July, 2009
* Copyright 2009 Ken Shirriff
* For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.htm http://arcfn.com
*
* Interrupt code based on NECIRrcv by Joe Knapp
* http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556
* Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/
*/
#ifndef IRremote_h
#define IRremote_h
// The following are compile-time library options.
// If you change them, recompile the library.
// If DEBUG is defined, a lot of debugging output will be printed during decoding.
// TEST must be defined for the IRtest unittests to work. It will make some
// methods virtual, which will be slightly slower, which is why it is optional.
// #define DEBUG
// #define TEST
// Results returned from the decoder
class decode_results {
public:
int decode_type; // NEC, SONY, RC5, UNKNOWN
unsigned long value; // Decoded value
int bits; // Number of bits in decoded value
volatile unsigned int *rawbuf; // Raw intervals in .5 us ticks
int rawlen; // Number of records in rawbuf.
};
// Values for decode_type
#define NEC 1
#define SONY 2
#define RC5 3
#define RC6 4
#define UNKNOWN -1
// Decoded value for NEC when a repeat code is received
#define REPEAT 0xffffffff
// main class for receiving IR
class IRrecv
{
public:
IRrecv(int recvpin);
void blink13(int blinkflag);
int decode(decode_results *results);
void enableIRIn();
void resume();
private:
// These are called by decode
int getRClevel(decode_results *results, int *offset, int *used, int t1);
long decodeNEC(decode_results *results);
long decodeSony(decode_results *results);
long decodeRC5(decode_results *results);
long decodeRC6(decode_results *results);
}
;
// Only used for testing; can remove virtual for shorter code
#ifdef TEST
#define VIRTUAL virtual
#else
#define VIRTUAL
#endif
class IRsend
{
public:
IRsend() {}
void sendNEC(unsigned long data, int nbits);
void sendSony(unsigned long data, int nbits);
void sendRaw(unsigned int buf[], int len, int hz);
void sendRC5(unsigned long data, int nbits);
void sendRC6(unsigned long data, int nbits);
// private:
void enableIROut(int khz);
VIRTUAL void mark(int usec);
VIRTUAL void space(int usec);
}
;
// Some useful constants
#define USECPERTICK 50 // microseconds per clock interrupt tick
#define RAWBUF 76 // Length of raw duration buffer
// Marks tend to be 100us too long, and spaces 100us too short
// when received due to sensor lag.
#define MARK_EXCESS 100
#endif
/*
* IRremote
* Version 0.1 July, 2009
* Copyright 2009 Ken Shirriff
* For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html
*
* Interrupt code based on NECIRrcv by Joe Knapp
* http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556
* Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/
*/
#include <Arduino.h>
#ifndef IRremoteint_h
#define IRremoteint_h
#ifndef IRremote_h
#include "IRremote.h"
#endif
#define CLKFUDGE 5 // fudge factor for clock interrupt overhead
#define CLK 256 // max value for clock (timer 2)
#define PRESCALE 8 // timer2 clock prescale
#define SYSCLOCK 16000000 // main Arduino clock
#define CLKSPERUSEC (SYSCLOCK/PRESCALE/1000000) // timer clocks per microsecond
#define ERR 0
#define DECODED 1
#define BLINKLED 13
// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
// clock timer reset value
#define INIT_TIMER_COUNT2 (CLK - USECPERTICK*CLKSPERUSEC + CLKFUDGE)
#define RESET_TIMER2 TCNT2 = INIT_TIMER_COUNT2
// pulse parameters in usec
#define NEC_HDR_MARK 9000
#define NEC_HDR_SPACE 4500
#define NEC_BIT_MARK 560
#define NEC_ONE_SPACE 1600
#define NEC_ZERO_SPACE 560
#define NEC_RPT_SPACE 2250
#define SONY_HDR_MARK 2400
#define SONY_HDR_SPACE 600
#define SONY_ONE_MARK 1200
#define SONY_ZERO_MARK 600
#define SONY_RPT_LENGTH 45000
#define RC5_T1 889
#define RC5_RPT_LENGTH 46000
#define RC6_HDR_MARK 2666
#define RC6_HDR_SPACE 889
#define RC6_T1 444
#define RC6_RPT_LENGTH 46000
#define TOLERANCE 25 // percent tolerance in measurements
#define LTOL (1.0 - TOLERANCE/100.)
#define UTOL (1.0 + TOLERANCE/100.)
#define _GAP 5000 // Minimum map between transmissions
#define GAP_TICKS (_GAP/USECPERTICK)
#define TICKS_LOW(us) (int) (((us)*LTOL/USECPERTICK))
#define TICKS_HIGH(us) (int) (((us)*UTOL/USECPERTICK + 1))
#ifndef DEBUG
#define MATCH(measured_ticks, desired_us) ((measured_ticks) >= TICKS_LOW(desired_us) && (measured_ticks) <= TICKS_HIGH(desired_us))
#define MATCH_MARK(measured_ticks, desired_us) MATCH(measured_ticks, (desired_us) + MARK_EXCESS)
#define MATCH_SPACE(measured_ticks, desired_us) MATCH((measured_ticks), (desired_us) - MARK_EXCESS)
// Debugging versions are in IRremote.cpp
#endif
// receiver states
#define STATE_IDLE 2
#define STATE_MARK 3
#define STATE_SPACE 4
#define STATE_STOP 5
// information for the interrupt handler
typedef struct {
uint8_t recvpin; // pin for IR data from detector
uint8_t rcvstate; // state machine
uint8_t blinkflag; // TRUE to enable blinking of pin 13 on IR processing
unsigned int timer; // state timer, counts 50uS ticks.
unsigned int rawbuf[RAWBUF]; // raw data
uint8_t rawlen; // counter of entries in rawbuf
}
irparams_t;
// Defined in IRremote.cpp
extern volatile irparams_t irparams;
// IR detector output is active low
#define MARK 0
#define SPACE 1
#define TOPBIT 0x80000000
#define NEC_BITS 32
#define SONY_BITS 12
#define MIN_RC5_SAMPLES 11
#define MIN_RC6_SAMPLES 1
#endif
/*********************************************************************************
**
**
** LVFA_Firmware - Provides Functions For Interfacing With The Arduino Uno
**
** Written By: Sam Kristoff - National Instruments
** Written On: November 2010
** Last Updated: Dec 2011 - Kevin Fort - National Instruments
**
** This File May Be Modified And Re-Distributed Freely. Original File Content
** Written By Sam Kristoff And Available At www.ni.com/arduino.
**
*********************************************************************************/
/*********************************************************************************
** Define Constants
**
** Define directives providing meaningful names for constant values.
*********************************************************************************/
#define FIRMWARE_MAJOR 02
#define FIRMWARE_MINOR 00
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define DEFAULTBAUDRATE 9600 // Defines The Default Serial Baud Rate (This must match the baud rate specifid in LabVIEW)
#else
#define DEFAULTBAUDRATE 115200
#endif
#define MODE_DEFAULT 0 // Defines Arduino Modes (Currently Not Used)
#define COMMANDLENGTH 15 // Defines The Number Of Bytes In A Single LabVIEW Command (This must match the packet size specifid in LabVIEW)
#define STEPPER_SUPPORT 1 // Defines Whether The Stepper Library Is Included - Comment This Line To Exclude Stepper Support
// Declare Variables
unsigned char currentCommand[COMMANDLENGTH]; // The Current Command For The Arduino To Process
//Globals for continuous aquisition
unsigned char acqMode;
unsigned char contAcqPin;
float contAcqSpeed;
float acquisitionPeriod;
float iterationsFlt;
int iterations;
float delayTime;
/*********************************************************************************
** syncLV
**
** Synchronizes with LabVIEW and sends info about the board and firmware (Unimplemented)
**
** Input: None
** Output: None
*********************************************************************************/
void syncLV();
/*********************************************************************************
** setMode
**
** Sets the mode of the Arduino (Reserved For Future Use)
**
** Input: Int - Mode
** Output: None
*********************************************************************************/
void setMode(int mode);
/*********************************************************************************
** checkForCommand
**
** Checks for new commands from LabVIEW and processes them if any exists.
**
** Input: None
** Output: 1 - Command received and processed
** 0 - No new command
*********************************************************************************/
int checkForCommand(void);
/*********************************************************************************
** processCommand
**
** Processes a given command
**
** Input: command of COMMANDLENGTH bytes
** Output: 1 - Command received and processed
** 0 - No new command
*********************************************************************************/
void processCommand(unsigned char command[]);
/*********************************************************************************
** writeDigitalPort
**
** Write values to DIO pins 0 - 13. Pins must first be configured as outputs.
**
** Input: Command containing digital port data
** Output: None
*********************************************************************************/
void writeDigitalPort(unsigned char command[]);
/*********************************************************************************
** analogReadPort
**
** Reads all 6 analog input ports, builds 8 byte packet, send via RS232.
**
** Input: None
** Output: None
*********************************************************************************/
void analogReadPort();
/*********************************************************************************
** sevenSegment_Config
**
** Configure digital I/O pins to use for seven segment display. Pins are stored in sevenSegmentPins array.
**
** Input: Pins to use for seven segment LED [A, B, C, D, E, F, G, DP]
** Output: None
*********************************************************************************/
void sevenSegment_Config(unsigned char command[]);
/*********************************************************************************
** sevenSegment_Write
**
** Write values to sevenSegment display. Must first use sevenSegment_Configure
**
** Input: Eight values to write to seven segment display
** Output: None
*********************************************************************************/
void sevenSegment_Write(unsigned char command[]);
/*********************************************************************************
** spi_setClockDivider
**
** Set the SPI Clock Divisor
**
** Input: SPI Clock Divider 2, 4, 8, 16, 32, 64, 128
** Output: None
*********************************************************************************/
void spi_setClockDivider(unsigned char divider);
/*********************************************************************************
** spi_sendReceive
**
** Sens / Receive SPI Data
**
** Input: Command Packet
** Output: None (This command sends one serail byte back to LV for each data byte.
*********************************************************************************/
void spi_sendReceive(unsigned char command[]);
/*********************************************************************************
** checksum_Compute
**
** Compute Packet Checksum
**
** Input: Command Packet
** Output: Char Checksum Value
*********************************************************************************/
unsigned char checksum_Compute(unsigned char command[]);
/*********************************************************************************
** checksum_Test
**
** Compute Packet Checksum And Test Against Included Checksum
**
** Input: Command Packet
** Output: 0 If Checksums Are Equal, Else 1
*********************************************************************************/
int checksum_Test(unsigned char command[]);
/*********************************************************************************
** AccelStepper_Write
**
** Parse command packet and write speed, direction, and number of steps to travel
**
** Input: Command Packet
** Output: None
*********************************************************************************/
void AccelStepper_Write(unsigned char command[]);
/*********************************************************************************
** SampleContinuosly
**
** Returns several analog input points at once.
**
** Input: void
** Output: void
*********************************************************************************/
void sampleContinously(void);
/*********************************************************************************
** finiteAcquisition
**
** Returns the number of samples specified at the rate specified.
**
** Input: pin to sampe on, speed to sample at, number of samples
** Output: void
*********************************************************************************/
void finiteAcquisition(int analogPin, float acquisitionSpeed, int numberOfSamples );
/*********************************************************************************
** lcd_print
**
** Prints Data to the LCD With The Given Base
**
** Input: Command Packet
** Output: None
*********************************************************************************/
void lcd_print(unsigned char command[]);
/*********************************************************************************
**
** LVIFA_Firmware - Provides Functions For Interfacing With The Arduino Uno
**
** Written By: Sam Kristoff - National Instruments
** Written On: November 2010
** Last Updated: Dec 2011 - Kevin Fort - National Instruments
**
** This File May Be Modified And Re-Distributed Freely. Original File Content
** Written By Sam Kristoff And Available At www.ni.com/arduino.
**
*********************************************************************************/
#include <Wire.h>
#include <SPI.h>
#include <LiquidCrystal.h>
//Includes for IR Remote
#ifndef IRremoteInt_h
#include "IRremoteInt.h"
#endif
#ifndef IRremote_h
#include "IRremote.h"
#endif
/*********************************************************************************
** Optionally Include And Configure Stepper Support
*********************************************************************************/
#ifdef STEPPER_SUPPORT
// Stepper Modifications
#include "AFMotor.h"
#include "AccelStepper.h"
// Adafruit shield
AF_Stepper motor1(200, 1);
AF_Stepper motor2(200, 2);
// you can change these to DOUBLE or INTERLEAVE or MICROSTEP
// wrappers for the first motor
void forwardstep1() {
motor1.onestep(FORWARD, SINGLE);
}
void backwardstep1() {
motor1.onestep(BACKWARD, SINGLE);
}
// wrappers for the second motor
void forwardstep2() {
motor2.onestep(FORWARD, SINGLE);
}
void backwardstep2() {
motor2.onestep(BACKWARD, SINGLE);
}
AccelStepper steppers[8]; //Create array of 8 stepper objects
#endif
// Variables
unsigned int retVal;
int sevenSegmentPins[8];
int currentMode;
unsigned int freq;
unsigned long duration;
int i2cReadTimeouts = 0;
char spiBytesToSend = 0;
char spiBytesSent = 0;
char spiCSPin = 0;
char spiWordSize = 0;
Servo *servos;
byte customChar[8];
LiquidCrystal lcd(0,0,0,0,0,0,0);
unsigned long IRdata;
IRsend irsend;
// Sets the mode of the Arduino (Reserved For Future Use)
void setMode(int mode)
{
currentMode = mode;
}
// Checks for new commands from LabVIEW and processes them if any exists.
int checkForCommand(void)
{
#ifdef STEPPER_SUPPORT
// Call run function as fast as possible to keep motors turning
for (int i=0; i<8; i++){
steppers.run();
}
#endif
int bufferBytes = Serial.available();
if(bufferBytes >= COMMANDLENGTH)
{
// New Command Ready, Process It
// Build Command From Serial Buffer
for(int i=0; i<COMMANDLENGTH; i++)
{
currentCommand = Serial.read();
}
processCommand(currentCommand);
return 1;
}
else
{
return 0;
}
}
// Processes a given command
void processCommand(unsigned char command[])
{
// Determine Command
if(command[0] == 0xFF && checksum_Test(command) == 0)
{
switch(command[1])
{
/*********************************************************************************
** LIFA Maintenance Commands
*********************************************************************************/
case 0x00: // Sync Packet
Serial.print("sync");
Serial.flush();
break;
case 0x01: // Flush Serial Buffer
Serial.flush();
break;
/*********************************************************************************
** Low Level - Digital I/O Commands
*********************************************************************************/
case 0x02: // Set Pin As Input Or Output
pinMode(command[2], command[3]);
Serial.write('0');
break;
case 0x03: // Write Digital Pin
digitalWrite(command[2], command[3]);
Serial.write('0');
break;
case 0x04: // Write Digital Port 0
writeDigitalPort(command);
Serial.write('0');
break;
case 0x05: //Tone
freq = ( (command[3]<<8) + command[4]);
duration=(command[8]+ (command[7]<<8)+ (command[6]<<16)+(command[5]<<24));
if(freq > 0)
{
tone(command[2], freq, duration);
}
else
{
noTone(command[2]);
}
Serial.write('0');
break;
case 0x06: // Read Digital Pin
retVal = digitalRead(command[2]);
Serial.write(retVal);
break;
case 0x07: // Digital Read Port
retVal = 0x0000;
for(int i=0; i <=13; i++)
{
if(digitalRead(i))
{
retVal += (1<<i);
}
}
Serial.write( (retVal & 0xFF));
Serial.write( (retVal >> 8));
break;
/*********************************************************************************
** Low Level - Analog Commands
*********************************************************************************/
case 0x08: // Read Analog Pin
retVal = analogRead(command[2]);
Serial.write( (retVal >> 8));
Serial.write( (retVal & 0xFF));
break;
case 0x09: // Analog Read Port
analogReadPort();
break;
/*********************************************************************************
** Low Level - PWM Commands
*********************************************************************************/
case 0x0A: // PWM Write Pin
analogWrite(command[2], command[3]);
Serial.write('0');
break;
case 0x0B: // PWM Write 3 Pins
analogWrite(command[2], command[5]);
analogWrite(command[3], command[6]);
analogWrite(command[4], command[7]);
Serial.write('0');
break;
/*********************************************************************************
** Sensor Specific Commands
*********************************************************************************/
case 0x0C: // Configure Seven Segment Display
sevenSegment_Config(command);
Serial.write('0');
break;
case 0x0D: // Write To Seven Segment Display
sevenSegment_Write(command);
Serial.write('0');
break;
/*********************************************************************************
** I2C
*********************************************************************************/
case 0x0E: // Initialize I2C
Wire.begin();
Serial.write('0');
break;
case 0x0F: // Send I2C Data
Wire.beginTransmission(command[3]);
for(int i=0; i<command[2]; i++)
{
#if defined(ARDUINO) && ARDUINO >= 100
Wire.write(command[i+4]);
#else
Wire.send(command[i+4]);
#endif
}
Wire.endTransmission();
Serial.write('0');
break;
case 0x10: // I2C Read
i2cReadTimeouts = 0;
Wire.requestFrom(command[3], command[2]);
while(Wire.available() < command[2])
{
i2cReadTimeouts++;
if(i2cReadTimeouts > 100)
{
return;
}
else
{
delay(1);
}
}
for(int i=0; i<command[2]; i++)
{
#if defined(ARDUINO) && ARDUINO >= 100
Serial.write(Wire.read());
#else
Serial.write(Wire.receive());
#endif
}
break;
/*********************************************************************************
** SPI
*********************************************************************************/
case 0x11: // SPI Init
SPI.begin();
Serial.write('0');
break;
case 0x12: // SPI Set Bit Order (MSB LSB)
if(command[2] == 0)
{
SPI.setBitOrder(LSBFIRST);
}
else
{
SPI.setBitOrder(MSBFIRST);
}
Serial.write('0');
break;
case 0x13: // SPI Set Clock Divider
spi_setClockDivider(command[2]);
Serial.write('0');
break;
case 0x14: // SPI Set Data Mode
switch(command[2])
{
case 0:
SPI.setDataMode(SPI_MODE0);
break;
case 1:
SPI.setDataMode(SPI_MODE1);
break;
case 2:
SPI.setDataMode(SPI_MODE2);
break;
case 3:
SPI.setDataMode(SPI_MODE3);
break;
default:
break;
}
Serial.write('0');
break;
case 0x15: // SPI Send / Receive
spi_sendReceive(command);
break;
case 0x16: // SPI Close
SPI.end();
Serial.write('0');
break;
/*********************************************************************************
** Servos
*********************************************************************************/
case 0x17: // Set Num Servos
free(servos);
servos = (Servo*) malloc(command[2]*sizeof(Servo));
for(int i=0; i<command[2]; i++)
{
servos = Servo();
}
if(servos == 0)
{
Serial.write('1');
}
else
{
Serial.write('0');
}
break;
case 0x18: // Configure Servo
servos[command[2]].attach(command[3]);
Serial.write('0');
break;
case 0x19: // Servo Write
servos[command[2]].write(command[3]);
Serial.write('0');
break;
case 0x1A: // Servo Read Angle
Serial.write(servos[command[2]].read());
break;
case 0x1B: // Servo Write uS Pulse
servos[command[2]].writeMicroseconds( (command[3] + (command[4]<<8)) );
Serial.write('0');
break;
case 0x1C: // Servo Read uS Pulse
retVal = servos[command[2]].readMicroseconds();
Serial.write ((retVal & 0xFF));
Serial.write( (retVal >> 8));
break;
case 0x1D: // Servo Detach
servos[command[2]].detach();
Serial.write('0');
break;
/*********************************************************************************
** LCD
*********************************************************************************/
case 0x1E: // LCD Init
lcd.init(command[2], command[3], command[4], command[5], command[6], command[7], command[8], command[9], command[10], command[11], command[12], command[13]);
Serial.write('0');
break;
case 0x1F: // LCD Set Size
lcd.begin(command[2], command[3]);
Serial.write('0');
break;
case 0x20: // LCD Set Cursor Mode
if(command[2] == 0)
{
lcd.noCursor();
}
else
{
lcd.cursor();
}
if(command[3] == 0)
{
lcd.noBlink();
}
else
{
lcd.blink();
}
Serial.write('0');
break;
case 0x21: // LCD Clear
lcd.clear();
Serial.write('0');
break;
case 0x22: // LCD Set Cursor Position
lcd.setCursor(command[2], command[3]);
Serial.write('0');
break;
case 0x23: // LCD Print
lcd_print(command);
break;
case 0x24: // LCD Display Power
if(command[2] == 0)
{
lcd.noDisplay();
}
else
{
lcd.display();
}
Serial.write('0');
break;
case 0x25: // LCD Scroll
if(command[2] == 0)
{
lcd.scrollDisplayLeft();
}
else
{
lcd.scrollDisplayRight();
}
Serial.write('0');
break;
case 0x26: // LCD Autoscroll
if(command[2] == 0)
{
lcd.noAutoscroll();
}
else
{
lcd.autoscroll();
}
Serial.write('0');
break;
case 0x27: // LCD Print Direction
if(command[2] == 0)
{
lcd.rightToLeft();
}
else
{
lcd.leftToRight();
}
Serial.write('0');
break;
case 0x28: // LCD Create Custom Char
for(int i=0; i<8; i++)
{
customChar = command[i+3];
}
lcd.createChar(command[2], customChar);
Serial.write('0');
break;
case 0x29: // LCD Print Custom Char
lcd.write(command[2]);
Serial.write('0');
break;
/*********************************************************************************
** Continuous Aquisition
*********************************************************************************/
case 0x2A: // Continuous Aquisition Mode On
acqMode=1;
contAcqPin=command[2];
contAcqSpeed=(command[3])+(command[4]<<8);
acquisitionPeriod=1/contAcqSpeed;
iterationsFlt =.08/acquisitionPeriod;
iterations=(int)iterationsFlt;
if(iterations<1)
{
iterations=1;
}
delayTime= acquisitionPeriod;
if(delayTime<0)
{
delayTime=0;
}
break;
case 0x2B: // Continuous Aquisition Mode Off
acqMode=0;
break;
case 0x2C: // Return Firmware Revision
Serial.write(byte(FIRMWARE_MAJOR));
Serial.write(byte(FIRMWARE_MINOR));
break;
case 0x2D: // Perform Finite Aquisition
Serial.write('0');
finiteAcquisition(command[2],(command[3])+(command[4]<<8),command[5]+(command[6]<<8));
break;
/*********************************************************************************
** Stepper
*********************************************************************************/
#ifdef STEPPER_SUPPORT
case 0x30: // Configure Stepper
if (command[2] == 5){ // Support AFMotor Shield
switch (command[3]){
case 0:
steppers[command[3]] = AccelStepper(forwardstep1, backwardstep1);
break;
case 1:
steppers[command[3]] = AccelStepper(forwardstep2, backwardstep2);
break;
default:
break;
}
}
else if(command[2]==6) { // All other stepper configurations
steppers[command[3]] = AccelStepper(1, command[4],command[5],command[6],command[7]);
}
else{
steppers[command[3]] = AccelStepper(command[2], command[4],command[5],command[6],command[7]);
}
Serial.write('0');
break;
case 0x31: // Stepper Write
AccelStepper_Write(command);
Serial.write('0');
break;
case 0x32: // Stepper Detach
steppers[command[2]].disableOutputs();
Serial.write('0');
break;
case 0x33: // Stepper steps to go
retVal = 0;
for(int i=0; i<8; i++){
retVal += steppers.distanceToGo();
}
Serial.write( (retVal & 0xFF) );
Serial.write( (retVal >> 😎 );
break;
#endif
/*********************************************************************************
** IR Transmit
*********************************************************************************/
case 0x34: // IR Transmit
IRdata = ((unsigned long)command [4] << 24) | ((unsigned long)command [5] << 16) | ((unsigned long)command [6] << 😎 | ((unsigned long)command [7]);
switch(command[2])
{
case 0x00: // NEC
irsend.sendNEC(IRdata, command[3]);
break;
case 0x01: //Sony
irsend.sendSony(IRdata, command[3]);
break;
case 0x02: //RC5
irsend.sendRC5(IRdata, command[3]);
break;
case 0x03: //RC6
irsend.sendRC6(IRdata, command[3]);
break;
}
Serial.write((IRdata>>16) & 0xFF);
break;
/*********************************************************************************
** Unknown Packet
*********************************************************************************/
default: // Default Case
Serial.flush();
break;
}
}
else{
// Checksum Failed, Flush Serial Buffer
Serial.flush();
}
}
/*********************************************************************************
** Functions
*********************************************************************************/
// Writes Values To Digital Port (DIO 0-13). Pins Must Be Configured As Outputs Before Being Written To
void writeDigitalPort(unsigned char command[])
{
digitalWrite(13, (( command[2] >> 5) & 0x01) );
digitalWrite(12, (( command[2] >> 4) & 0x01) );
digitalWrite(11, (( command[2] >> 3) & 0x01) );
digitalWrite(10, (( command[2] >> 2) & 0x01) );
digitalWrite(9, (( command[2] >> 1) & 0x01) );
digitalWrite(8, (command[2] & 0x01) );
digitalWrite(7, (( command[3] >> 7) & 0x01) );
digitalWrite(6, (( command[3] >> 6) & 0x01) );
digitalWrite(5, (( command[3] >> 5) & 0x01) );
digitalWrite(4, (( command[3] >> 4) & 0x01) );
digitalWrite(3, (( command[3] >> 3) & 0x01) );
digitalWrite(2, (( command[3] >> 2) & 0x01) );
digitalWrite(1, (( command[3] >> 1) & 0x01) );
digitalWrite(0, (command[3] & 0x01) );
}
// Reads all 6 analog input ports, builds 8 byte packet, send via RS232.
void analogReadPort()
{
// Read Each Analog Pin
int pin0 = analogRead(0);
int pin1 = analogRead(1);
int pin2 = analogRead(2);
int pin3 = analogRead(3);
int pin4 = analogRead(4);
int pin5 = analogRead(5);
//Build 8-Byte Packet From 60 Bits of Data Read
char output0 = (pin0 & 0xFF);
char output1 = ( ((pin1 << 2) & 0xFC) | ( (pin0 >> 😎 & 0x03) );
char output2 = ( ((pin2 << 4) & 0xF0) | ( (pin1 >> 6) & 0x0F) );
char output3 = ( ((pin3 << 6) & 0xC0) | ( (pin2 >> 4) & 0x3F) );
char output4 = ( (pin3 >> 2) & 0xFF);
char output5 = (pin4 & 0xFF);
char output6 = ( ((pin5 << 2) & 0xFC) | ( (pin4 >> 😎 & 0x03) );
char output7 = ( (pin5 >> 6) & 0x0F );
// Write Bytes To Serial Port
Serial.print(output0);
Serial.print(output1);
Serial.print(output2);
Serial.print(output3);
Serial.print(output4);
Serial.print(output5);
Serial.print(output6);
Serial.print(output7);
}
// Configure digital I/O pins to use for seven segment display
void sevenSegment_Config(unsigned char command[])
{
// Configure pins as outputs and store in sevenSegmentPins array for use in sevenSegment_Write
for(int i=2; i<10; i++)
{
pinMode(command, OUTPUT);
sevenSegmentPins[(i-1)] = command;
}
}
// Write values to sevenSegment display. Must first use sevenSegment_Configure
void sevenSegment_Write(unsigned char command[])
{
for(int i=1; i<9; i++)
{
digitalWrite(sevenSegmentPins[(i-1)], command);
}
}
// Set the SPI Clock Divisor
void spi_setClockDivider(unsigned char divider)
{
switch(divider)
{
case 0:
SPI.setClockDivider(SPI_CLOCK_DIV2);
break;
case 1:
SPI.setClockDivider(SPI_CLOCK_DIV4);
break;
case 2:
SPI.setClockDivider(SPI_CLOCK_DIV8);
break;
case 3:
SPI.setClockDivider(SPI_CLOCK_DIV16);
break;
case 4:
SPI.setClockDivider(SPI_CLOCK_DIV32);
break;
case 5:
SPI.setClockDivider(SPI_CLOCK_DIV64);
break;
case 6:
SPI.setClockDivider(SPI_CLOCK_DIV128);
break;
default:
SPI.setClockDivider(SPI_CLOCK_DIV4);
break;
}
}
void spi_sendReceive(unsigned char command[])
{
if(command[2] == 1) //Check to see if this is the first of a series of SPI packets
{
spiBytesSent = 0;
spiCSPin = command[3];
spiWordSize = command[4];
// Send First Packet's 8 Data Bytes
for(int i=0; i<command[5]; i++)
{
// If this is the start of a new word toggle CS LOW
if( (spiBytesSent == 0) || (spiBytesSent % spiWordSize == 0) )
{
digitalWrite(spiCSPin, LOW);
}
// Send SPI Byte
Serial.print(SPI.transfer(command[i+6]));
spiBytesSent++;
// If word is complete set CS High
if(spiBytesSent % spiWordSize == 0)
{
digitalWrite(spiCSPin, HIGH);
}
}
}
else
{
// SPI Data Packet - Send SPI Bytes
for(int i=0; i<command[3]; i++)
{
// If this is the start of a new word toggle CS LOW
if( (spiBytesSent == 0) || (spiBytesSent % spiWordSize == 0) )
{
digitalWrite(spiCSPin, LOW);
}
// Send SPI Byte
Serial.write(SPI.transfer(command[i+4]));
spiBytesSent++;
// If word is complete set CS High
if(spiBytesSent % spiWordSize == 0)
{
digitalWrite(spiCSPin, HIGH);
}
}
}
}
// Synchronizes with LabVIEW and sends info about the board and firmware (Unimplemented)
void syncLV()
{
Serial.begin(DEFAULTBAUDRATE);
i2cReadTimeouts = 0;
spiBytesSent = 0;
spiBytesToSend = 0;
Serial.flush();
}
// Compute Packet Checksum
unsigned char checksum_Compute(unsigned char command[])
{
unsigned char checksum;
for (int i=0; i<(COMMANDLENGTH-1); i++)
{
checksum += command;
}
return checksum;
}
// Compute Packet Checksum And Test Against Included Checksum
int checksum_Test(unsigned char command[])
{
unsigned char checksum = checksum_Compute(command);
if(checksum == command[COMMANDLENGTH-1])
{
return 0;
}
else
{
return 1;
}
}
// Stepper Functions
#ifdef STEPPER_SUPPORT
void AccelStepper_Write(unsigned char command[]){
int steps = 0;
int step_speed = 0;
int acceleration = 0;
//Number of steps & speed are a 16 bit values, split for data transfer. Reassemble 2 bytes to an int 16
steps = (int)(command[5] << 😎 + command[6];
step_speed = (int)(command[2] << 😎 + command[3];
acceleration = (int)(command[7] << 😎 + command[8];
steppers[command[4]].setMaxSpeed(step_speed);
if (acceleration == 0){
//Workaround AccelStepper bug that requires negative speed for negative step direction
if (steps < 0) step_speed = -step_speed;
steppers[command[4]].setSpeed(step_speed);
steppers[command[4]].move(steps);
}
else {
steppers[command[4]].setAcceleration(acceleration);
steppers[command[4]].move(steps);
}
}
#endif
void sampleContinously()
{
for(int i=0; i<iterations; i++)
{
retVal = analogRead(contAcqPin);
if(contAcqSpeed>1000) //delay Microseconds is only accurate for values less that 16383
{
Serial.write( (retVal >> 2));
delayMicroseconds(delayTime*1000000); //Delay for neccesary amount of time to achieve desired sample rate
}
else
{
Serial.write( (retVal & 0xFF) );
Serial.write( (retVal >> 8));
delay(delayTime*1000);
}
}
}
void finiteAcquisition(int analogPin, float acquisitionSpeed, int numberOfSamples)
{
//want to exit this loop every 8ms
acquisitionPeriod=1/acquisitionSpeed;
for(int i=0; i<numberOfSamples; i++)
{
retVal = analogRead(analogPin);
if(acquisitionSpeed>1000)
{
Serial.write( (retVal >> 2));
delayMicroseconds(acquisitionPeriod*1000000);
}
else
{
Serial.write( (retVal & 0xFF) );
Serial.write( (retVal >> 8));
delay(acquisitionPeriod*1000);
}
}
}
void lcd_print(unsigned char command[])
{
if(command[2] != 0)
{
// Base Specified By User
int base = 0;
switch(command[2])
{
case 0x01: // BIN
base = BIN;
break;
case 0x02: // DEC
base = DEC;
break;
case 0x03: // OCT
base = OCT;
break;
case 0x04: // HEX
base = HEX;
break;
default:
break;
}
for(int i=0; i<command[3]; i++)
{
lcd.print(command[i+4], base);
}
}
else
{
for(int i=0; i<command[3]; i++)
{
lcd.print((char)command[i+4]);
}
}
Serial.write('0');
}
May I know that is there any problem regarding the source code since I have no idea how to modify the code is already given. Thanks for your time to help me to resolve this problem.
Regards,
Wilson Leong
03-26-2013 12:32 AM
The firmware that you download with LIFA compiles and uploads as-is so there is not an issue with the code itself. Sammy is asking for an actual screenshot (a picutre) of the Arduino IDE when this error occurs. Sometimes a file will get opened twice for somereason in the same session of the IDE and will cause duplication errors.
P.S. You can edit your last post and remove the code from the main text.
03-26-2013 10:48 AM
Thanks for your time to reply back my answer. Actually I use the VIPM software to download LabVIEW Interface for Arduino and I have no idea how to modify the firmware as I downloaded from VIPM software. I open the LIFA_Base.ino file using the Arduino IDE software, the entire file are open together. I just upload the LIFA_Base.ino file to my arduino. When I upload the LIFA_Base.ino file to my Arduino, the error is displayed. The further error message is displayed as I mentioned before
May I know that what the problem that I faced? Thanks for your time.