타이머/카운터(이하 T/C) 인터럽트

ATmega128에는 8비트(0,2채널)와 16비트(1,3채널) 타이머/카운터가 있다.

10비트 프리스케일러(분주)를 선택 할 수 있다.

8Bit Timer/Counter

8비트 타이머 카운터에는 4가지 동작 모드가 있다.

이는 TCCR 레지스터의 WGM 비트 설정에 따라 결정된다.

  1. Normal 모드 -> Overflow Interrupt
  2. PWM, Phase Correct모드
  3. CTC 모드(Clear Timer on Compare Match)
  4. Fast PWM 모드

T/C에 관한 내용은 0번,2번 모드이다.

0번 모드(Normal)는 일반적인 오버플로우 타이머 인터럽트이고, 2번 모드(CTC)는 비교 일치시 인터럽트가 발생하는 방식이다.

TCCR0 레지스터를 잠깐 보고 넘어가보자.

보면, WGM00,01 비트가 나란하지 않은 것을 볼수 있다. 이렇기 때문에 일반적으로 시프트 연산자를 이용해서 해당 비트를 Set하거나 Clear할 수 있다.

보통 전체 초기화가 필요하지 않는다면, | (Bitwise OR oerator) 연산자를 이용해 해당 값만 바꿔주는게 일반적이다.

TCCR0 |= (0<<FOC0)|(0<<WGM01)|(0<<WGM00)|(0<<COM01)|(0<<COM00)|(1<<CS02)|(1<<CS01)|(1<<CS00);

위의 Table 53, COMxx 비트는 T/C기능으로 쓰기 위해 0으로 Set되어야 한다. 00이외의 설정은 PWM 출력시 사용한다.(나중에 설명)

CSxx 비트 설정을 통해 10비트 프리스케일러를 선택 가능하다. 프리스케일러란, 시스템에 들어오는 원클럭의 속도가 너무 빠르기 때문에 이를 분주하여 사용하는 것을 의미한다. (16Mhz Clock Source는 초당 16,000,000번의 속도로 카운트를 한다는 것인데, 분주없이 쓰게 되면, 62.5ns(nano second)로 상당히 빠르다. 반면 1024 분주를 쓰게 되면, 64ms로 제법 긴 시간을 카운트 할 수 있다.)

분주한다는 의미는 클럭을 덩어리로 보겠다는 의미이다.

이해를 돕기 위해 예를 들자면, 어떤 공장에 매초 16,000,000개의 계란이 들어오는데 이 계란을 검수해야한다. 프리스케일러가 없다는 이야기는 들어오는 계란을 개별적으로 검수하겠다는 이야기이다. 하지만 프리스케일러를 1024로 설정 한다면, 프리스케일러가 바구니를 만들고 각 바구니 당 1024개의 계란을 담아주겠다는 것을 이야기한다. 이제 검수자는 바구니가 몇개 들어오는지만 세면 된다.

비교 일치 모드로 사용할 것인지, 아니면 Overflow 모드로 사용할 것인지 TIMSK 레지스터, TOIE0, OCIE0를 통해 설정 가능하다.

그럼 LED가 1초 마다 토글되는 소스(오버플로우, CTC)를 작성하여 보자.

  • 오버플로우 인터런트
/*
 * Hello_AVR.cpp
 *
 * Created: 2017-01-07(YYYY-MM-DD) AM 5:08:05
 * Author : Michael Jun-Hyuk Im([email protected])
 */ 

#define F_CPU 16000000
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

volatile char tick_flag = 0;

ISR(TIMER0_OVF_vect){//오버플로우 루틴 0.008초마다 진입
    static unsigned char OVF=0; 
    TCNT0 = -125; //(256-125=131)

    OVF++;

    if(OVF == 125){ 
    tick_flag=1;
    OVF=0;
    }
}

void MI_GPIO_config()
{
    DDRD = 0x00; //입력 - SW 모듈
    DDRA = 0xff; //출력 - LED 모듈
    DDRG = 0x03; // 0,1 보드 LED, 2,3 보드 SW
}

