'Study/AVR ATmega128 Easy Processor Kit'에 해당되는 글 13건

Study/AVR ATmega128 Easy Processor Kit

13. Keypad와 7-Segment를 활용한 심화 작품 만들기

안녕하세요!!! 오늘은 저번 강의 시간에 배운 Keypad와 7-Segment를 활용한 작품을 만들어 볼까 합니다.


Easy Processor Kit을 준비 하시고 AVR Studio를 켜 봅시다~!


 - 실험 1


 우선 첫 번째 실험으로는 4*4로 배치 되어 있는 키패드에 0~15까지 번호를 매겨서 Segment에 출력 되도록 해 볼까요??


 대충 감이 오시나요?? 한번 코딩해보도록 하세요!! 제가 한 것과 비교해 가며 더욱더 효율적인게 무엇인지 판단하시면서 코딩 실력을 향상 시켜 볼 수 있답니다~~ 물론.. 저도 잘하지는 않지만 같이 공부하는 입장이자나요 ㅎㅎ 서두가 길었네요... 얼른 코딩합시다!



#include <avr/io.h>

 

#define KEY_DATA (*(volatile unsigned char *)0x5400) // KEY_DATA 주소 지정

#define KEY_SCAN (*(volatile unsigned char *)0x5800) // KEY_SCAN 주소 지정

#define DIG_SELECT (*(volatile unsigned char *)0x7000) // FND선택을 위한 주소 지정

#define FND_DATA (*(volatile unsigned char *)0x6C00) // FND data 값 저장 위한 주소 지정

 

void Platform_Init(void) // 레지스터 설정 함수

{

    MCUCR |= 0x80 ; // 외부 메모리 사용

}

 

void SEG(uint8_t data) // 0부터 차례대로 Segment에 표시 함수

{

switch(data) // 0부터 차례대로 Segment에 표시

    {

        case 0 :

            FND_DATA = ~0x3F; // 0 표시

            break;

        case 1 :

            FND_DATA = ~0x06; // 1 표시

            break;

        case 2 :

            FND_DATA = ~0x5B; // 2 표시

            break;

        case 3 :

            FND_DATA = ~0x4F; // 3 표시

            break;

        case 4 :

            FND_DATA = ~0x66; // 4 표시

            break;

        case 5 :

            FND_DATA = ~0x6D; // 5 표시

            break;

        case 6 :

            FND_DATA = ~0x7C; // 6 표시

            break;

        case 7 :

            FND_DATA = ~0x07; // 7 표시

            break;

        case 8 :

            FND_DATA = ~0x7F; // 8 표시

            break;

        case 9 :

            FND_DATA = ~0x6F; // 9 표시

            break;

    }

}

 

void Write_KeyPadData(uint8_t data) // 확인하고 싶은 행에 해당하는 값 입력

{

    KEY_DATA = data;

}

uint8_t Read_KeyPadData(void) // 열에 해당하는 값 리턴

{

    return KEY_SCAN;

}

 

void delay_us(unsigned char time_us) // us단위 delay를 위한 함수

{

    register unsigned char i;

    for(i=0;i<time_us;i++)

    {

        asm volatile("PUSH R0"); // 스택 푸쉬

        asm volatile("POP R0"); // 스택 팝

    }

}

 

void delay_ms(unsigned int time_ms) // ms단위 dealy를 위한 함수

{

    register unsigned int i;

    for(i=0;i<time_ms;i++)

    {

        delay_us(250); // 250us 딜레이(2^8=256까지 표현가능)

        delay_us(250);

        delay_us(250);

        delay_us(250); // 1ms 딜레이 표현

    }

}

 

void KeyPadScan() // 몇 번 버튼인지 스캔하는 함수

{

    register unsigned int Key_Data;

    uint8_t data;

 

    Write_KeyPadData(0x0E); // 1행 확인

    data = Read_KeyPadData(); // 열에 해당하는 값 읽음

    if(!(data&0x01)) return 3; // 3버튼

    if(!(data&0x02)) return 2; // 2버튼

    if(!(data&0x04)) return 1; // 1버튼

    if(!(data&0x08)) return 0; // 0버튼

     

    Write_KeyPadData(0x0D); // 2행 확인

    data = Read_KeyPadData(); // 열에 해당하는 값 읽음

    if(!(data&0x01)) return 7; // 7버튼

    if(!(data&0x02)) return 6; // 6버튼

    if(!(data&0x04)) return 5; // 5버튼

    if(!(data&0x08)) return 4; // 4버튼

 

    Write_KeyPadData(0x0B); // 3행 확인

    data = Read_KeyPadData(); // 열에 해당하는 값 읽음

    if(!(data&0x01)) return 11; // 11버튼

    if(!(data&0x02)) return 10; // 10버튼

    if(!(data&0x04)) return 9; // 9버튼

    if(!(data&0x08)) return 8; // 8버튼

     

    Write_KeyPadData(0x07); // 4행 확인

    data = Read_KeyPadData(); // 열에 해당하는 값 읽음

    if(!(data&0x01)) return 15; // 15버튼

    if(!(data&0x02)) return 14; // 14버튼

    if(!(data&0x04)) return 13; // 13버튼

    if(!(data&0x08)) return 12; // 12버튼


return 0xFF; // 아무것도 누르지 않을 경우 0xFF 리턴

}

 

int main(void)

