Question on the Arduino Uno adjusting high frequency PWM

Dear all,

I am writing to ask for help on the arduino uno programming on the high frequency PWM adjusting.

In my project, I am thinking to first receive high frequency PWM input, and read it, then reproduce a new pwm with adjusted duty cycle. The factor adjusting the new PWM duty cycle is based on the Photovaristor value.

The operating freuency is about 150kHz.

below is the program with adjusting duty cycle from input of the photovaristor value, it already able dim the led lamp in 150kHZ.


const byte LED = 3; // Timer 2 "B" output: OC2B
int divider =10;
const long frequency = 150000L; // Hz (eg:150000=150khz)
int inputPin = 2; // set the analog input at pin2
int val = 0; // create variable
void setup() 
{ Serial.begin(9600);
pinMode (LED, OUTPUT);

TCCR2A = _BV (WGM20) | _BV (WGM21) | _BV (COM2B1); // fast PWM, clear OC2B on compare
TCCR2B = _BV (WGM22) | _BV (CS21); // fast PWM, prescaler of 8
OCR2A = ((F_CPU / 8) / frequency) - 1; // zero relative 
//OCR2B = ((OCR2A + 1) / 2) - 1; // 50% duty cycle
} // end of setup

void loop()
{ 
//divider=1	100% val<500 dark val>500 normal light
//divider=2	50%
//divider=3	33%
//divider=4	25%
//divider=10	10%

val = analogRead(inputPin); 
Serial.write("val: "); 
Serial.print(val); //print the received input data to serialmonitor
Serial.write(" divider: "); 
if (val>10 && val<=200 ){ divider =1; }
if (val>200 && val<=400 ){ divider =2; }
if (val>400 && val<=600 ){ divider =3; }
if (val>600 && val<=800 ){ divider =4; }
if (val>800 && val<=1000 ){ divider =10; }
delay(50); 
Serial.print(divider); 
Serial.println(""); 
OCR2B = ((OCR2A + 1) / divider) - 1; 
// do other stuff here
}

But the problem now is how can I able to read the high frequency PWM.
The input PWM will be 10V at frequency 150kHZ(may change a bit)

Thank You.

QQ11011

How to use this forum

Please edit your post, select the code, and put it between [code][/code] tags.

You can do that by hitting the # button above the posting area.

Thank you for advice.

In the post problem, the key problem is how to get the digital pulse in PWM form( square wave),150kHz( may vary +- 10%), 10V into the Arduino Uno and successfully read the PWM. I also want to know the duty cycle of the input PWM signal.

Thank You.

I can’t help but think there’s got to be many cheap/easy hardware solutions. The number 5 keeps running through my mind. 5 - 5 - 5, for some reason 5! And the word ‘crystal’…

Run the input through a RC filter that gives an analog voltage proportional to the duty cycle. Read that with analogRead. Then do a PWM output with parameters suitably adjusted.

Thank You for advice.

Once again, I modified the program above to generate a high frequency 150kHz PWM square wave in Pwm output pin.
Then I connect the circuit as shown below, the output of circuit connect back to the analog-in pin 3 and use analogRead to read it.

Pwm output------1K ohm---------Pin3
!
!
0.01uF
!
Ground

I found out the the serial monitor show the value of analogRead vary a lot. Is it because the circuit parameter are not correct?( As I am new with RC filter.) Or it is because the program run too slow?...confused.

Below is the program.

const byte LED = 3;  // Timer 2 "B" output: OC2B

const long frequency = 150000L;  // Hz (eg:150000=150khz)
int PWMinputPin = 3;
int PWMinputvalue = 0;// set the analog input at pin2

void setup() 
 {  Serial.begin(9600);
  pinMode (LED, OUTPUT);

  TCCR2A = _BV (WGM20) | _BV (WGM21) | _BV (COM2B1); // fast PWM, clear OC2B on compare
  TCCR2B = _BV (WGM22) | _BV (CS21);         // fast PWM, prescaler of 8
  OCR2A =  ((F_CPU / 8) / frequency) - 1;    // zero relative  
  OCR2B = ((OCR2A + 1) / 3) - 1;             
  }  // end of setup

void loop()
  { PWMinputvalue = analogRead(PWMinputPin);
     Serial. println(PWMinputvalue);
     delay(500);
  }

Apart from the RC filter problem, I also concern on the program of PWM output in post 1.
As shown in the program below, the code " OCR2B = ((OCR2A + 1) / divider) - 1;" is placed in the void loop() rather than in the void setup(). I want to ask is it ok and wont damage the arduino board.

( As I read some post in this forum mentioned it is not good to change the timer in loop)
website: http://arduino.cc/forum/index.php?PHPSESSID=21c39dcf229523a4f56770bf3d8a20d1&/topic,128269

Thank You.

Below is the program of PWM output with adjustable value based on the photovaristor

