본문 바로가기
EmbeddedSystem/AVR

[AVR] atmega1281 - switch로 LED 점멸 제어

by TSpoons 2024. 10. 2.

#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