{

uint8_t keyvalue = 0; // 현재 키패드 값 저장하는 변수

uint8_t prevalue = 0xFF; // 이전 키패드 값 0xFF로 초기화 현재 키패드 값과 비교 위함

uint8_t keybutton = 0;


    Platform_Init(); // 초기 설정 함수

    while(1)

    {

keyvalue = KeyPadScan(); // 몇 번 버튼인지 스캔하는 함수


if(keyvalue != 0xFF && keyvalue != pre_val) // 이전의 값이랑 다르고, 키를 누른 상태일 때

keybutton = keyvalue; // 현재 키패드 값을 세그먼트에 출력할 키버튼으로 지정


if(keybutton < 10) // 키버튼의 값이 10보다 작은 경우

{

DIG_SELECT = 0x01;

SEG(0);

delay_ms(3); // 세그먼트 첫번째 자리에 0표시 및 3ms 딜레이


DIG_SELECT = 0x02;

SEG(keybutton);

delay_ms(3); // 세그먼트 두번째 자리에 키버튼 표시 및 3ms 딜레이

}

else // 키버튼의 값이 10보다 큰 경우

{

DIG_SELECT = 0x01;

SEG(keybutton/10);

delay_ms(3); // 세그먼트 첫번째 자리에 10의자리 표시 및 3ms 딜레이


DIG_SELECT = 0x02;

SEG(keybutton%10);

delay_ms(3); // 세그먼트 두번째 자리에 1의자리 표시 및 3ms 딜레이

}

pre_val = keyvalue; // 이전값에 현재 값 옮김

    }

}


 저는 이렇게 코딩 하였답니다~!! 자신의 것과 비교해 보시면서 코딩 실력을 저랑 같이 키워 나가자구요 ㅎㅎ

 모두들 아래와 같은 결과를 얻으셨나요??

  


 그리고 아마 실험을 하면서 어? 이렇게는 왜 안되지?? 하시는 분들이 많을 거에요. AVR 코딩의 Tip을 드리자면 while 문에 유의 하셔야 합니다.


 while 문에 유의하면서 코딩하더라도 키패드의 경우는 좀 특별한데요. 바로 채터링(chattering) 현상 때문입니다!


 - 채터링(chattering) 현상

 이 현상에 대해 아시는 분들도 있을거지만, 설명하자면 스위치나 릴레이 등의 접점이 개폐될 때 기계에서 발생하는 진동입니다. 스위치를 ON 또는 OFF로 했을 때, 접점 부분의 진동으로 말미암아 단속 상태가 반복되는 일, 키보드에서 이 상태가 발생하면 같은 문자가 여러 개 찍히게 되는 것이죠. 이해 되셨나요???


 즉, 키패드를 한 번 누르게 되면 한 개의 값이 나와야 하지만, 결과값이 여러 번 반복 되어서 나온다는 이야기입니다. 그렇다면 이것을 어떻게 해결 할까요??


 - 채터링(chattering)을 피하기 위한 방법


 1. 소프트웨어적으로 피하는 방법

 첫 번째로 소프트웨어적으로 피하는 방법입니다. 이 방법으로 아주 다양한 알고리즘이 존재합니다. 제일 간단하게로는 약간의 딜레이를 이용해서 스위치 값을 읽는 것이죠. 그럼 진동시의 값이 아닌 일정한 값이 들어오게 되겠죠?? 하지만 이 방법에는 한계가 있답니다. 그래서 나온 방법이 제가 소스코드에서 쓴 방법이죠. 키패드가 눌러지고, 현재 키패드의 값과 이전 키패드의 값을 비교하여 값이 다를 때만 받아들여 한번 누른 것과 같은 결과를 보이도록 나타낸 것입니다. 물론, 이 방법 말고도 여러분이 생각하여 적용하시면 됩니다!! ^^


 2. 하드웨어적으로 피하는 방법

 두 번째로는 하드웨어적으로 피하는 방법입니다. 여기에도 아주 다양한 하드웨어가 존재하는데 여기서는 널리 사용되는 방법인 R-S 플립플롭을 이용한 방법으로 예를 들어 보이겠습니다.


  그림과 같이 회로를 구성하면 되는데, 분석해보면 풀업저항으로 인해 U1B에는 5V가 들어가게 되고, 스위치가 연결된 U1A에는 0V가 들어가게 되는데요. 그럼 U1A NAND 게이트의 값은 1로 나올 것이고, U1B의 NAND 값은 0으로 나오겠네요! 최종 결과로는 당연히 1으로 나오겠죠?

 아하 그렇다면 스위치가 채터링으로 인해 떨어지게 되는 경우를 보게 된다면, U1A, U1B에는 풀업저항으로 인해 1의 값이 들어가게 되고 U1A의 NAND 게이트의 값은 1이었으니깐 여전히 U1B의 NAND 값은 당연히 0이고, 최종 결과로는 1이 유지가 되는 것을 알 수 있네요!!


 이렇게 채터링을 피하기 위한 방법들을 알아보았는데요. 원하시는 방법을 채택하여 적용하시면 된답니다~!!!


 - 실험 2


 다음 실험은 실험의 단골주제 계산기를 해보도록 하겠습니다!!


음~ 일단 키패드에서 어떻게 구현할 것인지 각 버튼의 기능을 설계 해보자면, 아래 표와 같습니다!


- 계산기에서 키패드 구성

이제 각 버튼에 대해서 구현할 수 있겠죠? 아까 했던 실험에서 조금만 추가하고, 변경하면 된답니다!! 그리고 여러 알고리즘들이 있을 수 있으니 제꺼는 참고해서 보세요! 연산기호를 Segment로 표시 할 때는 마음대로 하셔도 되요.



#include <avr/io.h>

 

#define KEY_DATA (*(volatile unsigned char *)0x5400) // KEY_DATA 주소 지정

#define KEY_SCAN (*(volatile unsigned char *)0x5800) // KEY_SCAN 주소 지정

#define DIG_SELECT (*(volatile unsigned char *)0x7000) // FND선택을 위한 주소 지정

#define FND_DATA (*(volatile unsigned char *)0x6C00) // FND data 값 저장 위한 주소 지정

  

void Platform_Init(void) // 레지스터 설정 함수

{

    MCUCR |= 0x80 ; // 외부 메모리 사용

}

 

void SEG(uint8_t data)

{

    switch(data) // 0부터 차례대로 Segment에 표시

    {    

        case 0 :

            FND_DATA = ~0x3F; // 0 표시

            break;

        case 1 :

            FND_DATA = ~0x06; // 1 표시

            break;

        case 2 :

            FND_DATA = ~0x5B; // 2 표시

            break;

        case 3 :

            FND_DATA = ~0x4F; // 3 표시

            break;

        case 4 :

            FND_DATA = ~0x66; // 4 표시

            break;

        case 5 :

            FND_DATA = ~0x6D; // 5 표시

            break;

        case 6 :

            FND_DATA = ~0x7C; // 6 표시

            break;

        case 7 :

            FND_DATA = ~0x07; // 7 표시

            break;

        case 8 :

            FND_DATA = ~0x7F; // 8 표시

            break;

        case 9 :

            FND_DATA = ~0x6F; // 9 표시

            break;

        case 11 :

            FND_DATA = ~0x46; // 덧셈

            break;

        case 12 :

            FND_DATA = ~0x40; // 뺄셈

            break;

        case 13 :

            FND_DATA = ~0x70; // 곱셈

            break;

        case 14 :

            FND_DATA = ~0x49; // 나눗셈

            break;

}

}

 

void Write_KeyPadData(uint8_t data) // 확인하고 싶은 행에 해당하는 값 입력

{

    KEY_DATA = data;

}

uint8_t Read_KeyPadData(void) // 열에 해당하는 값 리턴

{

    return KEY_SCAN;

}

 

void delay_us(unsigned char time_us) // us단위 delay를 위한 함수

{

    register unsigned char i;

    for(i=0;i<time_us;i++)

    {

        asm volatile("PUSH R0"); // 스택 푸쉬

        asm volatile("POP R0"); // 스택 팝

    }

}

 

