AVR 스위치 입력 값에 따라서 LED 제어하기 - AVR 연습하기

2013.01.02 16:37




직장 근무로 인해서 블로그 관리에 어려움이 있습니다_2019.07.27



이번에는 AVR에 입력을 주어서 LED를 제어해봅니다.

3개의 스위치를 브레드보드에 꼽고 스위치를 누를 때마다 들어오는 LED가 달라지도록 프로그래밍 했습니다.

입력으로 AVR을 제어할 때는 I/O레지스터 중 3가지 (DDRx, PORTx, PINx)레지스터가 모두 사용되고 if 조건문으로 비교해서 결과가 같으면 출력하도록 합니다.


연습 하드웨어 회로는?




기본 LED 연습회로에 푸쉬스위치만 추가된 회로이고 별도의 변경은 없습니다.

모듈의 경우에는 아래 핀번호가 적혀있어서 번호만 보고 맞춰 연결하면 되고, TINY2313을 바로 사용할때는 위 회로도의 핀배치를 보고 연결합니다.

그리고 스위치가 GND에 연결되어있는데 이 때는 코딩시에 입력포트를 풀업(초기상태 1)로 설정해 주어야 스위치 입력 프로그래밍이 가능합니다.

VCC에 연결했을 경우에는 AVR에서 풀다운은 지원하지 않으므로 4,7K정도의 저항을 포트와 GND에 연결해주어야 하고 스위치를 VCC에 연결해야하며 프로그래밍시에 Tri-State(초기상태 0)으로 설정해 주셔야 합니다. 그럼 코드비전 소스코드부터 볼까요!



CodeVisionAVR 용 소스코드


#include <tiny2313.h>    // TINY2313의 기본 입출력 관련 헤더파일을 포함합니다.

#include <delay.h>    // 지연용 함수관련 헤더파일을 포함합니다.


void main(void)    // main()함수를 호출합니다.

{

PORTB=0x00;    // 포트B의 초기값은 8비트 모두 0 (0V)로 설정합니다.

DDRB=0xFF;    // 포트B의 8비트 모두 출력으로 설정합니다.

PORTD=0x70;    // 포트D의 PD6, PD5, PD4를 입력전 1인상태로 설정합니다.

DDRD=0x00;    // 포트D의 7비트 모두 입력으로 설정합니다.

                   

while (1)    // 아래 구문을 무한 반복합니다.

      {

        if(PIND.6==0)    // 포트D의 6번핀의 입력이 0 이면

        { 

        PORTB.4=1;

        PORTB.5=1;

        PORTB.6=1;

        PORTB.7=1;    // 포트B의 4, 5, 6, 7 번 포트에 1 (5V) 출력

        delay_ms(500);     // 위 상태를 0.5초 유지

        }

        if(PIND.5==0)    // 포트D의 5번핀의 입력이 0 이면

        {

        PORTB.0=1;

        PORTB.1=1;

        PORTB.2=1;

        PORTB.3=1;    // 포트B의 1, 2, 3, 4 번 포트에 1 (5V) 출력

        delay_ms(500);    // 위 상태를 0.5초 유지

        }       

        if(PIND.4==0)    // 포트D의 4번핀의 입력이 0 이면

        {

        PORTB.0=1;

        PORTB.1=1;

        PORTB.2=1;

        PORTB.3=1;

        PORTB.4=1;

        PORTB.5=1;

        PORTB.6=1;

        PORTB.7=1;    // 포트D의 0, 1, 2, 3, 4, 5, 6, 7번 전체 1 (5V) 출력

        delay_ms(500);    // 위 상태를 0.5초 유지

        }        

       PORTB=0x00;    // 입력없으면 포트B의 8비트 전체 0 (0V) 출력        

      }

}


코드비전은 비트제어가 쉽기 때문에 입력역시 간단하게 처리가능합니다.
if 조건문에서 0이 되어야 하는 이유는 DDRD에서 입력으로 설정후에 PORTD로 풀업(1) 즉 모든 비트에 아무 입력이 없을 때 1인 상태로 설정해 두었기 때문에 스위치를 누르면 해당비트만 0 됩니다.
이때 if문에서 해당 비트가 0 이 되었는지 확인 후에 0 이면 if문 아래 괄호에 실행하고자 하는 코드를 입력하면 됩니다.



AVR Studio 용 소스코드


#include <avr/io.h>    // AVR의 기본 입출력 관련 헤더파일을 포함합니다.

#define F_CPU 8000000UL    // AVR칩에 사용중인 크리스탈 주파수 값을 상수로 설정합니다.

#include <util/delay.h>    // 지연 함수관련 헤더파일을 포함합니다.


unsigned char pind6, pind5, pind4;    

// 부호없는 Char형으로 pind6, pind5, pind4 를 생성합니다.


int main()    //  main()함수를 호출합니다.

