2012-04-16 2 views
1

AVR에서 제공하는 샘플 코드 (아래 코드 참조)를 기준으로 USART를 사용할 수 있도록 AVR Butterfly 내부 발진기를 교정 중입니다. 나는 또한 두 개의 타이머 제어 서보 모터를 사용하고 싶었으므로 보정 프로세스 후에 16 비트 타이머 1을 재사용 할 수 있는지 궁금하다. TCCR1A/B를 재설정하려고 시도했지만 작동하지 않았다. . 이걸로 나를 도울 수 있기를 바랍니다.AVR Butterfly - 내부 발진기 교정 후 타이머 재사용

void OSCCAL_Calibrate(void){ 
    unsigned char calibrate = 0; 
    int temp; 
    unsigned char tempL; 

    CLKPR = (1<<CLKPCE);  // set Clock Prescaler Change Enable 
    // set prescaler = 8, Inter RC 8Mhz/8 = 1Mhz 
    CLKPR = (1<<CLKPS1) | (1<<CLKPS0); 
    TIMSK2 = 0;    //disable OCIE2A and TOIE2 
    ASSR = (1<<AS2);  //select asynchronous operation of timer2 (32,768kHz)  
    OCR2A = 200;   // set timer2 compare value 
    TIMSK0 = 0;    // delete any interrupt sources 
    TCCR1B = (1<<CS10);  // start timer1 with no prescaling 
    TCCR2A = (1<<CS20);  // start timer2 with no prescaling 
    while((ASSR & 0x01) | (ASSR & 0x04));  //wait for TCN2UB and TCR2UB to be cleared 

    delayMs(1000); // wait for external crystal to stabilise 

    while(!calibrate) 
    { 
     cli(); // disable global interrupt 

     TIFR1 = 0xFF; // delete TIFR1 flags 
     TIFR2 = 0xFF; // delete TIFR2 flags 
     TCNT1H = 0;  // clear timer1 counter 
     TCNT1L = 0; 
     TCNT2 = 0;  // clear timer2 counter 

     while (!(TIFR2 & (1<<OCF2A))); // wait for timer2 compareflag 

     TCCR1B = 0; // stop timer1 

     sei(); // enable global interrupt 

     if ((TIFR1 & (1<<TOV1))) 
     { 
      temp = 0xFFFF;  // if timer1 overflows, set the temp to 0xFFFF 
     }else 
     { // read out the timer1 counter value 
      tempL = TCNT1L; 
      temp = TCNT1H; 
      temp = (temp << 8); 
      temp += tempL; 
     } 

     if (temp > 6250) 
      OSCCAL--; // the internRC oscillator runs to fast, decrease the OSCCAL 
     else if (temp < 6120) 
      OSCCAL++; // the internRC oscillator runs to slow, increase the OSCCAL 
     else 
      calibrate = 1; // the interRC is correct 

     TCCR1B = (1<<CS10); // start timer1 
    } 
} 

void motorInit(){ 
    // reset timer 1 
    TCCR1A = 0; 
    TCCR1B = 0; 

    // initialize Servo Pins 
    DDRB |= (1<<PB5) | (1<<PB6); 

    ICR1H = ICR_VALUE >> 8; 
    ICR1L = ICR_VALUE & (TOP_VALUE); 

    // reset OCRs 
    setServoSpeed(0, 0); 
    setServoSpeed(1, 0); 

    // Set Timer mode (PWM Phase & Freq. correct, clear on compare match) 
    // and prescaler (8) 
    TCCR1A = ((1<<COM1A1) | (1<<COM1B1));     
    TCCR1B = ((1<<WGM13) | (0<<CS12) | (1<<CS11) | (0<<CS10)); 
} 

답변

1

어쩌면 당신은 내가 얼마 전에 프로젝트에 사용되는 코드를 확인하실 수 있습니다,하지만 당신은 아마 당신이 조정해야 내가 56,700 전송 속도를위한 7.3768 MHz의 시스템 주파수를 감소 치료를해야합니다.

void OSCCAL_Calibrate(void) 
{ 
uint8_t LoopCount = (0x7F/2); 

ATOMIC_BLOCK(ATOMIC_RESTORESTATE) 
{ 
// Make sure all clock division is turned off (8MHz RC clock) 
CLKPR = (1 << CLKPCE); 
CLKPR = 0x00; 

// Inital OSCCAL of half its maximum 
OSCCAL = (0x7F/2); 

// Disable timer interrupts 
TIMSK1 = 0; 
TIMSK2 = 0; 

// Set timer 2 to asyncronous mode (32.768KHz crystal) 
ASSR = (1 << AS2); 

// Ensure timer 1 control register A is cleared 
TCCR1A = 0; 

// Start both counters with no prescaling 
TCCR1B = (1 << CS10); 
TCCR2A = (1 << CS20); 

// Wait until timer 2's external 32.768KHz crystal is stable 
while (ASSR & ((1 << TCN2UB) | (1 << TCR2UB) | (1 << OCR2UB))); 

// Clear the timer values 
TCNT1 = 0; 
TCNT2 = 0; 

while (LoopCount--) 
{ 
// Wait until timer 2 overflows 
while (!(TIFR2 & (1 << TOV2))); 

// Stop timer 1 so it can be read 
TCCR1B = 0x00; 

// Check timer value against ideal constant 
if (TCNT1 > OSCCAL_TARGETCOUNT) // Clock is running too fast 
OSCCAL--; 
else if (TCNT1 < OSCCAL_TARGETCOUNT) // Clock is running too slow 
OSCCAL++; 

// Clear timer 2 overflow flag 
TIFR2 |= (1 << TOV2); 

이 내용을 확인하십시오!