Stepper Motor Control

Hello folks!

I am developing a project where I need to put a Stepper Motor rotating at 1400RPM MAX. The most efficient approach that I have found was using Timers and Interrupts for this. So, I have built this code:

#include <avr/io.h>
#include <avr/interrupt.h>

#define MOTOR_DIR 5
#define MOTOR_STEP 3
#define MOTOR_FAULT 6
#define MOTOR_HOME 2
#define MOTOR_ENABLE 4
#define MOTOR_DECAY 12
#define MOTOR_SLEEP 11

int step_turns = 0;
int turns = 0;
long frequency = 16*10^6;
boolean estado = LOW;
int speed_all, speed_RPM;
long timer_period;
float time_beg = 0;
int count = 0;
volatile int rpm;
float delay_t;
volatile long freq = 0;

void setup() {
  init_motor();
  //Serial.begin(9600);
  Serial.begin(9600);
  Serial.println(TCCR2A);
  Serial.println(TCCR2B);
  Serial.println(TIMSK2);
  Serial.println(TCCR1A);
  Serial.println(TCCR1B);
  Serial.println(TIMSK1);
  // initialize Timer1
  cli();            // disable global interrupts
  //TCCR2A = 0;        // set entire TCCR1A register to 0
  //TCCR2B = 0;

  // enable Timer1 overflow interrupt:
  TIMSK2 = (1 << TOIE2);
  // Set CS10 bit so timer runs at clock speed:
  TCCR2B |= (1 << CS22) | (1<<CS21);
  // enable global interrupts:
  
  //Initialize Timer1
  //TCCR1A = 0;     // set entire TCCR1A register to 0
  //TCCR1B = 0;     // same for TCCR1B

  // set compare match register to desired timer count:
  //TCCR1A = 0;
  TCCR1B = (1 << CS12);// | (1<<CS10);
  
  //OCR1A = 6000;
  // turn on CTC mode:
  TCCR1B |= (1 << WGM12);
  // Set CS10 and CS12 bits for 1024 prescaler:
  //TCCR1B |= (1 << CS10);
  // enable timer compare interrupt:
  TIMSK1 |= (1 << TOIE1);
  sei();
  pinMode(9, OUTPUT);
  loop();
}

void loop() {  
  Serial.println(TCCR2A);
  Serial.println(TCCR2B);
  Serial.println(TIMSK2);
  Serial.println(TCCR1A);
  Serial.println(TCCR1B);
  Serial.println(TIMSK1);
  Serial.println("-----");
  delay(1000);
}

void init_motor()
{
  pinMode(MOTOR_DIR, OUTPUT);
  pinMode(MOTOR_STEP, OUTPUT);
  pinMode(MOTOR_ENABLE, OUTPUT);
  pinMode(MOTOR_DECAY, OUTPUT); 
  pinMode(MOTOR_SLEEP, OUTPUT);

  digitalWrite(MOTOR_ENABLE, LOW);
  digitalWrite(MOTOR_SLEEP, HIGH);
  digitalWrite(MOTOR_DECAY, LOW);
}

ISR(TIMER1_OVF_vect){
  PORTB ^= (1<<PORTB1);
}

ISR(TIMER2_OVF_vect)
{
  rpm = analogRead(A1) * 1.4;
  freq = (float) rpm * 20 / 3;
  freq = frequency/freq;
  noInterrupts();
  TCNT1 = 0;
  freq = frequency/freq;
  OCR1A = freq;
  interrupts();
}

For some reason, when I start the program the Registers are not zeroed. Is arduino using those registers for something else?

And if so, how can I avoid mess with that? Or is there any other solution?

Thanks for your patience!

Pedro

Is arduino using those registers for something else?

Yes it uses the three timers for driving the PWM pins. In addition Timer 0 is used to control the millis timer.

And if so, how can I avoid mess with that?

If you don't want to use the PWM then there is no need not to mess with them. If you do need PWM then look to make PWM signals with external hardware.

Thanks for the reply!

I am not using any pwm signals, but I don't know if the Arduino IDE is messing with it somehow, as they are supposed to be at 0 on the beggining and, clearly, are not.

Note that C/C++ uses ** and not ^ for exponentiation

How many pulses per second do you need?

I don't see any need for such a complicated program. I suspect a variation on the code in the second example in this demo would work.

...R

as they are supposed to be at 0 on the beggining and, clearly, are not.

Timer 0 is actively being used, the others are not. So you can change them. Do not worry about the default state.

Robin2: Note that C/C++ uses ** and not ^ for exponentiation

How many pulses per second do you need?

I don't see any need for such a complicated program. I suspect a variation on the code in the second example in this demo would work.

...R

Thanks Robin! The thing I noted is that if I use Arduino funtions I will not be able to achieve the speeds I need. I need around 1400RPM, and that, translated to steps, is a period of 200us between full steps 100us between toggles (toggle high, toggle low).

The problem is that the interruption that is supposed to write OCR1A wiht he right value given from the potenciometer reading is not doing so accordingly. The freq is the frequency I need to put it running at the desired speed (RPM).

DarkRidder: is a period of 200us between full steps 100us between toggles (toggle high, toggle low).

Don't split the time in half like that. Most stepper drivers only require a pulse of a few microseconds which is adequately provide by

digitalWrite(stepPin, HIGH);
digitalWrite(stepPin, LOW);

If you keep all the interval between steps as a single unit it gives you much more flexibility with the rest of your program.

...R

Solved!

The motor was resonant at 700RPM, so I had hold it against the table so that the vibration does not stop it.