Hello,
I am trying to use a stepper to track a sinusoidal reference. I would like to use t = millis() to calculate the value of a sinusoidal reference r = sin(2pif*t), however it clashes with the interrupts I set up to check the state of my encoder, blocking the operation at seemingly random points. Printing t results therefore in the same value being repeated indefinitely after a short period of the code working.
Here is some context in case it is needed:
I have a system that consists of a 5 V battery pack, a UNO, a ULN2003 drive, a 28BJ-48 stepper and a KY040 rotary encoder. The shaft of the encoder is connected to the one of the motor, so that every revolution of the motor's shaft corresponds to one revolution of the encoder's. The motor then rotates CKW if the current value of r is smaller than the previous value r_old, CCKW if the opposite is true. The value of the encoder y is updated using interrupts every time the state of PIN 3 changes.
The hardware is working, so it is surely a problem of the code and not the wiring, power supply etc. In fact:
- When replacing the millis() function by a counter the code works;
- When the encoder is not rotating the code works.
This is why I presume the problem is in the clashing of the encoder interrupt and the millis() function.
Here is my entire code:
// ================= Declarations =================
#define pi 3.1415926535897932384626433832795
float t;
float r_old;
float r;
// Encoder
const int PinCLK = 2; // Encoder CLK (White)
const int PinDT = 3; // Encoder DT (Brown)
int pos_last = 0; // Last position
volatile int y = 0; // Current position
// Motor
int Pin1 = 8; // Driver pin 1 (Yellow)
int Pin2 = 9; // Driver pin 2 (Orange)
int Pin3 = 10; // Driver pin 3 (Green)
int Pin4 = 11; // Driver pin 4 (Blue)
int v = 2; // Motor speed (1 max speed)
// ================= Functions =================
void idle (){
digitalWrite(Pin1, LOW);
digitalWrite(Pin2, LOW);
digitalWrite(Pin3, LOW);
digitalWrite(Pin4, LOW);
}
void CCKW (){
// 1
digitalWrite(Pin1, HIGH);
digitalWrite(Pin2, LOW);
digitalWrite(Pin3, LOW);
digitalWrite(Pin4, LOW);
delay(v);
// 2
digitalWrite(Pin1, HIGH);
digitalWrite(Pin2, HIGH);
digitalWrite(Pin3, LOW);
digitalWrite(Pin4, LOW);
delay (v);
// 3
digitalWrite(Pin1, LOW);
digitalWrite(Pin2, HIGH);
digitalWrite(Pin3, LOW);
digitalWrite(Pin4, LOW);
delay(v);
// 4
digitalWrite(Pin1, LOW);
digitalWrite(Pin2, HIGH);
digitalWrite(Pin3, HIGH);
digitalWrite(Pin4, LOW);
delay(v);
// 5
digitalWrite(Pin1, LOW);
digitalWrite(Pin2, LOW);
digitalWrite(Pin3, HIGH);
digitalWrite(Pin4, LOW);
delay(v);
// 6
digitalWrite(Pin1, LOW);
digitalWrite(Pin2, LOW);
digitalWrite(Pin3, HIGH);
digitalWrite(Pin4, HIGH);
delay (v);
// 7
digitalWrite(Pin1, LOW);
digitalWrite(Pin2, LOW);
digitalWrite(Pin3, LOW);
digitalWrite(Pin4, HIGH);
delay(v);
// 8
digitalWrite(Pin1, HIGH);
digitalWrite(Pin2, LOW);
digitalWrite(Pin3, LOW);
digitalWrite(Pin4, HIGH);
delay(v);
}
void CKW(){
// 1
digitalWrite(Pin4, HIGH);
digitalWrite(Pin3, LOW);
digitalWrite(Pin2, LOW);
digitalWrite(Pin1, LOW);
delay(v);
// 2
digitalWrite(Pin4, HIGH);
digitalWrite(Pin3, HIGH);
digitalWrite(Pin2, LOW);
digitalWrite(Pin1, LOW);
delay (v);
// 3
digitalWrite(Pin4, LOW);
digitalWrite(Pin3, HIGH);
digitalWrite(Pin2, LOW);
digitalWrite(Pin1, LOW);
delay(v);
// 4
digitalWrite(Pin4, LOW);
digitalWrite(Pin3, HIGH);
digitalWrite(Pin2, HIGH);
digitalWrite(Pin1, LOW);
delay(v);
// 5
digitalWrite(Pin4, LOW);
digitalWrite(Pin3, LOW);
digitalWrite(Pin2, HIGH);
digitalWrite(Pin1, LOW);
delay(v);
// 6
digitalWrite(Pin4, LOW);
digitalWrite(Pin3, LOW);
digitalWrite(Pin2, HIGH);
digitalWrite(Pin1, HIGH);
delay (v);
// 7
digitalWrite(Pin4, LOW);
digitalWrite(Pin3, LOW);
digitalWrite(Pin2, LOW);
digitalWrite(Pin1, HIGH);
delay(v);
// 8
digitalWrite(Pin4, HIGH);
digitalWrite(Pin3, LOW);
digitalWrite(Pin2, LOW);
digitalWrite(Pin1, HIGH);
delay(v);
}
// Interrupt
void isr () {
if (digitalRead(PinDT) == LOW)
{
y-- ;
}
else {
y++ ;
}
}
// Track: If the current rotary switch position has changed then update everything
void track() {
noInterrupts () ;
pos_last = y ; // read the volatile in a critical section
interrupts () ;
}
// ================= Setup =================
void setup() {
Serial.begin(9600);
// Encoder
pinMode(PinCLK,INPUT);
pinMode(PinDT, INPUT);
// Motor
pinMode(Pin1, OUTPUT);
pinMode(Pin2, OUTPUT);
pinMode(Pin3, OUTPUT);
pinMode(Pin4, OUTPUT);
// Attach the routine to service the interrupts
attachInterrupt(digitalPinToInterrupt(PinCLK), isr, LOW);
}
// ================= Loop =================
void loop() {
track(); // void function that uses interrupts to check when the
// rotary encoder changed position and updates its value if it did
t = 0.001*millis();
r_old = r;
r = 20*sin(0.05*pi*t);
Serial.println(t);
if(r-r_old<0) {
CKW(); // Turn 1 stepper step clockwise
}
if(r-r_old>0) {
CCKW(); // Turn 1 stepper step counter-clockwise
}
if(r-r_old==0) {
idle(); // Do not move
}
}
This is a shorter version including only the (in my opinion) relevant part:
#define pi 3.1415926535897932384626433832795
float t;
float r_old;
float r;
// Encoder
const int PinCLK = 2; // Encoder CLK (White)
const int PinDT = 3; // Encoder DT (Brown)
int pos_last = 0; // Last position
volatile int y = 0; // Current position
void idle (){
...
}
void CCKW (){
...
}
void CKW(){
...
}
// Interrupt
void isr () {
if (digitalRead(PinDT) == LOW)
{
y-- ;
}
else {
y++ ;
}
}
// Track: If the current rotary switch position has changed then update everything
void track() {
noInterrupts () ;
pos_last = y ; // read the volatile in a critical section
interrupts () ;
}
// ================= Setup =================
void setup() {
Serial.begin(9600);
// Attach the routine to service the interrupts
attachInterrupt(digitalPinToInterrupt(PinCLK), isr, LOW);
}
// ================= Loop =================
void loop() {
track(); // void function that uses interrupts to check when the
// rotary encoder changed position and updates its value if it did
t = 0.001*millis();
r_old = r;
r = 20*sin(0.05*pi*t);
Serial.println(t);
if(r-r_old<0) {
CKW(); // Turn 1 stepper step clockwise
}
if(r-r_old>0) {
CCKW(); // Turn 1 stepper step counter-clockwise
}
if(r-r_old==0) {
idle(); // Do not move
}
}