variable de acceso dentro de ISR? [cerrado]

-1

Actualmente estoy contando los pasos del movimiento de mi motor paso a paso en un ISR, pero no puedo averiguar dónde debo leer el valor incrementado ( step_count ) para un procesamiento adicional. El motor se mueve cuando "le dice" que lo haga. Parece muy importante donde coloco la lectura, ya que estoy obteniendo resultados diferentes según donde la coloco.

Agregué el código completo a continuación.

Esta es mi rutina ISR:

volatile speed_profile profile
ISR(TIMER1_COMPA_vect)
{
  // Holds next delay period.
  unsigned int new_first_step_delay;

  // Remember the last step delay used when accelrating.
  static int last_accel_delay;

  // Counting steps when moving.
  static unsigned int step_count = 0;

  // Keep track of remainder from new_step-delay calculation to incrase accurancy
  static unsigned int rest = 0;
  OCR1A = profile.first_step_delay;  
  switch (profile.run_state)
  {

    case STOP:     
      step_count = 0;
      profile.moved_steps = step_count; // step_count gets read by an global variable where should i place this . 
      rest = 0;
      break;

    case ACCEL:
      step_count++;
      profile.accel_count++;
      //do something

      // Chech if we should start decelration.
      if (step_count >= profile.decel_start)
      {
        profile.accel_count = profile.decel_length;
        profile.run_state = DECEL;
      }

      // Chech if we hitted max speed.
      else if (new_first_step_delay <= profile.min_time_delay)
      {
        last_accel_delay = new_first_step_delay;
        new_first_step_delay = profile.min_time_delay;
        rest = 0;
        profile.run_state = RUN;
      }
      break;
    case RUN:
      digitalWrite(step_pin,!digitalRead(step_pin));
      step_count++;
       //Do something

      if (step_count >= profile.decel_start) 
      {
        profile.accel_count = profile.decel_length;
        // Start decelration with same delay as accel ended with.
        new_first_step_delay = last_accel_delay;
        profile.run_state = DECEL;
      }
      break;
    case DECEL:
      digitalWrite(step_pin,!digitalRead(step_pin));      
      step_count++;
      profile.moved_steps = step_count;
      // do something
      // Check if we at last step
      if(profile.accel_count >= 0)
      {
        profile.run_state = STOP;
        global_state = false;
      }

      break;

  }
    profile.first_step_delay = new_first_step_delay;  

} 

La colocación de la lectura aquí hace que sea imposible de procesar, ya que no me deja manipularla, cuando la leo en una variable diferente y proceso la otra variable, obtengo el valor de paso original, aunque el procesamiento (en este caso normalizando el valor), se realiza en la otra variable antes de que se imprima en la pantalla (Sí, tampoco lo entiendo). Un segundo inconveniente de colocarlo aquí es que cuando se le indica al motor que mueva 1000 pasos, no incrementa el valor del paso, sino que al moverlo nuevamente 1000 pasos cambia el valor a 1000 ... haciendo que el paso cuente un comando detrás.

Colocar la lectura al final de la rutina ISR hace posible procesar la variable, pero el valor que contiene, es inexacto, ya que no contiene el último valor, lo que confunde con el seguimiento del paso. -contar.

Se debe tener en cuenta que utilizo una protección contra interrupciones cuando leo el valor de profile.moved_steps para un procesamiento adicional, elijo no interactuar directamente con la variable para asegurarme de que no estoy escribiendo / leyendo o hago la mitad en caso de ¿Se está llamando la interrupción, que sospecho que podría ser el problema? La operación realizada dentro de la guarda es una simple lectura del valor en la variable temporal, que luego se procesa.

Entonces, mi pregunta, ¿dónde coloco la instrucción?

 profile.moved_steps = step_count;

de modo que obtenga el último valor, y no lo haga atascado, de modo que no pueda realizar ninguna operación con él.

el perfil nos instancia como volátil.

Supongo que podría seguir adivinando? pero mi instinto está diciendo que algo está muy mal? ... ¿Tengo los valores incorrectos?

aquí hay un ejemplo de trabajo mínimo:

Main.ino

#include "speed_profile.h"


void setup() {
  // put your setup code here, to run once:
  cli();
  output_pin_setup();
  timer1_setup();
  sei();
}

void loop() 
{
      int motor_steps = 23400;//-9600; //23400 -  100%
      // Accelration to use.
      int motor_acceleration = 500;//500;
      // Deceleration to use.
      int motor_deceleration = 500;//500;
      // Speed to use.
      int motor_speed = 1000; // 1000
      compute_speed_profile(motor_steps, motor_acceleration, motor_deceleration, motor_speed); 
}

.cpp

#include "speed_profile.h"


volatile speed_profile profile;

ros::NodeHandle nh;

std_msgs::Int16 status_step_count;
ros::Publisher chatter("tipper_status", &status_step_count);

bool global_state = false;
int received_data = 0;

void call_back_control( const std_msgs::Empty & msg)
{
  global_state = true;

}
void output_pin_setup()
{
  pinMode(en_pin, OUTPUT);
  pinMode(dir_pin, OUTPUT);
  pinMode(step_pin, OUTPUT);
  nh.initNode();
  nh.advertise(chatter);
  nh.subscribe(sub_control);
  //nh.subscribe(sub_command);
  profile.moved_steps = 0;
  profile.current_step_position = 0;
  delay(1000);
  nh.getHardware()->setBaud(57600);

}

void timer1_setup()
{
  // Tells what part of speed ramp we are in.
  profile.run_state = STOP;

  // Timer/Counter 1 in mode 4 CTC (Not running).
  TCCR1B = (1 << WGM12);

  // Timer/Counter 1 Output Compare A Match Interrupt enable.
  TIMSK1 = (1 << OCIE1A);
}


