Go Down

Topic: PWM frequency library (Read 366306 times) previous topic - next topic

dhruvrastogi

Hi everyone,

I want to use the library on my Mega 2560 to generate a PWM of 20kHz. I have been able to do so on my Uno but my waveform is getting distorted in Mega. I will really appreciate some help in understanding where I am going wrong.

The code I used is as follows:

Code: [Select]
#include <PWM.h>


void setup()
{
  // put your setup code here, to run once:
  pinMode(3, OUTPUT);
  InitTimersSafe();
  bool success = SetPinFrequency(3,20000);
}

void loop()
{
  // put your main code here, to run repeatedly:
  pwmWrite(3, 127);
 
}

lucian_v

Hi,
I am using this library to change frequency using pin9 on an arduino mini pro and is working fine but I want to ask if is possible to change pwm resolution using this library?

I mean now I can set values between 1 to 255 for duty cycle, that means 8 bits. Can this be somehow changed to have 10 bits (1024 values) or even more? Is there any way doing that with this library?

Thank you

stajo

Well this lib for sure aint working anymore, even if I fixed the issue according to post #135. I could get one timer working at the same time, after the fix I got another working, but then I couldnt get the first working.

mabos

Hi,

I am thinking about converting an old inverter welder to use an Arduino to switch on/off the two IGBT:s that control the welding current by sending a positive or a negative voltage to a transformer, to create the MMA welding current.

The idea is to start with just mimicking the existing welder control electronics that gives a PWM signal at 19 kHz. This works fine with the pwm.h library. However, I need to control two IGBT:s in the welder with two pins on the Arduino in such a way that when one pin goes high the other one goes low. So essentially, I want to invert the time axis for the output to one of the two PWM pins. Any idea about if this can be done by tweaking the library?

An other way to do it would to phase shift one of the signals, but then the phase shift has to be recalculated when the duty cycle is changed, since the two pins must never be high simultaneously.

If I can get this to work the next step would be to fine tune the welder behaviour with the welding current as input data.

wildcat99s

#214
Sep 18, 2019, 01:54 am Last Edit: Sep 18, 2019, 01:58 am by wildcat99s
Hello.  does anyone know if this library is still usable?  I found this webpage https://circuitdigest.com/microcontroller-projects/arduino-waveform-generator

on how to build an adjustable waveform generator.  And then stumbled onto this topic which seems to use the same library.  Tho i'm thinking someone else used the library to make this waveform generator webpage.

I've been able to install the library and upload the code, which was posted on the bottom of the website.  I had to make a couple minor changes to accept my LCD screen, but that's it.   It'll upload fine, but it's like the encoder isn't working, and it's new, and identical to the one he used.  but for some reason the code isn't working for me.  The frequency multiplier seems to change on it's own, starts at 1, then 10, 100, 1000, and then stays there.  If i turn the encoder, sometimes it will register and make the adjustment.... but i'm lucky to get it to change at all.

here's the code i'm using.  any ideas on what could be the problem.  i know it mentions modifying the internal timers, and didn't know if that's something that my arduino IDE 1.8.8 is blocking or effecting somehow... or if there's something else going on.

one thing i've noticed, tho not sure if it's related.  when i've added the library, #include <PWM.h>, the PWM isn't highlighted like rest of the libraries are.  so i wasn't sure if that's because it's a non-arduino approved library, or if it's not actually uploading the library.

thanks

Code: [Select]


#include <PWM.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27,20,4);



int Encoder_OuputA  = 11;
int Encoder_OuputB  = 12;
int Encoder_Switch = 10;
int Previous_Output;
int multiplier = 1;

double angle = 0;
double increment = 0.2;

const int signal_pin = 9; 
const int Sine_pin = 5;
int32_t frequency; //frequency to be set
int32_t lower_level_freq = 1; //Lowest possible freq value is 1Hz
int32_t upper_level_freq = 100000; //Maximum possible freq is 100KHz

void setup()
{
  lcd.init(); //Initialise  LCD
  lcd.backlight();
  lcd.setCursor(0, 1);
  lcd.print("Signal Generator"); //Intro Message line 1
 
  lcd.print("-CircuitDigest "); //Intro Message line 2
  delay(2000);
  lcd.clear();
  lcd.print("Freq:00000Hz");
  lcd.setCursor(0, 1);
  lcd.print("Inc. by: 1 ");
 
  Serial.begin(9600); //Serial for debugging
  InitTimersSafe(); //Initialize timers without disturbing timer 0
 
//pin Mode declaration
  pinMode (Encoder_OuputA, INPUT);
  pinMode (Encoder_OuputB, INPUT);
  pinMode (Encoder_Switch, INPUT);

  Previous_Output = digitalRead(Encoder_OuputA); //Read the inital value of Output A

 attachInterrupt(0,generate_sine,CHANGE);
}

 

void loop()
{
  if (digitalRead(Encoder_OuputA) != Previous_Output)
   {
     if (digitalRead(Encoder_OuputB) != Previous_Output)
     {
       frequency = frequency + multiplier;
      Serial.println(frequency);
       pwmWriteHR(signal_pin, 32768); //Set duty cycle to 50% by default -> for 16-bit 65536/2 = 32768
       SetPinFrequencySafe(signal_pin, frequency);
       lcd.setCursor(0, 0);
       lcd.print("Freq:     Hz");
       lcd.setCursor(5, 0);
       lcd.print(frequency);
     }
     else
     {
       frequency = frequency -   multiplier;
       
Serial.println(frequency);
       pwmWriteHR(signal_pin, 32768); //Set duty cycle to 50% by default -> for 16-bit 65536/2 = 32768
       SetPinFrequencySafe(signal_pin, frequency);
       lcd.setCursor(0, 0);
       lcd.print("Freq:     Hz");
       lcd.setCursor(5, 0);
       lcd.print(frequency);
     }
   }

      if (digitalRead(Encoder_Switch) == 0)
   {
   multiplier = multiplier * 10;

   if (multiplier>1000)
   multiplier=1;
   
  Serial.println(multiplier);
   lcd.setCursor(0, 1);
   lcd.print("Cng. by:     ");
   lcd.setCursor(8, 1);
   lcd.print(multiplier);
   
   delay(500);
   while(digitalRead(Encoder_Switch) == 0);
   }

   Previous_Output = digitalRead(Encoder_OuputA); 
 
}

void generate_sine()
{
   double sineValue = sin(angle);
   sineValue *= 255;
   int plot = map(sineValue, -255, +255, 0, 255);
   Serial.println(plot);
   analogWrite(Sine_pin,plot);
   angle += increment;

   if (angle > 180)
   angle =0;
}


J-M-L

I'd written something not to far (without the Sine Wave stuff) that will work with an I2C LCD, a rotary encoder and switch and the PWM Frequency library.

rotating the know increases or decreases the frequency and clicking on the knob will switch the steps between 1,10,100, 1k, 10k, 100k, display the value you set on the 1st line of the LCD  and the actual frequency the UNO achieves on the second line.

I've just tested it again after recompiling with the current IDE and checked on my oscilloscope and it seems to work fine all the way to 2MHz.

here is the code:
Code: [Select]
// -----------------------------------------
// written for Arduino UNO, should work on a Mega is you switch the frenquencyPin to 11
// Leveraging multiple libraries (see links below)
// Author: J-M-L for Arduino Forum (https://forum.arduino.cc/index.php?action=profile;u=438300)
// originally posted at  https://forum.arduino.cc/index.php?topic=117425.msg4309683#msg4309683
//
// Pin 0 & 1 : left unused for Serial
// Pin 2 to rotary encoder DT  (will use interrupts)
// Pin 3 to rotary encoder CLK (will use interrupts)
// Pin 4 to rotary encoder SW
// Pin 5
// Pin 6
// Pin 7
// Pin 8
// Pin 9 The Pin exhibing the frequency
// Pin 10
// Pin 11
// Pin 12
// Pin 13
// Pin A0
// Pin A1
// Pin A2
// Pin A3
// Pin A4 to I2C SDA (LCD)
// Pin A5 to I2C SCL (LCD)
// -----------------------------------------

#include <PWM.h> // https://github.com/terryjmyers/PWM (https://forum.arduino.cc/index.php?topic=117425.msg883455#msg883455)

// As frequency increases, resolution will decrease and you won't get the exact match
const long MinFrequency = 0L; // 0 Hz
const long MaxFrequency = 2000000L; // 2 MHz

const byte frenquencyPin = 9;

#include <LiquidCrystal_I2C.h> // https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library
LiquidCrystal_I2C lcd(0x27, 16, 2); // 16 cols, 2 lignes. I2C address is 0x27. connect LDC's SDA on A4, SCL on A5

#include <Encoder.h> // https://www.pjrc.com/teensy/td_libs_Encoder.html
Encoder rotaryEncoder(2, 3); // connect pin D2 to Encoder's DT & D3 to Encoder's CLK)

#include <simpleBouton.h> // http://forum.arduino.cc/index.php?topic=375232.0  @bricoleau efficient button's library.
simpleBouton encoderSwitch(4);// connect pin D4 to Encoder's SW

long currentFrequency;
long currentRotaryValue;

enum : long {x1 = 1L, x10 = 10L, x100 = 100L, x1000 = 1000L, x10000 = 10000L, x100000 = 100000L} stepMultiplier = x1;

void displayFrequencyTarget(long f)
{
  char freqMessage[20];
  dtostrf(f, 7, 0, freqMessage); // right aligned, white space padding 7 positions to accomodate from 0 to 2000000
  strcat(freqMessage, "Hz");
  Serial.println(freqMessage);
  lcd.setCursor(0, 0);
  lcd.print(freqMessage);
}

