Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

question on arduino PWM code

Status
Not open for further replies.

fm101

Member level 5
Joined
Apr 13, 2020
Messages
81
Helped
1
Reputation
2
Reaction score
4
Trophy points
18
Activity points
591
I got the following code from the internet. It is used to output sine signal using PWM.
(1)What I don't understand is that why there are two outputs from pin 4 and 10? output from pin 10 seems only square wave and not pwm for sine wave
(2) What is frequency of sine wave from pin 4 output?
(3) is it possible to output pwm sine signal on pin 10 for higher frequency 31250 Hz using the same code for pin 4?

thanks

C-like:
uint8_t pVal = 127; //PWM value
const float pi2 = 6.28; //Pie times 2, for building sinewave
const int samples = 100; //number of samples for Sinewave. This value also affects frequency
int WavSamples[samples]; //Array for storing sine wave points
int count = 0; //tracks where we are in sine wave array

void setup() {
// Serial.begin(115200); //for debugging
  pinMode(10, OUTPUT); //pin used for analog voltage value
  pinMode(4,OUTPUT); //pin used to fake PWM for sinewave
  setPwmFrequency(10,1); //function for setting PWM frequency
  analogWrite(10,127); //set duty cycle for PWM

  float in, out; //used for building sine wave
 
  for (int i=0;i<samples;i++) //loop to build sinewave
  {
    in = pi2*(1/(float)samples)*(float)i; //calculate value for sine function
    WavSamples[i] = (int)(sin(in)*127.5 + 127.5); //get sinewave value and store in array
   // Serial.println(WavSamples[i]); //for debugging
  }
}

void loop() {
  if(count > samples) count = 0; //reset the count once we are through array
  bitBangPWM(WavSamples[count],4); //function for turning sinewave into "fake" PWM signal
  count++; //increment position in array
}

//Function to bit bang a PWM signal (we are using it for the sinewave)
//input are PWM high value for one cycle and digital pin for Arduino
//period variable determines frequency along with number of signal samples
//For this example a period of 1000 (which is 1 millisecond) times 100 samples is 100 milli second period so 10Hz
void bitBangPWM(unsigned long on, int pin) {
  int period = 1000; //period in micro seconds
  on = map(on, 0, 255, 0, period); //map function that converts from 8 bits to range of period in micro sec
 // Serial.println(on); //debug check
  unsigned long start = micros(); //get current value of micro second timer as start time
  digitalWrite(pin,HIGH); //set digital pin to high
  while((start+on) > micros()); //wait for a time based on PWM duty cycle
  start = micros();
  digitalWrite(pin,LOW); //set digital pin to low
  while((start+(period - on)) > micros()); //wait for a time based on PWM duty cycle
}

/**
 * https://www.arduino.cc/en/Tutorial/SecretsOfArduinoPWM
 * Divides a given PWM pin frequency by a divisor.
 *
 * The resulting frequency is equal to the base frequency divided by
 * the given divisor:
 *   - Base frequencies:
 *      o The base frequency for pins 3, 9, 10, and 11 is 31250 Hz.
 *      o The base frequency for pins 5 and 6 is 62500 Hz.
 *   - Divisors:
 *      o The divisors available on pins 5, 6, 9 and 10 are: 1, 8, 64,
 *        256, and 1024.
 *      o The divisors available on pins 3 and 11 are: 1, 8, 32, 64,
 *        128, 256, and 1024.
 *
 * PWM frequencies are tied together in pairs of pins. If one in a
 * pair is changed, the other is also changed to match:
 *   - Pins 5 and 6 are paired on timer0
 *   - Pins 9 and 10 are paired on timer1
 *   - Pins 3 and 11 are paired on timer2
 *
 * Note that this function will have side effects on anything else
 * that uses timers:
 *   - Changes on pins 3, 5, 6, or 11 may cause the delay() and
 *     millis() functions to stop working. Other timing-related
 *     functions may also be affected.
 *   - Changes on pins 9 or 10 will cause the Servo library to function
 *     incorrectly.
 *
 * Thanks to macegr of the Arduino forums for his documentation of the
 * PWM frequency divisors. His post can be viewed at:
 *   http://forum.arduino.cc/index.php?topic=16612#msg121031
 */
void setPwmFrequency(int pin, int divisor) {
  byte mode;
  if(pin == 5 || pin == 6 || pin == 9 || pin == 10) {
    switch(divisor) {
      case 1: mode = 0x01; break;
      case 8: mode = 0x02; break;
      case 64: mode = 0x03; break;
      case 256: mode = 0x04; break;
      case 1024: mode = 0x05; break;
      default: return;
    }
    if(pin == 5 || pin == 6) {
      TCCR0B = TCCR0B & 0b11111000 | mode;
    } else {
      TCCR1B = TCCR1B & 0b11111000 | mode;
    }
  } else if(pin == 3 || pin == 11) {
    switch(divisor) {
      case 1: mode = 0x01; break;
      case 8: mode = 0x02; break;
      case 32: mode = 0x03; break;
      case 64: mode = 0x04; break;
      case 128: mode = 0x05; break;
      case 256: mode = 0x06; break;
      case 1024: mode = 0x07; break;
      default: return;
    }
    TCCR2B = TCCR2B & 0b11111000 | mode;
  }
}
 

Hi,

