Variable frequency, constant duty cycle

Hi
Trying to get Variable frequency, constant duty cycle output from the arduino
I have a 0-5 v signal in and a center point at 2.5v That's 0
I like to send a 0 -8000 hz signal out vhen it is below or above center point
This is for controlling a motorcontroller I have. The motorcontroller requires a 0 - 8000hz signal and a bit defining direction.

The code I have tried with

#include <PWM.h>

int outputPin1 = 2;
int dutyCycleInput = 64500;      //1-65535 Pulse with 0-100%
int DbH = 510;
int DbL = 480;


void setup()
{
  InitTimersSafe();
  Serial.begin(9600);
  pinMode (2, OUTPUT);
  pinMode (3, OUTPUT);
  digitalWrite(2, LOW);
  digitalWrite(3, LOW);
}
void loop()
{
  //reading of analog input and computing of frequency out
  int sensorReading = analogRead(A0);
  int freqInput1 = map(sensorReading, DbH, 1023, 0, 8000);
  int freqInput2 = map(sensorReading, DbL, 0, 0, 8000);
  freqInput1 = constrain(freqInput1, 0, 8000);
  freqInput2 = constrain(freqInput2, 0, 8000);
  int freqInput = (freqInput1 + freqInput2);

  //thruster rotation bits
  if (sensorReading > DbH)
 { digitalWrite(2, HIGH);}
  else {digitalWrite(2, LOW);}

  if (sensorReading < DbL)
  {digitalWrite(3, HIGH);}
  else {digitalWrite(3, LOW);}

  //serial out for debug
  Serial.print("In: ");
  Serial.print(sensorReading);
  Serial.print("   Out1: ");
  Serial.print(freqInput1);
  Serial.print("   Out2: ");
  Serial.print(freqInput2);
  Serial.print("   Out   ");
  Serial.print(freqInput);
  Serial.println(" hz");

  //pwm output
  SetPinFrequencySafe(outputPin1, freqInput );
  pwmWriteHR(outputPin1, dutyCycleInput );
  
}

So... What is the question? Does you code do what you want? If not, what is it doing wrong?

I do not get any PWM output on pin 2 as i have defined in the program
I It does the calculation's as the debug info sendt out on the serial port.
But it will not give PWM output

If you are using an Arduino UNO you have to use a PWM pin controlled by Timer1 to get 16-bit PWM. That would be Pin 9 or Pin 10.

So i can only get this on 2 pins on the Uno?
On mega can i have 8 outputs or is it limited there as well?
If so, do I have to do something with the code to make it work?

psathammer:
Hi
Trying to get Variable frequency, constant duty cycle output from the arduino
I have a 0-5 v signal in and a center point at 2.5v That's 0
I like to send a 0 -8000 hz signal out vhen it is below or above center point
This is for controlling a motorcontroller I have. The motorcontroller requires a 0 - 8000hz signal and a bit defining direction.

The code I have tried with

#include <PWM.h>

int outputPin1 = 2;
int dutyCycleInput = 64500;      //1-65535 Pulse with 0-100%
int DbH = 510;
int DbL = 480;

void setup()
{
  InitTimersSafe();
  Serial.begin(9600);
  pinMode (2, OUTPUT);
  pinMode (3, OUTPUT);
  digitalWrite(2, LOW);
  digitalWrite(3, LOW);
}
void loop()
{
  //reading of analog input and computing of frequency out
  int sensorReading = analogRead(A0);
  int freqInput1 = map(sensorReading, DbH, 1023, 0, 8000);
  int freqInput2 = map(sensorReading, DbL, 0, 0, 8000);
  freqInput1 = constrain(freqInput1, 0, 8000);
  freqInput2 = constrain(freqInput2, 0, 8000);
  int freqInput = (freqInput1 + freqInput2);

//thruster rotation bits
  if (sensorReading > DbH)
{ digitalWrite(2, HIGH);}
  else {digitalWrite(2, LOW);}

if (sensorReading < DbL)
  {digitalWrite(3, HIGH);}
  else {digitalWrite(3, LOW);}

//serial out for debug
  Serial.print("In: ");
  Serial.print(sensorReading);
  Serial.print("  Out1: ");
  Serial.print(freqInput1);
  Serial.print("  Out2: ");
  Serial.print(freqInput2);
  Serial.print("  Out  ");
  Serial.print(freqInput);
  Serial.println(" hz");

//pwm output
  SetPinFrequencySafe(outputPin1, freqInput );
  pwmWriteHR(outputPin1, dutyCycleInput );
 
}

A constant duty cycle and a change in frequency are mutually exclusive. The instant you change frequency, you have changed that duty cycle.

Paul

Yes. The UNO only has one 16-bit timer which can control only two PWM pins.

Each timer can only have one frequency so I don't think you will get more than ONE frequency out of the UNO. An Ardiuno MEGA has more timers, but nowhere near 8.

I think you will need a different solution for your PWM needs. You might be able to do 8 kHz in software using the "BlinkWithoutDelay" technique and the micros() timer.

Paul_KD7HB:
A constant duty cycle and a change in frequency are mutually exclusive. The instant you change frequency, you have changed that duty cycle.

Paul

You mean at the instant of change, right? Because you can certainly generate a square wave (50% duty cycle) at more than one frequency.

Hi John
So basically you are saying that i only can output the same frequency on pin 9 and 10. Not 2 frequency at the same time?

I'm fairly new to the arduino programming and would appriciate a litte help on this matter..
I will have a look at the micros() timer and se if I can adapt it to suit my needs

Correct. Each Timer can only run at one frequency at a time. You can get PWM on two (UNO) or three (MEGA) pins from each timer but those two or three will have the same frequency.

Her eis how you would generate PWM on 8 pins in software:

float DutyCycle = 0.9842;

const byte ChannelCount = 8;
const byte ChannelPins[ChannelCount] = {2, 3, 4, 5, 6, 7, 8, 9};
bool ChannelStates[ChannelCount];
unsigned long ChannelFrequencies[ChannelCount];
unsigned long ChannelTimers[ChannelCount];
unsigned long ChannelOnTimes[ChannelCount];
unsigned long ChannelOffTimes[ChannelCount];

void setup()
{
  for (byte i = 0; i < ChannelCount; i++)
  {
    pinMode(ChannelPins[i], OUTPUT);
    SetChannelFrequency(i, 8000UL);
  }
}

void SetChannelFrequency(byte channel, unsigned long frequency)
{
  ChannelFrequencies[channel] = frequency;
  unsigned long cycleTime = 1000000 / frequency;
  ChannelOnTimes[channel] = cycleTime * DutyCycle;
  ChannelOffTimes[channel] = cycleTime - ChannelOnTimes[channel];
}

void loop()
{
  for (byte i = 0; i < ChannelCount; i++)
  {
    if (ChannelStates[i])
    {
      // HIGH
      if (micros() - ChannelTimers[i] >= ChannelOnTimes[i])
      {
        ChannelTimers[i] += ChannelOnTimes[i];
        ChannelStates[i] = LOW;
        digitalWrite(ChannelPins[i], ChannelStates[i]);
      }
    }
    else
    {
      // LOW
      if (micros() - ChannelTimers[i] >= ChannelOffTimes[i])
      {
        ChannelTimers[i] += ChannelOffTimes[i];
        ChannelStates[i] = HIGH;
        digitalWrite(ChannelPins[i], ChannelStates[i]);
      }
    }
  }
}

FYI, an Arduino DUE would give you 8 PWM with 8 different variable frequencies and variable duty cycles.

A constant duty cycle and a change in frequency are NOT exclusive on this board, provided you update the Duty cycle register so that the duty cycle keeps constant (e.g. 50%).

Hi John
Thanks for you input.
Will have a look at your code and se if i can get it to work tomorrow.
As far as I can see, the code you put as an example gives the same frequency on all pins?
How do you tie it to a analog input?

I in my original code wnat to use a duty cycle of 3000 insted. Do I still use 0.9842 as in your example

Hi ard_newbie

So then I can use my original code to make it work?
Have you some more info for me on it?

johnwasser:
You mean at the instant of change, right? Because you can certainly generate a square wave (50% duty cycle) at more than one frequency.

Exactly. Called "glitches".

Paul

psathammer:
As far as I can see, the code you put as an example gives the same frequency on all pins?
How do you tie it to a analog input?

Call SetChannelFrequency( channel, frequency); whenever you want to change the frequency of one of the output channels.

psathammer:
So then I can use my original code to make it work?
Have you some more info for me on it?

There are numerous PWM example skeches in the DUE sub forum, or use pwm_lib from antodom for the DUE.