오늘은 조금 지루하지만
비트 연산자에 대한 것이다.
프로그램 할 때 꼭 필요한 것이니 지루해도 하기로했다.
위의 사진은 저번에도 올렸던 아두이노 미니 회로도이다.
이번에도 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] = {0b00000100, 0b00001000, 0b00010000, 0b00100000}; 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 |
1 | #define bitClear(data, n) (data &= ~(1 << n)) | cs |
1 2 3 4 | char bitRead(char data, char n) { if(data & (1 << n) return 1; else return 0; } | cs |
또는
1 2 3 4 | char bitRead(char data, char n) { if(((data >> n) & 1) == 1) return 1; else return 0; } | cs |
'atmega328(아두이노 미니 이용)' 카테고리의 다른 글
스터디 상생 플러스 1 - 1 (MCU에 대한 지식 습득) (0) | 2020.04.09 |
---|---|
avr 로터리 엔코더 사용하기 05 (6) | 2017.10.09 |
비트 연산자 테스트 04 (0) | 2017.08.12 |
아두이노로 atmega 사용하기 02 (2) | 2017.08.10 |
아두이노 미니로 atmega328 사용하기 (avr studio) 01 (0) | 2017.08.09 |