const byte LED = 3; // Timer 2 "B" output: OC2B
int divider =10;
const long frequency = 150000L; // Hz (eg:150000=150khz)
int inputPin = 2; // set the analog input at pin2
int val = 0; // create variable
void setup() 
{ Serial.begin(9600);
pinMode (LED, OUTPUT);

TCCR2A = _BV (WGM20) | _BV (WGM21) | _BV (COM2B1); // fast PWM, clear OC2B on compare
TCCR2B = _BV (WGM22) | _BV (CS21); // fast PWM, prescaler of 8
OCR2A = ((F_CPU / 8) / frequency) - 1; // zero relative 
//OCR2B = ((OCR2A + 1) / 2) - 1; // 50% duty cycle
} // end of setup

void loop()
{ 
//divider=1	100% val<500 dark val>500 normal light
//divider=2	50%
//divider=3	33%
//divider=4	25%
//divider=10	10%

val = analogRead(inputPin); 
Serial.write("val: "); 
Serial.print(val); //print the received input data to serialmonitor
Serial.write(" divider: "); 
if (val>10 && val<=200 ){ divider =1; }
if (val>200 && val<=400 ){ divider =2; }
if (val>400 && val<=600 ){ divider =3; }
if (val>600 && val<=800 ){ divider =4; }
if (val>800 && val<=1000 ){ divider =10; }
delay(50); 
Serial.print(divider); 
Serial.println(""); 
[b]OCR2B = ((OCR2A + 1) / divider) - 1; [/b]
// do other stuff here
}

The capacitor you chose was too small to smooth properly. Here is what it looks like:

10 nF capacitor:

247
376
203
302
306
248
375
324
261
361
291
264
380
307
340
342
275
302
361
247

Changing to a bigger capacitor:

100 nF capacitor:

319
312
306
319
314
308
317
311
309
318
312
316
315
309
312

Changing to a 1 uF capacitor:

1 uF capacitor:

314
313
312
311
316
312
311
313
312
314
313
312
315
312
312
314
313
311

That's probably big enough, now just take an average over a few samples.

qq11011:
As shown in the program below, the code " OCR2B = ((OCR2A + 1) / divider) - 1;" is placed in the void loop() rather than in the void setup(). I want to ask is it ok and wont damage the arduino board.

It won't damage anything. I think it would be best to change it only if necessary. Writing to the register all the time might change the way the timer counts, however if you test if the new value is different to the old one, and only change OCR2B then, it should be OK.

How much capacitor would it take to flatten default 490-some Hz PWM?

Thank You for advice.

As I am constructing my new program, I still have some questions want to ask,
(Below code is first detect the Photovaristor value then futher analysis PWM input to generate new PWM)

        if (light>=0 && light<=500  )        //not completed
           {  if (PWMinputvalue>=0 && PWMinputvalue<=102 ){  OCR2B = ((OCR2A + 1) / 10) - 1;       }
              if (PWMinputvalue>102 && PWMinputvalue<=204 ){  OCR2B = ((OCR2A + 1)*2/ 10) - 1;       }
              if (PWMinputvalue>204 && PWMinputvalue<=306 ){  OCR2B = ((OCR2A + 1)*3/ 10) - 1;       }
              if (PWMinputvalue>306 && PWMinputvalue<=408 ){  OCR2B = ((OCR2A + 1)*4/ 10) - 1;       }
              if (PWMinputvalue>408 && PWMinputvalue<=510 ){  OCR2B = ((OCR2A + 1)*5/ 10) - 1;       }
              if (PWMinputvalue>510 && PWMinputvalue<=612 ){  OCR2B = ((OCR2A + 1)*6/ 10) - 1;       }
              if (PWMinputvalue>612 && PWMinputvalue<=714 ){  OCR2B = ((OCR2A + 1)*7/ 10) - 1;       }
              if (PWMinputvalue>714 && PWMinputvalue<=816 ){  OCR2B = ((OCR2A + 1)*8/ 10) - 1;       }
              if (PWMinputvalue>816 && PWMinputvalue<=918 ){  OCR2B = ((OCR2A + 1)*9/ 10) - 1;       }   
              if (PWMinputvalue>918 && PWMinputvalue<=1020 ){  OCR2B = ((OCR2A + 1)*10/ 10) - 1;     }           
           }

Questions:
[1] Is it ok to change the equation of register in different math calculation?The important issue is OCR2B need not to higher than OCR2A,right?

[2] As shown in the above code, I just divided the range of 0-1023 of PWMinputvalue into ten group and generate new PWM signal with ten duty cycle group, I want to know how to be more precise on the proportional PWM average voltage to PWMinputvalue (analogRead).

[3]As these code will place in void loop(), I also concern on is it necessary to add delay(xx);?

Thank You.

  1. I think you can change OCR2A and OCR2B. Yes, OCR2B should not be higher than OCR2A or it cannot PWM as it never reaches the count.

  2. What numbers are you coming up with? The higher the frequency the lower the available resolution because you are dealing in smaller numbers. Say for example OCR2A is 10, then OCR2B can only be 0 to 9 thus giving you only 10% increments.

  3. I don't see any need for delay unless you want to slow down serial prints or something.

Thank you for advice.

For the frequency set to 150kHz,
Is it possible to change the prescaler of 8 to 1 such that the OCR2A become106.667 ,(((16000000/1)/150000)+1)-1
then I can adjust the equation of OCR2B to have more increments, relatively more precise.