(stopWatch,로 구글에서 검색되었으며,
원출처는 - http://blogs.experiencelifemag.c...2008/03/ 입니다. )

역시 과제로 나왔던 내용이며,
저번시간과는 반대로 이번에는 소스를 먼저 공개하고,
차차 풀어나가는 식으로 포스팅을 하겠습니다. ^-^;

잘 기억이 나진 않지만,, 이번 소스의 스펙사항입니다.

1. 초는 0.1초 표시할 것
2. 버튼 1을 누르면 7세그먼트에 표시되는 시간은 멈추되,
   다시한번 눌렀을때 흐른 시간만큼이 다시 표시되어야 함
3. 버튼 2를 누르면 시간이 리셋됨

- Timer를 사용하여 시간을 체크할 것.
- Timer를 사용하여 7세그먼트를 표시할 것
   (저번포스팅에서는  delay를 통한 polling방식이였음)

다음은 소스코드이며, 적당히 주석을 달아보았습니다.
거의 라인바이라인으로 주석을 달았기 때문에 , 뒤의 포스팅을 보지 않으셔도 쉽게 이해하실 수 있을거라 생각됩니다.

 

#include<avr/io.h>                  

#include <avr/interrupt.h>           // 인터럽트를 시키기 위해서 포함시겨야 하는 Header 파일

 

 

#define TRUE 1                      // C에서는 TRUE FALSE를 지원하지 않기에 Define해줌

#define FALSE 0                     // 조금 더 직관적이지 않을까...  싶어서..  

 

volatile char bLED = TRUE;          // LED 출력과 관계 있는 변수,

// 인터럽트에서 파라미터를 받을수 없으므로 전역으로 설정해줌

volatile int TimeCounter = 0;       // 카운트를 세기위한 변수, 위와 같은 이유로 전역으로 설정해줌

volatile char LEDdigit[4] = {0,0,0,0}; // LED에 켜져야 할 값을 설정,  마찬가지 이유로 전역으로 설정해줌

 

// 7세그먼트의 출력값, number는 일반 숫자, Dotnumber .을 포함한 문자.

// or 연산을 하면 그만큼 연산량이 증가하여 룩업테이블 형식으로 따로 설정함

char number[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x27, 0x7f,0x67};

char Dotnumber[10]={0xBf,0x86,0xDb,0xCf,0xE6,0xEd,0xFd,0xA7, 0xFf,0xE7};

 

 

// 밑에서 만들어진 함수를 사용하기에, 선언해줌 (근데 안해줘도 컴파일러가 똑똑해서 해주는듯;)

void SetLED(int Time);

 

// Timer1번의 컴페어 인터럽트, 0.1초마다 인터럽트를 걸어준다.

ISR(TIMER1_COMPA_vect)

{

              TimeCounter++;  // 0.1초마다 카운터를 증가시킨다.

              if(bLED == TRUE) // 스위치가 눌리지 않았으면  카운터의 내용을 출력하고,

                                 // 눌렸으면 출력을 하지 않도록 값을 설정하지 않는다.

              {

               SetLED(TimeCounter);

              }

}

 

// LED를 켜는 인터럽트 , 16bit카운터를 사용하였다.

ISR(TIMER3_COMPA_vect)

{

static char index = 0;

static char ctrl[4] = { ~0x08, ~0x04, ~0x02, ~0x01};  // 이것때매 꽤고생 ~ 꼭 붙이기;

 

              index++;

              index &= 0x3; // 0,1,2,3

              PORTC = ctrl[index];

              PORTA = LEDdigit[index];

 

}

 

// LED SETUP

void SetLED(int Time)

{

 

              if(Time<9999) // 세자리가 넘어가기 전에는 다음과 같은 루틴을 실행하고 (저번에 안된예외처리)

              {

// 숫자를 변환하는 루틴은 그전과 같음,

// 0.1초를 따로 고려하지 않는다. 다만 사람이 볼 경우에 세번째 자리에 . 이있다면 0.1초 단위처럼 보이므로

// 세번째 자리에서만 그렇게 보이도록 출력한다.

                             int i ;

                             i = Time/1000;

                             LEDdigit[3] = number[i];

                             Time -= i * 1000;

 

                             i = Time/100;

                             LEDdigit[2] = number[i];

                             Time -= i * 100;

 

                             i = Time/10;

                             LEDdigit[1] = Dotnumber[i]; // 2번째 자리는 .이 붙어야 하므로 위의 다른 테이블을 참조

                             Time -= i * 10;

 

                             i = Time;

                             LEDdigit[0] = number[i];  

 

              }

              Else

// 출력할 수 있는 범위를 넘어서면 0으로 셋팅한뒤 TimeCounter를 리셋시킨다.

              {

                          LEDdigit[0] = number[1];

                          LEDdigit[1] = number[2];

                          LEDdigit[2] = Dotnumber[2];

                          LEDdigit[3] = number[1];

             }

}

 

 

int main()

{

// 전역변수를 초기 화 한다.

              bLED = TRUE; // lap이 걸리지 않은것으로 setting

              TimeCounter = 0; // 시간의 초 기화

 

//스위치와 7세그먼트의 사용을 셋업시키는 부분

              DDRC = 0x0f;

              DDRA = 0xff;

              DDRG = 0x03;

 

// 타이머를 초기화 하는 부분

// 0.1초를 정확히 맞추는데 8bit로는 .. 몇번 돌았는가도 연산을 해야할 것이라고 생각해서

// 16bit 카운터를 사용하기로 함

 

// 0.1초로 정확히 맞추기 위해서는;

              //16000000/256/6250 = 10Hz

              // OCR0 값이 8비트는 256 까지 되고

              // OCR1A 16비트는 65535까지 되는데;;

              // 6250을 포함하기에는 8bit는 너무 작다-_-;

 

              TCCR1A = 0x00;

              TCCR1B = 0x0C;

              TCCR1C = 0x00;

              OCR1A = 6249;

              TCNT1 = 0x0000;

 

// LED를 켜기위해서 사용되는 16bit 카운터, 이것은 8bit로 사용되도 무방하나, 16bit 카운트를 사용함

              TCCR3A = 0x00;

              TCCR3B = 0x0C;

              TCCR3C = 0x00;

              OCR3A = 250;

              TCNT3 = 0x0000;

 

// 카운터의 인터럽트를 사용함을 알림

              TIMSK = 0x10;

              ETIMSK = 0x10;

              TIFR = 0x00;

              ETIFR = 0x00;

 

              sei();// 전역설정

 

              while(1)

              {

               if(PING&0x04)

               {

                if(bLED == TRUE)                          bLED = FALSE; // 버튼이 한번 눌리면 더 이상 출력하지않음

                else                                               bLED = TRUE; // 다시눌리면 출력을 시작

             // 엄밀히 말해서 출력이 아니라 7세그먼트의 값을 다시 셋팅하고, 하지않고를 설정함

 

                while(PING&0x04) {}

               }

               if(PING&0x08) // 다른 버튼이 눌리면

               {

                TimeCounter = 0; // 카운터를 0으로 만들어서 출력을 처음부터 한다. 즉 리셋기능이된다.

                SetLED(TimeCounter);

                while(PING&0x08) {}

               }

              }

              return 0;

}


다음 포스팅부터는 현재 소스를 분석하여
1. 타이머
2. polling & Interrupt 에 관해서  포스팅할 예정입니다.
소스만으로 부족하다고 느끼신다면 다음 포스팅도 참고해주세요-

저작자 표시
신고
Posted by 천재소녀*

블로그 이미지
꿈꾸는아이, ㅋ Tasha의 완전범죄 구상소
천재소녀*

공지사항

Yesterday23
Today8
Total156,845

달력

 « |  » 2017.11
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30    

최근에 받은 트랙백

글 보관함