아두이노
- 오픈 소스를 기반으로 한 단일 보드 마이크로컨트롤러로 완성된 보드와 관련 개발 도구 및 환경
- 다수의 스위치나 센서로부터 값을 받아들여, LED나 모터와 같은 외부 전자 장치를 통제함으로써 환경과 상호작용이 가능한 물건을 만들 수 있다.
Arudino Uno
HelloWorld
int count = 0;
void setup() {
Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
Serial.print("HelloWorld:");
Serial.println(count++);
digitalWrite(LED_BUILTIN, HIGH);
delay(1000);
digitalWrite(LED_BUILTIN, LOW);
delay(1000);
}
ADC를 활용한 동작 테스트
void setup() {
Serial.begin(115200);
}
void loop() {
int switchGreen = analogRead(A0);
int switchYellow = analogRead(A1);
Serial.print("Green:");
Serial.print(switchGreen);
Serial.print(", Yellow:");
Serial.println(switchYellow);
delay(1000);
}
analogRead()
- 지정한 아날로그 핀에서 값을 읽는다.
- 0 ~ 5V의 입력 전압을 0 ~ 1023 사이의 정수 값으로 대응 (5V = 1023)
- 해상도: 5V/1024 = 0.49mV
Switch: Pull-Up & Pull-Down 저항
- Pull-Up 저항 상태: 스위치 off = HIGH(1), 스위치 on = LOW(0)
- Pull-Down 저항 상태: 스위치 off = LOW(0), 스위치 on = HIGH(1)
Switch 동작 확인
void setup() {
pinMode(8, INPUT);
pinMode(7, INPUT);
pinMode(6, INPUT);
pinMode(5, INPUT);
pinMode(4, INPUT);
Serial.begin(115200);
}
void loop() {
int switchGreen = digitalRead(8);
int switchYellow = digitalRead(7);
int switchRed = digitalRead(6);
int switchBlack = digitalRead(5);
int switchBlue = digitalRead(4);
Serial.print("Green:");
Serial.print(switchGreen);
Serial.print(", Yellow:");
Serial.print(switchYellow);
Serial.print(", Red:");
Serial.print(switchRed);
Serial.print(", Black:");
Serial.print(switchBlack);
Serial.print(", Blue:");
Serial.println(switchBlue);
delay(1000);
}
Motor
L9110 Truth Table
| Input | | MotorA | | |
|-------|----|---------|---|---|
| 1A | 1B | Output | | |
| L | L | Off | | |
| H | L | Forward | | |
| L | H | Reverse | | |
| H | H | Off | | |
모터 제어
- 방향제어: 정회전/ 역회전
- 속도 제어
Motor 동작 확인
#define PIN_MOTOR_CTRL_0 3
#define PIN_MOTOR_CTRL_1 11
#define PIN_SWITCH_GREEN 8
#define PIN_SWITCH_YELLOW 7
int prevSwitchGreen = HIGH;
int prevSwitchYellow = HIGH;
byte motorCtrlValue0 = 0;
void setup() {
pinMode(PIN_SWITCH_GREEN, INPUT);
pinMode(PIN_SWITCH_YELLOW, INPUT);
pinMode(PIN_MOTOR_CTRL_0, OUTPUT);
pinMode(PIN_MOTOR_CTRL_1, OUTPUT);
analogWrite(PIN_MOTOR_CTRL_0, 0);
analogWrite(PIN_MOTOR_CTRL_1, 0);
Serial.begin(115200);
}
void loop() {
int currentSwitchGreen = digitalRead(PIN_SWITCH_GREEN);
int currentSwitchYellow = digitalRead(PIN_SWITCH_YELLOW);
if ((prevSwitchGreen == LOW) && (currentSwitchGreen == HIGH))
{ // Green Button: 10씩 Fan 제어량을 증가시킨다.
motorCtrlValue0 = (motorCtrlValue0 < 245) ? (motorCtrlValue0 + 10) : 255;
analogWrite(PIN_MOTOR_CTRL_0, motorCtrlValue0);
analogWrite(PIN_MOTOR_CTRL_1, 0);
Serial.println(motorCtrlValue0);
}
if ((prevSwitchYellow == LOW) && (currentSwitchYellow == HIGH))
{ // Yellow Button: 10씩 Fan 제어량을 감소시킨다.
motorCtrlValue0 = (motorCtrlValue0 > 10) ? (motorCtrlValue0 - 10) : 0;
analogWrite(PIN_MOTOR_CTRL_0, motorCtrlValue0);
analogWrite(PIN_MOTOR_CTRL_1, 0);
Serial.println(motorCtrlValue0);
}
prevSwitchGreen = currentSwitchGreen;
prevSwitchYellow = currentSwitchYellow;
delay(100);
}
motorCtrlValue0가 30부터 모터가 작동하는 이유?
마찰력 등으로 인해 모터가 작동하기 위한 threshold. 여기서는 30부터 작동한다.
Motor 동작 확인2(Green/Yellow Button Control)
- 모터 역방향 회전
// Motor 동작 확인(Green/Yellow Button Control)
// 요구사항1. Green Button을 누르면 10씩 Fan 제어량이 증가하며 Fan이 정방향으로 회전한다.
// 요구사항2. Yellow Button을 누르면 10씩 Fan 제어량이 감소하며 Fan이 역방향으로 회전한다.
// 정방향/ 역방향은 정해진 방향이 없으며 서로 반대 방향이면 된다.
// 제약: 제어량 Overflow가 발생해서는 안된다.
#define PIN_MOTOR_CTRL_0 3
#define PIN_MOTOR_CTRL_1 11
#define PIN_SWITCH_GREEN 8
#define PIN_SWITCH_YELLOW 7
int prevSwitchGreen = HIGH;
int prevSwitchYellow = HIGH;
byte motorCtrlValue0 = 127; // 중간값 고정
void setup() {
pinMode(PIN_SWITCH_GREEN, INPUT);
pinMode(PIN_SWITCH_YELLOW, INPUT);
pinMode(PIN_MOTOR_CTRL_0, OUTPUT);
pinMode(PIN_MOTOR_CTRL_1, OUTPUT);
analogWrite(PIN_MOTOR_CTRL_0, 0); // 초기화
analogWrite(PIN_MOTOR_CTRL_1, 0);
Serial.begin(115200);
}
void loop() {
int currentSwitchGreen = digitalRead(PIN_SWITCH_GREEN);
int currentSwitchYellow = digitalRead(PIN_SWITCH_YELLOW);
if ((prevSwitchGreen == LOW) && (currentSwitchGreen == HIGH))
{ // 1. Green Button을 누르면 10씩 Fan 제어량이 증가하며 Fan이 정방향으로 회전한다.
// 255 -> 5V output
motorCtrlValue0 = (motorCtrlValue0 < 245) ? (motorCtrlValue0 + 10) : 255;
analogWrite(PIN_MOTOR_CTRL_0, motorCtrlValue0);
analogWrite(PIN_MOTOR_CTRL_1, 127);
Serial.println(motorCtrlValue0);
}
if ((prevSwitchYellow == LOW) && (currentSwitchYellow == HIGH))
{ // 2. Yellow Button을 누르면 10씩 Fan 제어량이 감소하며 Fan이 역방향으로 회전한다.
motorCtrlValue0 = (motorCtrlValue0 > 10) ? (motorCtrlValue0 - 10) : 0;
analogWrite(PIN_MOTOR_CTRL_0, motorCtrlValue0);
analogWrite(PIN_MOTOR_CTRL_1, 127);
Serial.println(motorCtrlValue0);
}
prevSwitchGreen = currentSwitchGreen;
prevSwitchYellow = currentSwitchYellow;
delay(100);
}
모터를 역회전시키는 로직을 다시 이해해보자
- Yellow 버튼을 눌렀을 때 감지Yellow 버튼이 눌렸다가 떼어진 상태를 감지한다.
if ((prevSwitchYellow == LOW) && (currentSwitchYellow == HIGH))
- prevSwitchYellow: 이전 루프에서의 버튼 상태
- currentSwitchYellow: 현재 루프에서 읽은 버튼 상태
- Fan 제어량 감소
motorCtrlValue0 = (motorCtrlValue0 > 10) ? (motorCtrlValue0 - 10) : 0;
- 현재 제어량 motorCtrlValue0이 10보다 크면 10 감소
- 제어량이 0 이하로 떨어지지 않도록 제어합니다.(제어량이 0이 되면 Fan은 정지 상태에 가까워짐.)
- PWM 신호를 통해 역회전 설정두 PWM 핀에 신호를 설정한다.
analogWrite(PIN_MOTOR_CTRL_0, motorCtrlValue0); analogWrite(PIN_MOTOR_CTRL_1, 127);
- PIN_MOTOR_CTRL_0: Fan의 현재 제어량 motorCtrlValue0을 PWM 값으로 설정
- PIN_MOTOR_CTRL_1: 고정된 127 값(중립값)으로 설정
그렇다면, 역회전이 이루어지는 이유는 무엇일까?
모터는 일반적으로 두 개의 PWM 핀(PIN_MOTOR_CTRL_0과 PIN_MOTOR_CTRL_1)을 통해 동작한다.
- 정방향: 한 쪽 핀에 PWM 제어량을 보내고, 다른 쪽은 고정값(127) 유지.
- 역방향: 동일한 방식으로 핀의 역할을 바꾸어 신호를 전송.
위 코드에서는 analogWrite() 설정이 핀마다 다르게 적용되어 정방향과 역방향 회전을 구분한다.
- Green 버튼: PIN_MOTOR_CTRL_0의 제어량이 증가 → 정방향.
- Yellow 버튼: PIN_MOTOR_CTRL_0의 제어량이 감소 → 역방향.
모터 드라이버는 두 PWM 핀의 상대적인 신호 차이를 보고 회전 방향을 결정한다. 코드에서 PIN_MOTOR_CTRL_1은 고정값(127)으로 유지되고,
PIN_MOTOR_CTRL_0의 값이 감소하면서 신호가 반대로 전달되기 때문에 역회전이 발생한다.
Capacitor
- 콘덴서 축전지
- 전기를 일시적으로 저장한다.
Capacitor가 없을 때
Servo Motor가 Arduino의 최대 전류 용량보다 많은 전류를 소모할 경우 Arduino board가 비정상 동작할 수 있다. (ex. Board Reset)
PWM
Pulse Width Modulation(PWM)
- 펄스파의 duty rate를 조절하여 펄스 폭을 변화시킴으로써 평균 전압을 가변한다.
- 디지털 형태의 펄스 폭을 가변함으로써 아날로그 출력의 진폭을 조절하는 효과
analogWrite()
analogWrite(Pin 번호, 아날로그 값(0~255))
- 디지털 출력만으로 아날로그 값(PWM파)을 핀에 출력한다.
- LED 밝기 조절, 삼색 LED의 여러 색상 표현, DC 모터의 회전 속도 조절 등에 사용.
- 호출시, analogWrite()(또는 digitalRead(), digitalWrite())가 불릴 때까지 특정 듀티 사이클의 구형파를 발생시킨다.
- 대부분의 핀에서 PWM 신호의 주파수는 약 490Hz (Uno에서 5,6 번 핀은 약 980Hz)
- 대부분의 아두이노 보드(ATmega168/ ATmega328P)에서 3, 5, 6, 9, 10, 11번 핀에서 동작
Capacitor 연결
void setup() {
pinMode(10, OUTPUT);
analogWrite(10, 127); // 2.5v
Serial.begin(115200);
}
void loop() {
int value = analogRead(A0);
Serial.println(value / 1023.0 * 5.0);
delay(500);
}
Motor
모터란?
- 전기에너지 -> 기계에너지로 바꾸는 동력기계장치
- 전력을 받아 축에 회전력을 발생
- 모터 내부에 자석을 놓아 자기장을 만들고, 중앙 축에 연결된 도선에 전류를 흐르게 하면 전자력이 발생되어 회전력이 생긴다.
Motor Type
DC 모터
- 외부의 고정된 부분(고정자)에 영구 자석을 배치하고 내부의 회전체에 코일을 사용하여 구성
- 회전체(회전자/ 전기자)에 흐르는 전류의 방향을 전환함으로써 발생하는 자기장과 자석 자기장의 상호 반발력을 이용해 회전력을 얻는다.
- DC모터는 다른 구동장치에 비해 가볍고 구조가 간단하여 선풍기, 냉장고 등 가전제품부터 전기자동차, 고속 열차 등 운송수단까지 광범위하게 사용됨
서브모터
- 지정된 각도만큼 회전할 수 있다.
- 목표치에 대한 위치/ 방위/ 자세 등의 제어가 자동으로 가능
- 자동화 생산 시스템, 로봇, 장난감, 가전제품 등 광범위하게 쓰인다.
Lib | Servo
attach()
servo.attach(pin);
servo.attach(pin, min, max);
- pin: 서보 모터가 연결된 핀 번호 (PWM 핀이어야 함, 아두이노 보드에 따라 다름).
- min: 서보 펄스의 최소값(기본값: 544μs).
- max: 서보 펄스의 최대값(기본값: 2400μs).
write()
- 서보 모터의 위치를 설정. 서보 모터를 특정 각도로 회전시킨다.
servo.write(angle);
- angle: 서보 모터의 목표 각도(0~180도)
Servo 모터 동작 예제
// Servo 동작 시나리오
// 1. 초록색 버튼: Fan의 회전 속도가 10씩 빨라진다.
// 2. 노란색 버튼: Fan의 회전 속도가 10씩 느려진다.
// 3. 빨간색 버튼: Fan의 회전이 정지하고 Fan 목의 각도가 90도에 위치한다.
// 4. 검정색 버튼: Fan 목의 각도가 10씩 증가한다.
// 5. 파란색 버튼: Fan 목의 각도가 10씩 감소한다.
// 제약: Overflow가 일어나서는 안된다.
#include <Servo.h>
#define PIN_MOTOR_CTRL_0 3
#define PIN_MOTOR_CTRL_1 11
#define PIN_SWITCH_GREEN 8
#define PIN_SWITCH_YELLOW 7
#define PIN_SWITCH_RED 6
#define PIN_SWITCH_BLACK 5
#define PIN_SWITCH_BLUE 4
#define PIN_SERVO_CTRL 13
int prevSwitchGreen = HIGH;
int prevSwitchYellow = HIGH;
int prevSwitchRed = HIGH;
int prevSwitchBlack = HIGH;
int prevSwitchBlue = HIGH;
byte motorCtrlValue0;
byte servoPosition = 90;
Servo servoRotate;
void setup() {
servoRotate.attach(PIN_SERVO_CTRL);
servoRotate.write(servoPosition);
pinMode(PIN_SWITCH_GREEN, INPUT);
pinMode(PIN_SWITCH_YELLOW, INPUT);
pinMode(PIN_SWITCH_RED, INPUT);
pinMode(PIN_SWITCH_BLACK, INPUT);
pinMode(PIN_SWITCH_BLUE, INPUT);
pinMode(PIN_MOTOR_CTRL_0, OUTPUT);
pinMode(PIN_MOTOR_CTRL_1, OUTPUT);
pinMode(PIN_SERVO_CTRL, OUTPUT);
analogWrite(PIN_MOTOR_CTRL_0, 0);
analogWrite(PIN_MOTOR_CTRL_1, 0);
Serial.begin(115200);
}
void loop() {
// Fan Control
int currentSwitchGreen = digitalRead(PIN_SWITCH_GREEN);
int currentSwitchYellow = digitalRead(PIN_SWITCH_YELLOW);
int currentSwitchRed = digitalRead(PIN_SWITCH_RED);
if ((prevSwitchGreen == LOW) && (currentSwitchGreen == HIGH)) {
motorCtrlValue0 = (motorCtrlValue0 < 245) ? (motorCtrlValue0 + 10) : 255;
analogWrite(PIN_MOTOR_CTRL_0, motorCtrlValue0);
Serial.println(motorCtrlValue0);
}
if ((prevSwitchYellow == LOW) && (currentSwitchYellow == HIGH)) {
motorCtrlValue0 = (motorCtrlValue0 > 10) ? (motorCtrlValue0 - 10) : 0;
analogWrite(PIN_MOTOR_CTRL_0, motorCtrlValue0);
Serial.println(motorCtrlValue0);
}
if ((prevSwitchRed == LOW) && (currentSwitchRed == HIGH)) {
motorCtrlValue0 = 0;
analogWrite(PIN_MOTOR_CTRL_0, motorCtrlValue0);
Serial.println(motorCtrlValue0);
servoPosition = 90;
servoRotate.write(servoPosition);
Serial.println(servoPosition);
}
prevSwitchGreen = currentSwitchGreen;
prevSwitchYellow = currentSwitchYellow;
prevSwitchRed = currentSwitchRed;
// Rotate Control
int currentSwitchBlack = digitalRead(PIN_SWITCH_BLACK);
int currentSwitchBlue = digitalRead(PIN_SWITCH_BLUE);
if ((prevSwitchBlack == LOW) && (currentSwitchBlack == HIGH)) {
servoPosition = (servoPosition < 170) ? (servoPosition + 10) : 180;
servoRotate.write(servoPosition);
Serial.println(servoPosition);
}
if ((prevSwitchBlue == LOW) && (currentSwitchBlue == HIGH)) {
servoPosition = (servoPosition > 10) ? (servoPosition - 10) : 0;
servoRotate.write(servoPosition);
Serial.println(servoPosition);
}
prevSwitchBlack = currentSwitchBlack;
prevSwitchBlue = currentSwitchBlue;
delay(100);
}
Servo 모터 동작2 : Cooling Fan Practice
// Cooling Fan Practice
// 1. 초록색 버튼 : 최대 속도의 50%로 Fan 회전. (제어량과 회전 속도는 비례한다고 가정)
// 2. 노란색 버튼 : 최대 속도로 Fan 회전.
// 3. 빨간색 버튼 : Fan 회전 정지.
// 4. 검정색 버튼 : Fan 목의 회전을 멈추고 정면(90도, 나를 바라보는 방향)을 바라본다.
// 5. 파란색 버튼 : Fan 목이 30~150도 사이에서 연속적으로 회전한다.(30도, 150도 도달 시 Fan 목 회전 방향 전환)
// 제약 : Servo 의 position 설정 시 servoRotate.read()의 return값을 변수 copy 없이즉시 전달인자로 활용해야 한다.
#include <Servo.h>
#define PIN_MOTOR_CTRL_0 3
#define PIN_MOTOR_CTRL_1 11
#define PIN_SWITCH_GREEN 8
#define PIN_SWITCH_YELLOW 7
#define PIN_SWITCH_RED 6
#define PIN_SWITCH_BLACK 5
#define PIN_SWITCH_BLUE 4
#define PIN_SERVO_CTRL 13
int prevSwitchGreen = HIGH;
int prevSwitchYellow = HIGH;
int prevSwitchRed = HIGH;
int prevSwitchBlack = HIGH;
int prevSwitchBlue = HIGH;
int motorValMax = 255;
byte motorCtrlValue0;
byte servoPosition = 90;
int rotateFlag = 0;
Servo servoRotate;
void setup() {
servoRotate.attach(PIN_SERVO_CTRL);
servoRotate.write(servoPosition);
pinMode(PIN_SWITCH_GREEN, INPUT);
pinMode(PIN_SWITCH_YELLOW, INPUT);
pinMode(PIN_SWITCH_RED, INPUT);
pinMode(PIN_SWITCH_BLACK, INPUT);
pinMode(PIN_SWITCH_BLUE, INPUT);
pinMode(PIN_MOTOR_CTRL_0, OUTPUT);
pinMode(PIN_MOTOR_CTRL_1, OUTPUT);
pinMode(PIN_SERVO_CTRL, OUTPUT);
analogWrite(PIN_MOTOR_CTRL_0, 0);
analogWrite(PIN_MOTOR_CTRL_1, 0);
Serial.begin(115200);
}
void loop() {
// Fan Control
int currentSwitchGreen = digitalRead(PIN_SWITCH_GREEN);
int currentSwitchYellow = digitalRead(PIN_SWITCH_YELLOW);
int currentSwitchRed = digitalRead(PIN_SWITCH_RED);
if ((prevSwitchGreen == LOW) && (currentSwitchGreen == HIGH)) {
// 1. 초록색 버튼 : 최대 속도의 50%로 Fan 회전. (제어량과 회전 속도는 비례한다고 가정)
analogWrite(PIN_MOTOR_CTRL_0, motorValMax/2);
Serial.println(motorValMax/2);
}
if ((prevSwitchYellow == LOW) && (currentSwitchYellow == HIGH)) {
// 2. 노란색 버튼 : 최대 속도로 Fan 회전.
analogWrite(PIN_MOTOR_CTRL_0, motorValMax);
Serial.println(motorValMax);
}
if ((prevSwitchRed == LOW) && (currentSwitchRed == HIGH)) {
// 3. 빨간색 버튼 : Fan 회전 정지.
motorCtrlValue0 = 0;
analogWrite(PIN_MOTOR_CTRL_0, motorCtrlValue0);
Serial.println(motorCtrlValue0);
}
prevSwitchGreen = currentSwitchGreen;
prevSwitchYellow = currentSwitchYellow;
prevSwitchRed = currentSwitchRed;
// Rotate Control
int currentSwitchBlack = digitalRead(PIN_SWITCH_BLACK);
int currentSwitchBlue = digitalRead(PIN_SWITCH_BLUE);
if ((prevSwitchBlack == LOW) && (currentSwitchBlack == HIGH)) {
// 4. 검정색 버튼 : Fan 목의 회전을 멈추고 정면(90도, 나를 바라보는 방향)을 바라본다.
rotateFlag = 0;
servoPosition = 90;
servoRotate.write(servoPosition);
Serial.println(servoPosition);
}
if ((prevSwitchBlue == LOW) && (currentSwitchBlue == HIGH)) {
// 5. 파란색 버튼 : Fan 목이 30~150도 사이에서 연속적으로 회전한다.(30도, 150도 도달 시 Fan 목 회전 방향 전환)
rotateFlag = 1;
}
if((servoRotate.read() < 30) || (servoRotate.read() > 150)){
rotateFlag = rotateFlag * (-1);
}
if(rotateFlag != 0){
servoRotate.write(servoRotate.read() + rotateFlag);
Serial.println(servoRotate.read() + rotateFlag);
}
prevSwitchBlack = currentSwitchBlack;
prevSwitchBlue = currentSwitchBlue;
delay(100);
}
Interrupt
마이크로프로세서(CPU)가 프로그램을 실행하고 있을 때, 입출력 하드웨어 등의 장치에 예외상황이 발생하여 처리가 필요할 경우에 마이크로 프로세서에서 알려 처리할 수 있도록 함
EEPROM
- EEPROM(Electrically Erasable Programmable Read-Only Memory)은 전원이 꺼져도 데이터를 유지할 수 있는 비휘발성 메모리
- 일반적으로 설정 값이나 센서 데이터와 같이 전원이 꺼져도 저장해야 하는 정보를 저장하는 데 사용
EEPROM 저장 함수
EEPROM.wrtite(address, value)
- 지정된 주소에 데이터를 씁니다.
- 매개변수:
- address (0부터 시작): EEPROM 내 저장할 위치.
- value: 저장할 값 (0~255, 1바이트 크기).
- 주의: 값을 쓰기 전에 현재 값과 다를 경우에만 덮어씁니다.
EEPROM 읽기 함수
EEPROM.read(address)
- 지정된 주소에서 데이터를 읽습니다.
- 매개변수:
- address: 읽을 위치.
- 반환값: 저장된 값 (0~255).
EEPROM 업데이트 함수
EEPROM.update(address, value)
- 새로운 값이 기존 값과 다를 때만 쓰기 동작을 수행하여 EEPROM의 수명을 늘린다.
EEPROM 여러 바이트 읽고 쓰기
EEPROM.get(address, data)
- 지정된 주소에서 구조체나 배열 같은 여러 바이트 데이터를 읽는다.
EEPROM 초기화
EEPROM.begin(size)
EEPROM 전체 크기
EEPROM.length()
- EEPROM의 전체 크기를 반환
수정중
EEPROM Practice
'IVS > Arduino' 카테고리의 다른 글
[Arduino] 자료형, byte와 int의 차이 (0) | 2025.01.15 |
---|