[ATmega128] 7 세그먼트

해당 예제는 WinAVR 컴파일러 환경에서 동작합니다.

이번 예제는 스위치로 시계 같은 장치에서 사용되는 7세그먼트를 직접 제어하는 예제이다.


회로도


소스코드

#define F_CPU 16000000
#include <avr/io.h>
#include <util/delay.h>
unsigned char num_data[]={0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x27, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71};    
//cathod common 형의 비트 패턴

void main(void){
    unsigned char ch;
    DDRB=0xff;            //PB를 출력으로 설정
    DDRD=0x00;            //PD를 입력으로 설정
    PORTD= 0x0f;        //풀업저항 사용
    while(1){
        ch = (~PIND)&0x0f;    
//스위치에 따른 입력값을 정수로 숫자로 변환
        PORTB = num_data[ch];    //PORTB에 숫자에 따른 비트 패턴을 출력
    }
}

코드는 오히려 LED 예제보다 더 간단하다. 스위치를 통해 2진수 입력을 받아서 7-세그먼트에 16진수 숫자를 출력하는 프로그램이다. num_data[]배열은 7-세그먼트 부품마다 다르게 입력해 주어야 한다. 여기서 사용한 7-세그먼트는 7SEG-COM-CATHODE라는 소자로 공통 단자가 GND이고 LED에 HIGH 신호가 인가되면 LED가 켜지는 구조이다.

위 사진과 비슷하지만 DP 단자가 없다. 예를 들어서 2를 켜기 위해서는 a, b, d, e, g LED가 활성화 되어야하기 때문에0b01011011 가 출력되어야 한다. cathode, athode 방식에 따라서 num_data[] 배열이 달라진다. 그 이유는 공통 단자가 GND이냐 Vcc이냐에 따라 HIGH를 출력하면 불이 켜지는지 LOW를 출력하면 불이 켜지는 지 달라지기 때문이다.


주의할 점

스위치가 택트 스위치가 아니라 푸쉬 스위치를 써서 입력값을 유지할 수 있다.

스위치 입력값을 확인할 때 스위치가 눌려져 있으면 1을 의미하지만 핀으로는 LOW가 입력된다. 예를 들어서 입력을 10 = 0b1010으로 주었을 때 PIND는 0101을 입력으로 받는다. 따라서 not연산~ 을 해준 다음 0x0f와 &연산을 해준다.

'임베디드 > ATmega128' 카테고리의 다른 글

[ATmega128] GPIO 활용 - LED 예제2  (0) 2021.10.02
[ATmega128] GPIO 활용 - LED 예제1  (0) 2021.10.02

[ATmega128] LED 예제2

해당 예제는 WinAVR 컴파일러 환경에서 동작합니다.

이번 예제는 스위치 여러 개로 LED 여러 개를 컨트롤 하는 예제이다. LED가 켜지면 순차적으로 LED가 켜졌다가 꺼지도록 한다.

가장 위 입력은 LED를 켜고 끄는 ON/OFF 스위치이고 그 다음은 LED가 바뀌는 데 걸리는 시간을 줄이고 다른 스위치는 LED가 바뀌는 데 걸리는 시간을 늘리는 스위치이다.


회로도


소스코드

#define F_CPU 16000000
#include <avr/io.h>
#include <util/delay.h>
unsigned char led_on = 0;        //led_on이 1이면 led를 동작하도록 하기 위한 변수
unsigned char led = 0xfe;            //PD0의 LED만 켜지게 하기 위한 초기값
int delay_time = 10;
void delay(int delay_time){            //delay_time 변수 값만큼 50ms씩 delay
    while(delay_time--){
        _delay_ms(50);
    }
}
void main(){
    DDRD = 0x00;            //PD2~0을 입력으로 설정
    DDRB = 0xff;            //PB7~0을 출력으로 설정
    PORTD = 0x07;        //풀업저항을 사용하기 위해 PORTD2~0 = 1
    PORTB = 0xff;                //PORTB의 초기값 설정
    unsigned char key;
    while(1){
        key = PIND & 0x07;        //PIND와 들어온 신호를 비교
        switch(key){    //button이 GND와 연결되어 있어서 눌리면 0      열려있으면 1의 값이 입력
            case 0b00000110:        //PD.0과 연결된 버튼이 눌린 경우
                led_on=~led_on;        //led_on을 스위칭
                break;
            case 0b00000101:        //PD.1과 연결된 버튼이 눌린 경우
                if(led_on){            //LED가 꺼졌다가 다시 켜졌을 때 delay_time이 꺼지기 전의 값을 유지하기 위한 조건문
                    if(delay_time>1){
                    delay_time--;    
//delay 하는 횟수를 감소
                    }
                }
                break;
            case 0b00000011:        //PD2와 연결된 버튼이 눌린 경우
                if(led_on){            
                    if(delay_time<21){
                    delay_time++;    //delay 하는 횟수를 증가
                    }
                }
                break;
        }
        if(led_on){                    
            PORTB=led;        //PORTB에 led값을 출력
            delay(delay_time);        //delay_time * 50ms 만큼 delay
            if(led==0x7f)        //PB7과 연결된 LED가 켜진 경우
                led=0xfe;        //led를 초기값으로 설정
            else
                led=(led<<1)|0x01;    //led 변수를 한칸씩 shift하면서 0번 비트를 1로 세트한다.
        }
        else
        PORTB=0xff;    //led_on이 0인 경우 led를 모두 끔
            _delay_ms(200);
    }
}

