PWM 주파수를 25kHz로 설정


12

현재 다음 코드를 사용하여 4 개의 PWM 핀을 약 31kHz로 설정할 수 있습니다.

void setup()
{
    TCCR1B = TCCR1B & B11111000 | B00000001; // Set PWM frequency for D9 & D10:
    pinMode(pwmPin9, OUTPUT); // Sets the pin as output
    pinMode(pwmPin10, OUTPUT); // Sets the pin as output


    TCCR2B = TCCR2B & B11111000 | B00000001; // Set PWM for D3 & D11
    pinMode(pwmPin3, OUTPUT); // Sets the pin as output
    pinMode(pwmPin11, OUTPUT); // Sets the pin as output
}

이 설정을 어딘가에서 찾았지만이 4 개의 PWM 핀을 약 25 kHz로 설정하는 방법을 모르겠습니다. 어떻게 가능합니까?


3
AVR 타이머 작동 방식을 이해하십니까?
Ignacio Vazquez-Abrams 1


1
@ IgnacioVazquez-Abrams 익숙하지 않아서 처음에이 4 개의 핀을 약 25kHz로 설정해야합니다. 프로젝트를 끝내기 위해 서둘러 도움을 드리겠습니다. 내가 가진 코드는 31kHz로 설정되었습니다. 25kHz로 수정할 수 있습니까? DC 모터에는 그 주파수가 필요합니다.
user16307

1
@NickGammon 고맙지 만 지금은 이것들을 연구 할 시간이 충분하지 않습니다. 25kHz를 설정하는 코드 부분을 제공해 주시겠습니까? Im lost
user16307

2
듀티 사이클이 약간 달라 지도록 정확한 rpm을 조정해야합니다. 2 핀만 25kHz로 설정할 수 있습니까?
user16307

답변:


10

단일 Arduino Uno에서 161 단계로 25kHz에서 4 개의 PWM 채널을 가질 수 있다는 것을 깨달았 으므로이 두 번째 답변을 게시하고 있습니다. 이것은 포함 8 MHz의 메인 클럭 주파수를 변경 빠른 절반을 실행 전체 프로그램 이후 부작용을 보유하고 있습니다. 또한 세 타이머 아두 이노 타이밍 기능을 푸는 수단을 재구성하는 것을 포함한다 ( millis(), micros(), delay()delayMicroseconds()). 이러한 트레이드 오프가 허용 가능한 경우 다음과 같은 방식으로 진행됩니다.

void setup()
{
    // Set the main system clock to 8 MHz.
    noInterrupts();
    CLKPR = _BV(CLKPCE);  // enable change of the clock prescaler
    CLKPR = _BV(CLKPS0);  // divide frequency by 2
    interrupts();

    // Configure Timer 0 for phase correct PWM @ 25 kHz.
    TCCR0A = 0;           // undo the configuration done by...
    TCCR0B = 0;           // ...the Arduino core library
    TCNT0  = 0;           // reset timer
    TCCR0A = _BV(COM0B1)  // non-inverted PWM on ch. B
        | _BV(WGM00);  // mode 5: ph. correct PWM, TOP = OCR0A
    TCCR0B = _BV(WGM02)   // ditto
        | _BV(CS00);   // prescaler = 1
    OCR0A  = 160;         // TOP = 160

    // Same for Timer 1.
    TCCR1A = 0;
    TCCR1B = 0;
    TCNT1  = 0;
    TCCR1A = _BV(COM1A1)  // non-inverted PWM on ch. A
        | _BV(COM1B1)  // same on ch. B
        | _BV(WGM11);  // mode 10: ph. correct PWM, TOP = ICR1
    TCCR1B = _BV(WGM13)   // ditto
        | _BV(CS10);   // prescaler = 1
    ICR1   = 160;

    // Same for Timer 2.
    TCCR2A = 0;
    TCCR2B = 0;
    TCNT2  = 0;
    TCCR2A = _BV(COM2B1)  // non-inverted PWM on ch. B
        | _BV(WGM20);  // mode 5: ph. correct PWM, TOP = OCR2A
    TCCR2B = _BV(WGM22)   // ditto
        | _BV(CS20);   // prescaler = 1
    OCR2A  = 160;
}

void loop()
{
    analogWrite( 3,   1);  // duty cycle = 1/160
    analogWrite( 5,  53);  // ~ 1/3
    analogWrite( 9, 107);  // ~ 2/3
    analogWrite(10, 159);  // 159/160
}

