Mega Arduino 2560

I am trying to do a code using mega 2560 arduino to generate Pulse Width Modulation(PWM) with 4 KHZ and also I want to be able to change the duty cycle of PWM through the code. could you please help with that. This is my code. I feel it is not the write code. please let me know if there is a simpler way to do the code.

boolean toggle2 = 0;

void setup()

{

int LedPin = 11;

// put your setup code here, to run once:

pinMode (LedPin, OUTPUT); // set pin 11 as output (the LED pin)

Serial.begin(9600);

//int myprescaler = 6;

// initialize timer1

noInterrupts(); // disable all interrupts

TCCR2A = 0;

TCCR2B = 0;

TCNT2 = 0;

OCR2A = 249; // compare match register

TCCR2A |= (1 << WGM21); // CTC mode

//TCCR1B |= myprescaler;

TCCR2B |= (1 << CS11);

TIMSK2 |= (1 << OCIE2A); // enable timer compare interrupt

interrupts(); // enable all interrupts

}

ISR(TIMER2_COMPA_vect){//timer1 interrupt 8kHz toggles pin 9

//generates pulse wave of frequency 8kHz/2 = 4kHz (takes two cycles for full wave- toggle high then toggle low)

if (toggle2){

digitalWrite(11,HIGH);

toggle2 = 0;

}

else{

digitalWrite(11,LOW);

toggle2 = 1;

}

}

void loop() {

// put your main code here, to run repeatedly:

int LedPin = 11;

//analogWrite (LedPin,127); // sets brightness (voltage) to i

for (int i=10; i<=204; i=i+2) // increasing i value ()

{

// 204 in PWM represents 4V (max volts to get me Imax = 8mA)

// 51 in PWM represents 1V (min volts i want... Imin = 2mA)

// Serial.println (analogRead(LedPin));

delay (1);

}

for (int j=204; j>=25; j=j-2) // decreasing j value

{

analogWrite (LedPin,j);

//Serial.println (analogRead(LedPin));

delay (1);

}

}

You're right. It's not the WRITE code.
Please read the posts at the top about putting code within a post.
(Hint use tags!)

I am trying to do a code using mega 2560 arduino to generate Pulse Width Modulation(PWM) with 4 KHZ and also I want to be able to change the duty cycle of PWM through the code. could you please help with that. This is my code. I feel it is not the write code. please let me know if there is a simpler way to do the code. I am new to arduino.

boolean toggle2 = 0;


void setup() 

{

 int LedPin = 11;

 // put your setup code here, to run once:

pinMode (LedPin, OUTPUT);  // set pin 11 as output (the LED pin)

Serial.begin(9600);

//int myprescaler = 6;

 // initialize timer1 

 noInterrupts();           // disable all interrupts

 TCCR2A = 0;

 TCCR2B = 0;

 TCNT2  = 0;



 OCR2A = 249;                        // compare match register

 TCCR2A |= (1 << WGM21);                // CTC mode

 //TCCR1B |= myprescaler;

 TCCR2B |= (1 << CS11); 

 TIMSK2 |= (1 << OCIE2A);               // enable timer compare interrupt

 interrupts();                          // enable all interrupts

}



ISR(TIMER2_COMPA_vect){//timer1 interrupt 8kHz toggles pin 9

//generates pulse wave of frequency 8kHz/2 = 4kHz (takes two cycles for full wave- toggle high then toggle low)

if (toggle2){

digitalWrite(11,HIGH);

toggle2 = 0;

}

else{

digitalWrite(11,LOW);

toggle2 = 1;

}





}



void loop() {

 // put your main code here, to run repeatedly:



int LedPin = 11;



//analogWrite (LedPin,127);       // sets brightness (voltage) to i







for (int i=10; i<=204; i=i+2)   // increasing i value () 

{

 

 // 204 in PWM represents 4V (max volts to get me Imax = 8mA)

 // 51  in PWM represents 1V (min volts i want... Imin = 2mA)

// Serial.println (analogRead(LedPin));

delay (1);

}



for (int j=204; j>=25; j=j-2)   // decreasing j value 

{

 analogWrite (LedPin,j);

 //Serial.println (analogRead(LedPin));

 delay (1);

}

}

You don't need an ISR. The timer can implement PWM directly on two pins.

To get 4 kHz you have to divide the 16 MHz system clock by 4000. Timer2 is an 8-bit timer so the highest PWM divider is 256. That leaves you with a factor of 15.625 (4000/256). Since the available prescale factors are 1, 8, 64, 256, and 1024 the smallest factor above 15.625 is 64. 4000/64 = 62.5 so that gives you a choice of 62 or 63 PWM levels. One will be a little faster than 4 kHz and one will be slower than 4 kHz. You can't get exactly 4 kHz.

If you use Timer1, that has 65536 possible PWM levels. That leaves you a factor of 0.061035... (4000/65536). The smallest prescale factor aboce 0.06 is 1. 4000/1 = 4000 so you can use a maximum PWM level of 4000 and get exactly 4 kHz PWM.

Thank you for your explanation.
could you please tell me how I can change the frequency and duty cycle. Also, could you please add the code.

I'm sure SOMEONE has already written PWM code for Timer 4 on the ATmega2560. Try a Google search. Timer 4 controls PWM on Pin 6, Pin 7, and Pin 8.

I searched but I could not find the code. please add it if you can.

