Generate Accurate Pulses


The PulseOut Command is a reliable method for generating pulses if accuracy is not critical, the PulseOut command uses a calculation of the clock to speed for the timing .

If you need better accuracy and resolution then an alternative approach is required.

To generate pulses in the 100 us to 2500 us range with an accuracy of +- 1us over this range is practical using the approach shown in this example.

This example code works on a midrange PIC16F690 operating at 8Mhz. However, it should work on any Microchip PIC microcontroller, but may need some minor modifications.


    Pulse_Out_us ( word_value )

How It Works:

Timer1 is loaded with a preset value based upon the variable passed to the sub routine. The timer (Timer1) is started and the pulse pin (the output pin) is set high. When Timer1 overflows the Timer1 interrupt flag bit (TMR1IF) is set. This causes the program to exit a polling loop and set the pulse Pin off. Then, Timer1 is stopped and TMRIF flag is cleared and the sub routine exits.

This method supports delays between 5 us and 65535 us and uses Timer1.

Test Results:

These tests were completed using a Saleae Logic Analyzer.

Pulse setting Time Results

Pulse_Out_us (2500)

2501.375 us

Pulse_Out_us (1000)

1000.750 us

Pulse_Out_us (100)

100. 125 us

Pulse_Out_us (10)

10.125 us

Pulse_Out_us with less then 4

Unreliable results

Demonstration program:

    ; Code:  Output an accurate pulse
    ; Author: William Roth 03/13/2015

    #chip 16F690,8

    ; ---- Define Hardware settings
    ; ---- Define I2C settings - CHANGE PORTS AS REQUIRED
    #define I2C_MODE Master
    #define I2C_DATA PORTB.4
    #define I2C_CLOCK PORTB.6

    ; ---- Set up LCD - Using I2C LCD Backpack
    #define LCD_IO 10
    #define LCD_I2C_Address_1 0x4e ; default to 0x4E
    ; ----  May need to use SLOW or MEDIUM if your LCD is a slower device.
    #define LCD_SPEED Medium
    #define LCD_Backlight_On_State  1
    #define LCD_Backlight_Off_State 0

    ; ---- USART settings
    #define USART_BAUD_RATE 38400

    ; ---- Setup Pulse parameters
    #define PulsePin PORTC.4
    Dim Time_us As WORD
    Dir PulsePin Out     'Pulsout pin
    Set PulsePin off

    ; ---- Setup Timer
    InitTimer1 Osc, PS1_2  'For 8Mhz Chip
    'InitTimer1 Osc, PS1_4, 'For 16 Mhz Chip
    TMR1H = 0: TMR1L = 0   'Clear timer1
    TMR1IF = 0  'Clear timer1 int flag
    TMR1IE = on 'Enable timer1 Interrupt (Flag only)

    ' **** This is the MAIN loop *****
        PULSE_OUT_US (2500)  'Measured as 2501.375 us
        wait 19 ms
        Pulse_Out_US (1000)  'Measured as 1000.750 us
        wait 19 ms
        Pulse_Out_US (100)   'Measured as 100.125 us
        wait 19 ms
        Pulse_Out_US (10)    'Measured as 10.125 us
        Wait 19 ms

    SUB PULSE_OUT_US (IN Variable as WORD)
    TMR1H = 65535 - Variable_H      'Timer 1 Preset High
    TMR1L = (65535 - Variable) + 4  'Timer 1 Preset Low
    Set TMR1ON ON                'Start timer1
    Set PulsePin ON               'Set Pin high
    Do While TMR1IF = 0      'Wait  for Timer1 overflow
    Set PulsePin off          ' Pin Low
    Set TMR1ON OFF            ' Stop timer 1
    TMR1IF = 0             'Clear the Int flag

Also see PulseOut