Подключение модуля энкодера (KY-040) к Arduino и создание простейшего счетчика импульсов.

12.11.2016 20:35

jazon



Модуль энкодер KY-040 является механическим датчиком угла поворота, он преобразует угол поворота вращающегося объекта(например вала) в электрические сигналы сдвинутые на 90 градусов относительно друг друга. Данный модуль имеет три вывода - CLK, DT и SW. Сигналы, сдвинутые на 90 градусов относительно друг друга появляются именно на выводах CLK и DT при вращении по/против часовой стрелки, вывод SW используется для получения состояния центральной оси энкодера, которая работает как кнопка. 

Итак, не вдаваясь в подробности внутрисхемного устройства энкодера(об этом будет отдельная статья), произведем его подключение к плате Arduino Uno. Схема подключения модуля энкодера в связке с многоразрядным семисегментным индикатором:



Нам достаточно будет просто разобрать состояние сигналов которые дают вывода CLK и DT, для этого есть небольшая схемная диаграмма, которая покажет как сдвинуты сигналы при вращении в ту или иную стороны.



Из диаграммы видно что, каждый раз когда сигнал А(контакт CLK энкодера) переходит от высокого уровня к низкому, считывается состояние сигнала Б(контакт DT энкодера). Если сигнал Б даёт высокий уровень сигнала, это означает что вращение энкодера происходит по часовой стрелке. Если сигнал Б даёт низкий уровень сигнала при переходе сигнала А из низкого в высокий уровень, то это означает что вращение энкодера происходит против часовой стрелки. Считывая оба этих сигнала в программе, можно определить направление вращения, также при подсчете импульсов сигнала Б, можно инкрементировать либо декрементировать программный счетчик импульсов.

Чтобы считывать сигналы А и Б, а также сигналы центральной оси энкодера(напомню - она работает как кнопка), можно применить нижеописанную конструкцию. Эту конструкцию можно встраивать в скетч, добавляя в неё различный функционал, всё ограничивается только желанием и фантазией разработчика. Тело конструкции достаточно хорошо прокомментировано, в дальнейшем для простоты текста скетча можно убрать комментарии. Итак, конструкция для считывания и преобразования сигналов энкодера в полезные данные:

//Временные переменные для хранения уровней сигналов
//полученных от энкодера
unsigned char encoder_A, encoder_B, encoder_A_prev;
//Переменная для отслеживания нажатий кнопки - 
//центральной оси энкодера
static bool SW_State = false;

void setup() 
{
  //Предварительные установки
  //Объявления переменных
  //Инициализации портов и т.д.
}

void loop() 
{
  //CLK подключаем к пину 3 на плате Arduino
  //DT  подключаем к пину 4 на плате Arduino
  //Считываем значения выходов энкодера
  //И сохраняем их в переменных
  encoder_A = digitalRead(3);
  encoder_B = digitalRead(4);

  //Если уровень сигнала А низкий,
  //и в предидущем цикле он был высокий 
  if(!encoder_A && encoder_A_prev)
  {
    //Если уровень сигнала В высокий
    if(encoder_B)
    {
      //Значит вращение происходит по часовой стрелке
      //Здесь можно вставить операцию инкремента
      //Здесь можно вставлять какие либо свои 
      //операции по обработке данных в нужном направлении
    }
    //Если уровень сигнала В низкий
    else
    {
      //Значит вращение происходит против часовой стрелки
      //Здесь можно вставить операцию декремента
      //Здесь можно вставлять какие либо свои 
      //операции по обработке данных в нужном направлении
    }
  }
  //Обязательно нужно сохранить состояние текущего уровня сигнала А
  //для использования этого значения в следующем цикле сканирования программы
  encoder_A_prev = encoder_A;

  //Работаем с центральной осью энкодера - кнопкой
  //Этот кусок кода образует собой как бы перекидной триггер
  //Считываем значение пина 2 на плате Arduino
  //к которому подключен контакт SW энкодера
  //Если центральная ось нажата - то сигнал SW будет иметь низкий уровень
  if(!digitalRead(2))
  {
    //Если переменная SW_State установлена в false то установить её в true 
    if(!SW_State)
    {
      //И запомнить состояние
      SW_State = true;
    }
    //И наоборот - если переменная SW_State установлена в true, 
    //то сбросить её в false 
    else
    {
      //И запомнить состояние
      SW_State = false;
    }
  }
}


Скетч, для обработки сигналов энкодера и выводу значения счетчика на дисплей, показан ниже. В этот скетч встроена конструкция для считывания и преобразования сигналов энкодера, которая была описана выше. 


#include "LedControl.h"