void delay_ms(unsigned int time_ms) // ms단위 dealy를 위한 함수

{

    register unsigned int i;

    for(i=0;i<time_ms;i++)

    {

        delay_us(250); // 250us 딜레이(2^8=256까지 표현가능)

        delay_us(250);

        delay_us(250);

        delay_us(250); // 1ms 딜레이 표현

    }

}

 

uint8_t KeyPadScan()

{

    register unsigned int Key_Data;

    uint8_t data;

    

Write_KeyPadData(0x0E); // 1행 확인

    data = Read_KeyPadData(); // 열에 해당하는 값 읽음

    if(!(data&0x01))

        return 11; // 덧셈표시

    if(!(data&0x02))

        return 3; // 3표시

    if(!(data&0x04))

        return 2; // 2표시

    if(!(data&0x08))

        return 1; // 1표시


    Write_KeyPadData(0x0D); // 2행 확인

    data = Read_KeyPadData(); // 열에 해당하는 값 읽음

    if(!(data&0x01))

        return 12; // 뺄셈표시

    if(!(data&0x02))

return 6; // 6표시

    if(!(data&0x04))

        return 5; // 5표시

    if(!(data&0x08))

        return 4; // 4표시


    Write_KeyPadData(0x0B); // 3행 확인

    data = Read_KeyPadData(); // 열에 해당하는 값 읽음

    if(!(data&0x01))

        return 13; // 곱셈표시

    if(!(data&0x02))

        return 9; // 9표시

    if(!(data&0x04))

        return 8; // 8표시

    if(!(data&0x08))

        return 7; // 7표시


    Write_KeyPadData(0x07); // 4행 확인

    data = Read_KeyPadData(); // 열에 해당하는 값 읽음

    if(!(data&0x01))

        return 14; // 나눗셈표시

    if(!(data&0x02))

        return 50; // = 표시

    if(!(data&0x04))

        return 0; // 0표시

    if(!(data&0x08))

        return 100; // 취소표시


    return 0xFF; // 안누르면 0xFF 반환

}

 

int main(void)

{

    uint8_t first_operand=0; // 첫 번째 인수를 담을 변수

    uint8_t second_operand=0; // 두 번째 인수를 담을 변수

    uint8_t cal_signal=11; // 연산기호 담을 변수 더하기로 초기화

    uint8_t result_val=0; // 결과값을 담을 변수

    uint8_t keyvalue=0; // 키패드 스캔값 담을 변수

    uint8_t pre_val=0xFF; // 이전의 스캔값 0xFF로 초기화

    uint8_t flag=0; // 플래그 0

    uint8_t first_sig=0; // 마이너스를 표현하기 위한 결과값의 왼쪽에 해당하는 값

    uint8_t equal=0; // 결과에 해당하는 스캔값을 저장할 변수

 

    Platform_Init();

    while(1)

    {

        keyvalue = KeyPadScan(); // 키스캔

        if(keyvalue != 0xFF && keyvalue != pre_val) // 이전의 값이랑 다르고, 키를 누른 상태일 때

        {

            if(flag == 0x00) // 첫번째 인수

            {

                first_operand = keyvalue; // 첫 번째 인수를 변수에 담기

                if(first_operand > 10) // 만약 그 인수가 숫자가 아니면 초기화

                {

                    first_operand = 0;

                    cal_signal = 11;

                    second_operand = 0;

                    result_val = 0;

                    first_sig = 0;

                    flag=0x00;

                }

                else

                    flag = 0x01; // 숫자면 플래그 1

            }

            else if(flag == 0x01) // 두번째 인수

            {

                cal_signal = keyvalue;

                if(cal_signal < 10 || cal_signal >= 50) // 연산기호가 아니면 초기화

                {

                    first_operand = 0;

                    cal_signal = 11;

                    second_operand = 0;

                    result_val = 0;

                    first_sig = 0;

                    flag=0x00;

                }

                else // 연산기호이면 플래그 2

                flag = 0x02;

            }

            else if(flag == 0x02) // 세번째 인수

            {

                second_operand = keyvalue;

                if(second_operand > 10) // 숫자가 아니면 초기화

                {

                    first_operand = 0;

                    cal_signal = 11;

                    second_operand = 0;

                    result_val = 0;

                    first_sig = 0;

                    flag=0x00;

                }

                else

                    flag = 0x03; // 숫자면 플래그 3

            }

            else // 결과

            {

                equal = keyvalue;

                if(equal==50) // 스캔값이 =이면

                {

                    switch(cal_signal)

                    {

                        case 11 : // 덧셈

                            result_val = first_operand + second_operand;

                            flag=0x00; // 초기화

                            break;

                        case 12 : // 뺄셈

                            if(first_operand < second_operand) // 결과가 -이면

                            {

                                result_val = second_operand - first_operand;

                                first_sig = 12; // 결과값에 - 붙임

                            }

                            else // 결과가 +이면

                                result_val = first_operand - second_operand;

                            break;         

                        case 13 : // 곱셈

                            result_val = first_operand * second_operand;

                            break; 

                        case 14 : // 나눗셈

                            if(second_operand == 0) // 나누는 값이 0이면 초기화

                            {

                                first_operand = 0;

                                cal_signal = 11;

                                second_operand = 0;

                                result_val = 0;

                                first_sig = 0;

                                flag=0x00;

                            }

                            else // 나누는 값이 0이 아니면

                                result_val = first_operand/second_operand;

                            break;

                    }

                }

                else // = 아니면 초기화

                {

                    first_operand = 0;

                    cal_signal = 11;

                    second_operand = 0;

                    equal = 0;

                    result_val = 0;

                    first_sig = 0;

                    flag=0x00;

                }

            }

        }

 

        /*-----------------출력-----------------*/

        DIG_SELECT = 0x01; // 1번 자리

        SEG(first_operand);

        delay_ms(3);

        DIG_SELECT = 0x04; // 2번 자리

        SEG(cal_signal);

        delay_ms(3);

 

        DIG_SELECT = 0x10; // 3번 자리

        SEG(second_operand);

        delay_ms(3);


        if(result_val < 10) // 결과 자리 결과 값이 10보다 작을 때

        {

            DIG_SELECT = 0x40;

            SEG(first_sig); // 0이거나 -

            delay_ms(3);

 

            DIG_SELECT = 0x80;

            SEG(result_val); // 1의 자리

            delay_ms(3);

        }

        else // 결과 값이 10보다 크거나 같을 경우

        {

            DIG_SELECT = 0x40;

            SEG(result_val/10); // 10의 자리

            delay_ms(3);

 

            DIG_SELECT = 0x80;

            SEG(result_val%10); // 1의 자리

            delay_ms(3);

        }

 

        pre_val = keyvalue; // 이전값에 현재 값 옮김

    }

}



