Джойстик. Урок 18. Ардуино

джойстик
Джойстик и светодиодная матрица
Джойстик и светодиодная матрица

Привет! В прошлый раз мы начали говорить про светодиодные матрицы. А как можно использовать матрицу лучше всего? Конечно управлять светодиодами используя джойстик.

В этом уроке мы подключим к Ардуино и светодиодную матрицу и джойстик. А обзор матрицы мы делали в прошлый раз. Посмотрите тот пост, если уже забыли или пропустили.

Для того, чтобы выполнить этот урок нам понадобиться

  • Ардуино UNO
  • Перемычки
  • Макетная плата
  • Светодиодная матрица
  • Резистор 220 Ом
  • Джойстик
  • Кабель USB

Джойстик KY-023

Джойстик KY-023 это небольшой модуль готовый к подключению к Ардуино. У него 5 контактов. По контактам данных VRX и VRY передаются аналоговые значения от двух потенциометров. Они определяют положение джойстика по осям X и Y.

При нажатии на ручку, срабатывает кнопка. Ее контакт SW передает цифровой сигнал.

Если мы отпустим ручку, то потенциометры вернуться в центральное положение. При этом они будут отправлять аналоговое значение около 512. Имейте в виду, что ровно 512, скорее всего, не будет.

В моем случае, ось Х в центральном положении выдавала 535. А Y все время менялась между 532-540. Этот момент придется учесть в программе.

Подключение

У джойстика 5 контактов. Питание 5 вольт, земля, цифровой контакт для кнопки и два аналоговых контакта потенциометров.

Принципиальная схема подключения джойстика
Принципиальная схема подключения джойстика
  • GND — земля
  • +5v — питание 5 вольт
  • VRX — аналоговый пин
  • VRY — аналоговый пин
  • SW — цифровой пин

Получаем данные от джойстика

Для начала проверим работу джойстика и попробуем получить от него данные и вывести их в монитор порта.

Загрузим простой скетч и откроем монитор. Считаем состояния кнопки и потенциометров и выведем их в монитор порта.

#define pinX    A2
#define pinY    A1
#define swPin    2

void setup() {
  Serial.begin(9600);
  
  pinMode(ledPin, OUTPUT);
  pinMode(pinX, INPUT);
  pinMode(pinY, INPUT);
  pinMode(swPin, INPUT);
  digitalWrite(swPin, HIGH);
}
 
void loop() {
  boolean Button = digitalRead(swPin);

  int X = analogRead(pinX);          
  int Y = analogRead(pinY);     

  Serial.print(X);                
  Serial.print("\t");
  Serial.print(Y);
  Serial.print("\t");
  Serial.println(Button); 
}

При отклонении джойстика от центрального положения данные потенциометров меняются. При клике на кнопку, данные на цифровом контакте также изменяются.

Данные от джойстика в мониторе
Данные от джойстика в мониторе

Управляем матрицей

Теперь объединим знания о светодиодной матрице и джойстике в небольшое подобие игры. Зажжем один из светодиодов на матрице и будем управлять им с помощью джойстика. А при клике на кнопку будем изменять цвет светодиода.

Подключим библиотеки и заведем все нужные переменные.

#include <FastLED.h>

//matrix settings
#define NUM_LEDS 256
#define DATA_PIN 3
#define BRIGHTNESS 8

//joystick settings
#define pinX    A2  // X 
#define pinY    A1  // Y
#define swPin    2  // Button

int red, green, blue; //colors

int row;            // row number
int col;            // column number

int lastDirection = 127; // start position
int newDirection;
CRGB leds[NUM_LEDS];

Инициализируем библиотеки и пины. И отобразим светодиод в начальной позиции.

void setup() {
  
  red = random(0, 255);
  green = random(0, 255);
  blue = random(0, 255);

  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  pinMode(pinX, INPUT);
  pinMode(pinY, INPUT);
  pinMode(swPin, INPUT);
  digitalWrite(swPin, HIGH);
  
  FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
  FastLED.setBrightness(BRIGHTNESS);
    leds[snakeDirection].setRGB(red, green, blue);
  FastLED.show();
}

Поскольку светодиоды на нашей матрице спаяны последовательно и конец одного ряда — это начало следующего. Нам понадобиться рассчитать переходы между рядами для нашего светодиода. Для этого напишем специальную функцию.

Она получит предыдущее состояние светодиода, а также координаты движений с джойстика. И вычислит следующий светодиод, который нужно зажечь.

int Snakedirection(int last, int dX, int dY ){
  dX = map(dX, 0, 1000, -1, 1);
  dY = map(dY, 0, 1000, -1, 1);
  int newDirection = last;
  
  if( dX != 0 ){ // moving in X direction
    
    if ( row&1 ){
      newDirection = last + dX; // четная
    } else {
      newDirection = last - dX; // не четная
    }
    
  } 
  
  if( dY < 0){ // moving in Y DOWN direction
    if ( row&1 ){
      newDirection = last + (col*2)+1; // четная
    } else {
      newDirection = last + (16-col-1)+(16-col); // не четная
    }
  } 
  if( dY > 0){ // moving in Y UP direction
    if ( row&1 ){
      newDirection = last - (last - 16*row) - (16 - col); // четная
    } else {
      newDirection = last - (col*2)-1; // не четная
    }
  }

  Serial.print(newDirection);
  Serial.print('\t');
  Serial.print(newDirection);
  Serial.print('\t');

  
  return newDirection;
}

