2016-07-13 2 views
0

가변 주파수 및 고정 듀티 사이클 (50 %)의 PWM 신호를 생성하려고합니다. 주파수는 0-25KHz 사이에서 달라야합니다. 이것은 ATMEGA32U4 마이크로 컨트롤러 용이며 Atmel Studio를 사용하여 C로 작성하고 있습니다. 데이터 시트를 읽었지 만 계산 방법과 사용 모드에 관해서는 머리 숙여 질 수 없습니다. 다른 자습서를 거친 후 CTC 모드를 사용하는 것이 가장 좋습니다.AVR 용 가변 주파수 PWM 신호 생성

주파수가 변수이기 때문에 사용해야하는 prescalar는 어떻게 선택합니까? 인터럽트를 사용해야합니까? 이러한 타이머 레지스터를 설정하는 방법에 대한 도움을 주시면 감사하겠습니다.

+0

당신은 더 구체적인 뭔가를 물어 시도해야합니다. 그 질문은 "다른 튜토리얼"을 답으로 요구할 것입니다. 읽은 자습서의 문제점은 무엇입니까? 어쩌면 당신이 이해하지 못하는 튜토리얼의 섹션/계산을 인용 할 수 있습니다. –

답변

0

나는 AT32UC3을 훨씬 더 좋아해서 ATMEGA32U4를 사용하지 않습니다. 그러나 정확한 코드는 ... 죄송합니다 ... 왜 원하는 주파수의 두 배로 타이머를 설정하고 그 안의 핀을 토글하지 않으시겠습니까? 당신의 의무는 항상 50 %가되어야합니다. 주파수 업데이트는

뭔가처럼 ... 짝수 또는 모든 n-th ISR 카운터/타이머 통화를 수행 할 수 있습니다

const int n=10; // must be even to ensure 50% duty 
volatile int ix=0; 
volatile int frequency=10000; 
isr_timercounter() 
{ 
// clear IRQ 
// toggle pin 
ix++; if (ix>=n) 
    { 
    ix=0; 
    // set timer/counter to 2*frequency 
    } 
} 

void main() 
{ 
// init timer/counter 
for (;;) 
    { 
    //do your stuff 
    frequency = ???; 
    } 
} 
1

32U4 내가에 대한 테스트를 한 된 328P 동일 타이머를 가지고 당신의 문제. 최고의 해상도를 제공하는 타이머 1을 사용했습니다. 이 타이머는 CTC 모드에서 실행될 수 있으며 채널 A는 토글 - 온 - 컴 페어 - 매치에서 고정 출력 핀에 바인딩 될 수있다. 따라서 설정이 매우 간단 해지고 인터럽트 로직이 필요하지 않습니다. OCR1A 에 쓰기 만하면 주파수를 간단히 제어 할 수 있습니다 (이 레지스터는 더블 버퍼링되어 주파수 변경시 글리치가 없어야합니다) *. n은 프리 스케일 값이 오버 플로우 레지스터 비교 여기서 x

f n x = f_cpu/(2 * n * (1 + x)) 

: CTC 모드에서 타이머 1

는의 출력 주파수를 갖는다. 16MHz 일 클럭에 가능한 주파수 범위를 탐색하여 제공한다 :

| N | f-min |  f-max |  r-min | r-max | x-100 | x-25k | 
+-----+--------+-----------+-----------+-----------+-------+-------+ 
| 1 | 122.1 | 8,000,000 | 4,000,000 | 0.0019 | n/a | 319 | 
| 8 | 15.3 | 1,000,000 | 500,000 | 0.00023 | 9,999 | 39 | 
| 64 | 1.91 | 125,000 | 62,500 | 0.000029 | 1,249 |  4 | 
| 256 | 0.49 | 31,250 | 15,625 | 0.0000073 | 311 | n/a | 
|1024 | 0.12 |  7,812 |  3,906 | 0.0000018 | 77 | n/a | 

N은 프리 스케일 설정 F 분 & F-최대 최소 달성 가능한 최대 주파수가 R-분 & R-최대 최소이고 및 최대 주파수 분해능, 마지막으로 x-100 & x-25k는 각각 100Hz 및 25kHz 출력에 대해 OCR1A에 필요한 값입니다. 전체 내용

여기서 일례를 작동 주파수 1Hz로, 2, 5, 10 ... 2 개 초 단위에서 500kHz까지 충분한 통해 사이클 범위의 동작을 관찰하기위한 프로그램이다

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

