Pulse Width Modulation (PWM) with NI-DAQmx and LabVIEW

Updated Jan 4, 2024



  • CompactDAQ Chassis
  • CompactDAQ Controller
  • Multifunction I/O Device


  • LabVIEW


  • NI-DAQmx

Operating System

  • Windows

This document is part of the Getting Started with NI-DAQmx Series.

A Pulse Width Modulation (PWM) Signal is a technique for generating digital pulses to control an analog circuit. A PWM signal consists of two main components that define its behavior: a duty cycle and a frequency. This article will go through hardware consideration with using NI-DAQmx hardware and resources to begin using PWM with software or hardware timing.

Hardware Considerations

The implementation of the PWM generation and the pulse counting depends on the hardware that you are using. Counters are preferable for generating PWM output. Please refer to your hardware's datasheet to see how many counters are available on that device and whether it can support PWM.


  • E, S, M and X series devices – Look at user manual
  • Other Digital Modules – check if they are Static (i.e. Software-Timed) or Hardware-Timed in the user manual
  • C Series - Check if your C Series modules can access the counters or timers on your CompactDAQ (cDAQ) chassis or controller's backplane.


  • cDAQ – look at number of counters on chassis in the user manual. This feature is only available in the modules that provide access to the chassis onboard counters. 

PWM with NI-DAQmx in LabVIEW 

To implement PWM in NI-DAQmx, make sure you have investigated your hardware and the capabilities it has. After that, you can determine the best solution to your application: Software Times or Hardware Timed PWM.

Software Timed Pulse Width Modulation
If your application does not have tight requirements, with respect to speed and precision, a digital output can be used with software timing control for pulse train or PWM generation.

Here is an example in the Community for implementing PWM with software timed digital I/O. 

Hardware Timed Pulse Width Modulation
  • Starting with an Example (recommended)
    1. Launch LabVIEW
    2. Navigate to Help >> Find Examples... which will launch the NI Example Finder
    3. Confirm you are in the Browse tab and navigate through the folders Hardware Input and Output >> DAQmx >> Counter Output
  1. Double click the example you want to use
  2. DO NOT edit this example. Any changes will overwrite the original example. 
    1. Click File >> Save As
    2. Choose the option that suits your needs. Recommendation is to choose Duplicate Hierarchy to new location
    3. Choose the location and click Save
    4. Close out for the example and open Example in the new location
  3. Once the local copy of the example is opened, you can change the configuration and the channel used in the example.
  • Starting from a Blank Block Diagram
    1. Create and initialize a counter output channel using the DAQmx Create Virtual Channel VI. There are three ways to define your counter output task in NI-DAQmx based on your application needs:
      • CO Pulse Freq
      • CO Pulse Time
      • CO Pulse Ticks - Note - Different hardware have different time-bases, running the same code with different hardware may change pulse widths.
Select appropriate inputs for Duty Cycle, Frequency, Counter(s), Idle State, and Initial Delay.
  1. Use the DAQmx Timing VI to configure the duration of the pulse generation.
Note: The Implicit instance should be used when no sample timing is needed, such as in counter tasks like pulse train generation. Additionally, choose Continuous as the sample mode.
  1. Call the DAQmx Start VI; this VI begins the pulse train generation.
  2. Place a While Loop to run continuously until the user presses the Stop button.
  3. Inside the While Loop:
    1. Create a Local Variable for the Duty Cycle. This will be compared to the original Duty Cycle variable and the comparison will act at the selector for the Case Structure.
    2. Place a Case Structure:
      1. True Case: Call the DAQmx Write VI. If the Duty Cycle has been changed, the new duty cycle is set using the DAQmx Write VI.
      2. False Case: Wire all the inputs straight to the outputs. If the duty cycle has not been changed, the false case of the case structure executes, and nothing is updated.
    3. Check for errors using the DAQmx Is Task Done VI.
    4. Add a Wait Until Next Millisecond Multiple VI to introduce a short time delay to the loop. This will prevent the loop from executing as fast as possible, consuming unnecessary processor resources.
  4. Call the DAQmx Clear Task VI to clear the task.
  5. Check for and display errors using the Simple Error Handler VI.

Note: This image is a LabVIEW snippet, which includes LabVIEW code that you can reuse in your project. To use a snippet, right-click the image, save it to your computer, and drag the file onto your LabVIEW diagram.