I'm trying to make an oscillator where I can adjust the frequency and the duty cycle independently, but I'm not having much luck. What I want is a frequency range from 1Hz to 1MHz; and the ability to adjust the duty cycle in 10% increments from 0% to 100%, give or take. Ideally, I'd also like to be able to specify a 25% or 75% duty cycle.
My question basically boils down to: What is the simplest (i.e cheapest and smallest) way to achieve an adjustable square wave oscillator with adjustable duty cycle, with the specifications above, and where adjusting either the frequency or the duty cycle does not cause the other to change?
Here follows a detailed explanation of how I got here:
My first thought was a 555 timer, but that was very problematic. Adjusting the duty cycle also had an impact on the frequency, and achieving a duty cycle of less than 50% was pretty much impossible.
My second attempt involved a schmitt inverter. Sadly, the schmitt zone wasn't centred evenly between VCC and GND, so I had to offset the input voltage using a voltage divider. This then limited the current to the point that the (TTL) schmitt did not function. I later swapped it out for a CMOS variant and removed the resistors, but still couldn't get anywhere near reliable operation.
My third idea was to get a microcontroller - specifically, a PIC12F675 - to use its ADC to read two potentiometers, and from these values generate a square wave programmatically. However, when I crunched the numbers, it turned out to be impractical.
A PIC12F675 has a maximum clock speed of 4MHz. If we assume that it will occasionally have to perform up to 10 instructions between changing output states, and bearing in mind that a full wave requires 2 state changes, we end up with a maximum output frequency of 200KHz. This is somewhat lower than I was looking for.
In addition, at this maximum frequency of 200KHz, the MCU will (by definition) be unable to change state any more quickly; and therefore the duty cycle will be fixed at 50%, defeating the purpose. We we assume that we require at least an adjustable range of 10% - 90%, we will be unable to generate an output frequency of more than approximately 20KHz. Or maybe 10KHz.
Using a faster MCU wouldn't help much. The ATmega328 has a maximum clock frequency of 16MHz, which would give us up to 80KHz output. Still not very useful.
My fourth idea involved two 555 timers - one generating an adjustable square wave with a fixed duty cycle, the other acting as a one-shot to generate the duty cycle. Unfortunately, the duty cycle would be measured in time, rather than percentage, and therefore adjusting the frequency would affect the duty cycle. In addition, at the extreme low or high end of the frequency range, the duty cycle adjustment knob would be totally ineffectual for the majority of its travel.
My fifth idea involved a 555 timer for generating the square wave (as above), with a 4017 decade counter to split the output into chunks. Connecting the first output, for example, would give me a 10% duty cycle. I could change the frequency without affecting the duty cycle. There are some problems with this approach, though.
Firstly, unless I wanted to be flipping jumpers by hand, I would need some way to control the output with a knob. So a microcontroller, then. The microcontroller would need some sort of programmable multi-channel switch, such as the PCA9548A. Unfortunately this is an 8-channel switch, and I'm using a decade counter. I could connect the 4017 reset to the 8th position, and make it an 8-way counter, but then I wouldn't be able to get 10% or 90% duty cycle. So I'd need quite a lot of parts: 1 capacitor, 1 pot, 1 555 timer, 1 MCU, 1 4017 and 2 8-channel switches.
If I wanted a 25% or 75% duty cycle, I would need to add to this list another 4017, another switch IC, another capacitor and some way to switch the capacitors programmatically.