struct CTC1 
{ 
    static void setup() 
    { 
     // CTC mode with TOP-OCR1A 

     TCCR1A = 0; 
     TCCR1B = _BV(WGM12); 

     // toggle channel A on compare match 

     TCCR1A = (TCCR1A & ~(_BV(COM1A1) | _BV(COM1A0))) | _BV(COM1A0); 

     // set channel A bound pin to output mode 

     DDRB |= _BV(1); // PB1 on 328p, use _BV(5) for PB5 on 32U4 
    } 

    static void set_freq(float f) 
    { 
     static const float f1 = min_freq(1), f8 = min_freq(8), f64 = min_freq(64), f256 = min_freq(256); 

     uint16_t n; 

     if (f >= f1)  n = 1; 
     else if (f >= f8) n = 8; 
     else if (f >= f64) n = 64; 
     else if (f >= f256) n = 256; 
     else    n = 1024; 

     prescale(n); 

     OCR1A = static_cast<uint16_t>(round(F_CPU/(2 * n * f) - 1)); 
    } 

    static void prescale(uint16_t n) 
    { 
     uint8_t bits = 0; 

     switch (n) 
     { 
      case 1: bits = _BV(CS10);    break; 
      case 8: bits = _BV(CS11);    break; 
      case 64: bits = _BV(CS11) | _BV(CS10); break; 
      case 256: bits = _BV(CS12);    break; 
      case 1024: bits = _BV(CS12) | _BV(CS10); break; 
      default: bits = 0; 
     } 

     TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11) | _BV(CS10))) | bits; 
    } 

    static inline float min_freq(uint16_t n) 
    { 
     return ceil(F_CPU/(2 * n * 65536)); 
    } 
}; 

void setup() 
{ 
    CTC1::setup(); 
} 

void loop() 
{ 
    for (uint8_t x = 0; x < 6; ++x) 
     for (uint8_t y = 0; y < 3; ++y) 
     { 
      float k = y > 0 ? (y > 1 ? 5 : 2) : 1; 

      CTC1::set_freq(k * pow(10, x)); 
      _delay_ms(2000); 
     } 
} 

int main() 
{ 
    setup(); 
    for (;;) 
     loop(); 
} 

은 신호는 PB1 (Arduino Uno의 디지털 핀 9)에서 관찰 할 수 있습니다. 32U4 채널 A는 PB5에 바인딩됩니다.

Aleksander Z.가 친절하게 언급했듯이 OCR1A 레지스터는 CTC 모드에서 더블 버퍼링되지 않습니다. 주파수를 전환하면 심각한 글리치가 발생할 수 있습니다.:

enter image description here

이 쉽게 고정 될 수있는 애플리케이션에 따라 바쁜 루핑 (이것은 매우 높은 주파수에서 잘 작동하지 않거나 매우 낮은 주파수 하에서 용납 지연이 발생할 수 있지만)

while (TCNT1 > x) 
    ; 
OCR1A = x; 

을 일으키기 :

enter image description here

+2

_ 주파수는 OCR1A에 쓰기 만하면 간단히 제어 할 수 있습니다 (이 레지스터는 더블 버퍼링되어 주파수 변경시 결함이 없어야 함) ._ 아니오, ** OCR1A는 CTC 모드에서 이중 버퍼링되지 않습니다. ** [데이터 시트] (http://www.atmel.com/Images/Atmel-42735-8-bit-AVR-Microcontroller-ATmega328-328P_datasheet.pdf), 페이지 162는 말합니다 : _Note : TOP이 카운터가 실행되는 동안 BOTTOM에 가까운 값으로 변경됨 CTC 모드는 이중 버퍼링을 제공하지 않으므로주의해서 수행해야합니다. OCR1A에 쓰여진 새로운 값이 TCNT1의 현재 값보다 낮 으면, 카운터는 비교 일치를 놓칠 것입니다. _ –

+0

이것을 지적 해 주셔서 감사합니다 - 그에 따라 게시물을 업데이트했습니다. Btw, 이러한 결함을 해결할 수있는 더 좋은 방법이 있다면 게시하십시오. – marangisto

+0

데이터 시트, 164 페이지 : 각 비교 일치 (COM1A [1 : 0] = 0x1)에서 논리 레벨을 토글하기 위해 OC1A를 선택하여 고속 PWM 모드에서 50 % 듀티 사이클의 주파수 파형 출력을 얻을 수 있습니다. 이것은 OCR1A가 TOP 값 (WGM1 [3 : 0] = 0xF)을 정의하는 데 사용되는 경우에만 적용됩니다. OCR1A가 0 (0x0000)으로 설정되면 생성 된 파형의 최대 주파수는 f_OC1A = f_clk_I/O/2가됩니다. 이 기능은 빠른 비교 모드의 이중 버퍼 기능이 고속 PWM 모드에서 활성화된다는 점을 제외하고는 CTC 모드의 OC1A 토글과 유사합니다. –