Detab Arduino sketch

This commit is contained in:
Blokkendoos
2018-05-15 01:16:39 +02:00
parent 3995dddd08
commit dc1f236e02
7 changed files with 346 additions and 334 deletions

View File

@@ -4,7 +4,7 @@ SoftwareServo *SoftwareServo::first;
#define NO_ANGLE (0xff)
SoftwareServo::SoftwareServo() : pin(0),angle(NO_ANGLE),pulse0(0),min16(34),max16(150),next(0)
SoftwareServo::SoftwareServo() : pin(0), angle(NO_ANGLE), pulse0(0), min16(34), max16(150), next(0)
{}
void SoftwareServo::setMinimumPulse(uint16_t t)
@@ -24,105 +24,104 @@ uint8_t SoftwareServo::attach(int pinArg)
pulse0 = 0;
next = first;
first = this;
digitalWrite(pin,0);
pinMode(pin,OUTPUT);
digitalWrite(pin, 0);
pinMode(pin, OUTPUT);
return 1;
}
void SoftwareServo::detach()
{
for ( SoftwareServo **p = &first; *p != 0; p = &((*p)->next) ) {
if ( *p == this) {
*p = this->next;
this->next = 0;
return;
}
for (SoftwareServo **p=&first; *p!=0; p=&((*p)->next) ) {
if (*p == this) {
*p = this->next;
this->next = 0;
return;
}
}
}
void SoftwareServo::write(int angleArg)
{
if ( angleArg < 0) angleArg = 0;
if ( angleArg > 180) angleArg = 180;
angle = angleArg;
// bleh, have to use longs to prevent overflow, could be tricky if always a 16MHz clock, but not true
// That 64L on the end is the TCNT0 prescaler, it will need to change if the clock's prescaler changes,
// but then there will likely be an overflow problem, so it will have to be handled by a human.
pulse0 = (min16*16L*clockCyclesPerMicrosecond() + (max16-min16)*(16L*clockCyclesPerMicrosecond())*angle/180L)/64L;
if (angleArg < 0) angleArg = 0;
if (angleArg > 180) angleArg = 180;
angle = angleArg;
// bleh, have to use longs to prevent overflow, could be tricky if always a 16MHz clock, but not true
// That 64L on the end is the TCNT0 prescaler, it will need to change if the clock's prescaler changes,
// but then there will likely be an overflow problem, so it will have to be handled by a human.
pulse0 = (min16*16L*clockCyclesPerMicrosecond() + (max16-min16)*(16L*clockCyclesPerMicrosecond())*angle/180L)/64L;
}
uint8_t SoftwareServo::read()
{
return angle;
return angle;
}
uint8_t SoftwareServo::attached()
{
for ( SoftwareServo *p = first; p != 0; p = p->next ) {
if ( p == this) return 1;
}
return 0;
for (SoftwareServo *p=first; p!=0; p=p->next ) {
if (p == this) return 1;
}
return 0;
}
void SoftwareServo::refresh()
{
uint8_t count = 0, i = 0;
uint16_t base = 0;
SoftwareServo *p;
static unsigned long lastRefresh = 0;
unsigned long m = millis();
uint8_t count = 0, i = 0;
uint16_t base = 0;
SoftwareServo *p;
static unsigned long lastRefresh = 0;
unsigned long m = millis();
// if we haven't wrapped millis, and 20ms have not passed, then don't do anything
if ( m >= lastRefresh && m < lastRefresh + 20) return;
lastRefresh = m;
// if we haven't wrapped millis, and 20ms have not passed, then don't do anything
if (m >= lastRefresh && m < lastRefresh + 20) return;
lastRefresh = m;
for ( p = first; p != 0; p = p->next ) if ( p->pulse0) count++;
if ( count == 0) return;
for (p=first; p!=0; p=p->next ) if (p->pulse0) count++;
if (count == 0) return;
// gather all the SoftwareServos in an array
SoftwareServo *s[count];
for ( p = first; p != 0; p = p->next ) if ( p->pulse0) s[i++] = p;
// gather all the SoftwareServos in an array
SoftwareServo *s[count];
for (p=first; p !=0; p=p->next ) if (p->pulse0) s[i++] = p;
// bubblesort the SoftwareServos by pulse time, ascending order
for(;;) {
uint8_t moved = 0;
for ( i = 1; i < count; i++) {
if ( s[i]->pulse0 < s[i-1]->pulse0) {
SoftwareServo *t = s[i];
s[i] = s[i-1];
s[i-1] = t;
moved = 1;
}
}
if ( !moved) break;
// bubblesort the SoftwareServos by pulse time, ascending order
for(;;) {
uint8_t moved = 0;
for (i = 1; i < count; i++) {
if (s[i]->pulse0 < s[i-1]->pulse0) {
SoftwareServo *t = s[i];
s[i] = s[i-1];
s[i-1] = t;
moved = 1;
}
}
if (!moved) break;
}
// turn on all the pins
// Note the timing error here... when you have many SoftwareServos going, the
// ones at the front will get a pulse that is a few microseconds too long.
// Figure about 4uS/SoftwareServo after them. This could be compensated, but I feel
// it is within the margin of error of software SoftwareServos that could catch
// an extra interrupt handler at any time.
for ( i = 0; i < count; i++) digitalWrite( s[i]->pin, 1);
// turn on all the pins
// Note the timing error here... when you have many SoftwareServos going, the
// ones at the front will get a pulse that is a few microseconds too long.
// Figure about 4uS/SoftwareServo after them. This could be compensated, but I feel
// it is within the margin of error of software SoftwareServos that could catch
// an extra interrupt handler at any time.
for (i=0; i<count; i++) digitalWrite(s[i]->pin, 1);
uint8_t start = TCNT0;
uint8_t now = start;
uint8_t last = now;
uint8_t start = TCNT0;
uint8_t now = start;
uint8_t last = now;
// Now wait for each pin's time in turn..
for ( i = 0; i < count; i++) {
uint16_t go = start + s[i]->pulse0;
// Now wait for each pin's time in turn..
for (i=0; i<count; i++) {
uint16_t go = start + s[i]->pulse0;
// loop until we reach or pass 'go' time
for (;;) {
now = TCNT0;
if ( now < last) base += 256;
last = now;
if ( base+now > go) {
digitalWrite( s[i]->pin,0);
break;
}
}
// loop until we reach or pass 'go' time
for (;;) {
now = TCNT0;
if (now < last) base += 256;
last = now;
if (base+now > go) {
digitalWrite(s[i]->pin, 0);
break;
}
}
}
}

View File

@@ -14,6 +14,7 @@ class SoftwareServo
uint8_t max16; // maximum pulse, 16uS units, 0-4ms range (default is 150)
class SoftwareServo *next;
static SoftwareServo* first;
public:
SoftwareServo();
uint8_t attach(int); // attach to a pin, sets pinMode, returns 0 on failure, won't
@@ -24,8 +25,8 @@ class SoftwareServo
uint8_t attached();
void setMinimumPulse(uint16_t); // pulse length for 0 degrees in microseconds, 540uS default
void setMaximumPulse(uint16_t); // pulse length for 180 degrees in microseconds, 2400uS default
static void refresh(); // must be called at least every 50ms or so to keep servo alive
// you can call more often, it won't happen more than once every 20ms
static void refresh(); // must be called at least every 50ms or so to keep servo alive
// you can call more often, it won't happen more than once every 20ms
};
#endif

View File

@@ -1,7 +1,3 @@
/*
* Original Code: Copyright 2011 by Eberhard Rensch <http://pleasantsoftware.com/developer/3d>
*
@@ -35,26 +31,24 @@
#include "StepperModel.h"
#include "config.h"
#define TIMER_DELAY 1024
#define VERSIONCODE "Spherebot 2.1"
StepperModel xAxisStepper(
XAXIS_DIR_PIN, XAXIS_STEP_PIN, XAXIS_ENABLE_PIN, XAXIS_ENDSTOP_PIN,
XAXIS_MS1_PIN, XAXIS_MS2_PIN, XAXIS_MS3_PIN,
XAXIS_SLP_PIN, XAXIS_RST_PIN,
XAXIS_VMS1, XAXIS_VMS2, XAXIS_VMS3,
XAXIS_MIN_STEPCOUNT, XAXIS_MAX_STEPCOUNT,
XAXIS_STEPS_PER_FULL_ROTATION, XAXIS_MICROSTEPPING);
XAXIS_DIR_PIN, XAXIS_STEP_PIN, XAXIS_ENABLE_PIN, XAXIS_ENDSTOP_PIN,
XAXIS_MS1_PIN, XAXIS_MS2_PIN, XAXIS_MS3_PIN,
XAXIS_SLP_PIN, XAXIS_RST_PIN,
XAXIS_VMS1, XAXIS_VMS2, XAXIS_VMS3,
XAXIS_MIN_STEPCOUNT, XAXIS_MAX_STEPCOUNT,
XAXIS_STEPS_PER_FULL_ROTATION, XAXIS_MICROSTEPPING);
StepperModel rotationStepper(
YAXIS_DIR_PIN, YAXIS_STEP_PIN, YAXIS_ENABLE_PIN, YAXIS_ENDSTOP_PIN,
YAXIS_MS1_PIN, YAXIS_MS2_PIN, YAXIS_MS3_PIN,
YAXIS_SLP_PIN, YAXIS_RST_PIN,
YAXIS_VMS1, YAXIS_VMS2, YAXIS_VMS3,
YAXIS_MIN_STEPCOUNT, YAXIS_MIN_STEPCOUNT,
YAXIS_STEPS_PER_FULL_ROTATION, YAXIS_MICROSTEPPING);
YAXIS_DIR_PIN, YAXIS_STEP_PIN, YAXIS_ENABLE_PIN, YAXIS_ENDSTOP_PIN,
YAXIS_MS1_PIN, YAXIS_MS2_PIN, YAXIS_MS3_PIN,
YAXIS_SLP_PIN, YAXIS_RST_PIN,
YAXIS_VMS1, YAXIS_VMS2, YAXIS_VMS3,
YAXIS_MIN_STEPCOUNT, YAXIS_MIN_STEPCOUNT,
YAXIS_STEPS_PER_FULL_ROTATION, YAXIS_MICROSTEPPING);
SoftwareServo servo;
boolean servoEnabled=true;
@@ -71,7 +65,7 @@ int serial_count = 0; // current length of command
char *strchr_pointer; // just a pointer to find chars in the cmd string like X, Y, Z, E, etc
boolean comment_mode = false;
int next_command_request_counter = 0; //if this counter reaches the maximum then a "ok" is sent to request the nex command
int next_command_request_counter = 0; //if this counter reaches the maximum then a "ok" is sent to request the nex command
int next_command_request_maximum = 1000;
// end comm variables
@@ -86,79 +80,91 @@ double yscaling = Y_SCALING_FACTOR;
const double maxFeedrate = 2000.;
// ------
void setup()
{
Serial.begin(BAUDRATE);
Serial.print(VERSIONCODE);
Serial.print("\n");
clear_buffer();
// disable the Ethernet chip/SD card
pinMode(4, OUTPUT);
digitalWrite(4, HIGH);
servo.attach(SERVO_PIN_1);
servo.write(DEFAULT_PEN_UP_POSITION);
if(servoEnabled)
// flash ALT LED
pinMode(ALT_PIN, OUTPUT);
digitalWrite(ALT_PIN, HIGH);
delay(150);
digitalWrite(ALT_PIN, LOW);
delay(150);
digitalWrite(ALT_PIN, HIGH);
delay(150);
digitalWrite(ALT_PIN, LOW);
Serial.begin(BAUDRATE);
Serial.print(VERSIONCODE);
Serial.print("\n");
clear_buffer();
servo.attach(SERVO_PIN_1);
servo.write(DEFAULT_PEN_UP_POSITION);
if (servoEnabled)
{
for(int i=0; i<100; i++)
{
for(int i=0;i<100;i++)
{
SoftwareServo::refresh();
delay(4);
}
SoftwareServo::refresh();
delay(4);
}
//--- Activate the PWM timer
Timer1.initialize(TIMER_DELAY); // Timer for updating pwm pins
Timer1.attachInterrupt(doInterrupt);
}
// activate the PWM timer
Timer1.initialize(TIMER_DELAY); // Timer for updating pwm pins
Timer1.attachInterrupt(doInterrupt);
#ifdef AUTO_HOMING
xAxisStepper.autoHoming();
xAxisStepper.setTargetPosition(0.);
commitSteppers(maxFeedrate);
delay(2000);
xAxisStepper.enableStepper(false);
xAxisStepper.autoHoming();
xAxisStepper.setTargetPosition(0.);
commitSteppers(maxFeedrate);
delay(2000);
xAxisStepper.enableStepper(false);
#endif
}
void loop() // input loop, looks for manual input and then checks to see if and serial commands are coming in
{
get_command(); // check for Gcodes
if(servoEnabled)
if (servoEnabled)
SoftwareServo::refresh();
Serial.flush();
}
//--- Interrupt-Routine: Move the steppers
// Interrupt-Routine: Move the steppers
void doInterrupt()
{
if(isRunning)
if (isRunning)
{
if(next_command_request_counter++ > next_command_request_maximum)
{
//Serial.print("forced ok\n");
next_command_request_counter = 0;
}
if (intervals_remaining-- == 0)
isRunning = false;
else
{
rotationStepper.doStep(intervals);
xAxisStepper.doStep(intervals);
}
if (next_command_request_counter++ > next_command_request_maximum)
{
//Serial.print("forced ok\n");
next_command_request_counter = 0;
}
if (intervals_remaining-- == 0)
isRunning = false;
else
{
rotationStepper.doStep(intervals);
xAxisStepper.doStep(intervals);
}
}
}
void commitSteppers(double speedrate)
{
long deltaStepsX = xAxisStepper.delta;
if(deltaStepsX != 0L)
if (deltaStepsX != 0L)
{
xAxisStepper.enableStepper(true);
}
long deltaStepsY = rotationStepper.delta;
if(deltaStepsY != 0L)
if (deltaStepsY != 0L)
{
rotationStepper.enableStepper(true);
}
@@ -166,10 +172,10 @@ void commitSteppers(double speedrate)
double deltaDistanceX = xAxisStepper.targetPosition-xAxisStepper.getCurrentPosition();
double deltaDistanceY = rotationStepper.targetPosition-rotationStepper.getCurrentPosition();
// how long is our line length?
double distance = sqrt(deltaDistanceX*deltaDistanceX+deltaDistanceY*deltaDistanceY);
// compute number of intervals for this move
double sub1 = (60000.* distance / speedrate);
double sub2 = sub1 * 1000.;
@@ -191,7 +197,7 @@ void commitSteppers(double speedrate)
// Serial.print(masterSteps);
// Serial.print(" dDistX:");
// Serial.print(deltaDistanceX);
// Serial.print(" dDistY:");
// Serial.print(" dDistY:");
// Serial.print(deltaDistanceY);
// Serial.print(" distance:");
// Serial.print(distance);
@@ -219,7 +225,7 @@ void get_command() // gets commands from serial connection and then calls up sub
if (serial_char == '\n' || serial_char == '\r') // end of a command character
{
next_command_request_counter = 0;
next_command_request_counter = 0;
buffer[serial_count]=0;
process_commands(buffer, serial_count);
clear_buffer();
@@ -270,24 +276,23 @@ boolean getValue(char key, char command[], double* value)
void check_for_version_controll(char command)
{
if(command == 'V')
if (command == 'V')
{
Serial.print(VERSIONCODE);
Serial.print("\n");
}
}
void process_commands(char command[], int command_length) // deals with standardized input from serial connection
{
double nVal;
boolean hasNVal = getValue('N', command, &nVal);
//if(hasNVal) {Serial.println("linenumber detected");};
//if (hasNVal) {Serial.println("linenumber detected");};
double getcs;
boolean hasCS = getValue('*', command, &getcs);
//if(hasCS) {Serial.println("checksum detected");};
//if (hasCS) {Serial.println("checksum detected");};
// checksum code from reprap wiki
int cs = 0;
@@ -296,25 +301,25 @@ void process_commands(char command[], int command_length) // deals with standard
cs = cs ^ command[j];
cs &= 0xff; // Defensive programming...
if(!(cs == (int)getcs || hasCS == false)) // if checksum does not match
if (!(cs == (int)getcs || hasCS == false)) // if checksum does not match
{
Serial.print("rs ");
Serial.print((int)getcs);
Serial.print((int)getcs);
//Serial.print((int)nVal);
Serial.print("\n");
//Serial.flush();
//Serial.flush();
}
else //continue if checksum matches or none detected
else //continue if checksum matches or none detected
{
//Serial.println("checksum match ");
j=0;
j = 0;
while (j < MAX_CMD_SIZE )
{
if ((command[j] == 'G') || command[j] == 'M') {break;}
j++;
}
if(command_length == 1)
if (command_length == 1)
{
check_for_version_controll(command[0]);
}
@@ -328,43 +333,51 @@ void process_commands(char command[], int command_length) // deals with standard
double xVal;
boolean hasXVal = getValue('X', command, &xVal);
if(hasXVal) xVal*=zoom*xscaling;
if (hasXVal) xVal *= zoom*xscaling;
double yVal;
boolean hasYVal = getValue('Y', command, &yVal);
if(hasYVal) yVal*=zoom*yscaling;
if (hasYVal) yVal *= zoom*yscaling;
double zVal;
boolean hasZVal = getValue('Z', command, &zVal);
double iVal;
boolean hasIVal = getValue('I', command, &iVal);
if(hasIVal) iVal*=zoom;
if (hasIVal) iVal *= zoom;
double jVal;
boolean hasJVal = getValue('J', command, &jVal);
if(hasJVal) jVal*=zoom;
if (hasJVal) jVal *= zoom;
double rVal;
boolean hasRVal = getValue('R', command, &rVal);
if(hasRVal) rVal*=zoom;
if (hasRVal) rVal *= zoom;
double pVal;
boolean hasPVal = getValue('P', command, &pVal);
getValue('F', command, &feedrate);
xVal+=currentOffsetX;
yVal+=currentOffsetY;
xVal += currentOffsetX;
yVal += currentOffsetY;
if(absoluteMode)
if (absoluteMode)
{
if(hasXVal)
tempX=xVal;
if(hasYVal)
tempY=yVal;
if (hasXVal)
tempX = xVal;
if (hasYVal)
tempY = yVal;
}
else
{
if(hasXVal)
tempX+=xVal;
if(hasYVal)
tempY+=yVal;
if (hasXVal)
tempX += xVal;
if (hasYVal)
tempY += yVal;
}
switch(codenum)
switch (codenum)
{
case 0: // G0, Rapid positioning
xAxisStepper.setTargetPosition(tempX);
@@ -378,25 +391,25 @@ void process_commands(char command[], int command_length) // deals with standard
break;
case 2: // G2, Clockwise arc
case 3: // G3, Counterclockwise arc
if(hasIVal && hasJVal)
if (hasIVal && hasJVal)
{
double centerX=xAxisStepper.getCurrentPosition()+iVal;
double centerY=rotationStepper.getCurrentPosition()+jVal;
drawArc(centerX, centerY, tempX, tempY, (codenum==2));
}
else if(hasRVal)
else if (hasRVal)
{
//drawRadius(tempX, tempY, rVal, (codenum==2));
}
break;
case 4: // G4, Delay P ms
if(hasPVal)
if (hasPVal)
{
unsigned long endDelay = millis()+ (unsigned long)pVal;
while(millis()<endDelay)
{
delay(1);
if(servoEnabled)
if (servoEnabled)
SoftwareServo::refresh();
}
}
@@ -426,28 +439,14 @@ void process_commands(char command[], int command_length) // deals with standard
break;
case 300: // Servo Position
if(getValue('S', command, &value))
if (getValue('S', command, &value))
{
servoEnabled=true;
if(value<0.)
value=0.;
else if(value>180.)
{
value=DEFAULT_PEN_UP_POSITION;
servo.write((int)value);
for(int i=0;i<100;i++)
{
SoftwareServo::refresh();
delay(2);
}
servoEnabled=false;
}
servo.write((int)value);
moveServo(value);
}
break;
case 400: // Propretary: Reset X-Axis-Stepper settings to new object diameter
if(getValue('S', command, &value))
if (getValue('S', command, &value))
{
xAxisStepper.resetSteppersForObjectDiameter(value);
xAxisStepper.setTargetPosition(0.);
@@ -458,7 +457,7 @@ void process_commands(char command[], int command_length) // deals with standard
break;
case 401: // Propretary: Reset Y-Axis-Stepper settings to new object diameter
if(getValue('S', command, &value))
if (getValue('S', command, &value))
{
rotationStepper.resetSteppersForObjectDiameter(value);
rotationStepper.setTargetPosition(0.);
@@ -469,13 +468,14 @@ void process_commands(char command[], int command_length) // deals with standard
break;
case 402: // Propretary: Reset Y-Axis-Stepper settings to new object diameter
if(getValue('S', command, &value))
if (getValue('S', command, &value))
{
zoom = value/100;
}
break;
default:
break;
break;
}
}
@@ -492,6 +492,25 @@ void process_commands(char command[], int command_length) // deals with standard
}
}
void moveServo(double value)
{
servoEnabled = true;
if (value < 0.)
value = 0.;
else if (value > 180.)
{
value = DEFAULT_PEN_UP_POSITION;
servo.write((int)value);
for(int i=0; i<100; i++)
{
SoftwareServo::refresh();
delay(2);
}
servoEnabled = false;
}
servo.write((int)value);
}
/* This code was ported from the Makerbot/ReplicatorG java sources */
void drawArc(double centerX, double centerY, double endpointX, double endpointY, boolean clockwise)
{
@@ -516,7 +535,6 @@ void drawArc(double centerX, double centerY, double endpointX, double endpointY,
bX = endpointX - centerX;
bY = endpointY - centerY;
// Clockwise
if (clockwise) {
angleA = atan2(bY, bX);
angleB = atan2(aY, aX);
@@ -534,7 +552,7 @@ void drawArc(double centerX, double centerY, double endpointX, double endpointY,
if (angleB <= angleA)
angleB += 2. * M_PI;
angle = angleB - angleA;
// calculate a couple useful things.
radius = sqrt(aX * aX + aY * aY);
length = radius * angle;
@@ -554,24 +572,24 @@ void drawArc(double centerX, double centerY, double endpointX, double endpointY,
for (s = 1; s <= steps; s++) {
// Forwards for CCW, backwards for CW
if (!clockwise)
step = s;
if (clockwise)
step = steps - s;
else
step = steps - s;
step = s;
// calculate our waypoint.
newPointX = centerX + radius * cos(angleA + angle * ((double) step / steps));
newPointY= centerY + radius * sin(angleA + angle * ((double) step / steps));
newPointY= centerY + radius * sin(angleA + angle * ((double) step / steps));
// start the move
xAxisStepper.setTargetPosition(newPointX);
rotationStepper.setTargetPosition(newPointY);
commitSteppers(feedrate);
while(isRunning)
while (isRunning)
{
delay(1);
if(servoEnabled)
if (servoEnabled)
SoftwareServo::refresh();
};
}

View File

@@ -30,8 +30,8 @@ StepperModel::StepperModel(
long minSC, long maxSC,
double in_kStepsPerRevolution, int in_kMicroStepping)
{
kStepsPerRevolution=in_kStepsPerRevolution;
kMicroStepping=in_kMicroStepping;
kStepsPerRevolution = in_kStepsPerRevolution;
kMicroStepping = in_kMicroStepping;
dirPin = inDirPin;
stepPin = inStepPin;
@@ -46,35 +46,32 @@ StepperModel::StepperModel(
minStepCount=minSC;
maxStepCount=maxSC;
pinMode(dirPin, OUTPUT);
pinMode(stepPin, OUTPUT);
pinMode(enablePin, OUTPUT);
if((sleepPin >=0))
{
pinMode(dirPin, OUTPUT);
pinMode(stepPin, OUTPUT);
pinMode(enablePin, OUTPUT);
if (sleepPin >=0) {
pinMode(sleepPin, OUTPUT);
digitalWrite(sleepPin, HIGH);
}
if((resetPin >=0))
{
if (resetPin >=0) {
pinMode(resetPin, OUTPUT);
digitalWrite(resetPin, HIGH);
}
if(endStopPin>=0)
pinMode(endStopPin, INPUT);
if((ms1Pin >=0))
{
pinMode(ms1Pin, OUTPUT);
digitalWrite(ms1Pin, vms1);
if (endStopPin>=0) {
pinMode(endStopPin, INPUT);
}
if((ms2Pin >=0))
{
pinMode(ms2Pin, OUTPUT);
digitalWrite(ms2Pin, vms1);
if (ms1Pin >=0) {
pinMode(ms1Pin, OUTPUT);
digitalWrite(ms1Pin, vms1);
}
if((ms3Pin >=0))
{
pinMode(ms3Pin, OUTPUT);
digitalWrite(ms3Pin, vms1);
if (ms2Pin >=0) {
pinMode(ms2Pin, OUTPUT);
digitalWrite(ms2Pin, vms1);
}
if (ms3Pin >=0) {
pinMode(ms3Pin, OUTPUT);
digitalWrite(ms3Pin, vms1);
}
digitalWrite(dirPin, LOW);
@@ -91,7 +88,7 @@ void StepperModel::resetSteppersForObjectDiameter(double diameter)
{
// Calculate the motor steps required to move per mm.
steps_per_mm = (int)((kStepsPerRevolution/(diameter*M_PI))*kMicroStepping+0.5);
if(endStopPin>=0)
if (endStopPin>=0)
{
#ifdef AUTO_HOMING
autoHoming();
@@ -105,12 +102,10 @@ void StepperModel::resetSteppersForObjectDiameter(double diameter)
long StepperModel::getStepsForMM(double mm)
{
long steps = (long)(steps_per_mm*mm);
// Serial.print("steps for ");
// Serial.print(mm);
// Serial.print(" mm: ");
// Serial.println(steps);
return steps;
}
@@ -126,8 +121,8 @@ void StepperModel::setTargetStepcount(long tsc)
enableStepper(true);
}
if (delta < 0) {
delta = -delta;
direction = false;
delta = -delta;
direction = false;
}
}*/
@@ -142,14 +137,14 @@ void StepperModel::setTargetPosition(double pos)
enableStepper(true);
}
if (delta < 0) {
delta = -delta;
direction = false;
delta = -delta;
direction = false;
}
}
double StepperModel::getCurrentPosition()
{
return (double)currentStepcount/steps_per_mm;
return (double)currentStepcount/steps_per_mm;
}
void StepperModel::enableStepper(bool enabled)
@@ -160,26 +155,28 @@ void StepperModel::enableStepper(bool enabled)
void StepperModel::resetStepper()
{
enableStepper(false);
currentStepcount=0;
targetStepcount=0;
delta=0;
currentStepcount = 0;
targetStepcount = 0;
delta = 0;
}
void StepperModel::doStep(long intervals)
{
counter += delta;
if (counter >= 0) {
if (counter >= 0)
{
digitalWrite(dirPin, direction?HIGH:LOW);
counter -= intervals;
if (direction) {
if(maxStepCount==0 || currentStepcount<=maxStepCount)
{
if (direction)
{
if (maxStepCount == 0 || currentStepcount<=maxStepCount) {
digitalWrite(stepPin, HIGH);
currentStepcount++;
}
} else {
if(minStepCount==0 || currentStepcount>=minStepCount)
{
}
else
{
if (minStepCount == 0 || currentStepcount>=minStepCount) {
digitalWrite(stepPin, HIGH);
currentStepcount--;
}
@@ -196,11 +193,11 @@ void StepperModel::autoHoming()
while(digitalRead(endStopPin))
{
digitalWrite(stepPin, HIGH);
digitalWrite(stepPin, LOW);
delay(1);
digitalWrite(stepPin, HIGH);
digitalWrite(stepPin, LOW);
delay(1);
}
currentStepcount= minStepCount-16;
currentStepcount = minStepCount-16;
}
#endif

View File

@@ -24,7 +24,6 @@
class StepperModel
{
private:
int dirPin;
int stepPin;
int enablePin;
@@ -68,7 +67,6 @@ public:
#ifdef AUTO_HOMING
void autoHoming();
#endif
void setTargetPosition(double pos);
double getCurrentPosition();

View File

@@ -19,17 +19,17 @@
* - renamed startBottom() to start(). This breaks some old code that expects start to continue counting where it left off
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* See Google Code project http://code.google.com/p/arduino-timerone/ for latest
*/
@@ -54,19 +54,19 @@ void TimerOne::initialize(long microseconds)
}
void TimerOne::setPeriod(long microseconds) // AR modified for atomic access
void TimerOne::setPeriod(long microseconds) // AR modified for atomic access
{
long cycles = (F_CPU / 2000000) * microseconds; // the counter runs backwards after TOP, interrupt is at BOTTOM so divide microseconds by 2
if(cycles < RESOLUTION) clockSelectBits = _BV(CS10); // no prescale, full xtal
else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11); // prescale by /8
else if((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11) | _BV(CS10); // prescale by /64
else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12); // prescale by /256
else if((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12) | _BV(CS10); // prescale by /1024
if (cycles < RESOLUTION) clockSelectBits = _BV(CS10); // no prescale, full xtal
else if ((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11); // prescale by /8
else if ((cycles >>= 3) < RESOLUTION) clockSelectBits = _BV(CS11) | _BV(CS10); // prescale by /64
else if ((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12); // prescale by /256
else if ((cycles >>= 2) < RESOLUTION) clockSelectBits = _BV(CS12) | _BV(CS10); // prescale by /1024
else cycles = RESOLUTION - 1, clockSelectBits = _BV(CS12) | _BV(CS10); // request was out of bounds, set as maximum
oldSREG = SREG;
cli(); // Disable interrupts for 16 bit register access
oldSREG = SREG;
cli(); // Disable interrupts for 16 bit register access
ICR1 = pwmPeriod = cycles; // ICR1 is TOP in p & f correct pwm mode
SREG = oldSREG;
@@ -83,79 +83,79 @@ void TimerOne::setPwmDuty(char pin, int duty)
oldSREG = SREG;
cli();
if(pin == 1 || pin == 9) OCR1A = dutyCycle;
else if(pin == 2 || pin == 10) OCR1B = dutyCycle;
if (pin == 1 || pin == 9) OCR1A = dutyCycle;
else if (pin == 2 || pin == 10) OCR1B = dutyCycle;
SREG = oldSREG;
}
void TimerOne::pwm(char pin, int duty, long microseconds) // expects duty cycle to be 10 bit (1024)
{
if(microseconds > 0) setPeriod(microseconds);
if(pin == 1 || pin == 9) {
if (microseconds > 0) setPeriod(microseconds);
if (pin == 1 || pin == 9) {
DDRB |= _BV(PORTB1); // sets data direction register for pwm output pin
TCCR1A |= _BV(COM1A1); // activates the output pin
}
else if(pin == 2 || pin == 10) {
else if (pin == 2 || pin == 10) {
DDRB |= _BV(PORTB2);
TCCR1A |= _BV(COM1B1);
}
setPwmDuty(pin, duty);
resume(); // Lex - make sure the clock is running. We don't want to restart the count, in case we are starting the second WGM
// and the first one is in the middle of a cycle
resume(); // Lex - make sure the clock is running. We don't want to restart the count, in case we are starting the second WGM
// and the first one is in the middle of a cycle
}
void TimerOne::disablePwm(char pin)
{
if(pin == 1 || pin == 9) TCCR1A &= ~_BV(COM1A1); // clear the bit that enables pwm on PB1
else if(pin == 2 || pin == 10) TCCR1A &= ~_BV(COM1B1); // clear the bit that enables pwm on PB2
if (pin == 1 || pin == 9) TCCR1A &= ~_BV(COM1A1); // clear the bit that enables pwm on PB1
else if (pin == 2 || pin == 10) TCCR1A &= ~_BV(COM1B1); // clear the bit that enables pwm on PB2
}
void TimerOne::attachInterrupt(void (*isr)(), long microseconds)
{
if(microseconds > 0) setPeriod(microseconds);
if (microseconds > 0) setPeriod(microseconds);
isrCallback = isr; // register the user's callback with the real ISR
TIMSK1 = _BV(TOIE1); // sets the timer overflow interrupt enable bit
// might be running with interrupts disabled (eg inside an ISR), so don't touch the global state
// might be running with interrupts disabled (eg inside an ISR), so don't touch the global state
// sei();
resume();
resume();
}
void TimerOne::detachInterrupt()
{
TIMSK1 &= ~_BV(TOIE1); // clears the timer overflow interrupt enable bit
// timer continues to count without calling the isr
// timer continues to count without calling the isr
}
void TimerOne::resume() // AR suggested
void TimerOne::resume() // AR suggested
{
TCCR1B |= clockSelectBits;
}
void TimerOne::restart() // Depricated - Public interface to start at zero - Lex 10/9/2011
void TimerOne::restart() // Depricated - Public interface to start at zero - Lex 10/9/2011
{
start();
start();
}
void TimerOne::start() // AR addition, renamed by Lex to reflect it's actual role
void TimerOne::start() // AR addition, renamed by Lex to reflect it's actual role
{
unsigned int tcnt1;
TIMSK1 &= ~_BV(TOIE1); // AR added
GTCCR |= _BV(PSRSYNC); // AR added - reset prescaler (NB: shared with all 16 bit timers);
GTCCR |= _BV(PSRSYNC); // AR added - reset prescaler (NB: shared with all 16 bit timers);
oldSREG = SREG; // AR - save status register
cli(); // AR - Disable interrupts
TCNT1 = 0;
SREG = oldSREG; // AR - Restore status register
resume();
do { // Nothing -- wait until timer moved on from zero - otherwise get a phantom interrupt
oldSREG = SREG;
cli();
tcnt1 = TCNT1;
SREG = oldSREG;
oldSREG = SREG; // AR - save status register
cli(); // AR - Disable interrupts
TCNT1 = 0;
SREG = oldSREG; // AR - Restore status register
resume();
do { // Nothing -- wait until timer moved on from zero - otherwise get a phantom interrupt
oldSREG = SREG;
cli();
tcnt1 = TCNT1;
SREG = oldSREG;
} while (tcnt1==0);
// TIFR1 = 0xff; // AR - Clear interrupt flags
// TIFR1 = 0xff; // AR - Clear interrupt flags
// TIMSK1 = _BV(TOIE1); // sets the timer overflow interrupt enable bit
}
@@ -164,46 +164,46 @@ void TimerOne::stop()
TCCR1B &= ~(_BV(CS10) | _BV(CS11) | _BV(CS12)); // clears all clock selects bits
}
unsigned long TimerOne::read() //returns the value of the timer in microseconds
{ //rember! phase and freq correct mode counts up to then down again
unsigned long tmp; // AR amended to hold more than 65536 (could be nearly double this)
unsigned int tcnt1; // AR added
unsigned long TimerOne::read() //returns the value of the timer in microseconds
{ //rember! phase and freq correct mode counts up to then down again
unsigned long tmp; // AR amended to hold more than 65536 (could be nearly double this)
unsigned int tcnt1; // AR added
oldSREG= SREG;
cli();
tmp=TCNT1;
SREG = oldSREG;
oldSREG= SREG;
cli();
tmp=TCNT1;
SREG = oldSREG;
char scale=0;
switch (clockSelectBits)
{
case 1:// no prescalse
scale=0;
break;
case 2:// x8 prescale
scale=3;
break;
case 3:// x64
scale=6;
break;
case 4:// x256
scale=8;
break;
case 5:// x1024
scale=10;
break;
}
do { // Nothing -- max delay here is ~1023 cycles. AR modified
oldSREG = SREG;
cli();
tcnt1 = TCNT1;
SREG = oldSREG;
} while (tcnt1==tmp); //if the timer has not ticked yet
char scale=0;
switch (clockSelectBits)
{
case 1:// no prescalse
scale = 0;
break;
case 2:// x8 prescale
scale = 3;
break;
case 3:// x64
scale = 6;
break;
case 4:// x256
scale = 8;
break;
case 5:// x1024
scale = 10;
break;
}
//if we are counting down add the top value to how far we have counted down
tmp = ( (tcnt1>tmp) ? (tmp) : (long)(ICR1-tcnt1)+(long)ICR1 ); // AR amended to add casts and reuse previous TCNT1
return ((tmp*1000L)/(F_CPU /1000L))<<scale;
do { // Nothing -- max delay here is ~1023 cycles. AR modified
oldSREG = SREG;
cli();
tcnt1 = TCNT1;
SREG = oldSREG;
} while (tcnt1==tmp); //if the timer has not ticked yet
//if we are counting down add the top value to how far we have counted down
tmp = ( (tcnt1>tmp) ? (tmp) : (long)(ICR1-tcnt1) + (long)ICR1 ); // AR amended to add casts and reuse previous TCNT1
return ((tmp*1000L)/(F_CPU /1000L))<< scale;
}
#endif
#endif

View File

@@ -39,24 +39,23 @@
#include <avr/io.h>
#include <avr/interrupt.h>
#define RESOLUTION 65536 // Timer1 is 16 bit
#define RESOLUTION 65536 // Timer1 is 16 bit
class TimerOne
{
public:
// properties
unsigned int pwmPeriod;
unsigned char clockSelectBits;
char oldSREG; // To hold Status Register while ints disabled
char oldSREG; // To hold Status Register while ints disabled
// methods
void initialize(long microseconds=1000000);
void start();
void stop();
void restart();
void resume();
unsigned long read();
void resume();
unsigned long read();
void pwm(char pin, int duty, long microseconds=-1);
void disablePwm(char pin);
void attachInterrupt(void (*isr)(), long microseconds=-1);
@@ -67,4 +66,4 @@ class TimerOne
};
extern TimerOne Timer1;
#endif
#endif