Measuring phase difference between two signals (e.g., voltage and current) with an STM32 microcontroller involves capturing timing or zero-crossing events using its built-in peripherals like timers, ADCs, or comparators. Here’s a step-by-step guide:
Methods to Measure Phase Difference
1. Zero-Crossing Detection (Digital Input)
Principle: Measure time difference between zero-crossings of two signals.
Hardware Setup:
- Condition signals to 0–3.3V (use op-amp comparators or Schmitt triggers).
- Connect signals to GPIO pins (e.g., PA0, PA1) with interrupt support.
STM32 Peripherals:
- TIM (Timer): Capture timestamps of zero-crossing edges.
- EXTI (External Interrupt): Trigger on rising/falling edges.
Code Example (HAL Library)
c
// Configure GPIO and EXTI for zero-crossing detection
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
static uint32_t time1, time2;
if (GPIO_Pin == GPIO_PIN_0) { // Signal 1
time1 = TIM2->CNT;
} else if (GPIO_Pin == GPIO_PIN_1) { // Signal 2
time2 = TIM2->CNT;
uint32_t phase_diff = abs(time2 - time1); // Timer ticks
float phase_deg = (phase_diff * 360.0) / TIM_PERIOD; // Convert to degrees
}
}
2. Analog Cross-Correlation (ADC + Timer)
Principle: Sample both signals with ADC and compute phase shift mathematically.
Hardware Setup:
- Use dual ADC mode (STM32F3/F4/H7) or simultaneous sampling.
- Feed signals to ADC channels (e.g., PA0, PA1).
Algorithm:
Apply cross-correlation or FFT to find time delay.
Code Example (Dual ADC)
c
// Configure ADC in dual mode
ADC_HandleTypeDef hadc1, hadc2;
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc1_buffer, BUFFER_SIZE);
HAL_ADC_Start_DMA(&hadc2, (uint32_t*)adc2_buffer, BUFFER_SIZE);
// Process buffers (e.g., find peak delay)
void Process_ADC_Data() {
int max_corr = 0;
int best_lag = 0;
for (int lag = -BUFFER_SIZE/2; lag < BUFFER_SIZE/2; lag++) {
int corr = 0;
for (int i = 0; i < BUFFER_SIZE; i++) {
if (i + lag >= 0 && i + lag < BUFFER_SIZE) {
corr += adc1_buffer[i] * adc2_buffer[i + lag];
}
}
if (corr > max_corr) {
max_corr = corr;
best_lag = lag;
}
}
float phase_deg = (best_lag * 360.0) / BUFFER_SIZE;
}
3. Timer Input Capture (High-Frequency Signals)
Principle: Use timer input capture to measure pulse timing.
Hardware Setup:
Connect signals to timer channels (e.g., TIM1_CH1, TIM2_CH2).
STM32 Peripherals:
Input Capture Mode: Records timestamps on rising/falling edges.
Code Example (PWM Phase Difference)
c
// Configure TIM1 in input capture mode
TIM_HandleTypeDef htim1;
HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_1); // Signal 1
HAL_TIM_IC_Start_IT(&htim1, TIM_CHANNEL_2); // Signal 2
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
static uint32_t time1, time2;
if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1) {
time1 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
} else if (htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2) {
time2 = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_2);
uint32_t phase_diff = abs(time2 - time1);
float phase_deg = (phase_diff * 360.0) / htim->Instance->ARR;
}
}
Key Considerations
1. Signal Conditioning:
- For AC signals, use op-amp circuits to scale and clamp voltages.
- Add low-pass filters to reduce noise.
2. Timer Resolution:
Higher timer clock = better accuracy (e.g., 72 MHz on STM32F4).
3. Frequency Range:
- Zero-crossing: Best for 50/60 Hz power lines.
- ADC + FFT: Suitable for higher frequencies (1 kHz–10 kHz).
4. STM32 Peripherals:
- High-end models (H7): Use hardware accelerators (e.g., HRTIM, FD CAN) for precision.
- Low-end models (F0): Rely on basic timers/ADC.
Example Calculation
If timer period = 1000 ticks and phase difference = 200 ticks:
Phase (degrees)=(200/1000)×360=72∘
Troubleshooting
- Noisy Signals: Increase hysteresis in comparators or use software debouncing.
- ADC Overflow: Adjust sampling rate or buffer size.
- Timer Overflow: Use 32-bit timers (e.g., TIM2 on STM32F4) for long intervals.
Conclusion
For low-frequency signals (50/60 Hz), zero-crossing detection is simple and effective. For higher frequencies, use ADC + FFT or timer input capture. The STM32’s flexible peripherals make it ideal for precise phase measurements.