[英]Why is DHT11 Sensor not giving correct readings on Arduino Mega?
[英]Arduino MEGA - Why is my timer interrupt incorrect on first run?
我正在使用 Arduino 计时器为 Arduino MEGA 2560 编写步进驱动程序类,但我遇到了一些意外行为,因为使用的计时器。 我要追求的本质如下:
为了测试这个类结构,我写了一个草图来测试运行步进电机一圈(子组件),提高速度,然后重复。 不幸的是,在我的草图的第一个循环(以及第四个循环)期间,我遇到了非常奇怪的计时器行为,其中计时器的频率似乎比预期的要高得多,因此以某种可怕的速度运行电机并且不是当前设置的“maxSpeed”。 循环 2 和 3 以及最多 10 次都显示了预期的行为,但我没有超过 10 次来寻找任何更深层次的模式。
我知道 init() 函数在设置之前会调整定时器寄存器,所以我在 setup() 中清除了定时器 1 到 5 的控制寄存器。 我想在这个应用程序中潜在地使用 micros() 和/或 millis(),所以我避免弄乱定时器 0。
在我进行了所有故障排除之后,我一直与两个潜在的根本原因保持一致(尽管我似乎无法找到两者的原因):
我使用的是 VS Code v1.62.0、Arduino 扩展 v0.4.7 和 C/C++ 扩展 v1.7.1。
下面是我的代码,以及运行我的测试的串行监视器输出。 任何人都可以找到我出错的地方吗? 预先感谢您的帮助!
CL42TClassTest.ino:
#include "CL42T.h"
// prescale value
int PreScale = 8;
// Step Counter
volatile unsigned long TestStepperSteps = 0;
bool oneShot = true;
const char TestStepperStepPort = 'E';
const int TestStepperStepBit = 3;
const int TestStepperControlBit = 2;
const int TestStepperTimerNum = 3;
const char TestStepperTimerOutput = 'A';
const int TestStepperOneRevSteps = 27774;
// create test stepper object (global object)
CL42T TestStepperDriveObject(TestStepperStepPort,TestStepperStepBit,TestStepperControlBit,TestStepperTimerNum,TestStepperTimerOutput,PreScale);
// Macros for anscillary equipment
#define VDC24_Setup DDRF |= B00010000 // set 24VDC Control Relay pin to OUTPUT
#define VDC24_On PORTF |= B00010000 // set 24VDC Control Relay pin HIGH
#define VDC24_Off PORTF &= B11101111 // set 24VDC Control Relay pin LOW
// max speed variable
int MAXspeed = 60;
void setup() {
Serial.begin(115200); // start serial at 115200 BAUD
while (!Serial) {
; // wait for serial to connect
}
// header
Serial.println(F("Program to test CL42T Class."));
// clear timer registers and print verification
clearTimersOneToFive();
Serial.println(F("Timers 1-5 Register Values After Reset:"));
// proceed to print out all timer 1-5 control registers, TCNT values, and OCR values...
// setup 24VDC relay and ensure OFF
Serial.print(F("Setting up 24VDC control relay..."));
VDC24_Setup;
VDC24_Off;
Serial.println(F("Done."));
// setup stepper drive object
Serial.print(F("Setting up Test Stepper drive object..."));
TestStepperDriveObject.SetupDrive();
Serial.println(F("Done."));
// Timer settings printout
Serial.println(F("Setup Timer Settings: "));
Serial.print(F("OCR3A Value: "));Serial.println(OCR3A);
Serial.print(F("TCNT3 Value: "));Serial.println(TCNT3);;
Serial.print(F("TCCR3A Value: "));prntByteBIN(TCCR3A);
Serial.print(F("TCCR3B Value: "));prntByteBIN(TCCR3B);
Serial.print(F("TCCR3C Value: "));prntByteBIN(TCCR3C);
Serial.print(F("TIMSK3 Value: "));prntByteBIN(TIMSK3);
Serial.print(F("TIFR3 Value: "));prntByteBIN(TIFR3);
// Step pin port values printout
Serial.println(F("Setup DDRE and PORTE: "));
Serial.print(F("DDRE = "));prntByteBIN(DDRE);
Serial.print(F("PORTE = "));prntByteBIN(PINE);
// indication for main loop start
Serial.println(F("Now starting main loop..."));
delay(1000);
}
void loop()
{
if (oneShot)
{
// Timer settings printout
Serial.println(F("First Loop Timer Settings:"));
// procede to print out all timer 1-5 control registers, TCNT, and OCR
// Step pin port values printout
Serial.println(F("First Loop DDRE and PORTE:"));
Serial.print(F("DDRE = "));prntByteBIN(DDRE);
Serial.print(F("PORTE = "));prntByteBIN(PINE);
// CL42T class settings
Serial.println(F("C42T Class Settings: "));
// proceed to print out all CL42T object values (addresses, masks, etc.)
// StepperSpeedRamp class settings
Serial.println(F("StepperSpeedRamp Class Settings:"));
// proceed to print out all StepperSpeedRamp object values
}
// set maxSpeed of drive & calculate OCR array, then apply
TestStepperDriveObject.SetMaxSpeed(MAXspeed);
TestStepperDriveObject.ApplyNewSpeed();
// turn on 24 VDC
Serial.print(F("Turning on 24VDC Control Relay..."));
VDC24_On;
Serial.println(F("Done."));
delay(1000);
// enable drive
Serial.print(F("Enabling Test Stepper Drive..."));
TestStepperDriveObject.EnableDrive();
Serial.println(F("Done."));
delayMicroseconds(500);
// set drive direction
Serial.print(F("Setting Test Stepper Direction to FWD..."));
TestStepperDriveObject.SetDirection('F');
Serial.println(F("Done."));
delayMicroseconds(500);
// move stepper drive one revolution
Serial.print(F("Starting Test Stepper at "));Serial.print(MAXspeed);Serial.println(F(" mm/s for one revolution..."));
TestStepperDriveObject.Increment(TestStepperOneRevSteps);
// monitor for end of movement
while (TestStepperSteps < TestStepperDriveObject.incrementSteps)
{
Serial.print(F("Steps taken: "));Serial.println(TestStepperSteps);
delay(250);
}
Serial.println(F("Done."));
// clear step tracker
TestStepperSteps = 0;
delayMicroseconds(500);
// disable stepper drive
Serial.print(F("Disabling Test Stepper Drive..."));
TestStepperDriveObject.DisableDrive();
Serial.println(F("Done."));
delayMicroseconds(500);
// turn off 24VDC
Serial.print(F("Turning off 24VDC Control Relay..."));
VDC24_Off;
Serial.println(F("Done."));
// adjust max speed up 20 mm/s
MAXspeed += 20;
// delay to slow test progression
delay(3000);
}
void prntByteBIN(byte b)
{
for(int i = 7; i >= 0; i--)
{
Serial.print(bitRead(b,i));
}
Serial.println();
}
void clearTimersOneToFive()
{
noInterrupts();
TCCR1A = 0;
TCCR1B = 0;
TCCR1C = 0;
TIMSK1 = 0;
TCNT1H = 0;
TCNT1L = 0;
TIFR1 |= B00001111;
TCCR2A = 0;
TCCR2B = 0;
TIMSK2 = 0;
TCNT2 = 0;
TIFR2 |= B00001111;
TCCR3A = 0;
TCCR3B = 0;
TCCR3C = 0;
TIMSK3 = 0;
TCNT3H = 0;
TCNT3L = 0;
TIFR3 |= B00001111;
TCCR4A = 0;
TCCR4B = 0;
TCCR4C = 0;
TIMSK4 = 0;
TCNT4H = 0;
TCNT4L = 0;
TIFR4 |= B00001111;
TCCR5A = 0;
TCCR5B = 0;
TCCR5C = 0;
TIMSK5 = 0;
TCNT5H = 0;
TCNT5L = 0;
TIFR5 |= B00001111;
interrupts();
}
// Test Stepper Step Interrupt
ISR(TIMER3_COMPA_vect) {
if (((*TestStepperDriveObject.stepPIN) & (1<<TestStepperDriveObject.stepBIT))) {
TestStepperSteps++;
if ((TestStepperDriveObject.incrementSteps > 0) && (TestStepperSteps >= TestStepperDriveObject.incrementSteps))
{
TestStepperDriveObject.StopDrive(); // position reached, stop drive
// TestStepperSteps = 0;
}
if (TestStepperSteps <= TestStepperDriveObject.accelSteps)
{ // acceleration phase
if (!(TestStepperSteps % TestStepperDriveObject.speedUpdateSteps))
{
TestStepperDriveObject.accelDecelIndex++;
*TestStepperDriveObject.stepOCRH = highByte(TestStepperDriveObject.OCRarray[TestStepperDriveObject.accelDecelIndex]);
*TestStepperDriveObject.stepOCRL = lowByte(TestStepperDriveObject.OCRarray[TestStepperDriveObject.accelDecelIndex]);
}
}
if ((TestStepperDriveObject.incrementSteps > 0) && (TestStepperSteps >= (TestStepperDriveObject.incrementSteps - TestStepperDriveObject.decelSteps)))
{ // deceleration phase - position tracking only
if (!(TestStepperSteps % TestStepperDriveObject.speedUpdateSteps))
{
*TestStepperDriveObject.stepOCRH = highByte(TestStepperDriveObject.OCRarray[TestStepperDriveObject.accelDecelIndex]);
*TestStepperDriveObject.stepOCRL = lowByte(TestStepperDriveObject.OCRarray[TestStepperDriveObject.accelDecelIndex]);
TestStepperDriveObject.accelDecelIndex--;
}
}
}
}
CL42T.h:
#ifndef CL42T_h
#define CL42T_h
#include "Arduino.h"
#include "StepperSpeedRamp.h"
class CL42T: public StepperSpeedRamp
{
public:
// register pointers
volatile uint8_t *directionPORT;
volatile uint8_t *directionDDR;
volatile uint8_t *directionPIN;
volatile uint8_t *enablePORT;
volatile uint8_t *enableDDR;
volatile uint8_t *enablePIN;
volatile uint8_t *alarmPORT;
volatile uint8_t *alarmDDR;
volatile uint8_t *alarmPIN;
volatile uint8_t *stepPORT;
volatile uint8_t *stepDDR;
volatile uint8_t *stepPIN;
volatile uint8_t *stepTCCRA;
volatile uint8_t *stepTCCRB;
volatile uint8_t *stepTCCRC;
volatile uint8_t *stepTIMSK;
volatile uint8_t *stepTIFR;
volatile uint8_t *stepTCNTH;
volatile uint8_t *stepTCNTL;
volatile uint8_t *stepOCRH;
volatile uint8_t *stepOCRL;
volatile uint8_t *stepOCRH2;
volatile uint8_t *stepOCRL2;
// timer register masks
uint8_t stepTCCRAmask;
uint8_t stepTCCRAOutput1Mask;
uint8_t stepTCCRAOutput2Mask;
uint8_t stepTCCRBmask;
uint8_t stepTCCRBstartMask;
uint8_t stepTimerOutputInterrupt1Mask;
// dual or single motor toggle variable
volatile int numMOTORS;
// step and control bits
volatile int stepBIT;
volatile int stepBIT2;
volatile int controlBIT;
volatile int controlBIT2;
// step target value
volatile int incrementSteps;
// single motor constructor:
CL42T(char StepPort, int StepBit, int ControlBit, int TimerNum, char TimerOutput, int PreScale);
// dual motor constructor:
CL42T(char StepPort1, int StepBit1, int ControlBit1, int TimerNum1, char TimerOutput1, int StepBit2, int ControlBit2, char TimerOutput2, int PreScale);
void SetupDrive(); // setup pointers, port directions, etc.
void ApplyNewSpeed(); // set OCRL/OCRH to OCRarray[0]
void SetDirection(char DriveDir); // set direction of CL42T stepper driver
void EnableDrive(); // enable CL42T stepper driver
void DisableDrive(); // disable CL42T stepper driver
void RunDrive(); // run single mmotor or both motors
void StopDrive(); // stop single motor or both motors
void Increment(int IncrementSteps); // run at maxSpeed for IncrementSteps
};
#endif
CL42T.cpp:
#include "Arduino.h"
#include "CL42T.h"
/*
* Single Motor Constructor:
* - set numMOTORS to 1
* - copy relevant parameters
* - set step pointers
* - set timer pointers and timer masks
*/
CL42T::CL42T(char StepPort, int StepBit, int ControlBit, int TimerNum, char TimerOutput, int PreScale)
:StepperSpeedRamp(PreScale)
{
// this is the single motor constructor - sets timer register pointers and timer register masks.
}
/*
* Dual Motor Constructor:
* - set numMOTORS to 2
* - copy relevant parameters
* - set step pointers
* - set timer pointers and timer masks
*/
CL42T::CL42T(char StepPort, int StepBit1, int ControlBit1, int TimerNum, char TimerOutput1, int StepBit2, int ControlBit2, char TimerOutput2, int PreScale)
:StepperSpeedRamp(PreScale)
{
// this is the dual motor constructor - sets timer register pointers and timer register masks.
}
/*
* Setup:
* - Set control I/O registers
* - Clear timer registers
* - Setup timer, but don't start it
*/
void CL42T::SetupDrive()
{
// clear timer registers and any pending interrupt flags, set timer control registers, clear TCNT, and set initial OCR value. This function DOES NOT set the clock select bits, as this is not the desired point for the timer to run.
}
void CL42T::ApplyNewSpeed()
{ // set OCR value from OCRarray[0]
}
void CL42T::SetDirection(char DriveDir)
{
// set direction pin LOW or HIGH
}
void CL42T::EnableDrive()
{
// set enable pin HIGH
}
void CL42T::DisableDrive()
{
// set enable pin LOW
}
void CL42T::RunDrive()
{
// TCNT to zero, clear pending timer compare match interrupt flags, set clock select bits to start timer
}
void CL42T::StopDrive()
{
// clear clock select bits in TCCRB to stop timer, disable timer interrupt, clear TCNT
}
void CL42T::Increment(int IncrementSteps)
{
// set target steps, then call RunDrive()
}
StepperSpeedRamp.h:
#ifndef StepperSpeedRamp_h
#define StepperSpeedRamp_h
#include "Arduino.h"
// Stepper Speed Ramp Class for CL42T drives
class StepperSpeedRamp
{
public:
// drive settings
double maxSpeed; // mm/s
// variables for speed ramp calculations
double Accel; // mm/s/s
double Decel; // mm/s/s
double mmPerStep; // mm/step
int preScale; // prescale selection
long CntFreq; // counter frequency
int speedUpdateSteps; // # steps
long maxSpeedSteps; // # steps
long maxAccelSteps; // # steps
long accelSteps; // # steps
long decelSteps; // # steps
long numStepsTemp; // # steps
long OCRmin;
long OCRo;
// speed update index (OCRarray[])
volatile int accelDecelIndex;
// speed ramp OCR values
volatile uint16_t OCRarray[21];
// member functions
StepperSpeedRamp(int PreScale);
void SetMaxSpeed(int MmPerSec);
void CalculateSpeedRamp();
};
#endif
StepperSpeedRamp.cpp:
#include "Arduino.h"
#include "math.h"
#include "StepperSpeedRamp.h"
/*
* Stepper Speed Ramp Class
*/
StepperSpeedRamp::StepperSpeedRamp(int PreScale)
{
// drive settings
maxSpeed = 60; // mm/s - default @ 60
// variables for speed ramp calculations
Accel = maxSpeed*10; // mm/s/s - accelerate in 100 ms
Decel = maxSpeed*10; // mm/s/s - decelerate in 100 ms
mmPerStep = 0.04; // mm/step
preScale = PreScale; // copy prescale value into object
CntFreq = 16000000/preScale; // calculate counter frequency at PreScale
speedUpdateSteps = 0; // # steps
maxSpeedSteps = 0; // # steps
maxAccelSteps = 0; // # steps
accelSteps = 0; // # steps
decelSteps = 0; // # steps
numStepsTemp = 10000; // use 10,000 steps as the calculation for speed ramp
OCRmin = 0; // minimum delay --> max speed
OCRo = 0; // first delay --> start speed (based on acceleration)
accelDecelIndex = 0; // speed update index (OCRarray[])
CalculateSpeedRamp(); // calculate OCRarray
}
void StepperSpeedRamp::SetMaxSpeed(int MmPerSec)
{
maxSpeed = MmPerSec; // set new maxSpeed value
Accel = maxSpeed*10; // accelerate in 100 ms
Decel = maxSpeed*10; // decelerate in 100 ms
CalculateSpeedRamp(); // calculate new OCRarray
}
void StepperSpeedRamp::CalculateSpeedRamp()
{
OCRmin = ((mmPerStep*(CntFreq/2))/(maxSpeed)); // calculate minimum OCR - based on max speed
OCRo = ((CntFreq/2)*sqrt((2*mmPerStep)/Accel)); // calculate first OCR value - based on accel
OCRarray[0] = OCRo; // load first OCR value into OCRarray
maxSpeedSteps = ((maxSpeed*maxSpeed)/(2*mmPerStep*Accel)); // calculate steps required to reach max speed
maxAccelSteps = ((numStepsTemp*Decel)/(Accel+Decel)); // calculate steps required to reach max deceleration phase
if (maxSpeedSteps < maxAccelSteps)
{ // trapezoidal speed profile
accelSteps = maxSpeedSteps;
decelSteps = (accelSteps*(Accel/Decel));
}
else if (maxSpeedSteps >= maxAccelSteps)
{ // triangular speed profile
accelSteps = maxAccelSteps;
decelSteps = (accelSteps*(Accel/Decel));
}
speedUpdateSteps = accelSteps / ((sizeof(OCRarray)/2)-2); // 0 indexed AND OCR[0] is already filled.
for (int i = 1;i < (sizeof(OCRarray)/2);i++)
{ // populate OCR array
OCRarray[i] = (OCRo*(sqrt((i*speedUpdateSteps)+1)-sqrt((i*speedUpdateSteps))));
}
}
好吧,老实说,我认为您提供了太多不相关的代码,这使得您很难分析您放在一起的内容。 Atmel 助记符(例如 TCCR1A)并没有让它变得更容易。 我可以推荐的是将一组 LED 连接到输出端口(您打算连接到步进电机的那些),减慢计时器的速度,以便 ISR 每几秒触发一次,并验证您获得正确的信号模式。 从那里开始,增加频率并继续前进。
好的,我已经剥离了代码,并将它们组合成一个文件,以简化对架构概念的测试(代码嵌入在最后)。
我想我已经找到了确凿的证据——我的 OCR 寄存器设置得太低,可能是加速阶段的最后一次分配。 我通过在打印当前步数的同时打印当前 OCR 值来捕获它。 这是显示吸烟枪的串行输出的片段:
Setting max speed...Done.
maxSpeed = 60
Accel = 600
Decel = 600
maxSpeedSteps = 75
maxAccelSteps = 5000
accelSteps = 75
decelSteps = 75
OCRo = 11547
OCRmin = 666
OCR 1 = 3094
OCR 2 = 2266
OCR 3 = 1873
OCR 4 = 1633
OCR 5 = 1466
OCR 6 = 1342
OCR 7 = 1245
OCR 8 = 1166
OCR 9 = 1101
OCR 10 = 1045
OCR 11 = 997
OCR 12 = 955
OCR 13 = 918
OCR 14 = 885
OCR 15 = 855
OCR 16 = 829
OCR 17 = 804
OCR 18 = 782
OCR 19 = 761
OCR 20 = 742
Starting movement...
OCR3A = 11547
Steps taken: 60
OCR3A = 742
Steps taken: 298
OCR3A = 144 <---------- OCR somehow too low
Steps taken: 1002
OCR3A = 144 <---------- OCR somehow too low
Steps taken: 1707
OCR3A = 144 <---------- OCR somehow too low
Steps taken: 2412
OCR3A = 144 <---------- OCR somehow too low
Steps taken: 3117
OCR3A = 144 <---------- OCR somehow too low
Steps taken: 3822
OCR3A = 144 <---------- OCR somehow too low
... // and it continues on until deceleration, which behaves as it should.
我的假设是我正在为 OCR 寄存器分配一个值,该值超出了我的 OCR 数组的范围。 但是,我不确定它是如何发生的。 步数只在加速阶段和减速阶段更新,速度更新“距离”(调整 OCR 之前的步数)是根据加速步数计算的,所以我看不出如何得到数组之间的不匹配索引和数组边界。 有任何想法吗?
代码:
#include "math.h"
class SpeedRamp
{
public:
// private:
long maxSpeed; // mm/s
long Accel; // mm/s/s
long Decel; // mm/s/s
double mmPerStep;
int preScale;
long CntFreq;
long maxSpeedSteps;
long maxAccelSteps;
long numStepsTemp;
uint16_t OCRmin;
uint16_t OCRo;
// public:
long accelSteps;
long decelSteps;
int speedUpdateSteps;
volatile int accelDecelIndex;
volatile uint16_t OCRarray[21];
SpeedRamp();
void SetMaxSpeed(int MmPerSec);
void CalculateSpeedRamp();
};
SpeedRamp::SpeedRamp()
{
maxSpeed = 60; // default to 60 mm/s
Accel = maxSpeed*10; // accelerate in 100 ms
Decel = maxSpeed*10; // decelerate in 100 ms
mmPerStep = 0.04;
preScale = 8;
CntFreq = 16000000L/preScale; // calculate timer count frequency based on prescale
numStepsTemp = 10000; // use 10,000 steps as speed ramp calculation
CalculateSpeedRamp();
}
void SpeedRamp::SetMaxSpeed(int MmPerSec)
{
maxSpeed = MmPerSec;
Accel = maxSpeed*10; // accelerate in 100 ms
Decel = maxSpeed*10; // decelerate in 100 ms
CalculateSpeedRamp();
}
void SpeedRamp::CalculateSpeedRamp()
{
OCRmin = ((mmPerStep*(CntFreq/2))/(maxSpeed));
OCRo = ((CntFreq/2)*sqrt((2*mmPerStep)/Accel));
OCRarray[0] = OCRo;
maxSpeedSteps = ((maxSpeed*maxSpeed)/(2*mmPerStep*Accel));
maxAccelSteps = ((numStepsTemp*Decel)/(Accel+Decel));
if (maxSpeedSteps < maxAccelSteps)
{
accelSteps = maxSpeedSteps;
decelSteps = (accelSteps*(Accel/Decel));
}
else
{
accelSteps = maxAccelSteps;
decelSteps = (accelSteps*(Accel/Decel));
}
speedUpdateSteps = round(accelSteps/(sizeof(OCRarray)/2));
for (int i = 0; i < (sizeof(OCRarray)/2); i++)
{
OCRarray[i] = (OCRo*(sqrt((i*speedUpdateSteps)+1) - sqrt((i*speedUpdateSteps))));
}
}
class StepperDrive: public SpeedRamp
{
public:
volatile uint8_t *stepPORT;
int stepBit;
volatile uint8_t *stepDDR;
volatile uint8_t *stepPIN;
volatile uint8_t *stepTCCRA;
volatile uint8_t *stepTCCRB;
volatile uint8_t *stepTCCRC;
volatile uint8_t *stepTIMSK;
volatile uint8_t *stepTIFR;
volatile uint16_t *stepOCRA;
volatile uint16_t *stepTCNT;
uint8_t stepTCCRAmask;
uint8_t stepTCCRAOutputMask;
uint8_t stepTCCRBmask;
uint8_t stepTCCRBStartMask;
uint8_t stepTimerOutputInterruptMask;
long incrementSteps;
long stepsTaken;
StepperDrive();
void SetupDrive();
void SetMaxSpeed(double MmPerSec);
void RunDrive();
void StopDrive();
void Increment(long IncrementSteps);
};
StepperDrive::StepperDrive()
:SpeedRamp()
{
stepPORT = &PORTE;
stepBit = 3; // PE3
stepDDR = &DDRE;
stepPIN = &PINE;
stepTCCRA = &TCCR3A;
stepTCCRB = &TCCR3B;
stepTCCRC = &TCCR3C;
stepTIMSK = &TIMSK3;
stepTIFR = &TIFR3;
stepOCRA = &OCR3A;
stepTCNT = &TCNT3;
stepTCCRAmask = B00000000;
stepTCCRAOutputMask = B01000000; // COM3A0 = 1 (toggle on compare match)
stepTCCRBmask = B00001000; // WGM32 = 1 (CTC, mode 4)
stepTCCRBStartMask = B00000010; // CS31 = 1 (prescale 8)
stepTimerOutputInterruptMask = B00000010; // OCIE3A = 1 (enable interrupt A)
stepsTaken = 0;
incrementSteps = 0;
}
void StepperDrive::SetupDrive()
{
// clear timer registers
*stepTCCRA = 0;
*stepTCCRB = 0;
*stepTCCRC = 0;
*stepTIMSK = 0;
*stepTCNT = 0;
}
void StepperDrive::SetMaxSpeed(double MmPerSec)
{
SpeedRamp::SetMaxSpeed(MmPerSec); // adjust private maxSpeed variable
}
void StepperDrive::RunDrive()
{
if (incrementSteps == 0)
{
incrementSteps = -1; // if no position target, give indication to ISR
}
accelDecelIndex = 0; // reset accelDecelIndex (OCRarray[])
stepsTaken = 0; // reset stepsTaken
*stepTCNT = 0; // reset timer count
noInterrupts();
*stepOCRA = OCRarray[0]; // set first OCR value
interrupts();
*stepDDR |= (1<<stepBit); // set step pin as OUTPUT
*stepPORT &= ~(1<<stepBit); // set step pin LOW
*stepTCCRA = (stepTCCRAOutputMask); // enable COM3A toggle on compare match
*stepTIMSK = (stepTimerOutputInterruptMask); // enable compare match interrupt
*stepTIFR |= B00001111; // clear any pending interrupts
*stepTCCRB = (stepTCCRBmask | stepTCCRBStartMask); // place timer in CTC mode, start timer at prescale 8
}
void StepperDrive::StopDrive()
{
*stepTCCRB = 0; // stop timer
*stepTCCRA = 0;
*stepTIMSK = 0; // clear interrupt enable
*stepPORT &= ~(1<<stepBit); // pull step pin LOW
}
void StepperDrive::Increment(long IncrementSteps)
{
incrementSteps = IncrementSteps; // set position target
RunDrive();
}
// global stepper drive object
StepperDrive stepperTest;
// global MAXspeed variable
double MAXspeed = 60;
void setup() {
Serial.begin(115200);
while (!Serial)
{
; // wait for serial to connect
}
delay(1000);
Serial.print(F("Setting up stepper object..."));
stepperTest.SetupDrive();
Serial.println(F("Done."));
Serial.println(F("Now starting main loop."));
}
void loop() {
Serial.print(F("Setting max speed..."));
stepperTest.SetMaxSpeed(MAXspeed);
Serial.println(F("Done."));
Serial.print(F("maxSpeed = "));Serial.println(stepperTest.maxSpeed);
Serial.print(F("Accel = "));Serial.println(stepperTest.Accel);
Serial.print(F("Decel = "));Serial.println(stepperTest.Decel);
Serial.print(F("maxSpeedSteps = "));Serial.println(stepperTest.maxSpeedSteps);
Serial.print(F("maxAccelSteps = "));Serial.println(stepperTest.maxAccelSteps);
Serial.print(F("accelSteps = "));Serial.println(stepperTest.accelSteps);
Serial.print(F("decelSteps = "));Serial.println(stepperTest.decelSteps);
Serial.print(F("OCRo = "));Serial.println(stepperTest.OCRo);
Serial.print(F("OCRmin = "));Serial.println(stepperTest.OCRmin);
Serial.println(F("OCR array:"));
for (int i = 0; i < (sizeof(stepperTest.OCRarray)/2); i++)
{
Serial.print(F("OCR "));Serial.print(i);Serial.print(F(" = "));Serial.println(stepperTest.OCRarray[i]);
}
Serial.println(F("Starting movement..."));
stepperTest.Increment(27774);
Serial.print(F("OCR3A = "));Serial.println(OCR3A);
while (stepperTest.stepsTaken < stepperTest.incrementSteps)
{
delay(100);
Serial.print(F("Steps taken: "));Serial.println(stepperTest.stepsTaken);
Serial.print(F("OCR3A = "));Serial.println(OCR3A);
}
Serial.println(F("Move complete."));
stepperTest.stepsTaken = 0;
MAXspeed += 10;
delay(3000);
}
ISR(TIMER3_COMPA_vect)
{ // OC3A is on pin PE3, controlled by OCR3A
if (PINE & (1<<3))
{ // step pin is HIGH
stepperTest.stepsTaken++;
if ((stepperTest.incrementSteps > 0) && (stepperTest.stepsTaken >= stepperTest.incrementSteps))
{ // if step target exists and has been reached, stop drive - targeted moves only
stepperTest.StopDrive();
}
if (!(stepperTest.stepsTaken % stepperTest.speedUpdateSteps)&&(stepperTest.stepsTaken <= stepperTest.accelSteps))
{ // acceleration phase - all moves
stepperTest.accelDecelIndex++;
if (stepperTest.OCRarray[stepperTest.accelDecelIndex] <= stepperTest.OCRmin)
{
OCR3A = stepperTest.OCRmin;
}
else
{
OCR3A = stepperTest.OCRarray[stepperTest.accelDecelIndex];
}
// OCR3A = stepperTest.OCRarray[stepperTest.accelDecelIndex];
}
if ((stepperTest.incrementSteps > 0)&&(!(stepperTest.stepsTaken % stepperTest.speedUpdateSteps))&&(stepperTest.stepsTaken >= (stepperTest.incrementSteps - stepperTest.decelSteps)))
{ // deceleration phase - targeted moves only
if (stepperTest.OCRarray[stepperTest.accelDecelIndex] <= stepperTest.OCRmin)
{
OCR3A = stepperTest.OCRmin;
}
else
{
OCR3A = stepperTest.OCRarray[stepperTest.accelDecelIndex];
}
// OCR3A = stepperTest.OCRarray[stepperTest.accelDecelIndex];
stepperTest.accelDecelIndex--;
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.