Hi,
I have to drive a stepper motor creating a square wave. Sometimes I want to use a sensor but the function of the sensor contains a delay of some milliseconds. The function is contained in an external library so I cant modify it. Obviously when I call the function the loop and also the stepper motor stop. There is a way to avoid this? I think no but maybe there are method that I dont know.
I post a very simple example sketch to make you understand the problem.
void mySensor(){
//other instructions
delay(10);
}
void setup() {
pinMode(7,OUTPUT); //pin connected to a stepper motor driver
}
void loop() {
//square wave to drive the motor
digitalWrite(7,HIGH);
delayMicroseconds(500);
digitalWrite(7,LOW);
delayMicroseconds(500);
mySensor(); //now the loop stops for 10ms
}
Jaason:
The function is contained in an external library so I cant modify it.
You certainly can, that's the beauty of the Open Source paradigm. Make your own copy of the library files with a different name. Then modify it to be non-blocking.
gfvalvo:
You certainly can, that's the beauty of the Open Source paradigm. Make your own copy of the library files with a different name. Then modify it to be non-blocking.
Yes I could but I'm not so good at programming and it would be my first time...
UKHeliBob:
What type of sensor and which library ?
Sensor TCS34725 with the Adafruit library;
The sensor has an integration time (I use the function GetRawData).
Maybe I can generate a square wave with PWM but then it would be difficult to count the pulses (->step of the motor), I dont know
What is the relationship between the sensor output and the stepper movement? How do you want the stepper to move depending on what is read by the sensor?
I had the exact same problem and fellow posters pointed me in the right direction. The approach below, a bit shortened from the Adafruit library example, helps to surf around the sensor delaying loop() execution. Here, a servo function and a random number function tick away with millis() while the sensor reads with 700ms. Give it a try.
#include <Wire.h>
#include <Servo.h>
#include <Adafruit_TCS34725.h>
Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_700MS, TCS34725_GAIN_1X);
const int interruptPin = 2;
volatile boolean state = false;
const byte timeServoInterval = 6;
int timeSimUserInterval; // Set "do something" interval programmatically
unsigned long timeNowServo = 0;
unsigned long timeNowUser = 0;
int angleCurrent;
int angleTarget;
Servo ovres;
void isr()
{
state = true;
}
/* tcs.getRawData() does a delay(Integration_Time) after the sensor readout.
We don't need to wait for the next integration cycle because we receive an interrupt when the integration cycle is complete*/
void getRawData_noDelay(uint16_t *r, uint16_t *g, uint16_t *b, uint16_t *c)
{
*c = tcs.read16(TCS34725_CDATAL);
*r = tcs.read16(TCS34725_RDATAL);
*g = tcs.read16(TCS34725_GDATAL);
*b = tcs.read16(TCS34725_BDATAL);
}
void setup()
{
pinMode(interruptPin, INPUT_PULLUP); //TCS interrupt output is Active-LOW and Open-Drain
attachInterrupt(digitalPinToInterrupt(interruptPin), isr, FALLING);
Serial.begin(19200);
tcs.begin();
tcs.write8(TCS34725_PERS, TCS34725_PERS_NONE); // Set persistence filter to generate an interrupt for every RGB Cycle, regardless of the integration limits
tcs.setInterrupt(true);
randomSeed(analogRead(0));
ovres.attach(3);
ovres.write(0);
angleCurrent = ovres.read(); // Seed with initial value to start
angleTarget = random(0, 180); // Seed with initial value to start
}
void loop()
{
readSensor();
simulateUserInput(); // Values (°) randomly generated within a range
rotateServo();
}
void readSensor()
{
if (state)
{
uint16_t r, g, b, c;
getRawData_noDelay(&r, &g, &b, &c);
Serial.print("R: "); Serial.print(r, DEC); Serial.print(" ");
Serial.print("G: "); Serial.print(g, DEC); Serial.print(" ");
Serial.print("B: "); Serial.print(b, DEC); Serial.print(" ");
Serial.print("C: "); Serial.print(c, DEC); Serial.print(" ");
Serial.println(" ");
tcs.clearInterrupt();
state = false;
}
}
void rotateServo()
{
if (millis() - timeNowServo >= timeServoInterval) // Check if it is time to rotate
{
timeNowServo = millis(); // Record the current time
if (angleCurrent != angleTarget) // Don't write to servo if target angle is reached
{
if (angleCurrent <= angleTarget)
{
angleCurrent ++;
ovres.write(angleCurrent);
}
else
{
if (angleCurrent >= angleTarget)
{
angleCurrent --;
ovres.write(angleCurrent);
}
}
}
}
}
void simulateUserInput() // Set target angle programmatically (later through user input)
{
if (millis() - timeNowUser > timeSimUserInterval)
{
timeNowUser = millis();
timeSimUserInterval = random(1000, 8000);
angleTarget = random(0, 180);
}
}