PWM Project Question

i have a unique PWM project and need advice on which platform to build it on.

project summary - two analog inputs, as example, using basic rotary pot and 5vdc to adjust input voltage from 0-5v. the output is one analog PWM signal that will vary in %PWM and frequency. one pot controls frequency (1-250Hz) and the other %PWM (10-90%). each pot is independent of the other. i would also like to have some sort of display that indicates the set frequency and %PWM. pot to output should have accuracy of 1, 1%PWM and 1Hz across the full range of each pot.

prototype summary - i have a fully working prototype on breadboard, all analog, no display. settings would be indicated by dial markings around pot knobs.

goal - my all analog solution has many discrete components and is not elegant, thus i am seeking an alternate solution, possible implemented in Arduino

can it be done with Arduino, and which one (smaller footprint is best).

can it be done with Arduino

Probably.
However, it is not easy and you might not be able to achieve every PWM value for every frequency.

Start off by trying to understand the way PWM is achieved by the use of Timer 1 and Timer 2, by reading the data sheet for the processor.

Grumpy_Mike:
Probably.
However, it is not easy and you might not be able to achieve every PWM value for every frequency.

Start off by trying to understand the way PWM is achieved by the use of Timer 1 and Timer 2, by reading the data sheet for the processor.

from some simple math, if i use 50% PWM as the reference point i can easily adjust Ton and Toff by adding/subtracting the delta % to each value.

as example, 250Hz = 0.004s cycle = t, @50%PWM thats Ton=0.002s and Toff=0.002sec = t/2
now lets say the PWM input says 40%
i would subtract 10% from Ton and add 10% to Toff
if PWM went to 60%, i would add 10% to Ton and subtract 10% from Toff

so for any given freq, cycle time t = [(Ton+(10%*Ton))+(Toff-(10%*Toff))] = t = [(Ton-(10%*Ton))+(Toff+(10%*Toff))]
Ton=Toff=t/2 because this defines 50%PWM

so there are just 3 unique states, <50%, =50%, >50%

let the code loop at the rate of t, so after every cycle the code loops to detect changes in settings. the pitfall i see is, there will be a small delay after each cycle as the code needs time to loop, but this should happen way faster than my max 250Hz.

in essence, the code runs like Ton,Toff,loop time,Ton,Toff,loop time,Ton,Toff,loop time ...... etc.

your thoughts?

Hi,
I think you need to google arduino variable frequency PWM

It has been pointed out you need to

Grumpy_Mike:
Start off by trying to understand the way PWM is achieved by the use of Timer 1 and Timer 2, by reading the data sheet for the processor.

Tom... :slight_smile:

hi Tom
i read the other docs for PWM, but from 1-250Hz do i really need to do that advanced stuff?

isnt this just simple 50%pwm @ 1Hz

void loop()
{
digitalWrite(ledPin, HIGH); // sets the LED on
delay(500); // waits for a 1/2 second
digitalWrite(ledPin, LOW); // sets the LED off
delay(500); // waits for a 1/2 second
}

delay() must be in intervals of clock speed, which is perfectly ok for my 1-250Hz needs, i can use whatever delay values that are closest to each Hz value.

i would just write my sensor reading code into the loop
i see delayMicroseconds() has a max limitation, but i can create a if-then in the loop, evaluate the value of time (freq) and then use delay() for 100Hz and below, or delayMicroseconds() for above 100Hz to 250Hz. this should allow me to get the Hz needed across the range and not run into the delayMicroseconds() max value limitation. and landing on non-integer Hz is ok, like 26ms is 38.46Hz, etc, but i would just use the nearest time value of the Hz, perhaps in some cases i jump a Hz, etc.

void loop()
{
// put all sensor reading, math, and variable settings here
// put write to LCD code here

// the delay time becomes a variable
digitalWrite(ledPin, HIGH); // sets the LED on
delayMicroseconds($ON); // waits some time
digitalWrite(ledPin, LOW); // sets the LED off
delayMicroseconds($OFF); // waits some time
}

i read the other docs for PWM, but from 1-250Hz do i really need to do that advanced stuff?

It depends on how accurate it needs to be. Once you add other stuff like

// put all sensor reading, math, and variable settings here
// put write to LCD code here

Then that itself takes up time that will not be constant. This will have the effect of making the off time actually longer than the time given in the delay. When you measure the output frequency it will jitter due to the time taken in the update the timers interrupt routine that is going off in the background.

At 250Hz you might be OK. But, don't forget that every program step takes time and I don't know if there will be enough time between state changes to write to your display (and read the pots).

And, don't forget that you're dealing with 1% of 250Hz pulse.

goal - my all analog solution has many discrete components

From what you've told us... probably not everything... :wink: you only need 2 pots.

DVDdoug:
At 250Hz you might be OK. But, don't forget that every program step takes time and I don't know if there will be enough time between state changes to write to your display (and read the pots).

And, don't forget that you're dealing with 1% of 250Hz pulse.
From what you've told us... probably not everything... :wink: you only need 2 pots.