이전 예제와 마찬가지로 스위치는 GND와 연결되어 있고 LED는 Vcc와 연결되어 있다. 입력 값을 확인하기 위해서 PIND & 0x07을 해주어서 하위 3비트의 입력값을 비교하고 해당 스위치에 맞는 동작을 한다.

스위치에 따른 동작이 끝나면 led_on 플래그가 1이면 다음 LED를 켜고 다음에 켜질 LED를 led변수에 입력한다. << 연산은 이진수를 왼쪽으로 쉬프트하는 연산기호이다.

delay 함수를 따로 선언해 준 이유는 _delay_ms() 함수가 입력값으로 변수를 받지 않아서이다. x = 1이고 _delay_ms(x)를 하게 되면 에러가 발생하므로 적당한 ms를 설정하고 반복 횟수로 지연 시간을 조절해야 한다.


주의할 점

이 예제에서는 여러 개의 키가 동시에 눌리는 경우에 동작이 되지 않는다. 이런 경우를 위해서 나중에 인터럽트에 대해서 공부하게 된다. while문 마지막에 LED가 꺼진 경우 200ms의 delay를 주게 되었는데 이것은 버튼을 눌렀다가 떼기 전에 다시 while문의 처음으로 돌아가서 여러 번 눌린 것으로 인식될 수 있기 때문이다. 이것 또한 인터럽트를 적용하고 입력 방식을 변경하면 해결할 수 있다.

'임베디드 > ATmega128' 카테고리의 다른 글

[ATmega128] GPIO 활용 - 7 세그먼트  (0) 2021.10.02
[ATmega128] GPIO 활용 - LED 예제1  (0) 2021.10.02

[ATmega128] LED 예제1

해당 예제는 WinAVR 컴파일러 기준 코드입니다.

회로도


소스코드

#define F_CPU 16000000
#include<avr/io.h>
#include<util/delay.h>
unsigned char led_on;
void PB_LEDOnOff(void) // LED ON/OFF 함수
{
    if (led_on) {            //led가 켜진 상태이면
        PORTB=0b00000001;    // LED 끔
        led_on = 0;
    }
    else {                //LED가 꺼진 상태이면
        PORTB=0b00000000;    // LED 켬
        led_on = 1;
    }
}
int main(void){
    unsigned char key;
    DDRB = 0b00000001; // 입출력 방향 설정
    DDRD = 0b00000000; // 입출력 방향 설정
    PORTD = 0b00000001; // 풀업저항 설정
    PORTB = 0b00000000;    //PORTB에 초기값 0x00으로 설정
    led_on = 1;
    while(1)
    {
        key = (PIND & 0b00000001); // 버튼 스위치 값을 읽기
        switch(key) // key와 값이 일치하면 해당 case 실행문을 실행
        {
        case 0b00000000: // 스위치가 눌렸음을 확인
            PB_LEDOnOff();
            _delay_ms(500); // 0.5초 시간 지연 발생
            break;
        default: // 변수와 값이 불일치하면 아무것도 하지 않음
            break;
        }
    }
}

코드 설명

DDRB = 0b00000001로 설정하여 PB0을 출력으로 사용한다. DDRD = 0b00000000이므로 PD0를 입력으로 사용한다. PORTD = 0b00000001로 하여 PD0과 연결된 풀업 저항을 활성화 시킨다. 풀업저항이 활성화 되면 입력값은 HIGH 상태를 유지시키고 Floating 현상을 방지해준다.

LED의 핀 반대방향으로 VCC와 연결되어 있기 때문에 출력이 LOW가 되어야 LED에 전압 강하가 생기기 때문에 불이 켜진다.

while문에서 보면 key = (PIND & 0b00000001) 구문을 통해서 버튼 스위치의 입력값을 확인한다. 버튼이 눌리면 PD0가 GND와 연결되면서 0의 값을 가지게 되므로 0b00000000 case에서 LED의 ON/OFF 상태를 변환시켜준다.


주의할 점

LED 예제를 풀 때 주의할 점으로는 우선 스위치와 LED의 반대방향이 Vcc인지 GND인지 확인하는 것이다. 또한 LED의 방향도 중요하다. 삼각형 방향이 항상 전압이 높은 곳에서 낮은 곳으로 흐르도록 해주어야 한다.

'임베디드 > ATmega128' 카테고리의 다른 글

[ATmega128] GPIO 활용 - 7 세그먼트  (0) 2021.10.02
[ATmega128] GPIO 활용 - LED 예제2  (0) 2021.10.02

+ Recent posts