본문 바로가기
코스웨어/13년 스마트컨트롤러

2013.05.20_[타이머카운터복습/인터럽트/풀업풀다운저항]_김성엽

by 알 수 없는 사용자 2013. 5. 22.
728x90
반응형

▶ Timer/Counter ( 복습!! )

: CPU가 시간을 재는것

AT91SAM7S256에는 16비트 타이머/카운러채널 (TC0~TC2)를 가지고 있습니다.

이들 3개의 채널은 서로 독립적으로 동작하며 이벤트카운트, 주파수 측정, 시간간격측정,시간지연, 펄스 발생 PWM 출력등의 기능 수행할 수 있다고 합니다.

AT91SAM7S256 은 MCK(Master Clock) 를 48Mhz 지원 하고있으며,

이 MCK 에 pre-scaler(분주비) 를 이용해 나누어줌으로써 초를 세기에 세분화 가능합니다. ( 그림 Table 33-1 )



1Tick(클럭당시간) * 배수(RC) = 1ms 에 맞춰 시간을 세분화 할 것이며, 최대한 오차가 작은 분주비를 사용하여야 할 것 입니다.

위의 표에서 확인된 오차가 제일 작은 128 분주비를 사용하였습니다!


▶ Advanced Interrupt Controller (AIC)

인터럽트가 발생하면 프로세서는 현재 수행중인 프로그램을 멈추고, 상태 레지스터와 PC(Program Counter)등을 스택에 잠시 저장한 후 인터럽트 서비스 루틴으로 점프한다. 인터럽트 서비스 루틴을 실행한 후에는 이전의 프로그램으로 복귀하여 정상적인 절차를 실행한다.


<기본 흐름>


소스로 확인해봅시다!! ( 외부인터럽트[풀업저항스위치]를 이용해 LED Toggle 시키기! ) 

#include "AIC.h"

void AIC_INIT()
{
PMC_PCER = 1<<PIOA; // P203, PMC_PCER 를 통해서 PIOA 전원공급.
PIO_ODR = 1<<INT_PIN; // P252, PIO_ODR 를 통해서 15번 핀 출력 비활성화.
PIO_PER = 1<<INT_PIN; // P250, PIO_PER 를 통해서 핀자체를 활성화.
PIO_IDR = 1<<INT_PIN; // P250, PIO_IDR 를 통해서 15번 핀의 Interrupt 를 비활성화.
AIC_IDCR = 1<<PIOA; // P175, AIC_IDCR 를 통해 AIC PIOA 장치 비활성화.

// 타이머 카운터 0 인터럽트 핸들러 등록(AIC_SVR[TC0], AIC_Handler)
AIC_SVR[PIOA] = (volatile unsigned int )AIC_Handler;

// The user may store in these registers the addresses of the corresponding handler for each interrupt source.
// AIC_SVR 레지는 인터럽트 소스로부터 호출하는 핸들러 주소를 저장합니다.
// 그리고 PC(Program Count)가 저장된 주소를 가져와서 MCU 가 실행을합니다.

PIO_PUDR = 1<<INT_PIN; // 내부에 존재하는 풀업저항 on(밑에 설명)
// 타이머 카운터 0 인터럽트 모드 설정(AIC_SMR[TC0], AIC_SRCTYPE_INT_HIGH_LEVEL, PRIOR_LOWEST)
AIC_SMR[PIOA] = ((0<<PRIOR) | (1<<SRCTYPE)); // Source type 은 외부인터럽트-Negative 로 맞춰줌. 하강엣지에 반응합니다.
// 스위치를 누르면 0V로 펄스신호(전압) 가 바뀐다.

AIC_ICCR = 1<<PIOA; // P181, PIOA 장치에 값을 초기화. Clears corresponding interrupt.
PIO_IFER = 1<<INT_PIN; // P253, Glitch Input Filter Enable Register
// PIN에 스위치를 통한 처음과 끝부분의 잡음 제거.
AIC_ISCR = 1<<PIOA; // Glitch Input Filter 를 설정하고 다시 켜줌. Sets corresponding interrupt.
PIO_IER = 1<<INT_PIN; // PIO의 15번 핀을 켜줌. 셋팅을 끝내고 열어줌! Interrupt Enable Register!!
AIC_IECR = 1<<PIOA; // 장치번호를 켜줘야 동작을 한다!

return;
}

