Hello Everyone, I have a working sketch which uses a stepper to drive a filter wheel to any one of four positions inputted by serial command. As it is now, I have to manually set a starting position each time the project is powered on. I would like to have the wheel drive at power-up until a magnet reaches a reed switch and then stop. Before altering the code I have so far, I have a separate sketch which I am including here in its entirety. Once I have this homing to a zero position, I will include this in the code.
The Nano is powered through the USB, while the driver board is powered by a 5v regulator. All grounds are common. As it is now, when the circuit is powered up, it drives the wheel, reporting to the serial monitor:
“0” (state of interrupt pin)
“4093” (steps taken per cycle)
“cycle count=n” (number of cycles attempted)
But the program never recognizes the change of state when I change digital pin 2 to low by switching it to ground. So there is something in the code I have not set up right and can’t seem to figure it out. I tried using another Nano just in case I may have damaged something in the experimenting.
[code]
#include <AccelStepper.h>
#define HALFSTEP 8
#define motorPin1 8 // IN1 on ULN2003 ==> Blue on 28BYJ-48
#define motorPin2 9 // IN2 on ULN2004 ==> Pink on 28BYJ-48
#define motorPin3 10 // IN3 on ULN2003 ==> Yellow on 28BYJ-48
#define motorPin4 11 // IN4 on ULN2003 ==> Orange on 28BYJ-48
int endPoint = 4096; // Move this many steps, approx one full turn
AccelStepper stepper1(HALFSTEP, motorPin1, motorPin3, motorPin2, motorPin4);
volatile boolean stopNow = false; // flag for Interrupt Service routine
int cycleCount = 0; // counter for endpoint cycles
boolean homed = false; // flag to indicate when motor is homed
void setup()
{
attachInterrupt(2, intService, LOW); // Enable interrupt D2, switch pulled low
Serial.begin(9600);
Serial.println(stepper1.currentPosition());
delay(5000);
stepper1.setMaxSpeed(1000.0);
stepper1.setAcceleration(200.0);
stepper1.setSpeed(400);
stepper1.moveTo(endPoint);
}
void loop()
{
if (stopNow)
{
detachInterrupt(0); // Interrupt not needed again (for the moment)
Serial.print("Interrupted at ");
Serial.println(stepper1.currentPosition());
stepper1.stop();
stepper1.setCurrentPosition(0);
Serial.print("position established at home...");
Serial.println(stepper1.currentPosition());
stopNow = false; // Prevents repeated execution of the above code
homed = true;
}
else
if (stepper1.distanceToGo() == 0 && !homed) //executed repeatedly until we hit the limitswitch
{
Serial.println(stepper1.currentPosition());
stepper1.setCurrentPosition(0);
stepper1.moveTo(endPoint);
cycleCount ++;
Serial.print("cycle count = ");
Serial.println(cycleCount);
Serial.println(stepper1.currentPosition());
}
stepper1.run();
if(homed)
{
Serial.println("I am homed");
}
}
void intService()
{
stopNow = true; // Set flag to show Interrupt recognised and then stop the motor
}
while all I/O pins are input by default, do you need to configure that pin with a pullup
pinMode (2, INPUT_PULLUP);
and you might consider using digitalPinToInterrupt(pin). See attachInterrupt()
i've never understood the distinction in hardware detecting a FALLING vs LOW state. Not sure if a persistent LOW condition immediately retriggers an interrupt once it completes. You might consider FALLING.
Thanks to both of you for replying. I've tried to implement the suggestions by using a digitalPinToInterrupt and commenting out the attachinterrupt and intService statements. Now it thinks it is already in home position. Motor does not turn, and monitor report "I am Homed". I tried using the article in Arduino Interrupts Tutorial with Example Interrupt Demonstration, but I'm just getting it all goofed up.
[code]
#include <AccelStepper.h>
#define HALFSTEP 8
#define motorPin1 8 // IN1 on ULN2003 ==> Blue on 28BYJ-48
#define motorPin2 9 // IN2 on ULN2004 ==> Pink on 28BYJ-48
#define motorPin3 10 // IN3 on ULN2003 ==> Yellow on 28BYJ-48
#define motorPin4 11 // IN4 on ULN2003 ==> Orange on 28BYJ-48
int endPoint = 4096; // Move this many steps, approx one full turn
AccelStepper stepper1(HALFSTEP, motorPin1, motorPin3, motorPin2, motorPin4);
volatile boolean stopNow = false; // flag for Interrupt Service routine
volatile int output = LOW;
int cycleCount = 0; // counter for endpoint cycles
boolean homed = false; // flag to indicate when motor is homed
void setup()
{
//attachInterrupt(2, intService, LOW); // Enable interrupt D2, switch pulled low
attachInterrupt(digitalPinToInterrupt(2),Switch, HIGH);
pinMode (2, INPUT);
Serial.begin(9600);
Serial.println(stepper1.currentPosition());
delay(5000);
stepper1.setMaxSpeed(1000.0);
stepper1.setAcceleration(200.0);
stepper1.setSpeed(400);
stepper1.moveTo(endPoint);
}
void loop()
{
if (stopNow)
{
detachInterrupt(0); // Interrupt not needed again (for the moment)
Serial.print("Interrupted at ");
Serial.println(stepper1.currentPosition());
stepper1.stop();
stepper1.setCurrentPosition(0);
Serial.print("position established at home...");
Serial.println(stepper1.currentPosition());
stopNow = false; // Prevents repeated execution of the above code
homed = true;
}
else
if (stepper1.distanceToGo() == 0 && !homed) //executed repeatedly until we hit the limitswitch
{
Serial.println(stepper1.currentPosition());
stepper1.setCurrentPosition(0);
stepper1.moveTo(endPoint);
cycleCount ++;
Serial.print("cycle count = ");
Serial.println(cycleCount);
Serial.println(stepper1.currentPosition());
}
stepper1.run();
if(homed)
{
Serial.println("I am homed");
}
}
void Switch()
//void intService()
{
stopNow = true; // Set flag to show Interrupt recognised and then stop the motor
}
there seems to be a beginners habit of coding plenty of lines before testing.
But you are on the right way with your testing code.
To narrow down the problem I suggest to check smaller things.
Checking if the interrupt really works.
Depending on your hardware not every pin can be configured for initiating interrupts.
here is a democode that I used to check if the interrupt works at all
struct Button {
const uint8_t PIN;
uint32_t numberKeyPresses;
bool pressed;
};
Button button1 = {18, 0, false};
// set IRAM attribute to place the ISR-code into Internal RAM
// which makes execution as fast as possible
void IRAM_ATTR isr() {
button1.numberKeyPresses += 1;
button1.pressed = true;
}
void setup() {
Serial.begin(115200);
pinMode(button1.PIN, INPUT_PULLUP);
attachInterrupt(button1.PIN, isr, FALLING);
}
void loop() {
if (button1.pressed) {
Serial.printf("Button 1 has been pressed %u times\n", button1.numberKeyPresses);
button1.pressed = false;
}
//Detach Interrupt after 1 Minute
static uint32_t lastMillis = 0;
if (millis() - lastMillis > 60000) {
lastMillis = millis();
detachInterrupt(button1.PIN);
Serial.println("Interrupt Detached!");
}
}
Next step would be making the stepper just turning around endlessly
increment a counter inside your interrup-service-routine (in short ISR) each time the ISR is called.
printout the value o fthis counter every second to see if the counter moves up while the magnet switches the read-contact.
another question what kind of electronic equipment do you have for checking?
Lately I had a strange problem that my code should measure a frequency of 0-50 Hz but it did not work correctly. It turned out that the optokoppler I was using produced a voltage of around half of the supply-voltage. I only found this by hanging up my oscilloscope to the input-pin.
Code was fine, circuitry was (almost) fine and still it did'nt worked.
So at least you should check with a digital multimeter if the voltage alternates between supply-voltage and zero if you switch the reed-contact with a magnet by hand or by hand-turning your wheel.