digitalWrite, digitalRead없이 레지스터에서 아두이노 핀 제어
아두이노에서 정의된 함수가 아니라, 직접 레지스터를 통해서 핀을 제어하는 방법에 대해서 소개하도록 하겠습니다.
1. 아두이노 우노(Arduino Uno - Datasheets)
포트 | 구분 | 범위 |
C | 아날로그 핀(Analog IN) | (A0~A5) |
B | 디지털 핀(Digital IN) | (D8~D13) |
D | 디지털 핀(Digital IN) | (D0~D7), (RESET) |
2. 아두이노 메가 2560(Arduino Mega 2560 - Datasheets)
포트 | 구분 | 범위 |
F | 아날로그 핀(Analog IN) | (A0~A7) / PF0~PF7 |
K | 아날로그 핀(Analog IN) | (A8~A15) / PK0~PK7 |
E | 디지털 핀(Digital IN) TX, RX | (D0, D1) / PE0~PE1 |
E | 디지털 핀(Digital IN) PWM | (D2, D3) / PE4~PE5 |
G | 디지털 핀(Digital IN) PWM | (D4) / PG5 |
E | 디지털 핀(Digital IN) PWM | (D5) / PE3 |
H | 디지털 핀(Digital IN) PWM | (D6~D9) / PH3~PH6 |
B | 디지털 핀(Digital IN) PWM | (D10~D13) / PB4~PB7 |
J | 디지털 핀(Digital IN) TX3, RX3 | (D14~D15) / PJ1, PJ0 |
H | 디지털 핀(Digital IN) TX2, RX2 | (D16~D17) / PH1, PH0 |
D | 디지털 핀(Digital IN) TX1, RX1 | (D18~D19) / PD3, PD2 |
D | 디지털 핀(Digital IN) SDA, SCL | (D20, D21) / PD1, PD0 |
A | 디지털 핀(Digital IN) | (D22~D29) / PA0~PA7 |
C | 디지털 핀(Digital IN) | (D30~D37) / PC0~PC7 |
D | 디지털 핀(Digital IN) | (D38) / PD7 |
G | 디지털 핀(Digital IN) | (D39) / PG2 |
G | 디지털 핀(Digital IN) | (D40) / PG1 |
G | 디지털 핀(Digital IN) | (D41) / PG0 |
L | 디지털 핀(Digital IN) | (D42~D49) / PL0~PL7 |
B | 디지털 핀(Digital IN) | (D50~D53) / PB0~PB3 |
3. 아두이노 우노(칩셋:atmega 328p)를 통한 사용 방법 소개
예) DDRB
XTAL | XTAL | D13 | D12 | D11 | D10 | D9 | D8 |
1 | 1 | 0(1) | 0(1) | 0(1) | 0(1) | 0(1) | 0(1) |
우리는 DDRB 레지스터가 핀 8 ~ 13의 모드를 INPUTS 또는 OUTPUTS로 제어 할 수 있는지 확인할 수 있습니다. 예를 들어, 핀 8의 비트가 0 값인 경우 핀 8은 입력 핀이고, 그렇지 않으면 1 값인 경우 출력 핀입니다. 우리는 6과 7에 해당하는 비트가 크리스탈을위한 것이기 때문에 1로 만들 수 있음을 알 수 있습니다.
그러나 우리는 이것을 arduino 소프트웨어에 어떻게 기록합니까? |
소프트웨어의 모든 비트를보고 싶다면 다음과 같이 할 수 있습니다. DDRB = B11111111; 이것은 6 개의 핀 모두가 출력임을 의미합니다. |
// 아두이노 소프트웨어에서의 코드
void setup() {
DDRB=B11100000; // 핀(Pin) 13번 출력 보드로 설정.
}
void loop() {
PORTB=B11100000; // 핀(Pin) 13번에 전원(Power on) 넣기
delay(1000);
PORTB=B11000000; // 핀(Pin) 13번에 전원(Power Off) 끄기
delay(1000);
}
C와 D 포트의 경우, 핀과 모드의 모드를 설정하는 방법은 B와 같습니다.
직렬 통신을위한 것이기 때문에 PORTD에 핀 0과 1이있는 한 가지 문제가 발생하며이를 변경하면 안됩니다.
이를 위해 "OR"함수 "|"를 사용할 것입니다.이 기호는 각 비트를 조작하는 프로그램에서 사용되며, 둘 다 0이면 결과는 0입니다.
그렇지 않으면 OR 게이트의 진리표와 같이 1입니다 (x | 0 = x ).
* OR표(논리 합) = x + y
1 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | |
1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | |
Result | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 0 |
이제 우리는 DDRD = DDRD | B11111100; 이것은 2에서 5까지의 핀이 출력이고 핀 0과 1이 수정 된 값으로 유지된다는 것을 의미합니다.
예를 들어 핀 0이 1이되어 DDRD가 초기 상태 B11111100과 B11111101 사이에서 OR 기능을 수행하면 결과는 DDRD = B11111101이므로 핀 0이 변경되어 직렬 통신이 필요한지 그렇지 않으면 핀 0이 0 값이 고정되어 변경되었습니다.
우리는 또한 "AND"함수 "&"를 사용할 수 있습니다 -이 기호는 각 비트를 작동하는 프로그램에서 사용되며 AND 게이트 (x & 1 = x)의 진리표와 같이 양쪽 모두 1이면 결과는 1입니다.
* AND(논리 곱) = x * y
1 | 0 | 1 | 1 | 1 | 0 | 0 | 0 | |
1 | 1 | 0 | 0 | 1 | 1 | 0 | 0 | |
Result | 1 | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
DDRD = DDRD & B11111111 프로그램의 경우, 핀 0과 1은 1이어야합니다. 그렇지 않으면 0이면 항상 0이됩니다.
이제 조금만 바꾸고 싶다면 8 비트를 전부 쓰지 않고 변경할 수 있지만 SET과 CLEAR를 사용하면 변경할 수 있습니다.
프로그램에서 13 번핀의 DDRB는 DDRB | = (1 << DDB5) (set-make 1)로 출력 모드로 전환됩니다. 여기서 DDB5는 PIN 13 비트입니다 (아래 그림은 atmega 328 데이터 시트에서 확인할 수 있습니다). PORTB는 PORTB | = (1 << PORTB5) (set)이며 PORTB5는 데이터 시트에 있습니다. 프로그램에서 비트를 지우거나 "0으로 설정"하기 위해 PORTB & = ~ (1 << PORTB5) (clear-make 0)을 사용합니다.
아래 이미지에서 PORTB, DDRB 및 PINB (atmega 데이터 시트에서 가져온 것)에 대한 비트 연관을 볼 수 있습니다.
PORTB - The Port B Data Register
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
0x05 (0x25) | PORTB7 | PORTB6 | PORTB5 | PORTB4 | PORTB3 | PORTB2 | PORTB1 | PORTB0 | PORTB |
Read/Write | R/W | R/W | R/W | R/W | R/W | R/W | R/W | R/W | |
Initial Value | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
DDRB - The Port B Data Direction Register
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
0x04 (0x24) | DDB7 | DDB6 | DDB5 | DDB4 | DDB3 | DDB2 | DDB1 | DDB0 | DDRB |
Read/Write | R/W | R/W | R/W | R/W | R/W | R/W | R/W | R/W | |
Initial Value | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
PINB - The Port B Input Pins Address
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | |
0x03 (0x23) | PINB7 | PINB6 | PINB5 | PINB4 | PINB3 | PINB2 | PINB1 | PINB0 | PINB |
Read/Write | R/W | R/W | R/W | R/W | R/W | R/W | R/W | R/W | |
Initial Value | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A |
아래의 프로그램은 위의 프로그램과 같은 것을 만들지만 핀13(Pin 13) 만 제어합니다.
void setup() {
DDRB |= (1<<DDB5); // 핀(pin) 13을 출력모드(Output)로 설정
}
void loop() {
PORTB |=(1<< PORTB5); // 핀 13번을 전원 켜기(Power on the led)
delay(1000);
PORTB &= ~(1<<PORTB5); // 핀 13번을 전원 끄기(Power off the led)
delay(1000);
}
출력 핀으로도 충분하므로 이제 digitalRead 대신 레지스터를 제어하여 한 핀을 읽으려고합니다.
위에서 언급했듯이 디지털 핀을 읽어야하는 레지스터는 PIN입니다.
이제 이것을 이해하기 위해 핀 8에있는 버튼을 의미하는 프로그램을 만들 것입니다. 버튼을 누르면 13 번 핀의 LED가 켜집니다.
먼저 핀 8을 입력 핀으로 만들고 핀 13을 출력 핀처럼 만들어야합니다.
DDRB | = (1 << DDB5); // 핀 13은 출력 모드입니다
DDRB & = ~ (1 << DDB0); // 핀 8은 입력 모드입니다
모든 물기를 쓰고 싶다면 DDRB = B11111110; 핀 9 ~ 13은 출력이고 핀 8 입력 (제로)입니다.
이제 8 번 핀이 하이 또는 로우 상태인지 읽으려면 하이 핀은 로직 1을 의미하고 로우 상태는 로직 0을 의미하므로 버튼을 누르면 핀 8에 해당하는 PINB 레지스터의 비트가 1이됩니다 .
PINB & B00000001과 같은 "&"연산을 수행하면 버튼을 누르고 PINB가 B00000001과 같은 형식을 갖는 경우 결과는 0과 다를 것입니다.
직렬 모니터에서 결과를 보려면 Serial.println ((PINB & B00000001)); 20이므로 1이 표시됩니다.
10 번 핀의 버튼을 움직이면 PINB & B00000100이됩니다. 결과는 4 가지 방법 22가 될 것입니다.
핀 8과 10을 입력으로 사용하는 두 개의 작은 프로그램 :
For pin 8: |
void setup() { //DDRB |= (1<<DDB5) ;// pin 13 - 출력모드 //DDRB&=~(1<<DDB0); //pin 8 - 입력모드 DDRB = B11111110; // 핀 8 입력핀, 9~13은 출력핀) Serial.begin(9600); } void loop() { Serial.println((PINB&B00000001)); if ((PINB & B00000001)==1){// PORTB |=(1<< PORTB5);//make pin 13 high and power on the led } else{ PORTB &=~ (1<<PORTB5);//make pin 13 low and power off the led } } |
For pin 10: |
void setup() { //DDRB |= (1<<DDB5) ;//pin 13 is in output mode //DDRB&=~(1<<DDB0); //pin 8 is in input mode DDRB = B11111011; //pin 10 input pins 8,9,11,12 and 13 output Serial.begin(9600); } void loop() { Serial.println((PINB&B00000100)); if ((PINB & B00000100)==4){// PORTB |=(1<< PORTB5);//make pin 13 high and power on the led } else{ PORTB &=~ (1<<PORTB5);//make pin 13 low and power off the led } } |
4. 아두이노 우노 - 구현 동작 / 사진, 영상
3색 LED (1번) 동작 - 포트: 디지털 9번 |
3색 LED (2번) 동작 - 포트: 디지털 10번 |
3색 LED (3번) 동작 - 포트: 디지털 11번 |
5. 아두이노 메가 2560 - 구현 동작 / 사진, 영상
3색 LED (1번) 동작 - 포트: 디지털 9번 |
|
3색 LED (2번) 동작 - 포트: 디지털 10번 |
3색 LED (3번) 동작 - 포트: 디지털 11번 |
7. 핀 제어 - 소스코드
아두이노 UNO R3 기종에 맞게 작성한 소스코드입니다.
void setup(){ void loop(){ PORTB = B00001001; |
아래의 소스코드는 Atmel Studio로 작성된 아두이노 R3 코드입니다.
atmel studio 화면의 예 |
/* 아두이노 우노 (칩:Atmega 328P) #define F_CPU 16000000UL #include <avr/io.h> int main(void) |
아두이노 우노 (칩:Atmega 328P) 소스코드 |
아래의 코드는 아두이노 메가 2560 기종을 기반으로 작성한 소스코드입니다.
/* #define F_CPU 16000000 #include <avr/io.h> int main(void) |
아두이노 메가 2560 (칩:Atmega 2560) 소스코드 |
소스파일:
* 참고 자료
Arduino ATmega328 Pinout, http://www.hobbytronics.co.uk/arduino-atmega328-pinout
Tutorial: Arduino Port Manipulation, http://tronixstuff.com/2011/10/22/tutorial-arduino-port-manipulation/
Bit Math Tutorial, http://playground.arduino.cc/Code/BitMath
Getting Started with Atmel Studio – Blink, http://www.crash-bang.com/getting-started-atmel-studio/
'공부 > 아두이노(Arduino)' 카테고리의 다른 글
전, 후진 - 자동차 구현 2(블루투스 추가) (0) | 2017.10.20 |
---|---|
전, 후진 - 자동차 구현 (0) | 2017.10.19 |
이더넷 - ENC28J60 모듈(RJ45) (0) | 2017.10.16 |
디스플레이 - LCD 2004A + I2C (0) | 2017.10.16 |
Knight (객체 - OOP) (0) | 2017.10.14 |