В очередном уроке мы рассмотрим работу Arduino с энкодером (который служит для преобразования угла поворота в эл. сигнал). С энкодера мы получаем 2 сигнала (А и В), которые противоположны по фазе. В данном уроке мы будем использовать энкодер фирмы SparkFun COM-09117, который имеет 12 положений на один оборот (каждое положение 30°). На приведенной ниже диаграмме вы можете видеть, как зависят выход А и В друг от друга при вращении энкодера по часовой или против часовой стрелки.
Каждый раз, когда сигнал А переходит от положительного уровня к нулю, мы считываем значение выхода В. Если В в этот момент находится в положительном состоянии, значит энкодер вращается по часовой стрелке, если В нуль, то энкодер вращается против часовой стрелки. Считывая оба выхода, мы при помощи МК можем определить направление вращения, и при помощи подсчета импульсов с А выхода - угол поворота. Конечно можно пойти еще дальше и при помощи вычисления частоты, можно определить насколько быстро происходит вращение энкодера. Как вы видите, энкодер имеет много преимуществ по сравнению с обычным потенциометром.
Используя энкодер мы будем управлять яркостью LED светодиода при помощи ШИМ выхода. Для считывания данных энкодера мы будем использовать простейший метод, основанный на программных таймерах, которые мы изучали в третьем уроке.
Как было сказано выше, мы будем использовать энкодер sparkfun. Первое, что необходимо сделать, это определить как часто нам нужно обращаться к выходам энкодера для считывания значений. Итак, представим себе, что в лучшем случае, мы можем повернуть ручку энкодера на 180° за 1/10 сек, т.е. это будет 6 импульсов за 1/10 сек или 60 импульсов в секунду. В реальности быстрее вращать не сможете. Т.к. нам необходимо отслеживать все полупериоды, то частота должна быть минимум 120 Герц. Для полной уверенности, давайте примем 200 Гц. (Примечание: т.к. у нас механический энкодер, то возможен дребезг контактов, а низкая частота позволяет отфильтровывать дребезг).
По сигналам программного таймера нам необходимо постоянно сравнивать текущее значение выхода А энкодера с предыдущим значением. Если состояние изменилось от положительного к нулю, то мы проверяем значение выхода В и смотрим положительное оно или нет. В зависимости от полученного результата мы увеличиваем или уменьшаем счетчик значения яркости светодиода.
Программа для данного урока приведена ниже. Она построена на базе предыдущего урока Fade, где использовалась функция millis() для задания временных интервалов. Временной интервал у нас будет 5 мс (200 Гц)
/* ** Энкодер ** Для управлением яркостью LED используется энкодер Sparkfun */ int brightness = 120; // яркость LED, начинаем с половины int fadeAmount = 10; // шаг изменения яркости LED unsigned long currentTime; unsigned long loopTime; const int pin_A = 12; // pin 12 const int pin_B = 11; // pin 11 unsigned char encoder_A; unsigned char encoder_B; unsigned char encoder_A_prev=0; void setup() { // declare pin 9 to be an output: pinMode(9, OUTPUT); // устанавливаем pin 9 как выход pinMode(pin_A, INPUT); pinMode(pin_B, INPUT); currentTime = millis(); loopTime = currentTime; } void loop() { currentTime = millis(); if(currentTime >= (loopTime + 5)){ // проверяем каждые 5мс (200 Гц) encoder_A = digitalRead(pin_A); // считываем состояние выхода А энкодера encoder_B = digitalRead(pin_B); // считываем состояние выхода B энкодера if((!encoder_A) && (encoder_A_prev)){ // если состояние изменилось с положительного к нулю if(encoder_B) { // выход В в полож. сост., значит вращение по часовой стрелке // увеличиваем яркость, не более чем до 255 if(brightness + fadeAmount <= 255) brightness += fadeAmount; } else { // выход В в 0 сост., значит вращение против часовой стрелки // уменьшаем яркость, но не ниже 0 if(brightness - fadeAmount >= 0) brightness -= fadeAmount; } } encoder_A_prev = encoder_A; // сохраняем значение А для следующего цикла analogWrite(9, brightness); // устанавливаем яркость на 9 ножку loopTime = currentTime; } }
Комментарии (17) | Я собрал (0) | Подписаться
Для добавления Вашей сборки необходима регистрация
Повторил код- Всё работает!
Т.е. вращаем влево- на одном пине появляются импульсы. Вращаем вправо- теперь импульсы появляются на втором, назначенном нами пине.
byte pinLed = 9; // Светодиод
byte brightness = 0; // Яркость
void setup() {
attachInterrupt(0, encoder, FALLING); // Пин А на пин 2 ардуино (можно на 3). Это 0-е прерывание (3 - это первое прерывание, меняем 0 на 1). FALLING - когда значение переходит с HIGH на LOW.
}
void loop() {
// Какой-то код...
}
void encoder() { // Функция обработки прерывания
if(digitalRead(pinB)) {
if(brightness + fadeAmount = 0) brightness -= fadeAmount;
}
analogWrite(pinLed, brightness); // устанавливаем яркость на 9 ножку
}
void encoder() { // Функция обработки прерывания
if (digitalRead(pinB)) {
if (brightness + fadeAmount < 255) {brightness += fadeAmount;}
} else {
if (brightness - fadeAmount > 0) {brightness -= fadeAmount;}
}
analogWrite(pinLed, brightness); // устанавливаем яркость на пин 9
}
int fadeAmount = 10; // шаг изменения яркости LED если взять простой энкодер на 24 такта , то каждый так увеличивает яркость на 10 , и того на полный круг 24 градации , что в свою очередь говорит о том что 10 множим на 24 получаем 240 , из этого смотрим дальше начинаем со 120 , и в итоге на пол оборота энкодера получим полное значение , и это обрабатывать с частотой 5 милисикунд , это 200 герц , где то около этого , сюда забыли преплюсовать работу бутлодера , и 200 герц частота счета , если перевести в обороты то это не так много , это 200 оборотов в секунду , помножим на минуту и это около 12 000 или близко к этому , из этого вывод что даже простой шаговик мы не сможем контролировать по шагам , не говоря про что то существенное , а если туда повесить производственный энкодер на 200 импульсов , то ардуино просто захлебнеться со счетом , ну как то так , могу и ошибаться , поправляйте если что
Если программа не успела до этого момента переполнить loopTime+5 (из-за долгого кода в таймере или прерывания, например), то таймер встанет на 50 дней. А если успела, то несколько миллисекунд код крутился без задержки.