/*
 * Подключаем библиотеку LedControl.h
 * и создаём объект класса LedControl
 * при этом, 7-ми сегметный дисплей с драйвером MAX72xx
 * должен быть подключен к плате Arduino следующим образом:
 * Arduino[Pin 5V] -> Display Module MAX72xx[VCC]
 * Arduino[PinGND] -> Display Module MAX72xx[GND]
 * Arduino[Pin 12] -> Display Module MAX72xx[DIN]
 * Arduino[Pin 11] -> Display Module MAX72xx[CLK]
 * Arduino[Pin 10] -> Display Module MAX72xx[LOAD/CS]
 * Arduino[Pin 4]  -> Encoder Module [CLK]
 * Arduino[Pin 3]  -> Encoder Module [DT]
 * Arduino[Pin 2]  -> Encoder Module [SW]
 */

LedControl lc = LedControl(12, 11, 10, 1);

//Проименовываем адреса портов на плате Arduino
const int Dir    = 4; 
const int Step   = 3;
const int Switch = 2;

//Counter - переменная для хранения значения счетчика
static long Counter = 0;

//SW_State - флаг триггер отслеживания нажатия центральной оси 
static bool SW_State = false;

//Временные переменные для хранения уровней сигналов энкодера
unsigned char encoder_A, encoder_B, encoder_A_prev;

void setup() 
{
  //Устройство(7-ми сегментный дисплей) выводим из спящего режима
  lc.shutdown(0, false);
  //Установить яркость дисплея на 8
  //Всего возможных режимов яркости от 0 до 15
  lc.setIntensity(0,8);
  //Очистить дисплей
  lc.clearDisplay(0);
  //Конфигурируем порты для энкодера
  pinMode(Dir,    INPUT);
  pinMode(Step,   INPUT);
  pinMode(Switch, INPUT);
}

void loop() 
{
  //Считываем значения выходов энкодера
  //И сохраняем их в переменных
  encoder_A = digitalRead(Step);
  encoder_B = digitalRead(Dir);

  //Если уровень сигнала А низкий,
  //и в предидущем цикле он был высокий
  if(!encoder_A && encoder_A_prev)
  {
    //Если уровень сигнала В высокий
    if(encoder_B)
    {
      //Значит вращение происходит по часовой стрелке
      //Наше условие:
      //Если значение счетчика больше или равно максимальному числу
      if(Counter >= 99999999)
      {
        //Обнулить значение счетчика
        Counter = 0;
      }
      else
      {
        //Иначе инкрементировать при каждом щелчке на единицу
        Counter ++;
      }
    }
    //Если уровень сигнала В низкий
    else
    {
      //Значит вращение происходит против часовой стрелки
      //Если значение счетчика меньше или равно нулю
      if(Counter <= 0)
      {
        //проинициализировать значение максимальным числом
        Counter = 99999999;
      }
      else
      {
        //Иначе декрементировать при каждом щелчке на единицу
        Counter --;
      }
    }
  }
  //Обязательно нужно сохранить состояние текущего уровня сигнала А
  //для использования этого значения в следующем цикле сканирования программы
  encoder_A_prev = encoder_A;

  //Работаем с центральной осью энкодера - кнопкой
  //Этот кусок кода образует собой как бы перекидной триггер
  //Считываем значение пина 2 на плате Arduino
  //которомый проименован как Switch
  //Если центральная ось нажата - то сигнал Switch будет иметь низкий уровень
  if(!digitalRead(Switch))
  {
    //Если переменная SW_State установлена в false то установить её в true 
    if(!SW_State)
    {
      //И запомнить состояние
      SW_State = true;
    }
    //И наоборот - если переменная SW_State установлена в true, 
    //то сбросить её в false 
    else
    {
      //И запомнить состояние
      SW_State = false;
    }
  }

  //Часть программы которая заполняет разряды 
  //семисегментного дисплея значением счетчика
  long intCounter = Counter;
  int  divCounter;
  
  for(int i = 0; i < 8; i ++)
  {
    divCounter = intCounter % 10;
    intCounter = intCounter / 10;
        
    if(intCounter == 0 && SW_State)
    {
      if(divCounter == 0)
      {
        if(i == 0)
        {
          lc.setChar(0, 0, '0', false);
        }
        else
        {
          lc.setChar(0, i, ' ', false);
        }
      }
      else
      {
        lc.setDigit(0, i, divCounter, false);
      }
    }
    else
    {
      lc.setDigit(0, i, divCounter, false);
    }
  }
}


Видео, как это работает:


Дополню наш материал, если вам интересно как работать с многоразрядными семисегментными индикаторами на базе микросхемы MAX7219, то добро пожаловать в статью по ссылке: Модуль многоразрядного 7-ми сегментного индикатора на базе микросхемы MAX72xx, подключение к Arduino и работа с библиотечными функциями. 

Надеемся, что вам понравился материал этой статьи, свои вопросы, пожелания и критику оставляйте в комментариях ниже.


Смотрите также



Расскажи о нас

Сообщение

Если у Вас есть опыт в работе с Arduino и собственно есть время для творчества, мы приглашаем всех желающих стать авторами статей публикуемых на нашем портале. Это могут быть как уроки, так и рассказы о ваших экспериментах с Arduino. Описание различных датчиков и модулей. Советы и наставления начинающим. Пишите и размещайте свои статьи в соответсвующей ветке форума.