아두이노에서 LCD 화면에 가변저항으로 받은 값 출력
회로도
과제 수행 순서
1. LCD 화면에 글자 출력
2. 가변저항 입력 값을 시리얼 모니터로 출력
3. 출력된 값을 LCD에 표시하기
1. LCD 화면에 글자 출력
아두이노와 pc를 연결 후 자신의 아두이노에 맞는 보드를 찾아 설정한다.
설정 후 자신의 아두이노 보드를 선택한다
아두이노와 lcd 연결을 하기 위해 라이브러리에 LiquidCrystal_I2C를 추가한다.
라이브러리에 LiquidCrystal_I2C를 추가하면 LCD를 사용할 수 있게 된다.
먼저 LCD 화면에 글자를 띄우기 전 LCD와 아두이노를 연결하기 위해 두 항목이 연결된 포트를 찾아야 한다.
//포트 위치 찾는 코드
#include <Wire.h>
void setup()
{
Wire.begin();
Serial.begin(9600);
while (!Serial); // 시리얼 모니터 대기
Serial.println("\nI2C Scanner");
}
void loop() // 반복
{
byte error, address;
int nDevices;//nDevices에 int 로 저장
Serial.println("Scanning...");
nDevices = 0;//초기값 설정
for(address = 1; address < 127; address++ )//address초기값 1로 설정, 126번 반복, 1씩 증가
{
// The i2c_scanner uses the return value of
// the Write.endTransmisstion to see if
// a device did acknowledge to the address.
Wire.beginTransmission(address);//위치 찾기 함수 실행
error = Wire.endTransmission();//검출시 종료 함수
if (error == 0)//에러값이 0일때
{
Serial.print("I2C device found at address 0x");//시리얼 위치는 0x로 시작
if (address<16)//주소가 16보다 작으면
Serial.print("0");//0을 출력
Serial.print(address,HEX);//주소와 HEX값 출력
Serial.println(" !");
nDevices++;//nDevices 1씩증가
}
else if (error==4)//에러값이 4일때
{
Serial.print("Unknown error at address 0x");//시리얼 위치는 0x로 시작
if (address<16)//주소가 16보다 크면
Serial.print("0");//0을 출력
Serial.println(address,HEX);//주소와 HEX값 출력
}
}
if (nDevices == 0)//nDevices값이 0일 경우
Serial.println("No I2C devices found\n");
else
Serial.println("done\n");
delay(5000); // 다음 스캔까지 5초 대기
}
여기서 찾은 시리얼 모니터에 표기된 포트 (작성자 기준 0x27) 을 기준으로 화면 출력하는 코드를 작성한다.
LCD 16X2는 다음과 같은 행열로 구성된다.
테스트용 코드를 화면중앙에 표시하기 위해 각각 (5,0) 과 (2,1)에 위치시킨다.
#include <LiquidCrystal_I2C.h> //LiquidCrystal 라이브러리 불러오기
LiquidCrystal_I2C lcd(0x27, 16, 2); //lcd 객체 선언
void setup()
{
lcd.begin(); //LCD 사용 시작
}
void loop()
{
lcd.setCursor(5, 0); // 커서를 5, 0에 가져다 놓아라. (열, 행)
lcd.print("Hi ^^"); // 5, 0에 Hi ^^를 출력해라.
delay(1000); // 1초 대기
lcd.setCursor(2, 1); // 커서를 3, 1로 가져다 놓아라. (열, 행)
lcd.print("Hello World!");
delay(1000); // 1초 대기
lcd.clear(); // 글자를 모두 지워라.
delay(1000); // 1초 대기
}
실행 시 Hi^^ 와 Hello World! 가 순차적으로 나오는 것을 확인할 수 있다.
2. 가변 저항 값을 시리얼 모니터로 출력
가변저항에 대한 자세한 설명은 참고자료에 잘 정리되어 있어 읽어보는 것을 추천한다.
가변저항기와 로터리 엔코더의 차이는 가변저항은 절대적 위치에 따라 전압값을 출력하고, 로터리 엔코더는 상대적 위치에 따라 전압값을 출력한다.
#define CLK 2 // 2번핀을 CLK로 지정
#define DT 3 // 3번핀을 DT로 지정
#define SW 4 // 4번핀을 스위치핀으로 지정
int counter = 0; // 회전 카운터 측정용 변수
int currentStateCLK; // CLK의 현재 신호상태 저장용 변수
int lastStateCLK; // 직전 CLK의 신호상태 저장용 변수
String currentDir =""; // 현재 회전 방향 출력용 문자열 저장 변수
unsigned long lastButtonPress = 0; // 버튼 눌림 상태 확인용 변수
void setup() {
// 엔코더의 핀들을 입력으로 설정
pinMode(CLK,INPUT);
pinMode(DT,INPUT);
pinMode(SW, INPUT_PULLUP); // 스위치핀은 내부 풀업저항 사용
// 시리얼통신 개시
Serial.begin(9600);
// CLK핀의 현재 상태 확인
lastStateCLK = digitalRead(CLK);
}
void loop() {
// CLK핀의 상태를 확인
currentStateCLK = digitalRead(CLK);
// CLK핀의 신호가 바뀌었고(즉, 로터리엔코더의 회전이 발생했했고), 그 상태가 HIGH이면(최소 회전단위의 회전이 발생했다면)
if (currentStateCLK != lastStateCLK && currentStateCLK == 1){
// DT핀의 신호를 확인해서 엔코더의 회전 방향을 확인함.
if (digitalRead(DT) != currentStateCLK) { // 신호가 다르다면 시계방향 회전
counter ++; // 카운팅 용 숫자 1 증가
currentDir ="시계방향 회전";
} else { // 신호가 같다면 반시계방향 회전
counter --; // 카운팅 용 숫자 1 감소
currentDir ="반시계 방향 회전";
}
Serial.print("회전방향: ");
Serial.print(currentDir); //회전방향 출력
Serial.print(" | Counter: ");
Serial.println(counter); // 회전 카운팅 출력
}
// 현재의 CLK상태를 저장
lastStateCLK = currentStateCLK;
// 버튼(스위치)이 눌렸는지 확인
int btnState = digitalRead(SW);
// 버튼(스위치)가 눌리면
if (btnState == LOW) {
//버튼이 눌린지 50ms가 지났는지 확인, 즉 버튼이 한번 눌린 후 최소 50 ms는 지나야 버튼이 다시 눌린것으로 감지
if (millis() - lastButtonPress > 50) { // 50ms 이상 지났다면
Serial.println("버튼 눌림!"); //버튼 눌림 메시지 출력
}
// 마자막 버튼이 눌린 시간 저장
lastButtonPress = millis();
}
// 잠시 대기
delay(1);
}
[출처] 아두이노로 로터리 엔코더 제어하기|작성자 황제곰
해당 코드는 시리얼 모니터에 로터리 엔코더 조정에 따른 값이 반영되어 출력된다.
3. 출력된 값을 LCD에 표시하기
마지막으로 시리얼 모니터에 출력되는 값을 LCD에 출력하도록 수정한다.
#include <LiquidCrystal_I2C.h> //LiquidCrystal 라이브러리 추가
#define CLK 2 // 2번핀을 CLK로 지정
#define DT 3 // 3번핀을 DT로 지정
#define SW 4 // 4번핀을 스위치핀으로 지정
LiquidCrystal_I2C lcd(0x27, 16, 2); //lcd 객체 선언
int counter = 0; // 회전 카운터 측정용 변수
int currentStateCLK; // CLK의 현재 신호상태 저장용 변수
int lastStateCLK; // 직전 CLK의 신호상태 저장용 변수
String currentDir =""; // 현재 회전 방향 출력용 문자열 저장 변수
unsigned long lastButtonPress = 0; // 버튼 눌림 상태 확인용 변수
void setup() {
// 엔코더의 핀들을 입력으로 설정
pinMode(CLK,INPUT);
pinMode(DT,INPUT);
pinMode(SW, INPUT_PULLUP); // 스위치핀은 내부 풀업저항 사용
// 시리얼통신 개시
Serial.begin(9600);
// CLK핀의 현재 상태 확인
lastStateCLK = digitalRead(CLK);
//lcd 사용
lcd.begin();
lcd.setCursor(0, 0);
lcd.print("Knob Value:");
lcd.setCursor(0, 1);
lcd.print("0");
}
void loop() {
// CLK핀의 상태를 확인
currentStateCLK = digitalRead(CLK);
// CLK핀의 신호가 바뀌었고(즉, 로터리엔코더의 회전이 발생했했고), 그 상태가 HIGH이면(최소 회전단위의 회전이 발생했다면)
if (currentStateCLK != lastStateCLK && currentStateCLK == 1){
// DT핀의 신호를 확인해서 엔코더의 회전 방향을 확인함.
if (digitalRead(DT) != currentStateCLK) { // 신호가 다르다면 시계방향 회전
counter --; // 카운팅 용 숫자 1 증가
} else { // 신호가 같다면 반시계방향 회전
counter ++; // 카운팅 용 숫자 1 감소
}
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Knob Value:");
lcd.setCursor(0, 1);
lcd.print(counter); // 회전 카운팅 출력
Serial.print("knob value: ");
Serial.println(counter); // 회전 카운팅 출력
}
// 현재의 CLK상태를 저장
lastStateCLK = currentStateCLK;
// 버튼(스위치)이 눌렸는지 확인
int btnState = digitalRead(SW);
// 버튼(스위치)가 눌리면
if (btnState == LOW) {
//버튼이 눌린지 50ms가 지났는지 확인, 즉 버튼이 한번 눌린 후 최소 50 ms는 지나야 버튼이 다시 눌린것으로 감지
if (millis() - lastButtonPress > 50) { // 50ms 이상 지났다면
Serial.println("clicked!"); //버튼 눌림 메시지 출력
//카운터 초기화
counter = 0;//카운터를 0으로 설정
lcd.setCursor(0, 1);
lcd.print("Reset! value=0");//화면에 해당 문구를 출력하여 사용자가 인식하도록 한다.
}
// 마자막 버튼이 눌린 시간 저장
lastButtonPress = millis();
}
// 잠시 대기
delay(1);
}
오른쪽으로 노브를 돌리면 + 왼쪽으로 돌리면 -로 값이 바뀌고 클릭하면 0으로 counter가 리셋된다.
시연 영상
<참고자료 >
LCD : https://codingrun.com/119
아두이노 예제 15. LCD에 글자 쓰기(I2C LCD 모듈 사용)
LCD(액정표시장치, Liquid Crystal Dispaly) 아두이노 예제 12강에서 진행했던 LCD에 글자 쓰기는 실습을 해보기에는 좋은 예제이다. 하지만 디지털 포트를 많이 차지하기 때문에 여러가지 부품을 사용해
codingrun.com
로터리 엔코더 모듈 (가변저항) : https://blog.naver.com/emperonics/222108739792
아두이노로 로터리 엔코더 제어하기
아두이노로 로터리 엔코더 제어하기 안녕하세요. 황제곰입니다. 이번 포스팅에서는 여러 가전제품에서 입력...
blog.naver.com