실험결과 입니다!! 왼쪽 위부터 덧셈, 뺄셈, 곱셈, 나눗셈 순이에요~! 연산 기호를 저는 그림과 같이 나타내 보았어요~~!! 


  

8 + 5 = 13 (왼쪽), 1 - 6 = -5 (오른쪽)

  

4 * 8 = 32 (왼쪽), 8 / 4 = 2 (오른쪽)


 소스코드를 대략적으로 설명하자면, 저는 키패드 리턴값을 0~9는 해당 숫자들을 그대로 표현하였고, 11~14는 연산기호를 표현 하였습니다. 그리고 취소 버튼의 경우 100으로 키패드 리턴값을 받구요. 어짜다보니, 취소버튼 뿐만 아니라 해당 플래그에서 다른 버튼이 들어오면 초기화 해버렸지만... 의미는 같으니까요~~^^ 또한, 플래그를 두어 각 단계마다 해당 값들을 받아서 변수에 저장 시켰답니다. 주석을 잘 보시고 이해하세요.


수고하셨어요!!! 이제 4개의 소자에 대해서 배웠으니 4개를 활용해서 재미난 작품들을 만들 수 있답니다.

다음 시간에는 Timer와 Counter에 대해서 배워보도록 할게요!! 안녕~!!




,
Study/AVR ATmega128 Easy Processor Kit

12. Easy Processor Kit 7-segment 제어하기

안녕하세요~!!! 진짜 추운 날씨죠?ㅠㅠ 얼마전에는 눈보라까지 치고 난리도 아니었어요..


춥지만 힘을 내서 공부를 해 볼까요?ㅎ


오늘은 지난 시간에 이야기 했던 7-segment에 대해서 공부하도록 할게요!


 - 7-Segment란?


 7-Segment(FND)란 7개의 조명편을 아래 그림과 같이 배치하고그 몇 개를 선택하여 조광함으로써 숫자나 문자를 표시할 수 있도록 한 표시장치치에요, LED를 조합하여 숫자나 문자를 나타내는 것이랍니다~

 이러한 각 LED는 어떻게 연결되어 있을까요?? 공통버스인 COM단자에 물려서 제어가 되는군요! 많이 보던 다이오드도 보이구요~

 그리고 Cathode와 Anode 이것은 이전 시간에 LED를 배웠을때 기억나시나요? 다이오드 방향에 따라서 동작방식이 결정되는 것을 말하는 거죠!

조금 더 자세히 알아 볼까요??


 - Segment Anode형

 회로가 복잡해 보이죠? 하지만 잘 보시게 되면 4개의 Segment로 구성되어 있다는 것을 알 수 있습니다. 혹시 시중에 붙여서 파는 Segment 소자들을 보신적 있으신가요? 다 저렇게 연결되어 있답니다~!

 Anode는 공통버스인 COM 단자에는 VCC를 연결하고 입력으로 GND(그라운드)에 해당하는 논리적인 0이 들어오면 해당 LED에 불이 들어오게 된답니다. 다이오드 방향을 보시고 다들 아시겠죠?

 각 핀의 영어들은 위의 그림에서 LED의 위치를 나타냅니다. 참고하세요!


- Segment Cathode형

 다음은 Cathode형을 살펴보도록 하죠. 여기서는 Anode형과 다른 것은 딱 한 가지 있네요. 바로 다이오드의 방향입니다.

 그럼 공통버스인 COM 단자에는 GND를 연결하고 입력으로 논리적인 1이 들어오면 해당 LED에 불이 들어오게 되는 것인거 아시겠죠?


 - 7-Segment 제어 방법

 이제 Segment가 대충 어느 것인지는 알았고, Kit의 회로도를 한번 살펴보도록 하죠.

 D플립플롭으로 FND_DATA, FND_CS가 신호가 들어오게 되네요. FND_DATA는 이름에서 부터 감이 오는 것과 같이 어느 LED가 켜질 것인지에 대한 데이터가 가겠네요. FND_CS의 경우 Segment의 밑 부분의 버스들 있죠? FND_COM 이라는 버스로 Segment에 들어가게 된답니다.


 그렇다면 FND_CS의 역할은 무엇일까요?? 버스의 갯수를 보고 감이 오시나요? 바로 어느 Segment가 해당 데이터로 켜질 것인가에 대한 데이터를 담고 있습니다. 즉, FND_CS가 정한 Segment에 FND_DATA에 해당하는 LED를 키는 것이죠! 


 그렇긴한데... 약간 의문이 듭니다. 8개를 동시에 켜지도 못하면 무용지물이 될터인데.. 여기서 아주 중요한 개념이 이제 나옵니다!


 - 잔상효과

- 잔상효과

 우리가 일상에서 보던 Segment들은 어떻게 동시에 값을 나타내고 있던 것일까요? 바로 위의 그림처럼 잔상효과를 이용하는 것입니다.

Kit에 보시게 되면 총 8개의 Segment가 있는데, 이를 동시에는 켜지 못하니 하나씩 Segment를 키는 것이죠. 그리고 이를 빠르게 돌린다면?? 마치 다 켜져 보이는 것처럼 나타 날 것입니다.

 바로 이러한 개념을 이용하는 것이에요!! 오늘 강좌의 핵심이니 잘 기억해 두세요!


 - Segment 동작 흐름도

 이제 쉽게 그림으로 흐름도를 보도록 하죠. 이해가 되시죠? CPLD를 통해 FND_DATA, FND_CS의 값들이 결정 되고, 해당 데이터의 값이 Segment로 들어가서 제어가 되는 형태입니다!

 혹시나 해서 다시 한번! CPLD 외부 메모리 맵핑 주소를 올립니다. ㅎㅎ 자주 보이죠?


 - 실습


 자 이제 개념 공부는 다했으니 직접 실습해보도록 합시다!! AVR Studio를 켜시고 코드를 입력해 보도록 하죠.


#include <avr/io.h>

#define DIG_SELECT (*(volatile unsigned char *)0x7000) // FND 선택을 위한 주소 지정

#define FND_DATA (*(volatile unsigned char *)0x6C00) // FND data 값 저장 위한 주소 지정

 

void ExtFndSet(int sel)

