본문 바로가기

atmega 비트연산자 03

반응형

오늘은 조금 지루하지만

비트 연산자에 대한 것이다.


프로그램 할 때 꼭 필요한 것이니 지루해도 하기로했다.




위의 사진은 저번에도 올렸던 아두이노 미니 회로도이다.


이번에도 LED를 이용할 것이다.(4개 정도 이용)


일단 LED를 PD2( D2 ),

 PD3 ( D3 ),

 PD4 ( D4 ),

 PD5 ( D5 )


연결한 상태로 진행할 것이다.



일단 처음에는 LED를 키고 끄는 것 부터 할 것이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#define F_CPU 16000000L
#include <avr/io.h>
#include <util/delay.h>
 
int main(void) {
    DDRD = 0b00111100;
 
    while(1) {
        PORTD = 0b00010100;
        _delay_ms(1000);
        PORTD = 0b00101000;
        _delay_ms(1000);
    }
    return 0;
}
cs

DDRD = 0b00111100;로 PD2 ~ 5번을 1(출력)으로 설정했다.


PORTD = 0b00010100;로 2, 4번째에 HIGH신호를 주고 3, 5번째에는 LOW신호를 주고

1초 지연하고

PORTD = 0b00101000;로 3, 5번째에는 HIGH 2, 4번째에는 LOW신호를 줬다.




  이렇게 간단한 코드는 위의 방식을 사용하여 할 수 있지만

나중에 더 어려운 코드를 작성할 시에는 저런 방법으로 하기에는 힘들다.



예를 들어 LED를 순차적으로 1개씩 켰다 끄는 것은 위의 방법대로 하면

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#define F_CPU 16000000L
#include <avr/io.h>
#include <util/delay.h>
 
int main(void) {
    DDRD = 0b00111100;
 
    while(1) {
        PORTD = 0b00000100;
        _delay_ms(1000);
        PORTD = 0b00001000;
        _delay_ms(1000);
        PORTD = 0b00010000;
        _delay_ms(1000);
        PORTD = 0b00100000;
        _delay_ms(1000);
    }
    return 0;
}
cs


위의 코드같이 작성하든가

아니면

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#define F_CPU 16000000L
#include <avr/io.h>
#include <util/delay.h>
 
unsigned int LED_ON[4= {0b000001000b000010000b000100000b00100000};
 
int main(void) {
    DDRD = 0b00111100;
 
    while(1) {
        for(int i = 0; i < 4; i++) {
            PORTD = LED_ON[i];
            _delay_ms(1000);
        }
    }
    return 0;
}
cs

이러한 방식으로 작성해야 한다.



솔직히 저건 너무 귀찮은 코드이다.


이때 비트 연산자를 사용하면 간단하게 할 수 있다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#define F_CPU 16000000L
#include <avr/io.h>
#include <util/delay.h>
 
int main(void) {
    DDRD = 0b00111100;
 
    while(1) {
        for(int i = 2; i < 6; i++) {
            PORTD = 1 << i;
            _delay_ms(1000);
        }
    }
    return 0;
}
cs

보면 일단 i의 값이  2 ~ 5으로 변하고

PORTD = 1 << i;라는 코드가 생겼다.

이 뜻은 '1이라는 숫자를 왼쪽으로 i번 만큼 이동하고 오른쪽에는 0을 채워'라는 뜻인데


이것을 처음 보면 모를 수 있으니 예를 보여주겠다.



x라는 변수가 0b00000001이라는 숫자라고 가정해보자

그럼 x << 1은 0b00000010라는 숫자가 된다.

x << 2는 0b00000100라는 숫자가 되고

x << 3은 0b00001000라는 숫자가 된다.


그럼 만약 y라는 변수가 0b00000101라는 숫자라고 가정하면

y << 1은 0b00001010라는 숫자가 되고

y << 2는 0b00010100라는 숫자가 된다.


반대로 >>는 오른쪽으로 이동한다는 뜻으로

x가 0b1000000이라고 한다면

x >> 1은 0b01000000이고

x >> 2는 0b00100000가 된다.





여기 까지는 비트를 이동시키는 연산자였고

다음은 논리 연산자이다.(여기가 더 지루할 수 있다)



논리 연산자는

&

| (키보드 Enter위에 있다)

^

~이 있다.(이것들도 필요하다)



일단 &는 and라는 뜻으로 두가지를 비교했을 때

둘 다 참(1)이면 참(1) 둘 중 하나라도 거짓(0)이면 거짓(0)이다.


x = 0b10001

y = 0b00001라고 했을 때

x & y 는 0b00001이다.




|은 or이라는 뜻으로 둘 중 하나라도 참(1)이면 참(1)이다.


x = 0b10001

y = 0b00101이라고 했을 때

x | y 는 0b10101이다.


^은 반전을 시켜주는 비트 연산자로 참(1)이면 반전 거짓(0)이면 그대로 이다.


x = 0b111000

y = 0b100111

x ^ y 는 0b011111이다.(y값에서 1이 있는 부분만 x랑 비교해서 반전)



~은 not이라는 뜻으로 

x = 0b0101이면

~x는 0b1010이다.



다시 위의 코드로 돌아가서

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#define F_CPU 16000000L
#include <avr/io.h>
#include <util/delay.h>
 
int main(void) {
    DDRD = 0b00111100;
 
    while(1) {
        for(int i = 2; i < 6; i++) {
            PORTD = 1 << i;
            _delay_ms(1000);
        }
    }
    return 0;
}
cs


PORTD = 1 << i;를 해석하면

i가 2 ~ 5로 변하니깐

PORTD = 1 << 2 = 0b00000100

PORTD = 1 << 3 = 0b00001000

PORTD = 1 << 4 = 0b00010000

PORTD = 1 << 5 = 0b00100000

이다.




만약에 특정 비트만 1로 바꾸고 싶다면 |연산자와 << 연산자를 사용하면 된다.


ex) x = 0b11010이라는 숫자에서 2번째 값(0)을 1로 바꾸고 싶다면(0b11110)


x = x | (1 << 2) 라고 하면 된다.

또는 x |= 1 << 2라고 해도 상관없다.



아두이노에서는 위의 코드가 하나의 함수로 되어있다고 한다.

bitSet(data, n);인데 이것은 data라는 데이터에서 n번째를 1로 바꾸고 싶을 때 사용한다.


1
#define bitSet(data, n)        (data |= (1 << n))
cs





반대로 특정 부분을 0으로 만들고 싶으면

bitClear(data, n);라는 함수를 사용하면 된다.


1
#define bitClear(data, n)        (data &= ~(1 << n))
cs


또는 특정 숫자의 n번째 자리에 1인지 0인지를 읽기 위해서
아두이노에서는
bitRead(data, n);이라는 함수가 있다.
1
2
3
4
char bitRead(char data, char n) {
    if(data & (1 << n) return 1;
    else return 0;
}
cs

또는

1
#define bitRead(data, n)        ((data >> n) & 1)
cs

등이 있다.

1
2
3
4
char bitRead(char data, char n) {
    if(((data >> n) & 1== 1return 1;
    else return 0;
}
cs


비트 연산자는 나중에 복잡한 코드를 작성할 때 필요하니 알아두자


반응형