Programming/C2008. 12. 6. 21:51

사실 별로 재미있지는 않습니다.

(이강좌는 8bit 마이크로컨트롤러에서 사용하는 것을 기준으로  char은 8bit  int는 16bit 로 가정하고 진행 됩니다. ) 

그래도 중요하고 꼭 알고 넘어가야 하는 문제이기 때문에..

 

비트연산자에 대해 공부 해 보겠습니다.

 

비트연산자는

&

| (Shift + \ 입니다. 모음 ㅣ(이),  L(엘)의 소문자, 대문자 I(아이) 가 아닙니다. )

^

~

<<

>>

 

이렇게 6가지가 있습니다.

 

 &  (AND)

 둘다 1이면 1

 0 & 0  =>

 0 & 1  =>

 1 & 0  =>

 1 & 1  =>

0

0

0

1

 |  (OR)

 둘중 하나이상 1이면 1

 0 |  0  =>

 0 |  1  =>

 1 |  0  =>

 1 |  1  =>

0

1

1

1

 ^  (XOR)

 둘이 서로 다르면 1

 0 ^  0  =>

 0 ^  1  =>

 1 ^  0  =>

 1 ^  1  =>

0

1

1

0

 ~  (NOT)

 1이었으면 0, 0이었으면 1

~0  =>

~1  =>

1

0

 <<

 왼쪽으로 비트 이동

0b00000011 << 3 

0b00011000 

 >>

 오른쪽으로 비트 이동

0b01100011 >> 2 

0b00011000 

 

어려운것은 없죠?

한가지 알고 넘어가야 할 부분은  << 나 >> 로 이동할때 이동한 만큼의 비트가 버려지고 0으로 채워 집니다.

잘 모르시겠다구요? 그럼 한번 예를 들어 보겠습니다.

 

unsigned char num=0xFF;

num= num<<4;

 

num은 얼마가 될까요?? 

바로 0xF0;

2진수로 풀어 보겠습니다.

0xFF==0b11111111 입니다.

0b 1111 1111              을 왼쪽으로 4번 비트 이동 하겠습니다.

0b 1111 1111 0000      입니다. 비게 되는 오른쪽은 0으로 채워집니다.  그리고 빨간 1111은 버려지게 됩니다.

왜 버려지냐구요? 바로 변수 선언을 8bit 로 했기 때문이죠.. 빨간 1111을 저장할 공간이 없기 때문에 버려집니다.

그래서 남은건 0b 1111 0000 == 0xF0

 

만약 num 가 int 형 이고 초기값이 0x00FF 였다면  어떻게 되었을까요??

그렇죠.. 0x0FF0 이 됩니다.

쉽죠??

 

그럼 각 연산자들이 어떤 상황일때 자주 쓰이는지 알아 보겠습니다.

 

 

먼저

& 연산자

& 연산자는 둘다 1이어야 1이 되기 때문에

1)특정 비트만 0으로 만들고 싶을때

2)특정 비트만 확인 하고 싶을때 (masking)

로 많이 사용됩니다. 

예를 들어 보겠습니다.

1)특정 비트만 0으로 만들고 싶을때

PORTA 에 LED8개가 붙어 있고 모두 켜져 있습니다.(PORTA==0xFF) 

그런데 다른 비트는 건드리지 않고 0번 1번 7번 비트의 LED 만 끄고 싶다면???

PORTA=PORTA & 0x7C;

라고 하면 됩니다.

쓰고 보니 PORTA=0x7C; 라고 하면 되지 않느냐? 라고 물으실 분들을 위해 다른 가정을 하나 더 넣겠습니다.

현재 LED 가 어떻게 켜져 있는지 모르는데 0번 1번 7번 비트의 LED 만 끄고 싶다면??? 그렇다면..

PORTA=PORTA & 0x7C; 이런식으로 & 연산자를 쓰는 것이 다른 비트는 건드리지 않게 됩니다.

2)특정 비트만 확인 하고 싶을때 (masking)

특정 비트만 확인하는 부분은 조건문에서 많이 들어 가는데..

예를 들어 PORTA 에 스위치가 8개 붙어 있는데

PORTA 3번 비트에 달려 있는 스위치가 눌렸는지 판단하고 싶다면?? (스위치는 안눌렀을때 1 눌리면 0으로 가정합니다. )

if((PINA & 0x08) == 0){  ... } 

else 

 이런식으로 사용하게 되면 스위치가 눌렸다면 {  ... }  의 동작을 수행하고 눌리지 않았다면  else 문을 수행 하겠죠??

 

 

 

