Here are several ways to generate pulses with [STM32](https://www.ampheo.com/search/STM32), from simple to advanced methods: ![Pulse-width-Modulation-(PWM)-in-STM32F103C8](https://hackmd.io/_uploads/SygLgkNheg.jpg) **1. Basic GPIO Pulse (Software Timing)** **Simple Digital Write with Delay:** ``` c #include "main.h" #include "stm32f1xx_hal.h" // Adjust for your series #define PULSE_PIN GPIO_PIN_0 #define PULSE_PORT GPIOA void generateBasicPulse(uint32_t highTime_us, uint32_t lowTime_us) { HAL_GPIO_WritePin(PULSE_PORT, PULSE_PIN, GPIO_PIN_SET); // High delayMicroseconds(highTime_us); HAL_GPIO_WritePin(PULSE_PORT, PULSE_PIN, GPIO_PIN_RESET); // Low delayMicroseconds(lowTime_us); } // Custom microsecond delay (approximate) void delayMicroseconds(uint32_t us) { uint32_t start = HAL_GetTick() * 1000; while ((HAL_GetTick() * 1000 - start) < us) { __NOP(); // No operation } } ``` **Precise Software Pulse (Using DWT Cycle Counter):** ``` c #include "core_cm4.h" // For DWT (Cortex-M4/M7) void DWT_Init(void) { if (!(CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk)) { CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; DWT->CYCCNT = 0; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; } } void delayCycles(uint32_t cycles) { uint32_t start = DWT->CYCCNT; while ((DWT->CYCCNT - start) < cycles); } void generatePrecisePulse(uint32_t highTime_ns, uint32_t lowTime_ns) { uint32_t cpuFreq = 160000000; // 160 MHz uint32_t highCycles = (highTime_ns * cpuFreq) / 1000000000; uint32_t lowCycles = (lowTime_ns * cpuFreq) / 1000000000; HAL_GPIO_WritePin(PULSE_PORT, PULSE_PIN, GPIO_PIN_SET); delayCycles(highCycles); HAL_GPIO_WritePin(PULSE_PORT, PULSE_PIN, GPIO_PIN_RESET); delayCycles(lowCycles); } ``` **2. Timer-Based PWM Pulse (Hardware Generated)** **Using Timer PWM Mode:** ``` c TIM_HandleTypeDef htim2; void PWM_Pulse_Init(void) { TIM_OC_InitTypeDef sConfigOC = {0}; // Timer clock enable __HAL_RCC_TIM2_CLK_ENABLE(); htim2.Instance = TIM2; htim2.Init.Prescaler = 1600 - 1; // 16MHz/1600 = 10kHz htim2.Init.CounterMode = TIM_COUNTERMODE_UP; htim2.Init.Period = 10000 - 1; // 1Hz PWM htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; HAL_TIM_PWM_Init(&htim2); // PWM configuration sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 5000; // 50% duty cycle sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1); HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); } ``` **Single Pulse Mode (One-Shot):** ``` c void generateSinglePulse(uint32_t pulseWidth_us) { TIM_HandleTypeDef htim3; htim3.Instance = TIM3; htim3.Init.Prescaler = 16 - 1; // 16MHz/16 = 1MHz (1us per tick) htim3.Init.Period = pulseWidth_us - 1; // Pulse width in microseconds htim3.Init.CounterMode = TIM_COUNTERMODE_UP; htim3.Init.RepetitionCounter = 0; HAL_TIM_OnePulse_Init(&htim3, TIM_OPMODE_SINGLE); // Start single pulse HAL_TIM_OnePulse_Start(&htim3, TIM_CHANNEL_1); } ``` **3. Advanced Pulse Generation Methods** **Pulse Train with DMA (Burst Pulses):** ``` c uint32_t pulsePattern[] = { 1000, // High for 1000 cycles 500, // Low for 500 cycles 2000, // High for 2000 cycles 500, // Low for 500 cycles // ... more pulses }; void generatePulseTrain_DMA(void) { // Configure timer for PWM // Use DMA to transfer pulse pattern to timer CCR register HAL_TIM_PWM_Start_DMA(&htim2, TIM_CHANNEL_1, (uint32_t*)pulsePattern, sizeof(pulsePattern)/sizeof(pulsePattern[0])); } ``` **Input Capture + Output Compare (Precise Timing):** ``` c // Generate pulse after external trigger void TriggeredPulse_Init(void) { // Configure input capture on Channel 1 // Configure output compare on Channel 2 // Generate pulse when trigger detected } ``` **4. STM32CubeMX Configuration** **Graphical PWM Setup:** 1. Open .ioc file in STM32CubeIDE 2. Select timer (TIM1, TIM2, etc.) 3. Set channel to "PWM Generation CHx" 4. Configure parameters: * Prescaler: Timer clock divider * Counter Period: PWM frequency * Pulse: Duty cycle **Code Generation:** ``` c // CubeMX generates this in main.c MX_TIM2_Init(); // Auto-generated timer initialization // Start PWM HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1); // Change duty cycle dynamically __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, newPulseValue); ``` **5. Complete Practical Examples** **Example 1: Variable Width Pulse Generator** ``` c #include "main.h" TIM_HandleTypeDef htim3; GPIO_TypeDef* PULSE_PORT = GPIOA; uint16_t PULSE_PIN = GPIO_PIN_0; void PulseGenerator_Init(void) { // GPIO setup GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = PULSE_PIN; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Alternate = GPIO_AF2_TIM3; // Check datasheet HAL_GPIO_Init(PULSE_PORT, &GPIO_InitStruct); // Timer setup for 1MHz (1us resolution) htim3.Instance = TIM3; htim3.Init.Prescaler = 16 - 1; // 16MHz/16 = 1MHz htim3.Init.Period = 10000 - 1; // 10ms max pulse width htim3.Init.CounterMode = TIM_COUNTERMODE_UP; htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; HAL_TIM_PWM_Init(&htim3); // PWM channel setup TIM_OC_InitTypeDef sConfigOC = {0}; sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 1000; // 1ms initial pulse width sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1); HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1); } void setPulseWidth_us(uint32_t width_us) { if (width_us > 10000) width_us = 10000; // Limit to 10ms __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, width_us); } void generateSinglePulse_us(uint32_t width_us) { setPulseWidth_us(width_us); HAL_Delay(1); // Ensure pulse is generated setPulseWidth_us(0); // Turn off } ``` **Example 2: High-Frequency Pulse Burst** ``` c // Generate burst of pulses at high frequency void generatePulseBurst(uint32_t frequency_Hz, uint32_t pulseCount, uint32_t pulseWidth_us) { uint32_t period_us = 1000000 / frequency_Hz; // Configure timer for desired frequency htim2.Init.Prescaler = 16 - 1; // 1MHz timer htim2.Init.Period = period_us - 1; htim2.Init.RepetitionCounter = pulseCount - 1; // Number of pulses HAL_TIM_OnePulse_Init(&htim2, TIM_OPMODE_REPETITIVE); // Set pulse width __HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, pulseWidth_us); HAL_TIM_OnePulse_Start(&htim2, TIM_CHANNEL_1); } ``` **6. Advanced Techniques** **Using HRTIM (High-Resolution Timer) - [STM32G4](https://www.ampheo.com/search/STM32G4)/F3/H7:** ``` c // For ultra-precise pulses (picosecond resolution) void HRTIM_Pulse_Init(void) { // HRTIM provides much higher resolution than standard timers // Suitable for power electronics, digital power conversion } ``` **Pulse with Dead Time (For H-Bridges):** ``` c // Complementary outputs with dead time void ComplementaryPulse_Init(void) { TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0}; // Configure dead time (prevents shoot-through in bridges) sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_DISABLE; sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_DISABLE; sBreakDeadTimeConfig.DeadTime = 100; // Dead time in timer ticks sBreakDeadTimeConfig.BreakState = TIM_BREAK_DISABLE; HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig); } ``` **7. Measurement and Verification** **Pulse Measurement Function:** ``` c uint32_t measurePulseWidth(GPIO_TypeDef* port, uint16_t pin) { uint32_t startTime, endTime; // Wait for rising edge while (HAL_GPIO_ReadPin(port, pin) == GPIO_PIN_RESET); startTime = DWT->CYCCNT; // Wait for falling edge while (HAL_GPIO_ReadPin(port, pin) == GPIO_PIN_SET); endTime = DWT->CYCCNT; return (endTime - startTime) * (1000000000 / SystemCoreClock); // ns } ``` **8. Performance Considerations** **Method Selection Guide:** ![企业微信截图_20250926173800](https://hackmd.io/_uploads/SkZfyyVheg.png) **Optimization Tips:** * Use DMA for pulse trains to avoid CPU intervention * Select appropriate [timer clock](https://www.onzuu.com/category/clock-timing-ics) for required resolution * Enable timer preload registers for glitch-free updates * Use advanced timers (TIM1, TIM8) for complementary outputs **9. Complete Working Example** ``` c #include "main.h" TIM_HandleTypeDef htim2; int main(void) { HAL_Init(); SystemClock_Config(); // Initialize pulse generator (1MHz timer, 10ms max period) PulseGenerator_Init(); while (1) { // Generate 100μs pulse generateSinglePulse_us(100); HAL_Delay(1000); // Wait 1 second // Generate 500μs pulse generateSinglePulse_us(500); HAL_Delay(1000); // Continuous PWM at 1kHz, 25% duty cycle setPulseWidth_us(250); // 250μs high, 750μs low HAL_Delay(5000); setPulseWidth_us(0); // Stop PWM } } ``` **Key Points:** * Use software methods for simple, low-frequency pulses * Use hardware timers for precise, high-frequency pulses * DMA + timers for complex pulse patterns without CPU load * Always verify pulse characteristics with oscilloscope Choose the method based on your specific requirements for precision, frequency, and complexity!