void displayActualFrequency()
{
  char freqMessage[20];
  dtostrf(Timer1_GetFrequency(), 7, 0, freqMessage); // right aligned, white space padding 7 positions to accomodate from 0Hz to 2000000Hz
  strcat(freqMessage, "Hz");
  Serial.println(freqMessage);
  lcd.setCursor(0, 1);
  lcd.print(freqMessage);
}

void displayStepMultiplier()
{
  char multMessage[20];
  switch (stepMultiplier) {
    case x1: strcpy(multMessage,      "   1"); break;
    case x10: strcpy(multMessage,     "  10"); break;
    case x100: strcpy(multMessage,    " 100"); break;
    case x1000: strcpy(multMessage,   "  1k"); break;
    case x10000: strcpy(multMessage,  " 10k"); break;
    case x100000: strcpy(multMessage, "100k"); break;
  }
  Serial.println(multMessage);
  lcd.setCursor(12, 0);
  lcd.print(multMessage);
}

void setup()
{
  Serial.begin(115200);         // initialize Serial connection
  lcd.begin();                  // initialize the LCD
  lcd.backlight();

  currentRotaryValue = 0;// initialize the rotary encoder
  rotaryEncoder.write(currentRotaryValue);

  InitTimersSafe(); //initialize all timers except for 0, to save time keeping functions
  currentFrequency  = 0L;
  displayFrequencyTarget(currentFrequency);
  displayStepMultiplier();
  pwmWriteHR(frenquencyPin, 32768u);
  SetPinFrequency(frenquencyPin, currentFrequency);  //setting the frequency
}

void loop()
{
  // modify step factor
  if (encoderSwitch) {
    switch (stepMultiplier) {
      case x1: stepMultiplier = x10; break;
      case x10: stepMultiplier = x100; break;
      case x100: stepMultiplier = x1000; break;
      case x1000: stepMultiplier = x10000; break;
      case x10000: stepMultiplier = x100000; break;
      case x100000: stepMultiplier = x1; break;
    }
    displayStepMultiplier();
  }

  long newRotaryValue = rotaryEncoder.read() >> 1;   // my rotary delivers 2 ticks per step, others delivers 4 in which case do >>2

  if (newRotaryValue != currentRotaryValue) { // we turned the knob
    long newFrequency = currentFrequency + (newRotaryValue - currentRotaryValue) * stepMultiplier;
    currentRotaryValue = newRotaryValue;
    newFrequency = constrain(newFrequency, MinFrequency, MaxFrequency);

    if (newFrequency != currentFrequency) {
      currentFrequency = newFrequency;
      displayFrequencyTarget(currentFrequency);
      pwmWriteHR(frenquencyPin, 32768u);
      if (SetPinFrequencySafe(frenquencyPin, currentFrequency)) displayActualFrequency();
    }
  }
}


Note that the library I use for the rotary encoder connected to those pins will switch to interrupt based tick capture, so you can't use those pins for the sine wave of the example. The library works though with only 1 pin on interrupt (or none) so you could free up pin 2 to generate the the Sine wave.

of course issuing ISR at 2MHz would put quite a toll on your UNO and so you should not go that far then.

Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

wildcat99s

I tried to compile the code and it's not letting me because i have a nano.  But i do have a spare uno and mega 2560 i'll try it on later.

i was able to play around with the code i posted yesterday, and got it to do a little more.  But there is something wrong somewhere as the rotary encoder isn't working like it's supposed too.  but i'm gonna continue working on it on my free time to see if i can get it working.

For the moment i'm just crudely coding a PWM so i can run a mosfet to control a homemade hot air soldering gun using a gas drier igniter element and a small air pump so i can repair a computer motherboard.  but i would like to get a working frequency generator so i can test some transformers i want to make in the future.

J-M-L

#217
Sep 18, 2019, 08:05 pm Last Edit: Sep 18, 2019, 08:09 pm by J-M-L
I tried to compile the code and it's not letting me because i have a nano.
It should compile just fine (I just did), you need to install the 4 libraries I'm using:

Code: [Select]
#include <PWM.h> // https://github.com/terryjmyers/PWM (https://forum.arduino.cc/index.php?topic=117425.msg883455#msg883455)
#include <LiquidCrystal_I2C.h> // https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library
#include <simpleBouton.h> // http://forum.arduino.cc/index.php?topic=375232.0  @bricoleau efficient button's library.
#include <Encoder.h> // https://www.pjrc.com/teensy/td_libs_Encoder.html




don't try to reinvent the wheel - focus on solving your specific use case and leverage an existing Rotary encoder library. This one is pretty stable and proven
Code: [Select]
#include <Encoder.h> // https://www.pjrc.com/teensy/td_libs_Encoder.htmlThat's what I have used in the example above

once your stuff work, if you want to use your own code for the encoder then you'll have a "simple" step
Hello - Please do not PM me for help,  others will benefit as well if you post your question publicly on the forums.
Bonjour Pas de messages privés SVP, postez dans le forum directement pour que ça profite à tous

JacksonAudio

Did anyone ever have any luck getting this to work on an Atmega1284? I'm stuck at this point.

Go Up