Еще одна функция будет отвечать за перерисовку светодиодов. Она получит номер светодиода, который надо зажечь в данный момент.

int snakeMove(int snakeDirection){
  FastLED.clear();
    leds[snakeDirection].setRGB(red, green, blue);
  FastLED.show();

  row = (int)(snakeDirection/16);  // row number 
  if ( row&1 ){
    col = (row+1) * 16 - snakeDirection - 1;
  } else {
    col = snakeDirection - row * 16;
  }
  
  Serial.print(snakeDirection);
  Serial.print('\t');
  Serial.print(row);
  Serial.print('\t');
  Serial.println(col);
  
  return snakeDirection;
}

Функция color() будет менять цвет светодиода на случайный. По умолчанию кнопка на модуле отправляет 1, поэтому добавим в условие знак !

void color(boolean sw){
  if(!sw){

    red = random(0,255);
    green = random(0,255);
    blue = random(0,255);
    
  }
}

А в управляющем цикле просто соединим эти функции и установим небольшую задержку.

void loop() {
  color( digitalRead(swPin) );
  newDirection = Snakedirection(lastDirection, analogRead(pinX), analogRead(pinY));
  lastDirection = snakeMove(newDirection);
  delay(100);
}
Управляем матрицей с помощью джойстика
Управляем матрицей с помощью джойстика

Полный текст программы

#include <FastLED.h>

//maatrix settings
#define NUM_LEDS 256
#define DATA_PIN 3
#define BRIGHTNESS 8

//joystick settings
#define pinX    A2  // ось X джойстика
#define pinY    A1  // ось Y джойстика
#define swPin    2  // кнопка джойстика

int row;            // row number
int col;            // column number

int lastDirection = 127; // start direction
int newDirection;

int red, green, blue; //colors
CRGB leds[NUM_LEDS];

void setup() {

  red = random(0, 255);
  green = random(0, 255);
  blue = random(0, 255);
  
  Serial.begin(9600);
  pinMode(pinX, INPUT);
  pinMode(pinY, INPUT);
  pinMode(swPin, INPUT);
  digitalWrite(swPin, HIGH);
  
  FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
  FastLED.setBrightness(BRIGHTNESS);
  leds[lastDirection].setRGB(red, green, blue);
  FastLED.show();
}

int Snakedirection(int last, int dX, int dY ){
  dX = map(dX, 0, 1000, -1, 1);
  dY = map(dY, 0, 1000, -1, 1);
  int newDirection = last;
  
  if( dX != 0 ){ // moving in X direction
    
    if ( row&1 ){
      newDirection = last + dX; // четная
    } else {
      newDirection = last - dX; // не четная
    }
    
  } 
  
  if( dY < 0){ // moving in Y DOWN direction
    if ( row&1 ){
      newDirection = last + (col*2)+1; // четная
    } else {
      newDirection = last + (16-col-1)+(16-col); // не четная
    }
  } 
  if( dY > 0){ // moving in Y UP direction
    if ( row&1 ){
      newDirection = last - (last - 16*row) - (16 - col); // четная
    } else {
      newDirection = last - (col*2)-1; // не четная
    }
  }

  Serial.print(newDirection);
  Serial.print('\t');
  Serial.print(newDirection);
  Serial.print('\t');

  
  return newDirection;
}

int snakeMove(int snakeDirection){
  FastLED.clear();
  leds[snakeDirection].setRGB(red, green, blue);
  FastLED.show();

  row = (int)(snakeDirection/16);  // row number 
  if ( row&1 ){
    col = (row+1) * 16 - snakeDirection - 1;
  } else {
    col = snakeDirection - row * 16;
  }
  
  Serial.print(snakeDirection);
  Serial.print('\t');
  Serial.print(row);
  Serial.print('\t');
  Serial.println(col);
  
  return snakeDirection;
}

void color(boolean sw){
  if(!sw){

    red = random(0,255);
    green = random(0,255);
    blue = random(0,255);
    
  }
}

void loop() {
  color( digitalRead(swPin) );
  newDirection = Snakedirection(lastDirection, analogRead(pinX), analogRead(pinY));
  lastDirection = snakeMove(newDirection);
  delay(100);
}

Заключение

Мы рассмотрели использование джойстика для Ардуино. И соединили его со светодиодной матрицей. Наверное, вы обратили внимание, что готовый проект похож на игру змейка из старых телефонов. Что ж, попробуем реализовать ее в будущем.

2 комментария на “Джойстик. Урок 18. Ардуино

  1. Hi! How is your matrix wired? As in, do all rows go from left to right? or does it alternate each row?

    For example, my Matrix goes from left to right on all rows:
    First row, LED 0 to LED 7
    Second row, LED 8 to LED 15
    Third row, LED 16 to LED 23
    And so on…

    However, there are some Matrix that go like this:
    First row, LED 0 to LED 7
    Second row, LED 15 to LED 8
    Third row, LED 16 to LED 23
    Fourth row, LED 31 to LED 24
    And so on…

    So, which one is yours?

    1. Hello! Ok, it was easy. int lastDirection = 135; // start direction means LED number where a snake appers at the beginning of the game. So, you can change it to 0 or 1. Or make it random. My matrix goes like П style. Therefore, First row, LED 0 to LED 15, Second row, LED 16 to LED 32. And so on.
      And there is a Snakedirection(int last, int dX, int dY) function that caclulates transitions between rows and lines. Looks like it has to be changed for your matrix.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *