1

I am trying to change the frequency of the PWM output from an Arduino Uno R3 (Been using Pin 9) to 200 Hz with a duty cycle of 20%. This is for an ESC that is connected to a 12V motor, and I know the ESC works as if I input a 200 HZ wave from a waveform generator the motor runs. However, I have been finding it difficult to do the same thing with an Arduino Uno and I believe it is due to the frequency being a default of 490 Hz, so I need a way to change that frequency to 200 Hz. Are there any libraries or specific ways to do so?

Thanks!

2
  • 1
    please add your code to the post ... format as "code"
    – jsotola
    Commented Oct 27, 2022 at 23:23
  • Haven't used a library for this yet, but you can find promising results in a web search. Like this library
    – chrisl
    Commented Oct 27, 2022 at 23:59

2 Answers 2

2

You can also use my newly-created AVR_PWM library to shield you from dealing with complex hardware registers

For example

#include "AVR_PWM.h"

#if ( PWM_USING_ATMEGA2560 )
  // Pins tested OK in Mega
  //#define pinToUse      12            // Timer1B on Mega
  //#define pinToUse      11            // Timer1A on Mega
  //#define pinToUse       9            // Timer2B on Mega
  //#define pinToUse       2            // Timer3B on Mega
  //#define pinToUse       3            // Timer3C on Mega
  //#define pinToUse       5            // Timer3A on Mega
  //#define pinToUse       6            // Timer4A on Mega
  //#define pinToUse       7            // Timer4B on Mega
  #define pinToUse       8            // Timer4C on Mega
  //#define pinToUse      46            // Timer5A on Mega
  //#define pinToUse      45            // Timer5B on Mega
  //#define pinToUse      44            // Timer5C on Mega

#elif ( PWM_USING_ATMEGA_32U4  )
  // Pins tested OK on 32u4
  //#define pinToUse      5            // Timer3A on 32u4
  #define pinToUse      9            // Timer1A on 32u4
  //#define pinToUse      10            // Timer1B on 32u4

#else

  // Pins tested OK on Nano / UNO
  #define pinToUse      9            // Timer1A on UNO, Nano, etc
  //#define pinToUse     10            // Timer1B on UNO, Nano, etc
  //#define pinToUse      5               // Timer0B on UNO, Nano, e
  //#define pinToUse       3            // Timer2B on UNO, Nano, etc
#endif

//creates pwm instance
AVR_PWM* PWM_Instance;

float frequency;
float dutyCycle;

void setup()
{
  Serial.print(F("\nStarting PWM_Basic on "));
  Serial.println(BOARD_NAME);
  Serial.println(AVR_PWM_VERSION);

  //assigns PWM frequency of 200 Hz and a duty cycle of 0%
  PWM_Instance = new AVR_PWM(pinToUse, 200, 0);
}

void loop()
{
  frequency = 200;
  dutyCycle = 20;

  PWM_Instance->setPWM(pinToUse, frequency, dutyCycle);

  delay(10000);
  dutyCycle = 90;

  PWM_Instance->setPWM(pinToUse, frequency, dutyCycle);

  delay(10000);
}
1
  • This works for me, thank you!
    – wroex24
    Commented Oct 29, 2022 at 17:13
2

If you are prepared to use Timer 2 (Pin D3) this code will do it:

void setup() 
 {
  pinMode (3, OUTPUT);

  TCCR2A = bit (WGM20) | bit (WGM21) | bit (COM2B1); // fast PWM, clear OC2B on compare
  TCCR2B = bit (WGM22) | bit (CS20) | bit (CS21) | bit (CS22); // prescaler of 1024
  OCR2A =  77;    // zero relative  
  OCR2B =  15;    // 20% duty cycle
  }  // end of setup

void loop()
  {
  // do other stuff here
  }

More information on the Atmega328P timers on my page about timers.

The figure 77 is obtained from:

16000000 / 1024 / 78 = 200.32

In other words, the prescaler of 1024 is divided into the clock of 16 MHz, and then we count up to 78, giving a result of just over 200. I actually use 77 because the timer is zero-relative (it counts from 0 to 77, giving 78 counts). This means the frequency is slightly out (it will be 200.32 Hz rather than 200 but that could be close enough).


You could also do it with Timer 1 (pin D10) to get slightly more accurate results, like this:

void setup() 
 {
  pinMode (10, OUTPUT);

  // mode 15
  TCCR1A = bit (WGM10) | bit (WGM11) | bit (COM1B1); // fast PWM, clear OC1B on compare
  TCCR1B = bit (WGM12) | bit (WGM13) | bit (CS11);   // fast PWM, prescaler of 8
  OCR1A = 10000 - 1;   // what to count to
  OCR1B = 2000 - 1;    // duty cycle
  }  // end of setup

void loop()
  {
  // do other stuff here
  }

In this case I have used a prescaler of 8 and a count-up value of 10000, as follows:

16000000 / 8 / 10000 = 200

In this case the answer is exactly 200, which will be more accurate than the 200.32 obtained from using Timer 2. That is because Timer 1 is a 16-bit timer and has higher resolution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.