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

,

최근 댓글

최근 트랙백

알림

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

링크

Yuria

카운터

Today :
Yesterday :
Total :