ros::Subscriber<std_msgs::Empty> sub_control("tipper_control", &call_back_control );

void compute_speed_profile(signed int motor_steps, unsigned int motor_accel, unsigned int motor_decel, unsigned int motor_speed)
{
  while (global_state == false)
  {
    //do nothing
    status_step_count.data = profile.current_step_position; //profile.current_step_position;
    chatter.publish( &status_step_count);
    nh.spinOnce();
    delay(1);

  }

  profile.min_time_delay = A_T_x100 / 500;
  profile.first_step_delay = (T1_FREQ_148 * sqrt(A_SQ / 100)) / 100;
  profile.decel_length = -(3000 - 1500);
  profile.decel_start = 3000 + profile.decel_length;
  profile.first_step_delay = profile.min_time_delay;
  profile.run_state = ACCEL;
  profile.accel_count = 0;

  OCR1A = 10;
  // Set Timer/Counter to divide clock by 8
  TCCR1B |= ((0 << CS12) | (1 << CS11) | (0 << CS10));

  while (global_state == true)
  { 
    cli();
    int temp =  profile.moved_steps;     // Keeping ISR disable shortest time possible
    sei();

    if (profile.dir == CCW)
    {
      profile.current_step_position -=   temp;
    }
    else
    {
      profile.current_step_position =  temp;
    }    

    status_step_count.data = profile.current_step_position;
    chatter.publish( &status_step_count);

    nh.spinOnce();
    delay(1);
  }
}


ISR(TIMER1_COMPA_vect)
{
  // Holds next delay period.
  unsigned int new_first_step_delay;

  // Remember the last step delay used when accelrating.
  static int last_accel_delay;

  // Counting steps when moving.
  static unsigned int step_count = 0;

  // Keep track of remainder from new_step-delay calculation to incrase accurancy
  static unsigned int rest = 0;
  OCR1A = profile.first_step_delay;
  switch (profile.run_state)
  {

    case STOP:
      step_count = 0;
      rest = 0;
      TCCR1B &= ~((1 << CS12) | (1 << CS11) | (1 << CS10)); // Stop the timer,  No clock source
      break;

    case ACCEL:
      step_count++;
      profile.accel_count++;
      if (new_first_step_delay <= profile.min_time_delay)
      {
        last_accel_delay = new_first_step_delay;
        new_first_step_delay = profile.min_time_delay;
        rest = 0;
        profile.run_state = RUN;
      }
      break;
    case RUN:
      step_count++;
      if (step_count >= profile.decel_start)
      {
        profile.accel_count = profile.decel_length;
        // Start decelration with same delay as accel ended with.
        new_first_step_delay = last_accel_delay;
        profile.run_state = DECEL;
      }
      break;
    case DECEL:
      step_count++;

      if (profile.accel_count >= 0)
      {

        profile.run_state = STOP;
        global_state = false;
      }

      break;

  }
  profile.moved_steps = step_count;
  profile.first_step_delay = new_first_step_delay;

}

.h

#ifndef speed_profile_h
#define speed_profile_h


#include <Arduino.h> 
#include <ros.h>
#include <std_msgs/Int16.h>
#include <std_msgs/Empty.h>

// Timer/Counter 1 running on 3,686MHz / 8 = 460,75kHz (2,17uS). (T1-FREQ 460750)
#define T1_FREQ 1382400

//! Number of (full)steps per round on stepper motor in use.
#define FSPR 1600

// Maths constants. To simplify maths when calculating in compute_speed_profile().
#define ALPHA (2*3.14159/FSPR)                    // 2*pi/spr
#define A_T_x100 ((long)(ALPHA*T1_FREQ*100))     // (ALPHA / T1_FREQ)*100
#define T1_FREQ_148 ((int)((T1_FREQ*0.676)/100)) // divided by 100 and scaled by 0.676
#define A_SQ (long)(ALPHA*2*10000000000)         // ALPHA*2*10000000000
#define A_x20000 (int)(ALPHA*20000)              // ALPHA*20000

// Speed ramp states
#define STOP  0
#define ACCEL 1
#define DECEL 2
#define RUN   3


// Motor direction 
#define CW  0
#define CCW 1

typedef struct 
{
 volatile unsigned char run_state : 3; // Determining the state of the speed profile
 volatile unsigned char dir: 1; // Determining the direction the motor has to move - Start being CCW 
 volatile unsigned int first_step_delay; // Period time for the next timer_delay, determines the acceleration rate. 
 volatile unsigned int decel_start; //  Determines at which step the deceleration should begin. 
 volatile signed int decel_length; // Set the deceleration length
 volatile signed int min_time_delay; //minium time required time_delay for achieving the wanted speed.
 volatile signed int accel_count; // counter used when computing step_delay for acceleration/decelleration. 
 volatile unsigned int moved_steps; // Used by ros to publish current tipper position
 volatile unsigned int current_step_position; // contains the current step_position
 volatile unsigned int step_counter; //used for debug purpose

}speed_profile;


void computation_of_speed_profile(signed int motor_steps, unsigned int motor_accel, unsigned int motor_decel, unsigned int motor_speed);
#endif
    
pregunta J.Down

1 respuesta

2

Tener dos variables diferentes para hacer el trabajo de una variable parece extraño. Inicialice some_variable fuera de ISR y hágalo volátil para que el compilador no lo optimice haciéndolo constante, lo que sucede si usa algún tipo de optimización. De esa manera solo incrementa tu variable cuando quieras

    
respondido por el Artūras Jonkus

Lea otras preguntas en las etiquetas