2016-11-20 2 views
4

안녕하세요. 좋은 스택 오버플로입니다. 내 문제는 결코 실행하지 않는 인터럽트 서비스 루틴 (ISR)입니다! 여기에 내 설정에 대한 정보가 있습니다 : 나는 avr attiny85를 깜박입니다. 지금까지 main.c와 두 개의 모듈 인 timer와 hardwareInit으로 프로젝트의 기본 프레임을 설정했습니다. 타이머 모듈에서 timer0_init 함수를 사용하여 타이머 0을 CTC 모드로 오버플로 1ms를 설정하는 데 사용하고 있습니다. 여기에 기능입니다 : 설정 한 타이머AVR 타이머 오버플로 인터럽트가 작동하지 않습니다.

void timer0_init(void) 
{ 
    cli(); 
    TCCR0B |= 3; //clock select is divided by 64. 
    TCCR0A |= 2; //sets mode to CTC 
    OCR0A = 0x7C; //sets TOP to 124 so the timer will overflow every 1 ms.  
    TIMSK |= 2;  //Enable overflow interrupt 
    sei();   //enable global interrupts 
} 

가, 내가 증가하는 ISR 때마다 카운터 오버 플로우 틱 추가, 그래서 나는 등 경과 된 시간을 추적,

ISR(TIMER0_OVF_vect) 
{ 
    cli(); 
    //ticks ++; 
    PORTB |= (1 << PORTB0); 
    sei(); 
} 
을 유지할 수 있습니다

당신이 볼 수 있듯이, 나는 진드기 ++를 주석 처리했다. 작동하지 않았기 때문이며, 단순히 LED를 켜는 PORTB |= (1 << PORTB0);으로 바꿨다. 따라서 인터럽트가 실행되면 LED가 켜져 있다는 증거로 알 수있다.
불행히도, 나는 그것을 켜지 못하고 내가 무엇을 놓쳤는지를 볼 수 없습니다. (내가 1. 올바른 핀에 LED를 설정하고 올바른 레지스터에서 올바른 비트를 조작하고 있다는 것을 증명하기 위해이 무언가를 무한 루프에 넣고 LED가 켜지는 것을 확인했다.)

/*================================= main.c =================================*/ 

#define F_CPU 8000000UL 

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

#include "timer.h" 
#include "hardwareInit.h" 


int main(){ 

    //Initialize hardware HERE 
    DDRB |= (1 << PORTB0); //set this pin as an output for an LED 

    SetClockPrescale(1); //internal clock divided by 1 = 8 MHz, from hardwareInit 

    timer0_init();   //set up timer0 for 1 ms overflow 


    while(1) 
    { 
     /* if(getTicks() > 0) 
     { 
      PORTB |= (1 << PORTB0); 
      _delay_ms(1000); 
      PORTB &= ~(1 << PORTB0); 
      _delay_ms(1000); 
     } */ 

    } 
    return 0; 
} 

그럼, 당신은 무한 루프에서 보는 것은 처음 시도 것입니다,하지만 작동하지 않았다 후, 난 그냥를 가진 간단한 무언가를 시도 : 자세한 설명은

, 여기 내 main.c에있다 빈 루프 (이전 물건을 주석 처리) 및 인터럽트가 LED가 켜지도록 트리거 될 때까지 대기합니다.

도움을 주시면 감사하겠습니다. 왜 이것이 작동하지 않았는지 나는 아주 당황 스럽다.

+2

TIMSK'변경 시도 | = 2; 'TIMSK'로 | = (1 < <4); 및'TIMER0_OVF_vect'를'TIM0_COMPB_vect '로 변경합니다. 아니 보장. – andars

+0

또는 타이머 초기화를 그대로두고 벡터를 'TIM0_OVF_vect'로 변경해보십시오. – andars

답변

8

@andars가 올바르게 지적한대로 잘못된 ISR을 사용하고 있습니다. CTC "Compare Timer on Compare"모드에서 타이머는 비교 일치시 지워지므로 절대로 오버플로하지 않습니다.

그래서 타이머의 잘못된 인터럽트도 활성화했습니다. TIMSK 레지스터의 비트 1은 timer0에서 타이머 오버플로 인터럽트를 활성화합니다. 이전의 이유로 인해 발생하지 않습니다. datasheet에서 가져 왔습니다.

enter image description here

당신이 비교 값을 설정 OCR0A를 사용하는 것처럼, 당신은 활성화해야 비트 4 - OCIE0A : 타이머/카운터 0의 출력이을 활성화 일치 인터럽트를 비교.

ISR로 돌아 가면 TIMSK에서 설정 한 비트에 따라 ISR(TIMER1_COMPA_vect) 또는 ISR(TIMER1_COMPB_vect)이 필요합니다. 비교 값은 OCR0A 또는 OCR0B과 일치하는 레지스터에도 기록해야합니다.


참고

, 당신은 코드가보다 투명하게 내 의견으로는, 단지 레지스터 이름과 같은 코드에서 비트 이름을 사용할 수 있습니다.

해당 인터럽트 활성화 코드는 다음과 같이 변경한다 :

void timer0_init(void) 
{ 
    cli();   
    TCCR0B |= (1<<CS01) | (1<<CS00); //clock select is divided by 64. 
    TCCR0A |= (1<<WGM01);    //sets mode to CTC 
    OCR0A = 0x7C;      //sets TOP to 124 so the timer will overflow every 1 ms.  
    TIMSK |= (1<<OCIE0A);    //Output Compare Match A Interrupt Enable 
    sei();        //enable global interrupts 
} 

ISR :

ISR(TIMER0_COMPA_vect) 
{ 
    cli(); 
    //ticks ++; 
    PORTB |= (1 << PORTB0); 
    sei(); 
} 
+1

좋습니다! 나는 CTC 모드의 요점을 놓치고 있었다. OCR0A를 124로 설정하면 TOP이 124로 변경되었으므로 타이머가 오버플로됩니다. 이제는 오버플로가 타이머가 "실제"상단에 도달하는 경우 (이 경우 255)에 분명합니다. 내가 말한 다른 것들에 대해서는 분명히 해두겠습니다. 당신은 "틀린 타이머의 틀린 방해를 가능하게했다,"그러나 나는 진짜로. TIMSK 레지스터와 바이너리 값이 00000010 인 값 2를 OR 연산하여 효과적으로 TOIE0 비트를 1로 설정했습니다. 다음 행은 동일합니다. TIMSK | = 2; TIMSK | = (1 << TOIE0); – chen

+1

몇 가지 수정 사항을 나열한 답변의 후반부에 동일하게 적용됩니다. "레지스터의 비트 3은 클럭 분할과 관련이 없습니다." 나는 비트 3을 설정하지 않았고, 전체 레지스터에 값 3 또는 00000011을 ORing하여 처음 2 비트 (CS00 및 CS01)를 설정하여 64의 시계 부분을 얻었습니다. 정정 2와 동일합니다. 이것이 내 게으르다가 ORing과 값 사이에 표기법을 섞어서 비트를 ORing하여 비트 이름으로 옮긴다. 혼란을 드려 죄송합니다. 말이 돼? – chen

+0

수정하여 답을 수정하면 답변을 upvote 받아 수락합니다. 당신의 도움을 주셔서 감사합니다! – chen

관련 문제