비트 연산자를 이해하기 위해서는 우선 논리 연산자에 대해 알아야 한다.
논리 연산자는 if 조건문에 사용되며 아래와 같이 세가지가 있고 아두이노 스케치 상 각각의 표기 방법이 정해져 있다.
논리 AND : 코드상 표기 && (키보드 shift + '7' 두 번 클릭) // 두 조건의 결과가 모두 참일 때 만 참
논리 OR : 코드상 표기 || (키보드 shift + '\' 두 번 클릭) // 두 조건의 결과중 하나만 참이이도 참
논리 NOT : 코드상 표기 ! (키보드 shift + '1' 한 번 클릭) // 조건의 결과가 참이면 거짓, 거짓 이면 참
연산자 | 조건1 | 조건2 | 결과 |
&& AND |
참 | 참 | 참 |
참 | 거짓 | 거짓 | |
거짓 | 참 | 거짓 | |
거짓 | 거짓 | 거짓 | |
|| OR |
참 | 참 | 참 |
참 | 거짓 | 참 | |
거짓 | 참 | 참 | |
거짓 | 거짓 | 거짓 | |
! NOT |
참 | 거짓 | |
거짓 | 참 |
사용 예
if ( 조건1 && 조건2 ) { 실행 코드 } // 조건1과 조건2가 모두 참일 경우 코드 실행
if ( 조건1 || 조건1 ) { 실행 코드 } // 조건1 또는 조건2가 참일 경우 코드 실행
if ( !조건 ) { 실행 코드 } // 조건이 거짓일 경우 코드 실행, ~조건이 아니면
if (digitalRead(2) == HIGH && digitalRead(3) == HIGH) { 실행 코드 } // 두 스위치의 값이 모두 HIGH이면 코드 실행
* "=="는 비교연산자이다. 값1 == 값2, 값1과 값2가 같으면 참, 다르면 거짓
if (digitalRead(2) == HIGH || digitalRead(3) == HIGH) { 실행 코드 } // 두 스위치의 값중 하나만 HIGH여도 코드 실행
if (!digitalRead(2) == LOW) { 실행 코드 } // 스위치의 값이 LOW가 아니면(0이 아니면) 코드 실행
비트 연산
비트 연산은 두 변수의 같은 자리 비트값을 논리 연산을 하는 것이고 표기 방법 및 연산 방법은 아래와 같다.
* 같은 자리의 기준(비트 인덱스)은 변수의 LSB(맨 오른쪽 비트) 부터 0, 왼쪽으로 이동할수록 증가한다.
비트인덱스 7654 3210
val1 = 1; (0000 0001)
val2 = 2; (0000 0010)
비트 AND : 코드상 표기 & // 두 비트값이 모두 1이면 1
비트 OR : 코드상 표기 | // 두 비트값중 하나만 1이어도 1
비트 NOT : 코드상 표기 ~ // 비트값이 1이면 0
비트 XOR (배타적 OR, Exclusive OR) : 코드상 표기 ^ // 두 비트값이 다르면 1, 같으면 0
연산자 | 조건1 | 조건2 | 결과 |
& AND |
1 | 1 | 1 |
1 | 0 | 0 | |
0 | 1 | 0 | |
0 | 0 | 0 | |
| OR |
1 | 1 | 1 |
1 | 0 | 1 | |
0 | 1 | 1 | |
0 | 0 | 0 | |
~ NOT |
1 | 0 | |
0 | 1 | ||
^ XOR |
1 | 1 | 0 |
1 | 0 | 1 | |
0 | 1 | 1 | |
0 | 0 | 0 |
사용 예
uint8_t num1 = 5; // 자료형이 양수 8비트인 숫자 5 = 0000 0101
uint8_t num2 = 2; // 자료형이 양수 8비트인 숫자 2 = 0000 0010
uint8_t value; // 자료형이 양수 8비트인 변수 선언
value = num1 & num2; // 0000 0101 & 0000 0010 -> 0000 0000 = 0
value = num1 | num2; // 0000 0101 | 0000 0010 -> 0000 0111 = 7
value = num1 ^ num2; // 0000 0101 ^ 0000 0010 -> 0000 0111 = 7
value = 253 ^ 250; // 1111 1101 ^ 1111 1010 -> 0000 0111 = 7
value = ~num1; // ~(0000 0101) -> 1111 1010 = 250
value = num1 & 1; // 0000 0101 & 0000 0001 -> 0000 0001 = 1
num1 &= 1; // 자신과 1의 비트 AND 연산 후 자신에게 값 할당, num1 = num1 & 1;
num1 |= 2; // 자신과 2의 비트 OR 연산 후 자신에게 값 할당
num1 ^= 3; // 자신과 3의 비트 XOR 연산 후 자신에게 값 할당
void setup() {
Serial.begin(9600);
uint8_t num1 = 5; // 자료형이 양수 8비트인 숫자 5 = 0000 0101
uint8_t num2 = 2; // 자료형이 양수 8비트인 숫자 2 = 0000 0010
uint8_t value; // 자료형이 양수 8비트인 변수 선언
value = num1 & num2; // 0000 0101 & 0000 0010 -> 0000 0000
Serial.println(value);
for (int i = 0; i < 8; i++) Serial.print(bitRead(value, 7-i));
Serial.println();
value = num1 | num2; // 0000 0101 | 0000 0010 -> 0000 0111
Serial.println(value);
for (int i = 0; i < 8; i++) Serial.print(bitRead(value, 7-i));
Serial.println();
value = num1 ^ num2; // 0000 0101 ^ 0000 0010 -> 0000 0111
Serial.println(value);
for (int i = 0; i < 8; i++) Serial.print(bitRead(value, 7-i));
Serial.println();
value = 253 ^ 250; // 1111 1101 ^ 1111 1010 -> 0000 0111
Serial.println(value);
for (int i = 0; i < 8; i++) Serial.print(bitRead(value, 7-i));
Serial.println();
value = ~num1; // ~(0000 0101) -> 1111 1010
Serial.println(value);
for (int i = 0; i < 8; i++) Serial.print(bitRead(value, 7-i));
Serial.println();
value = num1 & 1; // 0000 0101 & 1(0000 0001) -> 0000 0001
Serial.println(value);
for (int i = 0; i < 8; i++) Serial.print(bitRead(value, 7-i));
Serial.println();
}
void loop() {
}
* bitRead(val, 비트 인덱스) 함수는 변수의 비트값을 읽어오는 함수이고, 비트 인덱스는 변수의 LSB(맨 오른쪽 비트) 부터 0, 왼쪽으로 이동할수록 증가한다.
비트인덱스 7654 3210
val = 1; (0000 0001)
* Serial.println(val, BIN); 함수는 시리얼 모니터로 비트값을 출력해주는 함수이다. 하지만 MSB 영역의 연속된 0값은 표시하지 않는다.
Serial.println(27, BIN); // 31 = 0001 0111 -> 10111
Serial.println(1, BIN); // 1 = 0000 0001 -> 1
8비트의 모든 값을 시리얼 모니터에 표시하기 위해
for (int i = 0; i < 8; i++) Serial.print(bitRead(value, 7-i)); 코드를 사용해 주었다.
* 아두이노 비트 관련 함수
bit(n) 함수는 비트 인덱스 n의 비트값이 1일 경우의 값을 출력해 준다.
비트인덱스 . . . . . . . . 7654 3210
uint8_t n = 15; // (1000 0000 0000 0000) = 32768
Serial.println(bit(n)); // 비트 인덱스 15가 1일때 값은?
비트 인덱스의 범위는 0 ~ 31까지 이다. 32비트 값까지만 계산하여 출력한다. 인덱스의 범위를 넘어서면 0을 출력한다.
bitSet(val, n) 함수는 변수 val의 특정 비트인덱스 n의 값에 1을 쓴다.
uint16_t val = 0; // (0000 0000 0000 0000)
bitSet(val, 15); // (1000 0000 0000 0000)
Serial.println(val); // 32768
bitClear(val, n) 함수는 변수 val의 특정 비트의 값을 지운다(0을 쓴다, 0으로 만든다).
uint16_t val = 32768; // (1000 0000 0000 0000)
bitClear(val, 15); // (0000 0000 0000 0000)
Serial.println(val); // 0
bitWrite(val, n, b) 함수는 변수 val의 특정 비트인덱스 n의 값에 b값(0또는 1)을 쓴다. bitSet()와 bitClear() 함수 기능을 한 함수로 처리할 수 있다.
uint16_t val = 0; // (0000 0000 0000 0000)
bitWrite(val, 15, 1); // (1000 0000 0000 0000) , bitSet(val, 15)
bitWrite(val, 15, 0); // (0000 0000 0000 0000) , bitClear(val, 15)
Serial.println(val); // 0
highByte(val) 함수는 word(아두이노 우노의 경우 16 비트 자료형)의 높은바이트(MSB(왼쪽) 8비트)를 추출한다.
0000 0000 0000 0000 - 2Byte(16bit)
| MSB 영역 | LSB 영역 |
uint16_t val = 25489 // (0110 0011 1001 0001)
uint8_t MSB = highByte(val);
Serial.println(MSB ); // (0110 0011)
lowByte(val) 함수는 word(아두이노 우노의 경우 16 비트 자료형)의 낮은바이트(LSB(오른쪽) 8비트)를 추출한다.
uint16_t val = 25489 // (0110 0011 1001 0001)
uint8_t LSB = highByte(val);
Serial.println(LSB ); // (1001 0001)
테스트 스케치
void setup() {
Serial.begin(9600);
uint8_t n = 15; // 비트 인덱스
Serial.println(bit(n)); // 비트 인덱스 15의 값이 1일때의 값은?
uint16_t val = 0; // (0000 0000 0000 0000)
bitSet(val, 15); // (1000 0000 0000 0000)
for (int i = 0; i < 16; i++) Serial.print(bitRead(val, 15-i));
Serial.println();
Serial.println(val);
bitClear(val, 15); // (0000 0000 0000 0000)
for (int i = 0; i < 16; i++) Serial.print(bitRead(val, 15-i));
Serial.println();
Serial.println(val);
bitWrite(val, 15, 1); // (1000 0000 0000 0000)
bitWrite(val, 15, 0); // (0000 0000 0000 0000)
val = 25489; // (0110 0011 1001 0001)
uint8_t MSB = highByte(val);
for (int i = 0; i < 8; i++) Serial.print(bitRead(MSB, 7-i));
Serial.println();
Serial.println(MSB); // (0110 0011), 99
uint8_t LSB = lowByte(val);
for (int i = 0; i < 8; i++) Serial.print(bitRead(LSB, 7-i));
Serial.println();
Serial.println(LSB); // (1001 0001), 145
}
void loop() {
}
관련 글
[arduino] - 아두이노 - 비트 마스크, bit mask
[arduino] - 아두이노 - 도트 매트릭스 제어하기, dot matrix
'Arduino' 카테고리의 다른 글
ESP8266 / ESP32 - time.h 라이브러리 이용 시간 출력 및 NTP 서버 시간 동기화 하기 (0) | 2019.10.28 |
---|---|
아두이노 - 도트 매트릭스 제어하기, dot matrix (0) | 2019.10.22 |
아두이노 - 비트 마스크, bit mask (0) | 2019.10.19 |
아두이노 - 비트 시프트 연산자 (0) | 2019.10.16 |
아두이노 우노와 NodeMcu의 성능 비교, MCU 속도 벤치 마크 (0) | 2019.10.16 |
아두이노 - 배열 값 shuffle, 배열의 값을 무작위 순서대로 섞는 방법 (0) | 2019.10.07 |
아두이노 - random() 함수 사용하기, 랜덤함수 (0) | 2019.10.06 |
아두이노 - 무드등, 블루투스 연결 스마트폰 원격제어 (0) | 2019.10.05 |