{

PORTB=0x00;    // 포트B의 8비트 전체 초기값을 0 (0V)로 설정합니다.

DDRB=0xFF;    // 포트B의 8비트 전체를 출력으로 사용합니다.

PORTD=0x70;    // 포트D의 PD6, PD5, PD4를 입력전 1인 상태로 설정합니다.

DDRD=0x00;    // 포트D의 7비트 전체를 입력으로 사용합니다.

while(1)    // 아래구문을 무한 반복합니다.

{

pind6=PIND&0x40;    // pind6변수에 PIND과 0x40과 AND연산한 결과를 넣습니다.

pind5=PIND&0x20;    // pind5변수에 PIND과 0x20과 AND연산한 결과를 넣습니다.

pind4=PIND&0x10;    // pind4변수에 PIND과 0x10과 AND연산한 결과를 넣습니다.


if(pind6==0)    // 포트D의 6번핀의 입력이 0 이면

{

PORTB=PORTB|0x10;

PORTB=PORTB|0x20;

PORTB=PORTB|0x40;

PORTB=PORTB|0x80;    // 포트B의 4, 5, 6, 7번 포트에 1 (5V)를 출력합니다.

_delay_ms(500);    // 위 상태를 0.5초 유지합니다.

}

if(pind5==0)    // 포트D의 5번핀의 입력이 0 이면

{

PORTB=PORTB|0x01;

PORTB=PORTB|0x02;

PORTB=PORTB|0x04;

PORTB=PORTB|0x08;    // 포트B의 1, 2, 3, 4번 포트에 1 (5V)를 출력합니다.

_delay_ms(500);    // 위 상태를 0.5초 유지합니다.

}

if(pind4==0)    // 포트D의 4번핀의 입력이 0 이면

{

PORTB=0xFF;    // 8비트 전체에 1 (5V) 출력합니다.

_delay_ms(500);    // 위 상태를 0.5초 유지합니다.

}

PORTB=0x00;    // 입력이 없으면 포트B의 8비트 전체에 0 (0V)를 출력합니다.

}


return 0;    // main함수에 0을 리턴합니다.

}



프로그래밍 후 동작은?



스위치 누르는 것에 따라 하위 4비트 상위 4비트 전체 LED ON 동작합니다.

이 지겨운 회로도 타이머 인터럽트 후에는 한번 등장하고 끝날 겁니다.~~!



BinGoon AVR/AVR 연습, Tutorial , , , , , ,

  1. Blog Icon
    남영진

    안녕하세요
    죄송하지만 한가지만 물어볼게요
    여기서 RORTD = 0x7F; 인데 B0111 1111; 아닌가요?
    연결되어있는거 보면 PD6,PD5,PD4 연결되어있는데 B0111 인데 그 뒤에 F는 1111이면 PD3,PD2,PD1,PD0도 다 연결되어야 하는건 아닌가요? PD3~PD0 연결안해도 F(1111)적어도 상관이 없는건가요?

  2. D포트에는 스위치 밖에 없어 편의상 D포트 전체값 7F를 주었네요. 연결한 부분만 쓰셔도 됩니다. 지적 감사합니다. 헛갈리는 부분이라면 정정 하겠습니다.
    앞으로도 많이 방문해주세요 ㅎ

  3. Blog Icon
    한현욱

    안녕하세요 잘보고 있는데요 궁금한게 있습니다.
    while문 돌고 있는 상황에서 스위치를 누르게되면 portd에 무는 값이 들어가나요?

    처음 pind6 변수에 0b0100 0000이 들어가서 스위칠 누르면 0b0000 0000이 되는거죠?

  4. 안녕하세요^ 먼저 방문해 주셔서 감사드립니다.
    본론으로 가서 스위치 입력을 해석하자면 먼저 void main() 구문 바로 아래 포트를 초기화 하는 구문이 있는데요. 거기서 DDRD=0x00;으로 입력으로 D포트를 입력으로 사용했고 입력으로 사용했을때 초기값은 풀업상태로 PORTD=0x7F로 2진수로 표현하면 0b01111111 상태로 있게 됩니다. 스위치는 각각 PIND6, PIND5, PIND4가 GND에 연결되있으니 PIND6 스위치를 누르게 되면 해당비트값인 0x40과 AND 연산되어 0으로 변경되게 되죠^ 그럼 2진수로 표현했을 때 0b00111111 이 되게됩니다.^
    부족한 글 봐주셔서 감사드립니다. 앞으로도 계속 찾아주세요.^
    업데이트는 자주없지만요...ㅎ

  5. Blog Icon
    avr

    안녕하세요^^* 잘 보고 있습니다.
    궁금한것이 있어서요
    pind6= PIND&0x40// 0b 0011 1111가 어떻게 나오는지 이해가 잘 안되서요 ㅠㅠ
    pind6=0111 1111 & 0100 0000 이면 0100 0000 아닌가요?

    입문한지 얼마 안되서 모르는게 많이 있네요 ㅠㅠ

    좋은 하루 되세요^^*

  6. 안녕하세요.^
    답변이 한동안 계속 늦어질것 같습니다. 그럼 답변을 ..
    먼저 PIND의 초기값은 DDRD에 의해 입력으로 설정되었고, PORTD = 0x70으로 PD6, PD5, PD4는 풀업상태로 포트D의 초기상태는 0b1110000 상태입니다. 이 상태에서 스위치는 GND로 연결되어 있기 때문에 스위치를 눌렀을 때 해당하는 비트가 0으로 변하게 되지요. 이 때 pind6를 예제로 보자면 pind6 = PIND&0x40 으로 0b01000000으로 연산결과 값이 나오는 것이 맞지요. 그래서 스위치를 누르게 되면 0b00000000로 변하게 되고 if문에서 if(pind6 == 0)이 성립되기 때문에 해당 if문 루틴에서 LED가 코드를 입력한대로 동작되게 되는 것이랍니다.^