Инкрементный кодер
может кто-нибудь сказать мне, что не так с моим кодом, я использую его для расчета оборотов с помощью инкрементного кодера
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;
}
@Adnan, 👍-1
Обсуждение1 ответ
Непостоянный.
По сути, любая переменная, объявленная в глобальной области (все, что вы объявляете до того, как приступите к настройке ()
), ДОЛЖНА иметь квалификатор 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
- Считывание нескольких поворотных энкодеров
- Считывание выходных данных энкодера с помощью оптрона
- Как выбрать входной контакт 600 кГц, разделить его на 4 и сгенерировать низкочастотный сигнал на выходном контакте Arduino
- подсчет оборотов инкрементного энкодера
- Инкрементный поворотный энкодер отправляет данные, когда вал не трогается
- Сможет ли Arduino Uno считывать 3-кратные инкрементальные энкодеры?
- Многооборотный потенциометр - это боль, стоит ли вместо этого использовать инкрементный энкодер?
- Необъяснимое поведение int в кодировщике/светодиодном проекте
Вам нужно рассказать нам больше о том, что в настоящее время происходит с вашей программой, чего вы ожидаете вместо этого., @jfpoilpret
он не дает никакого вывода в последовательном мониторе @jfpoilpret, @Adnan
Не могли бы вы уточнить свою проводку: к какому выводу Arduino вы подключили свой кодер?, @jfpoilpret
я подключил канал кодера А к цифровому контакту 2 на arduino, который является прерыванием 0., @Adnan
Что странно, так это то, что вы упомянули, что на последовательном мониторе нет выхода **NO**, что означало бы, что thzn
loop()
даже не вызывается? Я подозреваю, что ваш двигатель работает очень быстро и может генерировать слишком много прерываний, которые помешают работе функции loop ().. Не могли бы вы сначала попробовать добавить задержку в свой цикл (1 секунда была бы справедлива) и посмотреть, что произойдет?, @jfpoilpretКроме того, вы можете изменить порядок инициализации в вашем "setup ()" на первый " Serial.begin (...)", что даст время для последовательного инициализации перед запуском прерываний кодера., @jfpoilpret