{

    switch(sel) // 0부터 차례대로 Segment에 표시

    {

        case 0 :

            FND_DATA = ~0x3F; // Anode 방식이므로 0일 때 켜지기 때문에 앞에 not을 붙임, 0011 1111 으로 해당하는 Segment0이라는 표시가 나오게 됩니다.

            break;

        case 1 :

            FND_DATA = ~0x06; // 1 표시

            break;

        case 2 :

            FND_DATA = ~0x5B; // 2 표시

            break;

        case 3 :

            FND_DATA = ~0x4F; // 3 표시

            break;

        case 4 :

            FND_DATA = ~0x66; // 4 표시

            break;

        case 5 :

            FND_DATA = ~0x6D; // 5 표시

            break;

        case 6 :

            FND_DATA = ~0x7C; // 6 표시

            break;

        case 7 :

            FND_DATA = ~0x07; // 7 표시

            break;

        case 8 :

            FND_DATA = ~0x7F; // 8 표시

            break;

        case 9 :

            FND_DATA = ~0x6F; // 9 표시

            break;

        case 10 :

            FND_DATA = ~0x77; // A 표시

            break;

        case 11 :

            FND_DATA = ~0x7C; // b 표시

            break;

        case 12 :

            FND_DATA = ~0x39; // C 표시

            break;

        case 13 :

            FND_DATA = ~0x5E; // D 표시

            break;

        case 14 :

            FND_DATA = ~0x79; // E 표시

            break;

        case 15 :

            FND_DATA = ~0x71; // F 표시

            break;

        case 16 :

            FND_DATA = ~0x76; // H 표시

            break;

        case 17 :

            FND_DATA = ~0x40; // - 표시

            break;

        case 18 :

            FND_DATA = ~0x80; // . 표시

            break;

        case 19 :

            FND_DATA = ~0x00; // 공백 표시

            break;

      }

}

 

void delay_us(unsigned char time_us) // us단위 delay를 위한 함수

{

    register unsigned char i;

    for(i=0;i<time_us;i++)

    {

        asm volatile("PUSH R0"); // 스택 푸쉬

        asm volatile("POP R0"); // 스택 팝

    }

}

 

void delay_ms(unsigned int time_ms) // ms단위 dealy를 위한 함수

{

    register unsigned int i;

    for(i=0;i<time_ms;i++)

    {

        delay_us(250); // 250us 딜레이(2^8=256까지 표현가능)

        delay_us(250);

        delay_us(250);

        delay_us(250); // 1ms 딜레이 표현

    }

}

 

int main(void)

{

    int i;

    MCUCR = 0x80 ; // 외부 메모리 사용

     

    while(1)

    {

        for(i=0;i<20;i++) // 0부터 .까지 표현하기 위한 for 구문

        {

            DIG_SELECT = 0xFF; // 모든 FND 선택

            ExtFndSet(i);

            delay_ms(200); // 200ms 지연

        }

    }

}


주석을 보면서 하나하나 분석해 나가도록 하세요!ㅎㅎ 설명하자면 8개의 FND에서 "0"부터 "."까지 표시를 하게 되는 것입니다.


 잘 나와죠??ㅎㅎ


그리고, 팁을 주자면 DIG_SELECT 즉, FND_CS와 FND_DATA를 잘 조절하여서 각 segment마다 다른 값들을 표시할 수도 있습니다!!


오늘도 공부하느라 수고하셨구요~!! 다음시간에는 키패드와 Segment를 활용한 실험들을 해볼 계획입니다!!


다음시간에 뵈요~



,
Study/AVR ATmega128 Easy Processor Kit

11. Easy Processor Kit 외부 keypad 제어 하기

안녕하세요^^ 


오늘은 외부 keypad를 제어 해보려고 합니다~!!! 