void setup(void) {
  // Clear the control registers
  TCCR4B = 0;
  TCCR4A = 0;

  // Set the clock prescale to 1
  TCCR4B |= (1<<CS10);

  // Set TOP to 3999.  
  // Frequency is 16 MHz / (prescale * (TOP+1)) == 4 kHz.
  ICR4 = 3999;         

  // Start at 50% Duty Cycle
  OCR4A = 2000;

  // Set mode to 14: FastPWM using ICR for TOP
  TCCR4A |= 1<<WGM41;
  TCCR4B |= (1<<WGM42) | (1<<WGM43);
          
  // Select non-inverting FastPWM  (higher numbers give higher duty cycle)
  TCCR4A |= (1<<COM4A1); 
}

void loop() {
    // Ramp duty cycle up at about 1 step per millisecond.  Reaches max in about 4 seconds.
    for (i=0; i<4000; i++) 
    OCR4A = i;  
    delay(1);
  }
}

Thank you so much for your help

Hi
when I tried this code, it give me sine wave not pulse width modulated signal (PWM).

what I am looking for is getting PWM with 4 k HZ or more and take the output from pin 11. Also, I want to be able to change the duty cycle. please help me.

What did you look at the signal with?
The output pins only put 0 and 5V, definitely a square wave looking signal.
If you are seeing sinewave, then you likely have a load on the signal, or your oscilloscope has low bandwidth and is filtering the signal to make it look sine-like.

If it HAS to be Pin 11 (which you failed to disclose before) you will have to switch to Timer 1:

void setup(void) {
  // Clear the control registers
  TCCR1B = 0;
  TCCR1A = 0;

  // Set the clock prescale to 1
  TCCR1B |= (1<<CS10);

  // Set TOP to 3999.  
  // Frequency is 16 MHz / (prescale * (TOP+1)) == 4 kHz.
  ICR1 = 3999;         

  // Start at 50% Duty Cycle
  OCR1A = 2000;

  // Set mode to 14: FastPWM using ICR for TOP
  TCCR1A |= 1<<WGM11;
  TCCR1B |= (1<<WGM12) | (1<<WGM13);
          
  // Select non-inverting FastPWM  (higher numbers give higher duty cycle)
  TCCR1A |= (1<<COM1A1); 
}

void loop() {
  // Ramp duty cycle up at about 1 step per millisecond.  Reaches max in about 4 seconds.
  for (i=0; i<4000; i++) 
      OCR1A = i;  
      delay(1);
  }
}

Thank you so much. The code worked but I do not want it to move fast with different duty cycle at the same time. I want the code to give me only 50% duty cycle then I can change it to different duty cycle by changing the code. could you please help me to develop this code.

mohareb_heba:
Thank you so much. The code worked but I do not want it to move fast with different duty cycle at the same time. I want the code to give me only 50% duty cycle then I can change it to different duty cycle by changing the code. could you please help me to develop this code.

I have fixed the code to give you the 50% duty cycle you want:

void setup(void) {
  // Clear the control registers
  TCCR1B = 0;
  TCCR1A = 0;
  // Set the clock prescale to 1
  TCCR1B |= (1<<CS10);
  // Set TOP to 3999.  
  // Frequency is 16 MHz / (prescale * (TOP+1)) == 4 kHz.
  ICR1 = 3999;         
  // Start at 50% Duty Cycle
  OCR1A = 2000;
  // Set mode to 14: FastPWM using ICR for TOP
  TCCR1A |= 1<<WGM11;
  TCCR1B |= (1<<WGM12) | (1<<WGM13);
          
  // Select non-inverting FastPWM  (higher numbers give higher duty cycle)
  TCCR1A |= (1<<COM1A1); 
}
void loop() {
//  // Ramp duty cycle up at about 1 step per millisecond.  Reaches max in about 4 seconds.
//  for (i=0; i<4000; i++) 
//      OCR1A = i;  
//      delay(1);
//  }
}

I'm surprised you couldn't figure out how to fix it yourself. I don't know how you are going to "change it to different duty cycle by changing the code" if you don't understand the code. Good luck.

I have a question as I know to get different duty cycle, we have to use analogwrite function, for example
analogwrite (64) // give 25%duty cycle
Analogwrite (127) // give 50%duty cycle
Analogwrite (191) //give 75% duty cycle

Is this write????

Is this write

No, it is not even right.

Once you start messing with the timers all the analogue write stuff goes out the window.

I studied the code and I understood how I can change the duty cycle. Now, I want to get the PWM cycle time in minutes not in Micro seconds. Do you have any idea how I can do that???
Thank you

Now, I want to get the PWM cycle time in minutes not in Micro seconds.

Nice of you to tell us this at the start. >:(

This can be done in the main software using a "blink without delay" technique, example in the IDE. Or as an interrupt driven task from the timers with the ISR counting how many times it has been called and setting any output high or low depending on that number.

Mohareb_heba:
I studied the code and I understood how I can change the duty cycle. Now, I want to get the PWM cycle time in minutes not in Micro seconds. Do you have any idea how I can do that???
Thank you

4KHz is one full cycle every 250 microseconds. HOW do you express that in minutes? 0.000004167 minutes per cycle.

Arduino site on PWM -- top hit on search words arduino pwm -- perhaps search only works for certain people
https://www.arduino.cc/en/Tutorial/SecretsOfArduinoPWM

perhaps search only works for certain people

I think it works for everyone if you hold your mouth right.