공부/아두이노(Arduino)

digitalWrite, digitalRead없이 레지스터에서 아두이노 핀 제어

도도-도윤 2017. 10. 17. 21:12

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 개의 핀 모두가 출력임을 의미합니다.
DDRB = B11111100; 이것은 핀 8 및 9가 입력이고 핀 10 내지 13 출력임을 의미합니다

이것을 선언하는 다른 방법은 다음과 같습니다.

DDRB = 0b11111111;
DDRB = 0b11111100;

이제 이들을 입력 또는 출력으로 선언 한 후이를 높게 또는 낮게 만들 필요가 있습니다.

우리는 DDRB 레지스터와 같은 PORTB 레지스터가 유일한 차이점은 "0"은 LOW를 의미하고 "1"은 HIGH를 의미합니다.
따라서 PORTB = B11111111; 이것은 모든 핀이 HIGH임을 의미합니다.
PORTB = B11011111; 이것은 핀 13이 LOW임을 의미합니다.


// 아두이노 소프트웨어에서의 코드


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

         }

 }


참고자료: http://www.eprojectszone.com/2016/07/30/how-to-control-arduino-pins-from-registers-without-digitalwrite-and-digitalread/



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(){
        DDRB = B00001111;
 }


 void loop(){
  
        PORTB = B00000011;
        delay(1000);
        PORTB &= ~B00000011;
        delay(1000);
 
        PORTB = B00000101;
        delay(1000);
        PORTB &= ~B00000101;
        delay(1000);

        PORTB = B00001001;
        delay(1000);
        PORTB &= ~B00001001;
        delay(1000);
 
 }


아래의 소스코드는 Atmel Studio로 작성된 아두이노 R3 코드입니다.




 atmel studio 화면의 예


/* 

    아두이노 우노 (칩:Atmega 328P)
*/

#define F_CPU 16000000UL

#include <avr/io.h>
#include <util/delay.h>


int main(void)
{
       DDRB |= (1 << DDB1);
       DDRB |= (1 << DDB2);
       DDRB |= (1 << DDB3);
 
       /* Replace with your application code */
       while (1)
       {
               PORTB |= (1<<PORTB1);
               _delay_ms(1000);
               PORTB &= ~(1<<PORTB1);
              _delay_ms(1000);
  
               PORTB |= (1<<PORTB2);
              _delay_ms(1000);
               PORTB &= ~(1<<PORTB2);
              _delay_ms(1000);
  
              PORTB |= (1<<PORTB3);
             _delay_ms(1000);
              PORTB &= ~(1<<PORTB3);
             _delay_ms(1000);
        }
}

 아두이노 우노 (칩:Atmega 328P) 소스코드


아래의 코드는 아두이노 메가 2560 기종을 기반으로 작성한 소스코드입니다.


/*
 * atmega-mega-2560.cpp
 *
 * Created: 2017-10-17 오후 9:16:25
 */


#define F_CPU 16000000

#include <avr/io.h>
#include <util/delay.h>


int main(void)
{
       DDRH |= (1 << DDH6);
       DDRB |= (1 << DDB4);
       DDRB |= (1 << DDB5);
 
       while (1)
      {
            PORTH |= ( 1 << PH6 );
            _delay_ms(1000);
            PORTH &= ~ ( 1 << PH6 );
            _delay_ms(1000);
  
            PORTB |= (1<< PB4 );
            _delay_ms(1000);
            PORTB &= ~ ( 1 << PB4 );
            _delay_ms(1000);
  
            PORTB |= (1<< PB5 );
           _delay_ms(1000);
            PORTB &= ~ ( 1 << PB5 );
           _delay_ms(1000);
     }
 
}


 아두이노 메가 2560 (칩:Atmega 2560) 소스코드


소스파일:

Source.zip




* 참고 자료


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/

Source.zip
0.0MB