우선 key pad가 무엇인지 알아야겠죠??


 - Keypad란?


 

 여러가지 기능을 수행할 수 있도록 만들어진 독립된 작은 장치입니다. 키를 누르게 되면 ON이 되어 Low 값이든, High 값이든 기계로 흘러 들어가게 된답니다. 값에 따라 여러가지 기능들을 수행 할 수 있겠죠?? 일종의 스위치라고 생각하면 됩니다!


 키패드를 과연 어떻게 제어를 할까요?? 알아보도록 하죠.


 - keypad 제어 방법


 자 키패드 회로도를 한번 살펴보죠~~ 화질이 좋지는 않은데, 이전에 공유해 드렸던 easy-pro-kit-base-v12.pdf 파일을 참조하세요!ㅎㅎ 6강에 올려놓았습니다!!(http://feelsoverygood.tistory.com/35)


 어라?? LED와 Dip switch 번에 보던 칩들이 한꺼번에 붙어 있네요! 버퍼(위쪽, 열에 해당)와 D 플립플롭(아래쪽, 행에 해당)을 이용하는군요. 그러고 보니 풀업저항 또한 이용하네요 Dip switch와 거의 모양이 흡사하죠?? 동작 방식 또한 스위치 형태이기 때문에 비슷하답니다.

 또한, 자세히 보시면 버퍼에도 4개의 포트만, 플립플롭에도 4개의 포트만을 사용한 것을 볼 수 있답니다. 즉, 총 8개의 포트로 4*4의 키패드를 입력 받을 수 있게 해놓았답니다.


- Keypad 흐름도

 키를 눌렀을 때의 흐름을 처음부터 설명하자면, MCUCR 레지스터에서 외부 메모리를 쓰겠다고 입력되면, 하위, 상위포트로 어드레가 나눠지고 각 포트의 값은 CPLD에 들어가게 되어 어떤 외부장치를 이용할 것인지 결정하게 됩니다. 그럼 이제 아래 표처럼 KEY_DATA와 KEY_SCAN의 값이 각각 플립플롭과 버퍼에 들어가게 됩니다.

- 이제는 다 알죠?? 외부 메모리 맵핑 주소입니다.

 그런 다음 이제 버튼이 눌러졌는지 읽고 싶은 행에 Low의 값을 주게 되면 버튼을 누른 열은 Low의 값이 버퍼로 들어가겠죠?? 즉, 키패드가 총 4행으로 이루어져 있으니 KEY_DATA에 1행씩 Low 값을 주어(나머지 행들은 High 값으로 주어야합니다! 그렇게 해야 한줄씩만 확인이 가능하기 때문이죠.) 키패드가 눌러졌는지 KEY_SCAN의 값으로 확인이 되겠죠??? 물론! KEY_DATA의 값이 while문을 통해 1행~4행을 반복하여 Low 값을 주어 확인을 하고 있답니다!!


즉! KEY_DATA에는 1행씩 Low값을 주고, KEY_SCAN으로는 눌러진 키에 해당하는 곳에 Low값이 들어오게 되는 겁니다.

 이런 방식(한 행씩 스캔하는 방식)이 다이나믹 구동이라고 한답니다~!


 - 실습


 이해 되셨나요?? 아마 이해가 안되시면 소스코드를 통하여 이해를 해보도록 하죠!! 그럼 이제 소스코드를 작성해 봅시다.




#include <avr/io.h>

 

#define LED_CS (*(volatile unsigned char *)0x4800) // LED 주소 지정

#define KEY_DATA (*(volatile unsigned char *)0x5400) // KEY_DATA 주소 지정

#define KEY_SCAN (*(volatile unsigned char *)0x5800) // KEY_SCAN 주소 지정

 

void Platform_Init(void) // 레지스터 설정 함수

{

    MCUCR |= 0x80 ; // 외부 메모리 사용

}

 

void LED_ON(uint8_t data) // LED 키는 함수

{

    LED_CS = data; // data 값에 해당하는 LED

}

 

void Write_KeyPadData(uint8_t data) // 확인하고 싶은 행에 해당하는 값 입력

{

    KEY_DATA = data;

}

uint8_t Read_KeyPadData(void) // 열에 해당하는 값 리턴

{

    return KEY_SCAN;

}

 

void KeyPadScan()

{

    register unsigned int Key_Data;

    uint8_t data;

    uint16_t led;

 

    Write_KeyPadData(0x0E); // 0000 1110으로 1행을 확인하기 위함

    data = Read_KeyPadData(); // 열에 해당하는 누른 키패드는 0, 누르지 않은 키패드는 1의 값을 data에 저장

    if(!(data&0x01))LED_ON(0x04); // data0000 0001 and 후 그 값이 0이면(data1110) 4번 키패드를 누른 것이므로 LED4를 표시(키패드 구성도 참조하면 4번째 열이 제일 하단비트인 것을 알 수 있다.)

    if(!(data&0x02))LED_ON(0x03); // 3번 키패드 표시(1101)

    if(!(data&0x04))LED_ON(0x02); // 2번 키패드 표시(1011)

    if(!(data&0x08))LED_ON(0x01); // 1번 키패드 표시(0111)

 

    Write_KeyPadData(0x0D); // 이번에는 0000 1101으로 2행을 확인하기 위함

    data = Read_KeyPadData(); // 열에 해당하는 값 대입

    if(!(data&0x01))LED_ON(0x08); // 8번 키패드 표시(1110)

    if(!(data&0x02))LED_ON(0x07); // 7번 키패드 표시(1101)

    if(!(data&0x04))LED_ON(0x06); // 6번 키패드 표시(1011)

    if(!(data&0x08))LED_ON(0x05); // 같은 방법으로 반복

     

    Write_KeyPadData(0x0B); // 3행 확인

    data = Read_KeyPadData();

    if(!(data&0x01))LED_ON(0x0C);

    if(!(data&0x02))LED_ON(0x0B);

    if(!(data&0x04))LED_ON(0x0A);

    if(!(data&0x08))LED_ON(0x09);

     

    Write_KeyPadData(0x07); // 4행 확인

    data = Read_KeyPadData();

    if(!(data&0x01))LED_ON(0x10);

    if(!(data&0x02))LED_ON(0x0F);

    if(!(data&0x04))LED_ON(0x0E);

    if(!(data&0x08))LED_ON(0x0D);

}

 

int main(void){

    Platform_Init();

    while(1){

        KeyPadScan();

    }

}



 위의 소스코드가 이해가 가시나요?? 그럼 Keypad에 관해서 다 배우신 겁니다.ㅎㅎ

설명하자면 LED에 keypad의 번호를 표시하는 소스코드입니다. 

 그리고, 프로테우스로 테스트 시뮬레이션을 하고자 하시는분은 외부 메모리 설정 대신 DDRn, PORTn, PINn 을 쓰시면 됩니다.


 앞서 설명 한 것과 같이 KEY_DATA에 1행씩 Low 값을 주고, KEY_SCAN의 값을 반환 받아서 확인하는 것 보이시죠??

실험 결과는 아래와 같습니다~!


- 왼쪽 : 키패드 1번, 오른쪽 : 키패드 16번


키패드 위치는 외부 LED 오른쪽 아래에 있답니다~ 참조하시구요!! 오늘은 여기까지 입니다!

다음시간에는 7-segment에 대해서 배우도록 하겠습니다. 수고 하셨어요!



,
Study/AVR ATmega128 Easy Processor Kit

10. 외부 LED와 Dip Switch를 활용한 심화 작품 만들기

안녕하세요~~!!! 오늘은 정말 추운 하루인데요ㅠㅠ 모두들 감기 조심하시구요. 온도가 무려 -6도가 되어서 아침 출근길에 귀가 시려워 고생했어요..


모두들 추운데 힘내시고요~!! 이제 본론으로 들어와서 오늘 하려고 한 실험인 외부 LED와 Dip Switch를 활용한 심화 작품을 만들려고 해요.


벌써 2개나 배웠네요!!!^^ 이대로 쭉쭉 진도 나가보죠.


우선 지난번에 한대로 실험 환경 준비해주시고!


시작해봅시다!!


 - 실험1


먼저 해볼 실험은 Dip Switch가 하나라도 on이면 LED를 점멸시키고, 모두 OFF 일 경우 LED 현재 상태를 유지하는 실험을 해보겠습니다.!!


AVR Studio 4를 실행해 주시고 소스코들 작성해보죠!!


물론 이것을 보고 그대로 하는 것도 도움이 됩니다만, 여러분들이 직접 머리 굴려가며 코드를 먼저 작성해보세요!! 그게 훨씬 더 도움이 됩니다.


그전에 딜레이에 관련해서 <util/dealy.h>를 쓰지 않고도 이와 같은 역할을 하는 함수를 구현할 수 있는데요. 이러한 함수에 대해서 공부하도록 하죠.



void delay_us(unsigned char time_us) // delay 함수 총 8cycle 이므로 1/8000000*8으로 1us 걸림

{

register unsigned char i; // I변수 선언

for(i=0;i<time_us;i++) // 4 cycle 총 소모

{

asm volatile("PUSH R0"); // 2 cycle push 소모

asm volatile("POP R0"); // 2 cycle pop 소모

}

}

void delay_ms(unsigned int time_ms) // 1us 4번 써서 1ms 되게 하는 함수

{

register unsigned int i;

for(i=0;i<time_ms;i++)

{

delay_us(250);

delay_us(250);

delay_us(250);

delay_us(250); // 250us 씩 4번 하여 1ms 되게 함 한 번에 못쓰는 것은 8bit 범위라 255까지 밖에 못 쓰기 때문

}

}



 자!! 대충 이해 가시나요? 먼저 마이크로초 단위의 딜레이인 delay_us를 살펴보면 현재 우리가 사용하는 Easy Processor Kit의 Hz가 8Mhz이므로 1cycle에 1/8000000 이 걸린다는 이야기이죠. 그리고 for 구문 안에서는 쓸때 없이 PUSH와 POP을 어셈블리어로 실행하였네요. 즉 kit의 mpu cycle을 총 8cycle(for 구문 4 cycle, PUSH 2 cycle, POP 2 cycle) 소모를 하게 만들었네요!!


 asm 명령어 같은 경우 인라인 함수로 어셈블리어로 작성할수 있답니다~!! 여기까지만 알아두세요. 인라인 함수의 장점은 컴파일러의 부담을 덜어주어 속도를 빠르게 할 수 있답니다.


 그럼 이제 밑의 밀리초 단위의 딜레이인 delay_ms 함수는 이해되시나요??? 그런데 왜 250을 4번이나 적용 하였을까요?? 그 이유는 바로 unsigned char 형이 0~255까지 입력을 받을 수 있기 때문이랍니다!! 이해 되셨죠? 그리하여 250us 4번을 불러 1ms를 맞춘거죠.


 우리가 원하던 실험을 이제 해볼까요?? 소스코드를 작성해 보세요!




#include <avr/io.h>

#define LED_CS (*(volatile unsigned char *)0x4800) // 외부 LED 메모리 주소

#define DIP_SW_CS (*(volatile unsigned char *)0x8000) // 외부 DIP Switch 주소

 

int main()

{

    MCUCR = 0x80; // 외부메모리 사용

    unsigned char input =0x00; // input 변수에 0x00 초기화

    unsigned char init = 0x00; // init 변수에 0x00 초기화

LED_CS = init; // LED 꺼진 상태로 초기화

    void delay_us(unsigned char time_us) // delay 함수 총 8cycle 이므로 1/8000000*8으로 1us 걸림

    {

        register unsigned char i; // I변수 선언

        for(i=0;i<time_us;i++) // 4 cycle 총 소모

        {

            asm volatile("PUSH R0"); // 2 cycle push 소모

            asm volatile("POP R0"); // 2 cycle pop 소모

        }

    }


    void delay_ms(unsigned int time_ms) // 1us 4번 써서 1ms 되게 하는 함수

    {

        register unsigned int i;

        for(i=0;i<time_ms;i++)

        {

            delay_us(250);

            delay_us(250);

            delay_us(250);

            delay_us(250); // 250us 4번 하여 1ms 되게 함 한 번에 못쓰는 것은 8bit 범위라 255까지 밖에 못 쓰기 때문

        }

    }

 

    void delay_s(unsigned int time_s) // 1ms 4번 써서 1s 되게 하는 함수

    {

        register unsigned int i;

        for(i=0;i<time_s;i++)

        {

            delay_ms(250);

            delay_ms(250);

            delay_ms(250);

            delay_ms(250); // 250ms 4번 하여 1s 되게 함

        }

    }


    while(1)

    {

        input = DIP_SW_CS; // 스위치 입력 input 변수에 지정

      

        if(input > 0x00) // 하나라도 on이라면

        {

            LED_CS = (!LED_CS); // LED 점멸

            delay_s(1); // 1초 지연

        }

    }

}



이건 제가 생각한 알고리즘입니다만 여러분께서 좀더 좋은 알고리즘이 있다 하시면 그것을 쓰시면 되요!!ㅎㅎ

딥 스위치의 값을 받아와서 하나라도 ON이면 LED를 1초간격으로 반복 점멸 하게 하였답니다. 이때 저는 ! 연산자 활용하여 값을 다 반대로 주었어요 ㅎㅎ


- 스위치가 on시 LED 점멸


- 스위치가 off시 LED 상태 유지


 - 실험 2


 이번에 해볼 실험은 딥 스위치와 외부 LED를 활용한 계산기입니다!!


 우선 딥 스위치를 보시면 총 8개가 있습니다. 그중 제일 아래 두개의 딥 스위치의 값을 덧셈(00), 뺄셈(01), 곱셈(10), 나눗셈(11) 순으로 나타내고 나머지 6개의 스위치를 각각 3개씩 연산자로 두는 겁니다. 그리고 결과는 당연히 LED로 나오겠죠? 감이 오셨나요??


 그럼 이제 소스코드를 작성하도록 하죠!



#include <avr/io.h>

#define LED_CS (*(volatile unsigned char *)0x4800) // 외부 LED 메모리 주소

#define DIP_SW_CS (*(volatile unsigned char *)0x8000) // 외부 DIP Switch 주소

 

int main()

{

    MCUCR = 0x80; // 외부 메모리 사용

    unsigned char input =0x00; // input 초기화

    unsigned char result = 0x00; // result 초기화

    unsigned char a = 0x00; // 연산자 a 초기화

    unsigned char b = 0x00; // 연산자 b 초기화

    while(1)

    {

        input = DIP_SW_CS; // 딥스위치 값 input에 저장

     

        if((input & 0x03)==0x00) // 덧셈일 경우

        {

            a = (input & 0xE0); // 왼쪽 3bit a 저장

            b = (input & 0x1C); // 오른쪽 3bit b 저장

            a =a >> 5; // a 5bit 우측시프트

            b =b >> 2; // b 2bit 우측시프트

            result = a+b; // 결과에 덧셈 값 저장

            LED_CS = result; // LED에 표시

        }

        else if((input & 0x03) == 0x01) // 뺄셈일 경우

        {

            a = (input & 0xE0);

            b = (input & 0x1C);

            a =a >> 5;

            b =b >> 2;

            if(a<b) // b가 클 경우

            {

                result = b-a; // 음수방지를 위해 반대로 계산

                result = result + 0x80; // 부호비트 1을 주기위함

            }

            else // a가 클 경우

            {

                result = a-b; // 원상태 뺄셈 저장

            }

            LED_CS = result; // LED에 결과 표시

        }

 

        else if((input & 0x03)==0x02) // 곱셈일 경우

        {

            a = (input & 0xE0);

            b = (input & 0x1C);

            a =a >> 5;

            b =b >> 2;

            result = a*b; // 곱셈값 저장

            LED_CS = result; // LED에 결과 표시

        }

 

        else if((input & 0x03)==0x03) // 나눗셈일 경우

        {

            a = (input & 0xE0);

            b = (input & 0x1C);

            a =a >> 5;

            b =b >> 2;

            if(b==0) // 만약 분모가 0일 경우

            {

                LED_CS = 0xFF; // 모든 LED

            }

else

{

result = a/b;

                LED_CS = result; // 아닐 경우 LED에 결과 표시

}

        }

    }

}

 


- 좌측 덧셈 : 100(4)+100(4) = 1000(8), 우측 뺄셈 : 010(2)-100(4)=10000010(-2)


- 좌측 곱셈 : 100(4)*100(4) = 10000(16), 우측 나눗셈 : 0/0=에러표시



 자 이렇게 하면 됩니다!! 물론 이 방법보다 좋은 방법이 있으신 분들은 그 방법을 통해서 하시면 되구요. 

 저 같은 경우는 제일 위쪽의 딥 스위치의 값인 연산자 a를 5bit 이동 시키고, 그다음 연산자 b를 2bit 이동시켜요. 

 그럼 이제 두개다 우리가 원하는 연산자들이 되었죠?? 그리고 딥스위치의 값에 따라 해당 값들을 LED로 나타냅니다!


 이 때! 주의해야할 점은 나눗셈과 뺄셈에서에요!

 뺄셈에서는 음수 방지를 위해 b가 클 경우 둘이 서로 자리를 바꾸어 계산한 다음 0x80을 더해서 부호비트를 on 시켰구요.

 나눗셈에서는 b가 0일 경우 모든 LED를 켜서 에러 표시를 나게끔 했답니다!


오늘은 여기까지 할게요! 이런 실험 말고도 다양한 실험이 가능하겠죠?

다음 시간에는 keypad에 관해서 공부해볼려고 해요!! 다음 시간에는 정신 바짝 차리세요! 내용이 어려울수도 있어요.  그럼 안녕!

,
Study/AVR ATmega128 Easy Processor Kit

9. Dip Switch 및 외부 LED 제어

오늘은 저번 시간에 배운 외부 LED와 함께 Dip Switch를 제어 실험을 해보려고 합니다.


힘을 내서 진도를 나가 볼까요??


우선 실험을 하기전에 Dip Switch란 무엇인지, 해당 소자의 회로가 어떻게 Kit에 구성되어 있는지 살펴보도록 하죠~~!!


 - Dip Switch란?

 Dip Switch는 일련의 ON-OFF 스위치로서, 양단의 회로를 이어주는 역할을 한다고 해요. 또한, 하드웨어의 변경 없이 사용자가 회로기판 상에서 기능을 임의로 선택할 수 있답니다.


 이제 딥 스위치가 어떤 것인지 알았고.. 다음은 회로를 한번 살펴 볼까요??'

 - 딥스위치 회로도

 

 회로를 보니 SN74HC541이라는 칩이 사용되고, 풀업저항이 연결되어 있네요!! 풀업저항은 다들 아시죠? 이전 시간에 했답니다!! 모르신 분들은 8. AVR의 GPIO 특성 이해 파트를 참고하세요!(http://feelsoverygood.tistory.com/60)

 그럼 스위치가 OFF일 때 1이, ON일 때 0이 칩에 입력되는 것을 알 수 있어요.


 칩에 대해서 살펴보고 가야겠죠?ㅎ

 - 딥스위치 칩

 다이어그램을 보니 OE1, OE2Low신호가 입력되면 1의 값이 버퍼에 들어가게 되네요. 따라서 A값 그대로 출력되며, OE1, OE2 둘 중 하나라도 High신호가 입력되면 0의 값이 버퍼에 들어가게 되므로, Z(임피던스)값이 나오게 됩니다!!


 - 실습


 그럼 이제 소자에 대한 준비는 완료 되었으니, 프로테우스를 이용해 실험에 대해 간단하게 시뮬레이션을 해보도록 할게요. 먼저 AVR Studio 4를 켜신 다음에 아래의 소스코드를 컴파일 해서 HEX 파일을 생성해 두세요!!


#include <avr/io.h>

 

int main()

{

    MCUCR = 0x00; /* 내부 메모리를 사용하겠다는 신호입니다만 시뮬레이션 상 직접 연결하므로 아무문제 없답니다. */

 

    DDRD = 0x00; // D포트 입력으로 설정

    DDRF = 0xFF; // F포트 출력으로 설정 => 해당 내용들은 kit를 이용할 때는 사용하지 않아요!!ㅎ

 

    whil7e(1)

    {

        PORTF = PIND; // F포트를 D포트 입력값으로 변경 즉, 스위치 동작에 따라 LED 켜짐

    }

}


 간단히 이야기해서 스위치에 따라 LED가 동작하는 것입니다~!! 이제 프로테우스를 실행시켜 아래 그림처럼 구성합니다~! 어떻게 하는건지는 다들 아시죠??? 모르시는 분들은 해당 강의 4. 프로테우스 사용법을 참조해 주세요!!(http://feelsoverygood.tistory.com/29)



 아주 깔끔하게 동작함을 알 수 있습니다. 참고로 LED가 10개인거 아시죠??? 맨 위 2개는 안켜지는게 당연한겁니다!!


 드디어!! 이제 본론인 실험을 시작하도록 하죠. 다시 AVR Studio 4를 켜시고 아래의 소스코드를 작성해 보도록 하죠.^^


 아아~~ 그전에 지난번 외부 LED 제어 시간에 배운 것들 잘 기억하고 계시죠?ㅎㅎ


DIP_SW_CS가 딥 스위치 외부 메모리 주소로 0x8000 인 것을 알겠네요. 마찬가지로 외부 LED 또한 0x4800 으로 맵핑이 되어 있어요. 그럼 맨 처음에 선언부터 해야겠죠?


#include <avr/io.h>

#define LED_CS (*(volatile unsigned char *)0x4800) // LED 외부 메모리 사용 위함

#define DIP_SW_CS (*(volatile unsigned char *)0x8000) // DIP Switch 외부 메모리 사용 위한 정의 0x8000

 

int main()

{

    MCUCR = 0x80; // 외부 메모리 사용

    unsigned char data =0x00; // data 변수 0x00 설정

    while(1)

    {

        data = DIP_SW_CS; // DIP Switch 입력을 data에 지정

        LED_CS = data; // DIP Switch에 따라 외부 LED 작동

    }

}



해당 결과의 사진입니다!! 간단하죠?ㅎㅎㅎ 오른쪽의 빨간박스 안이 딥스위치에요 ㅎㅎ 사진이 이래서 그런데 아래 부분부터 1111 0000 으로 입력하여 LED의 하위 4개가 켜진 것입니다~~


그럼 이제 이를 이용해서 여러가지 작품을 만들 수 있겠죠??


오늘은 여기까지 입니다!! 다음 시간에는 LED와 Dip Switch를 활용한 심화 작품들을 만들어 볼게요!!




,
 [ 1 ]  [ 2 ]  [ 3 ] 

최근 댓글

최근 트랙백

알림

이 블로그는 구글에서 제공한 크롬에 최적화 되어있고, 네이버에서 제공한 나눔글꼴이 적용되어 있습니다.

링크

Yuria

카운터

Today :
Yesterday :
Total :