| 연산자

| 연산자는 둘중 하나라도 1이면 1이 되기 때문에

1)특정 비트만 1으로 만들고 싶을때

로 많이 사용됩니다. 

 

예를 들어 보겠습니다.

1)특정 비트만 1으로 만들고 싶을때

AVR의 ADC관련 레지스터 중에 ADCSRA 라는 레지스터가 있습니다.

그런데 이 레지스터의 6번 비트를 1로 set 하면 ADC를 시작하라는 명령을 내리는 비트입니다.  다른 비트들은 ADC 관련 설정 값이죠..

만약.. ADC를 시작하고 싶은데 ADC 의 다른 설정은 건드리지 말아야 할때.. 바로 | 를 쓰면 됩니다.

ADCSRA |= 0x40; 이렇게 사용하면 해당 비트만 1로 만들수 있습니다.

포트 출력할때 특정포트만 1로 만들고 싶다면 동일한 방법으로 사용하면 됩니다.

 

 

^ 연산자 (XOR 발음 익스클루시브오알 ㅡㅡ;)

두개가 다르면 1이 되기 때문에

1)특정 비트를 토글하고 싶을때

많이 사용됩니다. 

 

예를 들어 보겠습니다.

PORTA 에 연결된 LED중 0번 비트에 연결된 LED만 켰다 껏다를 반복하고 싶습니다.

그럼 이렇게 코드는 어떻게 작성할까요??

while(1)

{

     PORTA = 0x01;

     delay_ms(1000);

     PORTA = 0x00;

     delay_ms(1000);

}

이렇게 작성해도 되지만  ^ 를 사용하면

while(1)

{

     PORTA ^= 0x01;       

     delay_ms(1000);

}

코드가 간단해 집니다.

PORTA 의 값이 뭐든 다른 비트는 변화 없이 0번 비트만 토글됩니다.

 

 

<<, >> 연산자

& 연산자는 둘다 1이어야 1이 되기 때문에

1)두개의 8bit 정수를 합쳐서 int 형 변수에 넣어 줄때  

2)나누기나 곱셈대신 사용할때

 

예를 들어 보겠습니다.

AVR 에는 10bit ADC 가 있습니다.

ADC 를 하게 되면 10bit 를 8bit씩 나눠 ADCH, ADCL 에 나눠 담기게 됩니다.

10bit 니까 8 , 2나 2 , 8로 나뉘게 됩니다.  (나뉘는 방법은 ADMUX 레지스터 안에 있는 ADLAR 비트에 의해 설정됩니다.)

 

 

 

ADLAR==0 일때 shift 연산자를 이용해서 16비트 변수에 담아 보겠습니다.

원칙적으로 A/D 변환결과를 읽을 때는 ADCL 부터 읽어야 합니다.

 

unsigned int temp=0x0000;

temp =  ADCL | (ADCH<<8);     //이렇게 써도 됨  temp =  ADCL + (ADCH*256);

 

ADLAR==1 일때도 한번 해보겠습니다.

 

unsigned int temp=0x0000;

temp =  (ADCL >>6 )  | (ADCH<<2) ;

 

벌써 비트 연산자가 막 들어가기 시작하네요...

곱셈이나 나눗셈을 대신 할때는 몇가지 조건이 있습니다.

먼저 정수형만 되고 2의 지수승만 됩니다.   2,4,8,16,32,64,128,256,512,1024 .....

예를 들어보겠습니다.

0x0F 를 <<2 한것과 *4 것을 비교해 보겠습니다.

0x0F 는 10진수로 15입니다.          *4하면 60 이죠

0x0F를  <<2 하면 0x3C 입니다.     십진수로 계산해 보면 60이죠

 

아래 표를 보면 << 와 *과의 관계가 이해가 되실 겁니다.

 <<1

*2

 <<2

*4

 <<3

*8 

 <<4

*16 

>> 와 / 도 마찬가지입니다.

 >>1

/2

 >>2

/4

 >>3

/8 

 >>4

/16 

 * 나 / 대신  <<, >> 를 쓰는 이유는 연산하는 속도가 빠르기 때문입니다.

 2,4,8,16,32,64,128,256,512,1024 ... 으로 나누거나 곱할때는 << 나 >> 를 쓰는 연습을 해 봅시다.  

 

 

이것으로 비트연산 강좌를 마칩니다. ^^ 모두 열공~

Posted by skensita