I'm having difficultly using an internal timer interrupt with my Arduino Nano to properly capture a specific value from a linear potentiometer and then instantly stopping the actuator.
I basically have the wiper of a linear potentiometer connected to the end of a linear actuator. The actuator extends/retracts via a L298N module being controlled by a Nano. From where its positioned, the potentiometer reads around "80" when the actuator is fully extended, and around "25" when fully retracted. I'm entering numbers via the serial monitor to prompt the actuator to move up or down, these numbers are being stored in the Nano's EEPROM.
My interrupt seems not to work while the actuator is in motion. For example, if I set the interrupt to stop the motor when the potentiometer reads "50", it just skips past this number without stopping the actuator. But if I set the interrupt to stop the motor when the potentiometer reads the minimum or maximum (where the actuator is currently located before activation), the actuator correctly doesn't extract or retract. I would think my interrupt is fast enough at 8Khz, so I feel there is something else prohibiting the actuator from stopping at a specific value between the max and min.
The my current code is below, any help would be much appreciated.
//timer2 will interrupt at 8kHz
#include <EEPROM.h>
#define EEPROM_SIZE
long number;
long x;
int toggle=0;
int old_x=0;
const int linPot = A1;
int MotorSpeed=255;
int enA = 9;
int in1 = 8;
int in2 = 7;
int currentPosition;
enum {IdleState, UpState, DownState} State;
void setup(){
Serial.begin(9600);
number = EEPROM.read(0);
x=number;
pinMode(enA, OUTPUT);
pinMode(in1, OUTPUT);
pinMode(in2, OUTPUT);
State = IdleState;
//cli();//stop interrupts
//set timer2 interrupt at 8kHz
TCCR2A = 0;// set entire TCCR2A register to 0
TCCR2B = 0;// same for TCCR2B
TCNT2 = 0;//initialize counter value to 0
// set compare match register for 8khz increments
OCR2A = 249;// = (16*10^6) / (8000*8) - 1 (must be <256)
// turn on CTC mode
TCCR2A |= (1 << WGM21);
// Set CS21 bit for 8 prescaler
TCCR2B |= (1 << CS21);
// enable timer compare interrupt
TIMSK2 |= (1 << OCIE2A);
sei();//allow interrupts
}//end setup
ISR(TIMER2_COMPA_vect){//timer1 interrupt 8kHz
//generates pulse wave of frequency 8kHz/2 = 4kHz
if(currentPosition==50){
HALT();
}
}
void loop(){
if ((Serial.available()&&toggle==0)){
x=Serial.parseInt();
old_x=x;
toggle=1;
}
if((Serial.available())&&(toggle==1)&&(Serial.parseInt()!=old_x)){
toggle=0;
}
if((toggle==1)&&(Serial.parseInt()==0)){
toggle=0;
}
if(x>78){
x=78;
}
if(x<0){
x=0;
}
EEPROM.write(0, x);
Serial.print("X :");
Serial.println(x);
int data = analogRead(linPot);
currentPosition = map(data, 0, 1023, 0, 100);
Serial.print("Potentiometer at ");
Serial.print(currentPosition);
Serial.println("%");
long difference = currentPosition-x;
Serial.print("Difference :");
Serial.println(difference);
if(difference>0){
State = UpState;
}
if(difference>0){
State = DownState;
}
if(difference==0){
State = IdleState;
}
switch (State) {
case IdleState:
Serial.println("Idle State");
HALT();
if((currentPosition-number)<0){
State = UpState;
}
if((currentPosition-number)>0){
State = DownState;
}
break;
case UpState:
Serial.println("Up State");
//Need to move down
DOWN();
if((currentPosition-number)>0){
State = DownState;
}
if((currentPosition-number)==0){
State = IdleState;
}
break;
case DownState:
Serial.println("Down State");
//Need to move up
UP();
if((currentPosition-number)<0){
State = UpState;
}
if((currentPosition-number)==0){
State = IdleState;
}
break;
}
}
void DOWN(){
analogWrite(enA, MotorSpeed);
digitalWrite(in1, HIGH);
digitalWrite(in2, LOW);
}
void UP() {
analogWrite(enA, MotorSpeed);
digitalWrite(in1, LOW);
digitalWrite(in2, HIGH);
}
void HALT () {
digitalWrite(in1, LOW);
digitalWrite(in2, LOW);
}
loop()
blockcurrentPosition
is updated inloop()
, possibly at a very slow pace (asSerial.parseInt()
can block for up to a whole second), it makes no sense to fire an interrupt just to test its value.