void MI_TC0_OVF_Config()
{
    TCCR0 |= (0<<FOC0)|(0<<WGM01)|(0<<WGM00)| //FOC0 일반적으로 0세트_WGM(00).Nomal Mode
    (0<<COM01)|(0<<COM00)| 
    (1<<CS02)|(1<<CS01)|(1<<CS00);    //CS(111).1024분주비. (1/16000000)*1024=0.000064    

    TCNT0 = -125; //(256-125=131) //Clock Time *125=0.008

    TIMSK |= (1<<TOIE0); //TOIE0 > Overflow Enable //OCIE0 > Compare    
}
int main(void)
{
    /* Replace with your application code */
    MI_GPIO_config();                    
    MI_TC0_OVF_Config();        
    sei();
        while (1)
        {        
            if(tick_flag == 1)
        {
            PORTA=PORTA^0xff;
            tick_flag=0;
        }
    }
       cli();
}
  • 비교 일치모드(CTC)
/*
 * Hello_AVR.cpp
 *
 * Created: 2017-01-07(YYYY-MM-DD) AM 5:08:05
 * Author : Michael Jun-Hyuk Im([email protected])
 */ 

#define F_CPU 16000000
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

volatile char tick_flag = 0;

ISR(TIMER0_COMP_vect) //CTC 8ms timer
{
     static unsigned char CTC=0; //메모리의 효율적인 사용을 위한 static 변수
     CTC++;

    if(CTC == 125){
     tick_flag=1;
     CTC=0;
    }
}

void MI_GPIO_config()
{
    DDRD = 0x00; //입력 - SW 모듈
    DDRA = 0xff; //출력 - LED 모듈
    DDRG = 0x03; // 0,1 보드 LED, 2,3 보드 SW
}

void MI_TC0_CTC_Config()
{
    TCCR0 |= (0 << FOC0)|(1 << WGM01)|(0 << WGM00)| //FOC0 일반적으로 0세트_WGM(00).Nomal Mode
    (0 << COM01)|(0 << COM00)| //COM(00).비교일치 OC 출력 세트
    (1 << CS02)|(1 << CS01)|(1 << CS00);    //CS(111).1024분주비. (1/16000000)*1024=0.000064    

    OCR0 = 125 - 1; 

    TIMSK |= (1 << OCIE0);
}
int main(void)
{
    /* Replace with your application code */
    MI_GPIO_config();                    
    MI_TC0_CTC_Config();        
    sei();
        while (1)
        {        
            if(tick_flag == 1)
        {
            PORTA=PORTA^0xff;
            tick_flag=0;
        }
    }
    cli();
}

PWM Mode

/*
 * Hello_AVR.cpp
 *
 * Created: 2017-01-07(YYYY-MM-DD) AM 5:08:05
 * Author : Michael Jun-Hyuk Im([email protected])
 */ 

#define F_CPU 16000000
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

void MI_GPIO_config()
{
    DDRD = 0x00; //입력 - SW 모듈
    DDRA = 0xff; //출력 - LED 모듈
    DDRG = 0x03; // 0,1 보드 LED, 2,3 보드 SW
}

void MI_TC0_PC_PWM_Config()
{
    DDRB |= (1 << PB4);
    TCCR0 |= (0 << FOC0)|(0 << WGM01)|(1 << WGM00)| //WGM(01) Phase    Correct PWM(DUAL Slope)
    (1 << COM01)|(0 << COM00)| //COM(10) Clear OC0 on compare match when up-counting. Set OC0 on compare match when down-counting.
    (1 << CS02)|(1 << CS01)|(1 << CS00);    //CS(111).1024분주비 (1/16000000)*1024=0.000064

    OCR0 = 127;
}

void MI_TC0_FAST_PWM_Config()
{
    DDRB |= (1 << PB4);
    TCCR0 |= (0 << FOC0)|(1 << WGM01)|(1 << WGM00)| //WGM(11) FAST PWM
    (1 << COM01)|(0 << COM00)| //COM(10) 
    (1 << CS02)|(1 << CS01)|(1 << CS00);    //CS(111).1024분주비 (1/16000000)*1024=0.000064

    OCR0 = 127;
}

int main(void)
{

   //Select One of Modes
    MI_TC0_PC_PWM_Config();    
    MI_TC0_FAST_PWM_Config();        

    sei();
        while (1)
        {        
            if(tick_flag == 1)
            {
                PORTA=PORTA^0xff;
                tick_flag=0;
            }
    }   
}

results matching ""

    No results matching ""