Skip to main content
Arduino

Return to Answer

You can get pretty close if you program the Timer 1 directly (not through the library), and have it run with the prescaler set to 1. Ideally, you want the period of the timer in clock cycles to be:

F_CPU / 15 kHz = 16,000 kHz / 15 kHz ≈ 1066.67 CPU cycles

If you round this to the nearest integer, you get

F_CPU / 1,067 = 16,000 kHz / 1,067 ≈ 14.9953 kHz

This is about 0.03% totoo slow, well within the tolerance of the ceramic resonator clocking the Uno.

Here is my attempt at this. TestedI have tested it.

constexpr float PWM_FREQUENCY = 15e3; // 15 kHz
constexpr uint16_t PERIOD = round(F_CPU / PWM_FREQUENCY);
void setup() {
 // Configure Timer 1 for 15 kHz PWM on pin 9 = PB1 = OC1A.
 DDRB |= _BV(PB1); // set pin as output
 TCCR1B = 0; // stop timer
 TCCR1A = _BV(COM1A1) // non-inverting PWN on OC1A
 | _BV(WGM11); // mode 14: fast PWM, TOP = ICR1
 TCCR1B = _BV(WGM12) // ditto
 | _BV(WGM13) // ditto
 | _BV(CS10); // clock @ F_CPU
 ICR1 = PERIOD - 1; // period
 OCR1A = PERIOD / 4; // duty cycle
}
void loop(){}

You can get pretty close if you program the Timer 1 directly (not through the library), and have it run with the prescaler set to 1. Ideally, you want the period of the timer in clock cycles to be:

F_CPU / 15 kHz = 16,000 kHz / 15 kHz ≈ 1066.67 CPU cycles

If you round this to the nearest integer, you get

F_CPU / 1,067 = 16,000 kHz / 1,067 ≈ 14.9953 kHz

This is about 0.03% to slow, well within the tolerance of the ceramic resonator clocking the Uno.

Here is my attempt at this. Tested.

constexpr float PWM_FREQUENCY = 15e3; // 15 kHz
constexpr uint16_t PERIOD = round(F_CPU / PWM_FREQUENCY);
void setup() {
 // Configure Timer 1 for 15 kHz PWM on pin 9 = PB1 = OC1A.
 DDRB |= _BV(PB1); // set pin as output
 TCCR1B = 0; // stop timer
 TCCR1A = _BV(COM1A1) // non-inverting PWN on OC1A
 | _BV(WGM11); // mode 14: fast PWM, TOP = ICR1
 TCCR1B = _BV(WGM12) // ditto
 | _BV(WGM13) // ditto
 | _BV(CS10); // clock @ F_CPU
 ICR1 = PERIOD - 1; // period
 OCR1A = PERIOD / 4; // duty cycle
}
void loop(){}

You can get pretty close if you program Timer 1 directly (not through the library), and have it run with the prescaler set to 1. Ideally, you want the period of the timer in clock cycles to be:

F_CPU / 15 kHz = 16,000 kHz / 15 kHz ≈ 1066.67 CPU cycles

If you round this to the nearest integer, you get

F_CPU / 1,067 = 16,000 kHz / 1,067 ≈ 14.9953 kHz

This is about 0.03% too slow, well within the tolerance of the ceramic resonator clocking the Uno.

Here is my attempt at this. I have tested it.

constexpr float PWM_FREQUENCY = 15e3; // 15 kHz
constexpr uint16_t PERIOD = round(F_CPU / PWM_FREQUENCY);
void setup() {
 // Configure Timer 1 for 15 kHz PWM on pin 9 = PB1 = OC1A.
 DDRB |= _BV(PB1); // set pin as output
 TCCR1B = 0; // stop timer
 TCCR1A = _BV(COM1A1) // non-inverting PWN on OC1A
 | _BV(WGM11); // mode 14: fast PWM, TOP = ICR1
 TCCR1B = _BV(WGM12) // ditto
 | _BV(WGM13) // ditto
 | _BV(CS10); // clock @ F_CPU
 ICR1 = PERIOD - 1; // period
 OCR1A = PERIOD / 4; // duty cycle
}
void loop(){}
Fixed DDRD → DDRB, tested.
Source Link
Edgar Bonet
  • 45.1k
  • 4
  • 42
  • 81

You can get pretty close if you program the Timer 1 directly (not through the library), and have it run with the prescaler set to 1. Ideally, you want the period of the timer in clock cycles to be:

F_CPU / 15 kHz = 16,000 kHz / 15 kHz ≈ 1066.67 CPU cycles

If you round this to the nearest integer, you get

F_CPU / 1,067 = 16,000 kHz / 1,067 ≈ 14.9953 kHz

This is about 0.03% to slow, well within the tolerance of the ceramic resonator clocking the Uno.

Here is my attempt at this. Not testedTested.

