18. PWM Configuration Defaults

Simulate a PWM (Pulse Width Modulation) driver configuration function using C++ default arguments.

Implement a function that configures PWM parameters and prints the resulting configuration.

Function Requirements:

Create a function setPWM with the following parameters:

  • duty (required): integer duty-cycle percentage
    • Valid range: 0–100
  • frequency (optional): PWM frequency in Hz
    • Default value: 1000
    • Valid range: 1–100000
  • deadtime (optional): dead-time in microseconds
    • Default value: 0
    • Valid range: 0–1000

⚠️ Rules:

  • Use one function only
  • Use default arguments, not function overloading
  • Default arguments must appear from right to left

 

Output Format:

The function must print the PWM configuration exactly as:

duty frequency deadtime

Values must be separated by a single space.

No additional text should be printed.

 

In main():

  • Read two integers: duty and mode
  • mode determines which parameters are provided:
  • mode == 0
    • Call setPWM(duty)
    • Use default frequency and deadtime
  • mode == 1
    • Read frequency
    • Call setPWM(duty, frequency)
  • mode == 2
    • Read frequency and deadtime
    • Call setPWM(duty, frequency, deadtime)

You may assume all input values are valid and within the specified ranges.

 

Example 1 

Input:

50 0

Output:

50 1000 0

 

Example 2

Input:

70 1 2000

Output:

70 2000 0

 

Example 3

Input:

90 2 5000 10

Output:

90 5000 10

 

Constraints:

  • 0 ≤ duty ≤ 100
  • 1 ≤ frequency ≤ 100000
  • 0 ≤ deadtime ≤ 1000
  • mode ∈ {0, 1, 2}

 

 


 

Need Help? Refer to the Quick Guide below

Default Arguments allow a function to be called with fewer arguments than declared. If the caller omits specific arguments, the compiler automatically substitutes the default values provided in the function declaration.

This simplifies function calls for "standard" or "common" use cases without forcing the user to provide every single parameter.

Syntax & Usage

1. Basic Declaration

Defaults are assigned in the function declaration (prototype), usually in the .h file.

// Declaration (in Header)
// If 'parity' or 'stop_bits' are omitted, they default to 0 and 1.
void uart_init(int baud_rate, int parity = 0, int stop_bits = 1);

// Implementation (in .cpp) - Do NOT repeat default values here
void uart_init(int baud_rate, int parity, int stop_bits) {
    // Hardware setup logic...
}

2. Calling the Function

The compiler fills in the gaps from right to left.

uart_init(9600);           // Equivalent to: uart_init(9600, 0, 1);
uart_init(115200, 1);      // Equivalent to: uart_init(115200, 1, 1);
uart_init(57600, 2, 2);    // Uses explicit values for all.

Rules & Logic

  1. Trailing Only: You can only provide defaults for the rightmost arguments.
    • void func(int a, int b = 5); ✅ OK
    • void func(int a = 1, int b); ❌ Error (Compiler cannot infer b if you only provide a).
  2. No Skipping: You cannot skip an argument in the middle.
    • To set stop_bits to 2, you must also provide parity explicitly.

Relevance in Embedded/Firmware

1. Simplified Configuration APIs

Hardware peripherals often have dozens of settings (speed, mode, polarity, phase, interrupts). Most users only need the "standard" configuration.

Instead of forcing the user to populate a massive struct or pass 10 arguments, you provide defaults for the 90% case.

// User sees simple API:
timer.start(100); // 100ms, default mode, default priority

// Power users can override:
timer.start(100, TIMER_ONE_SHOT, HIGH_PRIORITY);

2. Reducing Code Bloat (vs. Overloading)

If you used Function Overloading to achieve this, you would write 3 separate functions (one taking 1 arg, one taking 2 args, etc.).

With Default Arguments, there is only one function body in Flash memory. The compiler simply "pastes" the constant values at the call site.

3. Backward Compatibility

If you need to add a new parameter (e.g., uint8_t timeout) to an existing driver function, you can give it a default value. Existing code that calls the function without the new parameter will still compile without changes.

Common Pitfalls (Practical Tips)

PitfallDetails
❌ Definition ConflictDo not repeat the default values in the function definition (the .cpp file). It causes a compile error. Put them only in the header (.h).
❌ Ambiguity with OverloadingIf you have void func(int) and void func(int, int=0), calling func(5) is ambiguous. The compiler doesn't know which one to pick.
❌ Value BindingDefault values are bound at compile time, not runtime. If you change the default value in the library but don't recompile the application code, the app will still use the old default.
✅ Use ConstantsInstead of magic numbers (int timeout = 100), use named constants (int timeout = DEFAULT_TIMEOUT) for readability.