다른 답변 과 달리 수정 버전이 필요하지 않습니다 analogWrite(). 표준 버전이 정상적으로 작동합니다. 다음 사항 만주의해야합니다.

  1. 기록 된 값은 0 (항상 LOW를 의미 함)과 160 (항상 HIGH)을 포함해야합니다.
  2. 핀 3, 5, 9 및 10 만 사용할 수 있습니다. 시도 analogWrite() 만 PWM 출력을 제공하지 않을 것이다 핀 (6) 또는 (11), 또한 각 핀 (5) 또는 (3)에 주파수를 변경한다.

매우 오랜 시간이 지났으며 이제 다른 프로세서를 사용하는 Arduino Due와 같은 문제가 발생합니다. arduino.stackexchange.com/questions/67053/…
user16307

11

위상 보정 PWM 모드에서 타이머 1을 25kHz로 순환하도록 타이머 1을 구성 할 수 있으며 핀 9와 10에서 두 개의 출력을 다음과 같이 사용할 수 있습니다.

// PWM output @ 25 kHz, only on pins 9 and 10.
// Output value should be between 0 and 320, inclusive.
void analogWrite25k(int pin, int value)
{
    switch (pin) {
        case 9:
            OCR1A = value;
            break;
        case 10:
            OCR1B = value;
            break;
        default:
            // no other pin will work
            break;
    }
}

void setup()
{
    // Configure Timer 1 for PWM @ 25 kHz.
    TCCR1A = 0;           // undo the configuration done by...
    TCCR1B = 0;           // ...the Arduino core library
    TCNT1  = 0;           // reset timer
    TCCR1A = _BV(COM1A1)  // non-inverted PWM on ch. A
           | _BV(COM1B1)  // same on ch; B
           | _BV(WGM11);  // mode 10: ph. correct PWM, TOP = ICR1
    TCCR1B = _BV(WGM13)   // ditto
           | _BV(CS10);   // prescaler = 1
    ICR1   = 320;         // TOP = 320

    // Set the PWM pins as output.
    pinMode( 9, OUTPUT);
    pinMode(10, OUTPUT);
}

void loop()
{
    // Just an example:
    analogWrite25k( 9, 110);
    analogWrite25k(10, 210);
    for (;;) ;  // infinite loop
}

값을 0으로 쓰면 analogWrite25k()핀은 항상 낮음을, 320은 항상 높음을 의미합니다. 일반 analogWrite()거의 작동하지만 255를 320과 동일하게 해석합니다 (즉, 항상 HIGH).

이 코드는 Arduino Uno 또는 이와 유사한 보드 (ATmega168 또는 328 @ 16 MHz)를 가정합니다. 여기에 사용 된 방법에는 16 비트 타이머가 필요하므로 Uno에서 유일하게 사용할 수있는 타이머 1을 사용합니다. 그렇기 때문에 두 개의 출력 만 사용할 수 있습니다. 이 방법은 16 비트 타이머를 사용하여 다른 AVR 기반 보드에 적용 할 수 있습니다. Gerben이 지적했듯이 타이머에는 해당 ICRx 레지스터가 있어야합니다. Arduino Mega에는 각각 3 개의 출력을 가진 4 개의 타이머가 있습니다.


1
다른 타이머에는 ICRx레지스터 가 없으므로이 방법은 timer1에서만 작동한다고 설명하는 것이 유용 할 수 있습니다 . 타이머 0과 2에 대해 타이머 당 하나의 PWM 핀만 가질 수 있습니다.
Gerben

1
@ Gerben : 모든 16 비트 타이머에 해당 레지스터가 있습니까? 적어도 그들은 메가에 있습니다.
Edgar Bonet

1
예. 그러나 ATMega328에서는 timer1 만 16 비트입니다. 나머지는 8 비트입니다. 그리고 OP는 4 PWM 출력을 원하며 솔루션은 2 만 제공합니다.
Gerben

1
@ Gerben : 아니, 네 말이 맞아. ICRx를 요구하는 것은 타이머가 16 비트 여야한다는 점에서 불필요한 것 같습니다. 우노와 메가의 경우 다른 AVR 기반 아두 이노는 확실하지 않습니다. OP는 이것이 2 개의 PWM 채널 만 제공한다는 것을 이해합니다. 질문과 답변에 대한 내 의견을 참조하십시오.
Edgar Bonet 2016 년

2
@ techniche : 1. 나를 위해 작동합니다. 어쩌면 당신은 설정 COM4C1하는 것을 잊었 TCCR4A습니까? 2. 이것이 문제가 아닌 경우 어떻게 좋은 질문을합니까? 를 읽으십시오 . 그런 다음 전체 소스 코드를 포함하고 프로그램이 무엇을 기대하는지와 프로그램이 무엇을하는지 명확하게 명시 하여 질문 을 업데이트 하십시오 (“성공하지 못했습니다”는 유효한 문제 설명으로 간주되지 않습니다).
Edgar Bonet
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.