i only need PWM range of 10-90%, below 10 and above 90 is not useful for me (except for an actual 100%, which i may map to a high side voltage threshold on the input. so in code, i would have PWM steps in the 10-90% range, and then 100%

what i stated is about everything. the Ard output will drive a small opto-isolator, the load side of opto controls a ckt in a welding machine.

Grumpy_Mike:
However, it is not easy and you might not be able to achieve every PWM value for every frequency.

very true, due to need to round the numbers used in the delay function the actual output freq and %PWM will rarely be multiples of 1

for my use, thats ok.

as for the additional delay when processing code within the loop, i can estimate that time in usec and subtract that from the Toff number, just to get closer to expected value. when i get into the delay() area the additional time used to process code in the loop will be insignificant within the use of the device.

Grumpy_Mike:
However, it is not easy and you might not be able to achieve every PWM value for every frequency.

very true, due to need to round the numbers used in the delay function the actual output freq and %PWM will rarely be multiples of 1, but for my use, thats ok.

for clarity, my prototype has 555's at the heart of it, but uses many passive/discrete components, so having just the Ard, some code, one small opto-isolator, and two pots really makes things easier for me, and, best thing of all, if i need to, i can change the code. the pro's of my prototype is that i can do analog swing of both freq and PWM.

as for the additional delay when processing code within the loop, i can estimate that time in usec and subtract that from the Toff number, just to get closer to expected value. when i get into the delay() area the additional time used to process code in the loop will be insignificant within the use of the device.

thanks all for your replies, i think my feasibility question has been answered, and thanks for the additional feedback. its not my 1st rodeo with code and ckt's, but this is literally my 1st post about Arduino, i dont even own one yet ;), i may still look at other devices/IC's to do this, but at least now i know what i can and cannot do using Ard for my needs, etc.

Arduino_Kidd:
as for the additional delay when processing code within the loop, i can estimate that time in usec and subtract that from the Toff number, just to get closer to expected value. when i get into the delay() area the additional time used to process code in the loop will be insignificant within the use of the device.

That would be a very inefficient way to do things. Just use the millis() or micros() timer to tell you when to switch on and off. No need for delay().

When you get into the hardware timers, it doesn't work like you expect. The hardware timer is just a counter. In the most basic mode, it counts up from zero to a number you specify. Part-way though that count, it finds a "match" to another number you specify. At that point it flips the output from HIGH to LOW. By changing the second number (as a % of the first) then you control the PWM duty cycle. By changing the first number and the "pre scaler" that provides clock inputs, you control the PWM frequency.

Setting up the hardware timers to do PWM is much more complex than it ought to be but the chip has been designed to support many more functions than you can imagine. Once you get it right, the thing is totally hands-off with your code just updating one or two numbers to control these complex abilities.

MorganS:
That would be a very inefficient way to do things. Just use the millis() or micros() timer to tell you when to switch on and off. No need for delay().

When you get into the hardware timers, it doesn't work like you expect. The hardware timer is just a counter. In the most basic mode, it counts up from zero to a number you specify. Part-way though that count, it finds a "match" to another number you specify. At that point it flips the output from HIGH to LOW. By changing the second number (as a % of the first) then you control the PWM duty cycle. By changing the first number and the "pre scaler" that provides clock inputs, you control the PWM frequency.

Setting up the hardware timers to do PWM is much more complex than it ought to be but the chip has been designed to support many more functions than you can imagine. Once you get it right, the thing is totally hands-off with your code just updating one or two numbers to control these complex abilities.

millis() and micros() have resolution of 4 or 8 us depending on the Ard (250kHz and 125kHz respectively). so you are still bound to discrete values of freq and %PWM

and i dont quite follow when you say change the 2nd # as a % of the 1st. when you change %PWM on fixed frequency, you have to change both the on and off times by same %, but "-" on one side and "+" on the other in order to preserve frequency.

i can estimate that time in usec and subtract that from the Toff number, just to get closer to expected value

I think you missed the point where I said:-
time that will not be constant.
The time it takes to write to an LCD depends on what you are writing.

Grumpy_Mike:
I think you missed the point where I said:-
time that will not be constant.
The time it takes to write to an LCD depends on what you are writing.

i got it.
how long does it take for an Ard to write to an LCD, "Hz=166.66" and "PWM=38.25%"? perhaps i just write to LCD once after every change of input threshold?

did input change? yes --> write LCD, no --> skip writing to LCD

how long does it take for an Ard to write to an LCD, "Hz=166.66" and "PWM=38.25%"?

I have no idea, it depends on the specific LCD and the libiary you are using, even so it is likely to be variable with temperature. It depends on if the software looks a the busy pin before proceeding or just leaves a gap.

Basically you don't do that sort of thing in code. You need to use the blink without delay method - examples in the IDE.

Grumpy_Mike:
I have no idea, it depends on the specific LCD and the libiary you are using, even so it is likely to be variable with temperature. It depends on if the software looks a the busy pin before proceeding or just leaves a gap.

Basically you don't do that sort of thing in code. You need to use the blink without delay method - examples in the IDE.

thanks, i will investigate further.

Arduino_Kidd:
millis() and micros() have resolution of 4 or 8 us depending on the Ard (250kHz and 125kHz respectively). so you are still bound to discrete values of freq and %PWM

But we are talking about absurdly slow PWM. (So slow in fact that some devices such as Peltiers will be damaged.) The fastest speed asked for was 250Hz, which is 4000us per cycle. So even with "only" 4us resolution, you can get 1000 steps between fully-on and fully-off.

Depending on what else you coded, this resolution is not achievable but if you get 40us, that's still 1% in the worst case.

and i dont quite follow when you say change the 2nd # as a % of the 1st. when you change %PWM on fixed frequency, you have to change both the on and off times by same %, but "-" on one side and "+" on the other in order to preserve frequency.

Not with the hardware timers. If you're using a hardware timer then the total cycle time (frequency) and the on-time are adjusted. You don't ever change the off-time - that's a function of the other two numbers.

The hardware timers have a lot more capabilities than you can imagine.