Did you watch the video, where he explains the "bit bang pwm on pin 4" and the "hardware PWM in pin 10"?
...and that he uses the bit bang mode to generate the sinewave.

If yes, what exactly is unclear?

Btw: I personally don't like the bit bang solution.
The answer is also shown (but nit explained) in the video.
At first he sets the frequency to get 10 Hz. On the scope we can see 9.something Hz. While most people don't worry about the tiny difference...but me does.
Indeed the code uses "busy wait" for frequency timing... he expects 1000us...but there is code that needs to be processed outside his "1000us wait" so the total loop lasts 1000us + something. In the video the scope shows 9.39Hz means it is 6.5% too slow.
It is 1000us + 65us (fix delay by code).
But then he switches to 100us ... but in real world it is 100us + 65us = 165us ... now he is 65% slow.
The expected 100Hz sinewave becomes 100Hz/1.65 = 60.6Hz.

Every modern microcontroller provides
* interrupts (for exact timing, even in bit bang mode)
* or hardware timed PWM.
Both solutions give exact frequency output. No added timing error. Just the error of the system clock frequency.

You also should know:
* the video solution uses 100% of pricessing power. If you want the microcontroller to do anything else it will vary the "65us" delay. Every reaction on a button press or UART action will vary the output frequency.
* the interrupt controlled but bang solution maybe takes 5% of processing power. You have plenty 95% processing power to react on jey press or UART without shift in frequency
* the hardware PWM maybe takes 2% of processing power...with perfect frequency output.

While mist parts of the video is very good and descriptive (like the 2nd order LPF) .... I miss the frequency accuracy.
... My personal opinion.

Interrupt and hardware_PWM is no rocket science. Once used you will love it, because it works perfectly without special care.

Klaus
 

hi,
thanks for detailed explanation & time. of course and i agree, the exact frequency is crucial after all the aim here is to produce sine wave of specific frequency for use.i watched the video (more closely). in the end of video he is confused about how he got the 64hz signal instead of 100hz and your analysis makes sense. he did make good educational video expect for that part.

I have one question though, what is the difference between sine wave produced from pin 10 and pin 4?
1)On pin 10 he is outputting, a square wave of 50% duty cycle of certain frequency which when filtered should give sine wave. But since it is a square wave, the pulse width is not changing so should this be called PWM?
2)On pin 4 he is outputting, a PWM signal with varying pulse width corresponding to sine sample and using 2nd order filter to get sine wave

thanks,
 

Hi,

Pin 10 uses hardware PWM. (often used for LED brightness control)
Pin 4 is toggled by software (bit bang PWM)

1) you are right. He is ouputting 50% duty cycle square wave.
A square wave consists of several sine waves:
* the fundamental,
* 3x fundamental with 1/3 amplitude,
* 5x fundamental 1/5 amplitude,
* 7x fundamental 1/7 amplitude
* ...and son on.

So if you filter all overtones away, then the fundamental sine wave remains.

2) Yes.

***
What hardware/microcontroller do you use?

Klaus
 

Hi,

AFAIK: arduinio uno uses some kind of ATMEL AVR microcontroller.
Then the best way is to use the timer overflow to set a new PWM value.

Do a serach for "arduino UNO SPWM". ... or similar
Look for code that uses the timer(x) interrupt to set the new PWM value.
Then you get perfect (In frequency, amplitude, jitter, noise) results.

Klaus
 

so just to get sine wave of certain frequency it is adequate to produce square wave and use filter, no need for SPWM, is this so?
 

Hi,

it depends.

if you want low distortion (low overtones) and/or variable frequency .. the better choice is an SPWM.

for fixed frequency not too high quality .. the squarewave_and_filter method is suitable and easier.
 
final question:
i want to generate sine wave with highest frequency possible with arduino and according to the code above is 31250Hz, is it possible to get SPWM with that frequency?

thanks
 

I agree it is not rocket science but you have to learn the basics.

PWM is not trivial; you need to know the hardware and software rather intimately. Sometimes even reading the manual appear intimidating.

I always suggest doing a 16 or 64 step sine approximation because you can see the results if you have access to a scope.

But once you learn how to handle the timers you have learnt a lot.

I agree it is not rocket science.
 

i want to generate sine wave with highest frequency possible with arduino and according to the code above is 31250Hz, is it possible to get SPWM with that frequency?
no.
if the PWM frequency is 31kHz then you can generate maximum 1/2 of it as sine frequency (Nyquist). But then you just have two "points" per fullwave.
An almost useful sine waveform starts with 8 points ... quite good ones with 32 points. The more points the better.

You may increase the PWM frequency by reducing the PWM resolution.

But if you want some simple clean sinewave.. there are IC´s doing it for you. Either analog ones with a pot as frequency adjustment, or a digital one (DDS).
DDS gives fixed (adjustable via digital interface), non drifting frequency and good sine waveform.

Klaus
 
so just to get sine wave of certain frequency it is adequate to produce square wave and use filter, no need for SPWM, is this so?
A square wave can be shaped to resemble a sine by:
* Series L, C, load
or
* 2nd order LC filter (load across C).

The inductor value needs to be greater than that for SPWM. Since duty cycle is 100 percent, the power source can be lesser voltage and current than for SPWM.

A middle alternative is to apply equal length pulses (comb-like). The inductor can be a middle value between the already-mentioned methods.

In all methods the L & C values need to be tailored to the load & frequency.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top