Set fast PWM signal controlling DC through serial

Hi all,

I'm using an Arduino UNO to control a PWM signal at 32kHz. I'm sending the duty cycle for the signal through the serial port from a cpp driver I wrote. This duty cycle is a value between 110 (smallest dc i need) and 255.
The Arduino recognizes the value and writes it back correctly through an ACK byte I'm sending. Therefore, my communication through the serial port seems correct.

I can also hardcode a value directly to the PWM, so the initialization and writing through analogRead are fine.

My issue comes when trying to integrate both. The scope readings show that it kind of works, since the values are sometimes fine, but mostly the signal is permanently high for some reason I don't know, and I'm lost on ideas.

Any help would be appreciated! Thanks! This is the code I have so far.

#define PINOUT	5 
#define BAUDRATE	115200

byte rdata = 127, tmp;

void setup()
{
	//define as output
	DDRD |= _BV(PINOUT);

	//enable pwm
	TCCR0A = _BV(COM0A1) | _BV(COM0B1) | _BV(WGM00); 
	TCCR0B = _BV(CS00); 

	//enable serial port comm
	Serial.begin(BAUDRATE);
}

void loop()
{
	//something is available
	if(Serial.available() > 0);
	{
		rdata = Serial.read();

		//send back an ACK
		Serial.write(rdata);
	}

	//write as fast as we can
	analogWrite(PINOUT, byte(rdata));
}

I wonder if you have the wrong concept of analogWrite() ?

When you issue an analogWrite() command it starts producing a PWM output with the duty cycle that you specify and continues doing that indefinitely until you give another analogWrite() command.

It seems to me your PC would only need to send a value when the duty cycle needs to change.

...R

This duty cycle is a value between 110 (smallest dc i need) and 255.

Can you get that range of values out of your modified PWM? The problem with changing the PWM frequency is that you don't always get the full range of values.
Also you are doing nothing to restrict the range of input values, so if you get a LF or CR that translates into a PWM value you don't want

Thanks for the replies!

@Robin
Yup, that’s what I had understood that the analogWrite does. My values change constantly and automatically so I need to send them periodically even though most of the times it’s a small change.

@Mike
I don’t think I really checked the range of values. When I’m back in the lab I’ll take a look at that, I didn’t know changing the frequency could cause an issue with my available range… I’m not sure I understand what you mean by restrict the range of input values. What are LF and CR? Still, I sanitize my input and check for errors and the correct value on the PC, and I’m pretty sure the data coming from there is correct since the value I write back is fine.

So the PWM seems to handle 110 and 255 correctly when hardcoded those values, so the range is correctly defined.

Anyone else have any idea what the issue could be? I'm stumped by this error...

Hi!

You should only change the duty cycle if it has changed.
I don't think it is a good ide to constantly call analowrite with the same value.

//something is available
	if(Serial.available() > 0);
	{
		rdata = Serial.read();

		//send back an ACK
		Serial.write(rdata);

	       //change duty cycle
	      analogWrite(PINOUT, byte(rdata));
	}

OOOOOOOOOOOOOH... now I understand what Robin2 meant.

Anyways, it still behaves weird. I added this in setup to default the PWM to off but it still goes high for some reason, even before I start sending it data.

	//initialize to off 
	analogWrite(PINOUT, 0);

I modified the loop function as olof_n suggested.

void loop()
{
	//something is available
	if(Serial.available() > 0);
	{
		rdata = Serial.read();

		//send back an ACK
		Serial.write(rdata);

		//write as fast as we can
		analogWrite(PINOUT, byte(rdata));
	}
}

It's still not working... I'm setting the PWM to be 0 duty cycle on setup, which works fine if I remove the serial comm, but once I add that if statement checking the serial port, it stops working.

if(Serial.available() > 0);

Remove the ; char.

if(Serial.available() > 0)
{
...
}

Olof, I love you man. That fixed it! I was running a while loop before that was waiting to get input until I changed it to an if statement, and I completely missed the ;

Thank you so much!

Thanks, had to look at the code a couple of times before I notised the ; char :slight_smile:

An ACK is a specific ascii character. You seem to be sending back the value which you received.