frequency and duty cycle with 2 pots

Hello everyone, i am using a simple sketch for a PWM signal, However every time i need to change the frequency i have to upload a new sketch, is there a way to set the frequency using a 2nd pot ?

#include <PWM.h>
int32_t frequency = 25000;

const int Pin = 9;
int PWM = 0;
void setup() {
  InitTimersSafe();
  bool succes = SetPinFrequencySafe(9, frequency);
}

void loop() {
  PWM = map(analogRead(A0), 0, 1023, 0, 255);
  analogWrite (Pin, PWM);
  delay(100);
}

What happens if, in loop, you read your second pot, convert (map) the value to your changed frequency and call SetPinFrequencySafe() just before the analogWrite? Seems reasonable but I've never used that PWM library.

Steve

PWM = map(analogRead(A0), 0, 1023, 0, 255); most people would simply write PWM = analogRead(A0) / 4;

I'd go about the task by getting a powers supply for your system, how ever you may power it. Using an Ohm meter find the center resistance of your pot. Leaving the pot set to the center resistance and using the projects final power supply, connect the pot to V+, gnd, and a Ax pin. Make and upload a sketch to the Arduino that will read and print out the reading. If the reading is stable enough, you now have a center point analog reading of the pot.

With the center reading, you can develop code to deliver a center frequency, you decide.

With a 10 bit AD converter you'll get 1023(1024) steps between 0V and V+( possibly 5v). 512 would be your center frequency, and you'll have 512 steps of adjustments above and below the center frequency to code as you like.

to make things more easy (for me at least) i have split the code into 2 halves, they work independently, but when i put them together my duty cycle pot only works from 0 to about 2% and then goes to full on.

#include <PWM.h>

void setup() {
}
void loop() {

int32_t frequency = map(analogRead(A1), 0, 1023, 0, 25000);
  InitTimersSafe();
  SetPinFrequencySafe(9, frequency);
  delay (50);
  
  analogWrite (9, map(analogRead(A0), 0, 1023, 0, 255));
  delay(50);
}

What kind of frequency are you looking for? Mainly what the highest frequency you are looking for? And what kind of tolerance are you looking for?

I have a library class that does exactly what you want, but I don't know if it would be fast enough. (uses polling of loop())

-jim lee

somewhere @ 1MHz should be enough, even though the wave will not be pretty, the signal should be fine.

1Mhz PWM frequency with a Uno. Interested to see if that will work.

The ESP32 has 2 PWM API's. The LED Control API and the MCPWM.

LED Control API LED Control (LEDC) - ESP32 - — ESP-IDF Programming Guide latest documentation

MCPWM API Motor Control Pulse Width Modulator (MCPWM) - ESP32 - — ESP-IDF Programming Guide latest documentation

The MCPWM might be of interest to you.

The MCPWM can output a frequency of 1/2 the periphery bus clock of 80Mhz.

So. one microsecond per pulse?

I'm using micros(). So mine is completely out.

-jim lee

The MCPWM can give one microsecond pulses.

LCD API uses clock ticks instead of uS.
Here is the code to convert uS to clock ticks

int usToTicks(int usec)
{
  return (int)((float)usec / ((float)REFRESH_USEC / (float)timer_width_ticks) * (((float)TIMER_FREQUENCY) / 50.0));
} // int usToTicks(int usec)

Basically one clock tick equals 1/3 of a uS.

The MCPWM has its own clock, the LCD API uses a hardware timer.

You can also use Timer1 directly on the Uno to generate a signal with variable duty cycle and frequency. Here is an example.

You have to set OCR1A, OCR1B and, possibly, the prescaler.
The output is fixed on pin 10.

For 1MHz with prescaler /1, OCR1A is 15. However, this is not very granular. That is, adjustment is in large steps.

Anyway, what are you doing with a 1MHz PWM signal ?

// timer1 example : adjustable frequency and duty cycle
// output on OC1B - needs pinMode OUTPUT.

noInterrupts();
//  Mode 15
TCCR1A =  ( _BV(WGM10) | _BV(WGM11) ) ;
TCCR1B =  ( _BV(WGM12) | _BV(WGM13) ) ;

TCCR1A |= _BV(COM1B1) ;  // connect OC1B (pin 10) to timer

OCR1A = 15 ;           // period in CPU ticks (16 per us @ ps /1 )
OCR1B =  ( OCR1A / 3 ) ;  //   33 % duty cycle  to 75%

TCCR1B |= _BV(CS10);         // start timer prescaler /1
interrupts();