constexpr float PWM_FREQUENCY = 15e3; // 15 kHz
constexpr uint16_t PERIOD = round(F_CPU / PWM_FREQUENCY);
void setup() {
 // Configure Timer 1 for 15 kHz PWM on pin 9 = PB1 = OC1A.
 DDRDDDRB |= _BV(PB1); // set pin as output
 TCCR1B = 0; // stop timer
 TCCR1A = _BV(COM1A1) // non-inverting PWN on OC1A
 | _BV(WGM11); // mode 14: fast PWM, TOP = ICR1
 TCCR1B = _BV(WGM12) // ditto
 | _BV(WGM13) // ditto
 | _BV(CS10); // clock @ F_CPU
 ICR1 = PERIOD - 1; // period
 OCR1A = PERIOD / 4; // duty cycle
}
void loop(){}

You can get pretty close if you program the Timer 1 directly (not through the library), and have it run with the prescaler set to 1. Ideally, you want the period of the timer in clock cycles to be:

F_CPU / 15 kHz = 16,000 kHz / 15 kHz ≈ 1066.67 CPU cycles

If you round this to the nearest integer, you get

F_CPU / 1,067 = 16,000 kHz / 1,067 ≈ 14.9953 kHz

This is about 0.03% to slow, well within the tolerance of the ceramic resonator clocking the Uno.

Here is my attempt at this. Not tested.

constexpr float PWM_FREQUENCY = 15e3; // 15 kHz
constexpr uint16_t PERIOD = round(F_CPU / PWM_FREQUENCY);
void setup() {
 // Configure Timer 1 for 15 kHz PWM on pin 9 = PB1 = OC1A.
 DDRD |= _BV(PB1); // set pin as output
 TCCR1B = 0; // stop timer
 TCCR1A = _BV(COM1A1) // non-inverting PWN on OC1A
 | _BV(WGM11); // mode 14: fast PWM, TOP = ICR1
 TCCR1B = _BV(WGM12) // ditto
 | _BV(WGM13) // ditto
 | _BV(CS10); // clock @ F_CPU
 ICR1 = PERIOD - 1; // period
 OCR1A = PERIOD / 4; // duty cycle
}
void loop(){}

You can get pretty close if you program the Timer 1 directly (not through the library), and have it run with the prescaler set to 1. Ideally, you want the period of the timer in clock cycles to be:

F_CPU / 15 kHz = 16,000 kHz / 15 kHz ≈ 1066.67 CPU cycles

If you round this to the nearest integer, you get

F_CPU / 1,067 = 16,000 kHz / 1,067 ≈ 14.9953 kHz

This is about 0.03% to slow, well within the tolerance of the ceramic resonator clocking the Uno.

Here is my attempt at this. Tested.

constexpr float PWM_FREQUENCY = 15e3; // 15 kHz
constexpr uint16_t PERIOD = round(F_CPU / PWM_FREQUENCY);
void setup() {
 // Configure Timer 1 for 15 kHz PWM on pin 9 = PB1 = OC1A.
 DDRB |= _BV(PB1); // set pin as output
 TCCR1B = 0; // stop timer
 TCCR1A = _BV(COM1A1) // non-inverting PWN on OC1A
 | _BV(WGM11); // mode 14: fast PWM, TOP = ICR1
 TCCR1B = _BV(WGM12) // ditto
 | _BV(WGM13) // ditto
 | _BV(CS10); // clock @ F_CPU
 ICR1 = PERIOD - 1; // period
 OCR1A = PERIOD / 4; // duty cycle
}
void loop(){}
Source Link
Edgar Bonet
  • 45.1k
  • 4
  • 42
  • 81

You can get pretty close if you program the Timer 1 directly (not through the library), and have it run with the prescaler set to 1. Ideally, you want the period of the timer in clock cycles to be:

F_CPU / 15 kHz = 16,000 kHz / 15 kHz ≈ 1066.67 CPU cycles

If you round this to the nearest integer, you get

F_CPU / 1,067 = 16,000 kHz / 1,067 ≈ 14.9953 kHz

This is about 0.03% to slow, well within the tolerance of the ceramic resonator clocking the Uno.

Here is my attempt at this. Not tested.

constexpr float PWM_FREQUENCY = 15e3; // 15 kHz
constexpr uint16_t PERIOD = round(F_CPU / PWM_FREQUENCY);
void setup() {
 // Configure Timer 1 for 15 kHz PWM on pin 9 = PB1 = OC1A.
 DDRD |= _BV(PB1); // set pin as output
 TCCR1B = 0; // stop timer
 TCCR1A = _BV(COM1A1) // non-inverting PWN on OC1A
 | _BV(WGM11); // mode 14: fast PWM, TOP = ICR1
 TCCR1B = _BV(WGM12) // ditto
 | _BV(WGM13) // ditto
 | _BV(CS10); // clock @ F_CPU
 ICR1 = PERIOD - 1; // period
 OCR1A = PERIOD / 4; // duty cycle
}
void loop(){}
lang-cpp

AltStyle によって変換されたページ (->オリジナル) /