static volatile unsigned int uiTic; // Timer_Handler 함수 호출을 카운트, 1m초
void Timer0_Init(void)
{
PMC_PCER = 1 << TC0; // PMC_PCER(Peripheral Clock Enable Register)에 타이머카운터 장치 활성화, P204, P33
// TC0(타이머카운터 0)에 클럭이 공급된다.
// 1. 시작 : 타이머 클럭 비활성화 ------------------
TC0_CCR = 1 << CLKDIS; //카운터 클럭 비활성화 명령(CLKDIS)을 Enable
// 2. 시작 : 타이머 인터럽트 비활성화 -------------
TC0_IDR = (1 << COVFS)|(1 << LOVRS)|(1 << CPAS)|(1 << CPBS)
|(1 << CPCS)|(1 << LDRAS)|(1 << LDRBS)|(1 << ETRGS); // 타이머 인터럽트 비활성화(TC_IDR 설정)
TC0_SR;// 타이머카운터 상태 레지스터 초기화(TC_SR 읽기)
TC0_CMR = (TIMER_CLOCK4 << TCCLKS) | (1 << CPCTRG); /*TC0_CMR(채널 모드 레지스터)에서
TCCLKS(Clock Selection)에 3을 넣어 분주비 128(TIMER_CLOCK4) 설정 | RC 비교방식 트리거 활성화*/
TC0_RC = 375; // MCK divided by 128 => 375000Hz, 1CK = (about)2.67us [TC_RC(Register C)설정]
// 한마디로 1ms에 인터럽터를 발생시키기 위해 375로 설정
// 3. 시작 : 타이머 카운터 0 인터럽트 비활성화 ------
AIC_IDCR = 1 << TC0; // 인터럽트 비활성화(AIC_IDCR) = Enable(1) << 타이머 카운터 0(TC0)
AIC_SVR[TC0] = (volatile unsigned int)Timer_Handler;
/*AIC_Source Vector Register = 타이머 카운터 0 인터럽트 핸들러 등록
여기서 Vector 레지스터는 인터럽트가 발생하면 점프하게 될 함수(ISR:인터럽트 서비스 루틴)의 주소만을 저장할 수 있다.
함수 전체를 저장할 수 있으면 좋겠지만, 그러기엔 ARM 레지스터의 용량이 너무 작다.
◎ Vector 가 뭔지 궁금해 하시는 분들을 위해
- 우리의 ARM은 폴링형 인터럽트와 vector형 인터럽트 등 인터럽트 처리방법 중에 vector형 인터럽트 처리 방식을 사용한다.
1. Polling 형 인터럽트
- 폴링은 투표, 개표 라는 뜻이다. 즉 CPU가 소프트웨어적으로 보드에 인터럽트를 낼수있는 하드웨어들을 차례대로
검사하는 방식이다. 하드웨어가 간단하고 저렴하지만, 인터럽트를 낼수있는 하드웨어 갯수 증가에 따라 속도가 느려진다.
이후 인터럽트가 검출된 장치를 처리한다. 여기서 "처리한다" 를 ISR(Interrupt Service Rutine)이라고 한다.
2. vector 형 인터럽트
- cpu가 소프트웨어적으로 하드웨어들을 검사하는것이 아니라,
인터럽트를 발생시킨 장치가 cpu에 ISR(우리가 만든 핸들러 함수)의
시작 번지를 제공하면 cpu가 이것을 먼저 처리하는 방식.
이 ISR들은 기본적으로 interrupt vector에 저장되어 있고 더 나아가
사용자가 ISR을 설정해주고 싶으면 Interrupt Handler를 작성/등록(AIC_SVR[TC0])해주면 된다.
하드웨어가 복잡하고 비싸지만, 빠르고, 장치 갯수에 상관없이 언제든지! 서비스를 제공한다.
AT91SAM7S256, atmega2560 등 에서는 이방식을 사용한다.
AIC_SMR[TC0] = (0 << PRIOR)|(3 << SRCTYPE);
/* TC0 인터럽트 소스 모드 레지 = 우선순위레벨(Priority Level)을 0 |
여기서 만약, 인터럽트 두개가 동시에 발생하면 ?
polling 방식은 순차적으로 장치를 검사하기 때문에 그 순서대로 우선순위를 정하지만
vector 방식은 인터럽트 우선순위를 제어할 수 있는 레지스터(AIC_SMR)가 존재하여,
레지스터에 값을 집어넣어 우선순위를 정한다.
[출처] [AVR] Interrupt|작성자 태희로그
[출처] [AVR] Interrupt|작성자 태희로그
Interrupt Source Type(SRCTYPE)를 High level Sensitive로 설정*/
AIC_ICCR = 1 << TC0; // 타이머 카운터 0 인터럽트 클리어(TC0)
TC0_IER = 1 << CPCS;
/* 타이머 카운터 인터럽트 활성화 레지스터 = RC 비교 인터럽트만 활성화*/
// 2. 끝 : 타이머 인터럽트 비활성화 ---------------
AIC_IECR = 1 << TC0; // 타이머 카운터 0 인터럽트 활성화(AIC_IECR, TC0)
// 3. 끝 : 타이머 카운터 0 인터럽트 비활성화 -------
TC0_CCR = 1 << CLKEN; // 타이머 클럭 활성화(TC_CCR, CLKEN)
// 1. 끝 : 타이머 클럭 비활성화 ------------------
TC0_CCR = 1 << SWTRG; // 타이머 시작(TC_CCR, SWTRG)
}
void Timer_Handler(void)
{
TC0_SR; //핸들러가 호출되면 현재 인터럽트가 발생된 상태이기 때문에
//다음 인터럽트가 발생할 수 있도록 상태 레지스터 초기화
++uiTic;
return;
}
void ms_Delay(unsigned int uims)
{
uiTic = 0;
while(uims > uiTic); //이 함수를 종료하려면 uims를 기다려야 한다
// uiTic은 1ms마다 증가하므로 uims에 1000을 넣으면
//약 1초를 기다려야 반복문이 종료된다.
}
'Study > 8-bit MCUs' 카테고리의 다른 글
스위치를 이용한 led제어 소스코드 (0) | 2015.06.09 |
---|---|
Atmega8a - Timer/Counter 레지스터 (0) | 2015.06.08 |
Timer/counter 참고하기! (0) | 2015.06.08 |
Atmega128 - 타이머/카운터 레지스터& 분주기 (1) | 2015.06.08 |
인터럽트를 사용한 led 제어 (미완성) (0) | 2015.06.08 |