void AIC_Handler()
{ // Timer/count 와는 다르게 인터럽트는 32개가 다 반응하므로 PIO로 외부인터럽트 신호를 확인해줘야한다.
static volatile unsigned int uiPin_state; // 빈번하게 호출되거나, 빨리 켜야할 필요가 있으면 static 을 붙여서
volatile unsigned int iCnt; // 미리 만들어 둔다. 하지만 많은 곳에 쓰이면 안되므로 조심해서 써야함.
uiPin_state = PIO_ISR; // 인터럽트가 발생하면 ISR레지의 상태값이 1로 변하고. 그 값을 변수에 저장한다. 
                       // 그리고 전역변수 선언시에 ISR레지를 바로 넣어주면 초기화값이 항상 0이므로 상태값을 읽지를 못하기때문에,

                       // 밑에 한번더 적어서 넣어준다. 
if(0 != (uiPin_state & (1<<INT_PIN)) ) // 마스킹.
{
  LED_Toggle();
}

for(iCnt=0; iCnt<1000000; ++iCnt);

uiPin_state = PIO_ISR; // 한번더 넣으면 인터럽트값이 0으로 바뀐다
AIC_EOICR = 0; // 인터럽트가 완료됨을 나타내고 종료숫자로 0을 준다.
return;
}

▶ 풀업 풀다운 저항 예시

피아노를 예를 들어 설명해보겠습니다.

아래에 각각의 음에 대한 주파수들입니다.

도 * C: 262Hz
레 * D: 294Hz
미 * E: 330Hz
파 * F: 349Hz
솔 * G: 392Hz
라 * A: 440Hz
시 * B: 495Hz
도 * C: 524Hz

만약에 주파수를 출력해 소리를 만들어주는 회로를 만들고, '단순히 스위치'를 사용한다면, 어떤일이 일어날까요!!?

도를 눌렀는데 미 가 나오고, 다시 눌렀다가 땠는데 파 가 나오고 정확하게 음이 나오지가 않습니다.

이유가 왜일까요!?

▶ 풀업, 풀다운 저항
누르면 불이 들어오고 끄면 불도 꺼져야 하는게 스위치의 기능입니다.
하지만 여기서는 파워를 다루는게 아니고 "시그널(신호)"을 다루는 것입니다.
스위치를 누르면 불이 들어오는게 분명히 맞지만, 근데 디지털 회로에서는 스위치를 껐을때 불이 꺼지는것이 아니라
"끌지 말지 나도 몰라" 라고 보는게 정답입니다.

즉 0인지 1인지 구별할 수 없는 상태가 되는 것입니다. 그런 상황을 피하기 위해 저항을 사용해보면, 풀업저항 소자가 따로 있는게 아니고 그런 용도에 사용되는 방법의 이름을 풀업, 풀다운이라고 부릅니다.


<그림2.a> 에서 스위치가 닫히면 파란점이 5V 가 걸리지만 스위치가 열렸을 때는 둥둥 떠다니는 상태가 됩니다. '0V라고 말하기도 뭐하고 5V라고 말하기도 뭐한상태!'. 한마디로 판독 불가.. 반면 <그림2.b>에서는 닫히면 빨간점에 5V 열리면 0V 가 확실히 걸리게 됩니다.

(GND 쪽에 저항이 연결되면 풀다운 저항, 5V 쪽에 저항이 연결되어있으면 풀업저항)

정리 : 디지털회로에서 풀업저항은 스위치가 열렸을때, 확실히 5V로 HIGH를 잡아주고, 풀다운저항은 스위치가 열렸을때 확실히 0V로 LOW 를 잡아줍니다. (신호의개념!!)


이렇게 회로를 고치고 나서 피아노를 두드려 보면,
원하는 결과가 나옵니다.



728x90