#define LED1 PC0
#define LED2 PC1
#define LED3 PC2
#define LED4 PC3
#define SW2 PE7
#include <avr/io.h>
uint8_t switch_hit();
int main(void){
static unsigned char cnt;
DDRC = _BV(LED1) | _BV(LED2) | _BV(LED3) | _BV(LED4);
PORTE = _BV(SW2);
while(1) {
if(switch_hit()) {
cnt++;
if(cnt % 2)
// turn on LED1 and LED2 and turn off LED3 and LED4
else
// turn on LED3 and LED4 and turn off LED1 and LED2
}
}
}
// 스위치가 눌려지는 순간에만 1을 반환하는 함수
uint8_t switch_hit(void) {
static uint8_t prev_state = _BV(SW2);
uint8_t cur_state;
cur_state = PINE&_BV(SW2);
if(prev_state != cur_state) {
prev_state = cur_state;
if(!cur_state) return 1;
else return 0;
}
else
return 0;
}
Q1. cnt의 값을 계속 증가시키면 overflow가 발생하는데 overflow가 발생에 따른 문제는 없는가?
- cnt는 1byte 8bit 자료형이므로, 0~255까지의 수를 저장할 수 있다.
- overflow 발생 시 0으로 다시 돌아가게 된다.
- 255보다 큰 수의 연산을 하는게 아닌 단순히 홀짝을 판별하므로 문제는 없다.
Q2. switch_hit() 함수는 스위치를 누르는 순간을 인식한다. 이와 달리 스위치를 눌렀다 뗴는 순간 LED 상태 변화 방향이 바뀌도록 switch_hit() 함수를 수정해 보자!
// 스위치를 누르는 순간 1을 반환하는 함수
uint8_t switch_hit(void) {
static uint8_t prev_state = _BV(SW2); // 이전 상태를 저장 (기본값: 스위치가 눌려있지 않은 상태)
uint8_t cur_state;
cur_state = PINE & _BV(SW2); // 현재 스위치 상태 읽기
if (prev_state != cur_state) { // 이전 상태와 현재 상태가 다를 때 (상태 변화)
prev_state = cur_state; // 현재 상태를 저장
if (!cur_state) { // 현재 상태가 눌림 상태 (0)일 때
return 1; // 눌림을 감지했으므로 1을 반환
}
}
return 0; // 눌리지 않은 경우 0을 반환
}
// 스위치를 눌렀다가 떼는 순간 1을 반환하는 함수
uint8_t switch_release(void) {
static uint8_t prev_state = _BV(SW2); // 이전 상태를 저장 (기본값: 스위치가 눌려있지 않은 상태)
uint8_t cur_state;
cur_state = PINE & _BV(SW2); // 현재 스위치 상태 읽기
if (prev_state != cur_state) { // 이전 상태와 현재 상태가 다를 때 (상태 변화)
prev_state = cur_state; // 현재 상태를 저장
if (cur_state) { // 현재 상태가 떼짐 상태 (1)일 때
return 1; // 떼짐을 감지했으므로 1을 반환
}
}
return 0; // 떼지 않은 경우 0을 반환
}
조금 더 간단히 하여
// 눌려진 스위치를 떼면 1을 반환하는 함수
uint8_t switch_hit(void) {
static uint8_t prev_state = _BV(SW2);
uint8_t cur_state;
cur_state = PINE&_BV(SW2);
if(prev_state != cur_state) {
prev_state = cur_state;
return cur_state;
}
- 누르는 순간을 식별하는 건 하강 엣지 검증
- 눌려진 스위치를 떼는 순간을 식별하는 건 상승 엣지 검증
Q3. 스위치를 눌렀다 떼도 LED 상태 변화의 방향이 바뀌지 않는 경우가 한번씩 있는데 이때 스위치를 좀 더 긴 시간 동안 누르고 있으면 이런 문제가 생기지 않는다. 스위치를 누르는 시간을 얼마 이상으로 하면 항상 스위치가 동작한다는 것을 보장할 수 있는가? 이와 같은 현상이 발생하는 이유를도 설명하라
Issue
- 기계적 접촉 문제 : 스위치 접점이 여러 번 빠르게 떨리는 바운스(bounce) 현상
=> 스위치를 짧게 누르면 디바운싱 문제로 인해 신호가 불안정하게 감지
- 지연 함수(delay) 사용 문제 : CPU가 NoOperation을 실행하므로 해당 시간 동안 다른 작업을 수행할 수 없게 만듦
=> 스위치 상태를 체크하지 못하여 상태 변화가 반영되지 않을 수 있음.
Solution
- SW: 5ms~50ms 이상의 눌림 시간을 유지하면 디바운싱 문제를 방지하고 항상 정상적인 동작을 보장
uint8_t switch_hit(void) {
static uint8_t prev_state = _BV(SW2);
uint8_t cur_state = PINE & _BV(SW2);
// 현재 상태를 확인
if (prev_state != cur_state) {
// 상태가 변화할 때마다 딜레이를 줌
for(uint8_t i=0 ; i = 100 ; i++){
_delay_ms(10);// 바운스를 위한 안정화 시간
}
// 다시 상태를 확인
cur_state = PINE & _BV(SW2);
prev_state = cur_state; // 새로운 상태로 업데이트
return cur_state; // 변경된 상태 반환
}
return 0; // 상태 변화 없음
}
- HW: RC회로 사용
이러면 시상수값에 따라 반응이 느려지도록 하여 디바운싱 문제를 해결할 수 있다.
https://m.blog.naver.com/sohnet/222627459492
9.[실습][회로 설계] 스위치 회로 블록 설계-디바운싱
"규칙으로 배우는 임베디드 시스템-회로 설계 및 PCB 설계 규칙" -회로 설계 규칙 편을 읽고 ...
blog.naver.com
'EmbeddedSystem > AVR' 카테고리의 다른 글
[AVR] Microchip studio Tutorial (1) | 2024.10.24 |
---|---|
[AVR] External Interrupts 2 (0) | 2024.10.15 |
[AVR] External Interrupt (0) | 2024.10.14 |
[AVR] atmega1281 - switch / delay 함수 (1) | 2024.09.30 |
[AVR] MCU 기초 - GPIO 사용 (0) | 2024.09.25 |