Инкрементный кодер

может кто-нибудь сказать мне, что не так с моим кодом, я использую его для расчета оборотов с помощью инкрементного кодера

long counter=0;
 long  rpm = 0, z =0;
 long  ini_time = 0;
long  end_time=0;




void setup(){
  attachInterrupt(0, A_RISE, RISING);

  Serial.begin(115200);
}//setup


void loop(){

    Serial.println(rpm);
}

void A_RISE(){
  counter ++;
  if (counter == 1)
    ini_time = micros();
  else if (counter>470){ //470 is ticks per revolution
    z = counter;
    rpm_counter(z);

    counter =0;
  }
}

void rpm_counter(int x){

  end_time=micros()-ini_time;
  rpm=(60*10^6)/end_time;

}

, 👍-1

Обсуждение

Вам нужно рассказать нам больше о том, что в настоящее время происходит с вашей программой, чего вы ожидаете вместо этого., @jfpoilpret

он не дает никакого вывода в последовательном мониторе @jfpoilpret, @Adnan

Не могли бы вы уточнить свою проводку: к какому выводу Arduino вы подключили свой кодер?, @jfpoilpret

я подключил канал кодера А к цифровому контакту 2 на arduino, который является прерыванием 0., @Adnan

Что странно, так это то, что вы упомянули, что на последовательном мониторе нет выхода **NO**, что означало бы, что thzn loop() даже не вызывается? Я подозреваю, что ваш двигатель работает очень быстро и может генерировать слишком много прерываний, которые помешают работе функции loop ().. Не могли бы вы сначала попробовать добавить задержку в свой цикл (1 секунда была бы справедлива) и посмотреть, что произойдет?, @jfpoilpret

Кроме того, вы можете изменить порядок инициализации в вашем "setup ()" на первый " Serial.begin (...)", что даст время для последовательного инициализации перед запуском прерываний кодера., @jfpoilpret


1 ответ


0

Непостоянный.

По сути, любая переменная, объявленная в глобальной области (все, что вы объявляете до того, как приступите к настройке ()), ДОЛЖНА иметь квалификатор volatile, если вы хотите использовать ее в подпрограмме обслуживания прерываний, иначе она не будет правильно использована/реализована/создана.

В соответствии с вашим кодом вам необходимо добавить voltatile ко всем четырем вашим глобальным переменным:

volatile int counter = 0;     // если вы останавливаетесь на 470, int-это все, что вам нужно
volatile long rpm = 0;
volatile long z = 0;          // в этом нет необходимости, см. Ниже!
volatile long ini_time = 0;
voltaile long end_time = 0;

Ваш ISR включает в себя некоторые бесполезные инструкции, которые увеличат время, необходимое для выполнения процедуры. Как предположил @jfpoilpret, вы можете постоянно прерывать loop(). Сокращение времени может решить эту проблему:

Во-первых, z = счетчик; rpm_counter(z); . Бессмысленно, если честно. Почему бы просто не вызвать rpm_counter со счетчиком?

Во-вторых, функция rpm_counter ()... в нем не используется аргумент, который вы послали! "x" нигде не используется в функции, так зачем вы ее отправляете?

В-третьих, даже если бы мое второе замечание было неверным, rpm_counter() на самом деле не обязательно должен быть функцией сам по себе. Если вы не собираетесь вызывать его из множества разных мест, просто вставьте содержимое функции в A_RISE():

else if (counter>470)
{ //470-это тики за оборот
    end_time = micros() - ini_time;
    rpm = (60*10^6) / end_time;
    counter = 0;
}

Это могло бы сэкономить много циклов выполнения.

,

“любая переменная, объявленная в глобальной области [ ... ], ДОЛЖНА иметь квалификатор volatile, если вы хотите использовать ее в рутине службы прерывания”. Это неверно. Квалификатор volatile необходим, если переменная будет использоваться как в ISR**, так и в основной программе. ОТО, если переменная используется только внутри ISR, она должна быть статической локальной, а не глобальной., @Edgar Bonet

Может быть, это то, что не так с кодом в моем вопросе здесь: https://arduinoprosto.ru/q/88812/variable-getting-set-to-zero-nondeterministically?noredirect=1#комментарий202751_88812, @Lucas