/* 버튼 코드 참조: https://kikiai.tistory.com/29
마우스 코드 참조: https://www.arduino.cc/reference/ko/language/functions/usb/mouse/mousemove/
위의 링크에 마우스 관련 함수 다 설명되있음.
조이스틱 코드 참조: http://blog.naver.com/PostView.nhn?blogId=boilmint7&logNo=220927175653
조이스틱에도 버튼이 있지만 사용하기 힘들어서 안썼음.
버튼: 핀 4개 있는데 2개 버리고 2개중 하나에 +5V, 하나는 그라운드랑 Pin2에 박으면 됨.
조이스틱: 그라운드랑 +5V는 말 그대로 그라운드랑 +5V에 연결
VRX, VRY 는 각각 A0, A1에 연결함. 나는 조이스틱핀이 아래를 보는 방향으로 구현해서 x, y축이 바뀜.
그래서 아래 코드 보면 A0, A1 순서가 다름.
*/
#include <Mouse.h> // 마우스 헤더(레오나르도가 아니면 라이브러리 깔아도 오류 뜸!, 무조건 레오나르도로 ㄱㄱ)
void setup() {
pinMode(2, INPUT); // 좌클릭 버튼
pinMode(4, INPUT); // 우클릭 버튼
Mouse.begin(); // 마우스 제어 시작
Serial.begin(9600); //시리얼 통신을 시작
}
void loop() {/* 다 다르겠지만 나는 조이스틱 초기 값이 x: 517, y: 506 정도였음. 이게 의미하는건
중심 좌표가 (512, 512) 쯤이라는건데, 사용하기 불편하므로 중심을 (0, 0)로 만들었다.
200을 나눈건 마우스가 너무 큰 범위로 움직이게 되기 때문에 크기를 줄여줬다.*/
int x = (analogRead(A1) - 517) / 260; /* 나누는 값은 맘대로 바꿔도 된다. 다만 500이 넘어가면 마우스가 움직이지 않게 된다.
왜냐하면 (analogRead(A1) - 517)의 최대값이 500정도 되는데, 거기에 500을 나눠버리면 0이 되기 때문*/
int y = - (analogRead(A0) - 506) / 260; /* 조이스틱을 위로 올리면 같이 +가 되야 되는데,
-가 되길래 그냥 -곱해줬다.*/
int Left_button = digitalRead(2); // 1이면 누른 상태, 0이면 안 누른 상태임.
int Right_button = digitalRead(4); // 위와 마찬가지
Sprint(x, y, Left_button, Right_button); // 시리얼 프린트
if (Left_button == 1) // Left button이 1이라는건 좌클릭을 하고 있다는 상태이므로 마우스를 누른 상태로 유지시켜주는 Mouse.press()를 사용함
{
Mouse.press(MOUSE_LEFT); // 좌클릭 한 상태 유지
}
else if (Left_button == 0 && Right_button == 0)
{
Mouse.release(); //클릭 상태 해제
}
else if (Right_button == 1) // 우클릭
{
Mouse.click(MOUSE_RIGHT);
}
Mouse.move(x, y); // 마우스를 움직이는 함수
}
// 루프안에 여러줄 있는거 꼴보기 싫어서 함수로 만듬. 별 의미 없음.
void Sprint(int x, int y, int lb, int rb)
{
Serial.print("X: ");
Serial.print(x);
Serial.print(' ');
Serial.print("Y: ");
Serial.print(-y); // 시리얼프린트에 -로 출력되길래 부호 바꿔줌.
Serial.print(' ');
Serial.print("Left_button: ");
Serial.print(lb);
Serial.print(' ');
Serial.print("Rigft_button: ");
Serial.println(rb);
}
저번에는 NeoPixel로 빨강, 초록, 파랑, 노랑, 흰색을 켰었는데 똑같은 코드를 5번이나 넣는 식으로 구현을 했었다.
개인적으로 이런 코드는 비효율적이라고 생각하기에, 배열을 사용해서 코드를 짧게 구현해 보려고 한다.
그리고 버튼을 누르고 있어야 NeoPixel이 켜지는 기능과 색을 조금 더 추가하려고 한다.
우선 단순하게 코드를 짜면 아래와 같다.
#include <Adafruit_NeoPixel.h>
#define LED 11 // LED Pin
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(1, LED, NEO_GRB + NEO_KHZ800);
const int SW = 10; // Button Pin
int led = 0; // LED의 상태를 저장해주는 변수
void setup() {
pixels.begin();
pixels.show();
pinMode(SW, INPUT);
}
void loop() {
// 버튼을 누르고 있을 때 Led를 켬
if (digitalRead(SW) == LOW) {
if (led == 0) {
pixels.setPixelColor(0, 100, 0, 0); // 빨강
pixels.show();
delay(1000);
}
if (led == 1) {
pixels.setPixelColor(0, 0, 100, 0); // 파랑
pixels.show();
delay(1000);
}
if (led == 2) {
pixels.setPixelColor(0, 0, 0, 100); // 초록
pixels.show();
delay(50);
}
if (led == 3) {
pixels.setPixelColor(0, 100, 100, 0); // 노랑
pixels.show();
delay(1000);
}
if (led == 4) {
pixels.setPixelColor(0, 100, 0, 100); // 보라
pixels.show();
delay(1000);
}
if (led == 5) {
pixels.setPixelColor(0, 0, 100, 100); // 하늘
pixels.show();
delay(1000);
}
if (led == 6) {
pixels.setPixelColor(0, 100, 100, 100); // 하양
pixels.show();
delay(1000);
led = -1;
}
led += 1;
}
// 버튼을 누르지 않았을 때는 정전 상태
else {
pixels.setPixelColor(0, 0, 0, 0);
pixels.show();
}
}
버튼을 누르고 있을 때는 LED가 켜지면서 색깔이 계속 바뀌고, 누르지 않았을 때는 정전 상태이다.
구현이 되긴 했지만 코드가 쓸데없이 길다. 1차원 배열과 %(나머지 연산)을 사용하면 아래와 같이 짧게 구현할 수 있다.
#include <Adafruit_NeoPixel.h>
#define LED 11 // LED Pin
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(1, LED, NEO_GRB + NEO_KHZ800);
const int SW = 10; // Button Pin
int led = 0; // LED의 상태를 저장해주는 변수
int R[7] = {100, 0, 0, 100, 100, 0, 100}; // 빨간색
int G[7] = {0, 100, 0, 100, 0, 100, 100}; // 초록색
int B[7] = {0, 0, 100, 0, 100, 100, 100}; // 파란색
void setup() {
pixels.begin();
pixels.show();
pinMode(SW, INPUT);
}
void loop() {
// 버튼을 누르고 있을 때 Led를 켬
if (digitalRead(SW) == LOW) {
// 배열을 사용함으로써 코드를 엄청 짧게 만들수 있음
pixels.setPixelColor(0, R[led%7], G[led%7], B[led%7]);
pixels.show();
delay(1000); // 1초 주기
led += 1;
}
// 버튼을 누르지 않았을 때는 정전 상태
pixels.setPixelColor(0, 0, 0, 0);
pixels.show();
}
위에 코드를 보면 R, G, B 3개의 배열에 빨강, 초록, 파랑, 노랑, 보라, 하늘, 하양의 RGB 값들이 순서대로 저장되어 있다.
(100, 0, 0) 같은 방식으로 여러 번 반복할 필요 없기 때문에 훨씬 코드가 짧아지게 된다.
R[led%7], G[...], B[...]의 의미 -> 지금 led 변수는 led의 색깔(순서)을 가리키는데 예를 들면
led = 3 -> R[3%7] = R[3] = 100,
led = 10 -> R[10%7] = R[3] = 100과 같은 방식이다.
%(나머지 연산)을 사용하지 않는다면 중간에 아래와 같이 조건문을 추가해야 되는데 위의 방법보다는 좋지 않은 방법 같다.
if (led == 6) {
led = -1;
}
마지막으로 2차원 배열을 사용해보자.
#include <Adafruit_NeoPixel.h>
#define LED 11 // LED Pin
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(1, LED, NEO_GRB + NEO_KHZ800);
const int SW = 10; // Button Pin
int led = 0; // LED의 상태를 저장해주는 변수
// RGB 값이 저장되어 있는 2차원 배열(빨강, 파랑, 초록, 노랑, 보라, 하늘, 하양)
int RGB[7][3] = {{100,0,0}, {0,100,0}, {0,0,100}, {100,100,0}, {100,0,100}, {0,100,100}, {100,100,100}};
void setup() {
pixels.begin();
pixels.show();
pinMode(SW, INPUT);
}
void loop() {
// 버튼을 누르고 있을 때 Led를 켬
if (digitalRead(SW) == LOW) {
// 배열을 사용함으로써 코드를 엄청 짧게 만들수 있음
pixels.setPixelColor(0, RGB[led%7][0], RGB[led%7][1], RGB[led%7][2]);
pixels.show();
delay(1000); // 1초 주기
led += 1;
}
// 버튼을 누르지 않았을 때는 정전 상태
pixels.setPixelColor(0, 0, 0, 0);
pixels.show();
}
맨 위에 있는 한눈에 다 안 보이던 코드가 이제는 한눈에 다 보인다.
RGB[7][3]은 7행 3열인 행렬이라고 생각하면 될 것 같다.
첫 번째 행에는 빨간색의 RGB 값, 두 번째 행에는 초록색의 RGB 값이 들어있는 식이다.
아래와 같이 잘 작동된다.
쉬운 예제더라도 다양한 방식으로 코드를 짜보는 게 처음 공부할 때는 도움이 되는 것 같다.
남이 짠 코드를 사용하더라도 그걸 그냥 사용하기만 하는 게 아니라, 자신의 것으로 만들고 사용하도록 하자. 그렇지 않으면 남는 게 정말 하나도 없다.