I'm looking to generate between 50Hz to 150Hz square waves with a PIC18F14K50, which is running with an 8MHz external crystal (XT).

Apart reading an analogue value for the frequency from a pot and displaying the value on a 7-seg display, the PIC doesn't do anything except the square wave.

My options are to either use the PWM module or just write code that alternates the relevant pin between 0 and 1. I don't necessarily mind doing the latter, except there will be a slight interruption when I periodically (maybe a couple of times per second) fetch the potentiometer value from the ADC.

I've never done PWM before so I looked it up. There is one place where you can type in your MCU's frequency and your desired frequency, and it'll give you the corresponding XC8 code. When I tried this, it seems 8MHz might actually be too fast, and I cannot produce a 50-150Hz square wave with the PWM module. My only option is to move down to 500kHz or to use the manual method.

Is this correct? Can I really not produce a 50-150Hz square wave using the PWM module if my MCU is running at 8MHz? Is there any better way to achieve this square wave?


2 Answers 2


If you really need to operate that slowly (usually faster is better, at least up to some kHz for PWM) then you have a couple choices- use a slower clock frequency (much lower, so maybe not desirable- but slower clock means less power consumption). It also does not give you fine resolution on the PWM period (because normally nobody cares that much as long as it is fast enough).

Or you can use the timer compare function to provide sub-microsecond accurate transitions since it can toggle the pin with the hardware compare function- you then set it up for the next compare (and, optionally, toggle the output pin). That would be the preferred approach, in my opinion.

Some of the 16F series parts have a numerically controlled oscillator peripheral (NCO), but I don't think it's available in the 18F series (could be wrong).


Spehro's answer covers the standard approaches. But the XC8 tool you mentioned is likely correct in saying that you cannot produce a 50Hz square wave directly with the Output Compare module. This is due to the fact that the 18F timers used for the Output Compare module can not be slowed down enough to fit their Period Reset values into an 8-bit field.

Timer2 seems to have a selectable pre-scaler and post-scaler (up to 1:16). This means that they can be "slowed down" to 31.25 kHz (i.e. 8MHz / (16 * 16) = 31.25 kHz). But that rate is still too fast for the Output Compare module to handle the 50Hz case: the max Period Reset value of 256 will produce a 122 Hz square wave (i.e. 31.25 kHz / 256 = 122 Hz).

If this is still unacceptable, I would suggest using the Timer to trigger an interrupt at some convenient rate, say 100 kHz. Set a counter variable to the number of interrupt pulses needed to achieve the desired output frequency (this will need to be a 16-bit variable). Then decrement that counter on each interrupt trigger. Once the counter gets to 0, toggle the output pin and reset the counter. This is essentially what the Output Compare module is doing for you. Basically all you are gaining by doing it yourself is the ability to use more bits in your own "Period Reset register" (the counter variable).


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.