Proton Tutorial - Digital To Analogue Conversion (DAC) via PWM

PWM, pulse wave modulation, is a feature of some PIC's. Even PIC's without PWM can use a software version of PWM, but the advantage of having hardware PWM is that you don't have to update the PWM cycle at all. In a software PWM situation, you must continuously refresh the PWM signal on the desired pin, and loose a lot of functionality with the program.The 16F877 features a few HPWM outputs, and can be used for many things (i.e. IR modulation), but in this example, its used for DAC.

HPWM is a pulse train that a user can specify its frequency and duty cycle. Duty cycle is the percentage of time that the pulse stays high compared to the time it stays low. So a duty cycle of 50% means it stays high for 50% of the time, and low for 50% of the time. A duty cycle of 25% means the pulse is high for 25% of the time, and low for 75% of the time.

50% duty cycle (freq = 2Khz);

25% duty cycle (freq = 2Khz);

No matter what the frequency, the duty cycle will be the same, just that the pulses will be more squished / stretched. There are limits with the frequency of the PWM, they are

XTAL frequency - Lowest useable PWM frequency

  • 4MHz - 244Hz
  • 8MHz - 489Hz
  • 10MHz - 611Hz
  • 12MHz - 733Hz
  • 16MHz - 977Hz
  • 20MHz - 1221Hz
  • 24MHz - 1465Hz
  • 33MHz - 2015Hz
  • 40MHz - 2442Hz

And with all XTAL speeds, the fastest possible frequency is 32767Hz. So there are limitations with the PWM in regards to the frequency that it can produce. The faster the frequency, the better for this application, as it increases the outputs response.

The duty cycle is a value between 0 and 255 where 0 is 0% and 255 is 100%, i.e. a duty cycle of 63 would actually mean 25% as 63 / 255 = .25 (25%). The RC circuit will average the pulses out and turn them into near solid DC, a 50%(127) duty cycle will read as 2.5V, and a 25%(63) would read 1.25V. And this is how DAC is performed with the PIC.

The command in Proton+ is


HPWM Channel , Dutycycle , Frequency


As it so turns out, the channels on the 16F877 are CCP1 and CCP2, but CCP1 is on PORTC.2 and CCP2 is on PORTC.1.. I have no idea why, but you can declare the pins into what would seem the correct format like so,


Declare CCP1_PIN = PORTC.1
Declare CCP2_PIN = PORTC.2


I'm using 1 channel for this example, and a simple RC circuit that will average the PWM signal and turn it into a rather constant analogue output. The op-amp is not required for all applications, but it definitely is good practice to use it as a buffer. The frequency should always be on max, i.e. 32767Hz for DAC, a lower frequency will make the output appear laggy / have a long response time.

The following diagram is with a duty cycle of 25% (63) and a frequency of 32767Hz on channel 1 (CCP1) eg: HPWM 1, 63, 32767 With a duty cycle of 25%, the output will be 25% of 5V, or 1.25V. Note the PSU/OSC are not shown.

The capacitor and RC will act as a filter, and slew the pulses together, giving the impression of a stable output. On an oscilloscope the ripple is clear, but in reality, to small to be of any concern. Any duty cycle between 0 and 255 can will be converted to 0-5V in this format.

Forum Activity

Member Access