#include <stdio.h>
#define SAMPLE_SIZE 400
#define ZERO_CROSS_THRESHOLD 50 // Adjust this threshold according to your signal
// Array to store ADC values obtained via DMA
uint16_t adc_samples[SAMPLE_SIZE];
// Function to detect zero crossings and determine positive/negative cycles
void detectZeroCrossings() {
int zeroCrossDetected = 0;
int i;
// Check for zero crossing
for (i = 1; i < SAMPLE_SIZE; i++) {
if ((adc_samples[i - 1] <= 2048 && adc_samples[i] >= 2048) ||
(adc_samples[i - 1] >= 2048 && adc_samples[i] <= 2048)) {
zeroCrossDetected = 1;
// Determine positive or negative cycle
if (adc_samples[i - 1] < adc_samples[i]) {
printf("Positive cycle detected\n");
} else {
printf("Negative cycle detected\n");
}
break;
}
}
if (!zeroCrossDetected) {
printf("No zero crossing detected\n");
}
}
int main() {
// Simulated ADC values obtained via DMA
// Replace this section with your actual DMA code to fill adc_samples array
// Assuming the array adc_samples is filled with ADC values
// Call function to detect zero crossings and determine cycles
detectZeroCrossings();
return 0;
}
if (adc_value >=1400 && adc_value <=1600){ Zero crossing detected }
Thanks you very much simply understood , Thanks a lot ofHello!
This will not detect a zero crossing. It will only detect if the value is in a given area.
The simple case: the last sample was less or equal to a value and the current sample is more, then you have
crossed that value.
BUT: if you have noise it might cross a few times. So you have to give it a hysteresis.
Dora.
Sir , will remove Analog filter the dc offset ? then it cannot use by an ADC ?Hi,
I fully agree with Dora.
You could also use analog or digital filters to suppress noise. Neither one is difficult.
Klaus
Removing the offset makes no sense. As you said you need the DC offset for proper ADC operation.Sir , will remove Analog filter the dc offset ? then it cannot use by an ADC ?
SirTo detect zero crossings, make use of the 90 degree capacitive phase advance. Detect peaks of the resulting sine wave. The peaks are zero crossings.
To detect positive portion of cycle, place a diode and capacitor to send a pulse at positive peaks. Add a similar network with diode oriented to detect negative peaks.
Simulation below. Values must be customized to work at 50 Hz.
Click this link to open Falstad's website and run my schematic in his animated interactive simulator.
tinyurl.com/yvl7ltkx
Sir
// ADC conversion complete callback
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc)
{
// Static variables to maintain state across function calls
static uint8_t consecutiveZeroCrossings = 0;
static uint8_t zeroCrossingFlag = 0;
// Check for zero crossing in the ADC buffer
for (int i = 1; i < 760; i++)
{
if (adcBuffer[i] >= 1450 && adcBuffer[i] <= 1500)
{
// Zero crossing detected
zeroCrossingDetected = 1;
zeroCrossingDetected_index = i; // Record the index of the detected zero crossing
// Check for consecutive zero crossings
consecutiveZeroCrossings++;
if (consecutiveZeroCrossings >= 6)
{
zeroCrossingFlag = 1;
// Check the signal portion
int8_t countPositive = 0;
int8_t countNegative = 0;
for (int j = i - 5; j < i; j++)
{
// Count positive and negative slopes in the signal portion
if (adcBuffer[j] < adcBuffer[j + 1])
{
countPositive++;
}
else if (adcBuffer[j] > adcBuffer[j + 1])
{
countNegative++;
}
}
if (countPositive >= 4)
{
// Signal portion is positive
signalPartFlag = 1;
}
else if (countNegative >= 4)
{
// Signal portion is negative
signalPartFlag = -1;
}
// Calculate RMS value starting from the detected zero crossing
double sumSquaredValues = 0.0;
int startIndex = zeroCrossingDetected_index % 380;
for (int k = 0; k < 384; k++)
{
int index = (startIndex + k) % 380;
// Add the squared value to the sum
sumSquaredValues += pow(adcBuffer[index], 2);
}
// Calculate the RMS value
double rmsValue = sqrt(sumSquaredValues / 380.0);
}
}
else
{
// Reset consecutiveZeroCrossings if a non-zero crossing is detected
consecutiveZeroCrossings = 0;
}
}
}
No sir can you tell meDo you know how to compare your results with noise to your accuracy specs with a simulator?
It iterates through the adcBuffer to find values within the range 1450-1500, indicating a zero crossing.
Thankyou very much sir ,Hello!
Sorry to have to repeat, but NO, IT DOES NOT INDICATE A 0 CROSSING!!!
The only thing it indicates is that your signal is within the range 1450 - 1500.
Suppose your 0 is at 1475 and you keep a + / - 25 for noise fluctuations.
Suppose that your signal is slow, going 1500, 1498, 1496, 1494, 1492, 1494, 1496, 1498, 1500. With your method,
you would detect a 0 crossing but there is none.
Again, detection means that you use:
- A variable containing the previous value
- The current value
- Possibly some hysteresis.
Write a state machine. With a state pos or neg, if the current state is pos and the current value is neg,
then you have a zero crossing. Same thing in the other direction. Use a #define HYS something, and
you can also take the HYS into account. Try with a few values to check what value works best.
Dora.
NB: beside this, if your signal variation is steep and goes from 1501 to 1449 or faster, what will you conclude???
-> It will never be in the [1450..1500] interval
-> BUT: it's obviously a 0 crossing.
// Define states
typedef enum {
POSITIVE,
NEGATIVE
} State;
// Define half cycles
typedef enum {
NONE,
POSITIVE_HALF_CYCLE,
NEGATIVE_HALF_CYCLE
} HalfCycle;
void detectZeroCrossingsAndHalfCycle(int *signal, int numSamples, int adcThreshold, int hysteresis) {
State currentState = POSITIVE;
HalfCycle currentHalfCycle = NONE;
for (int i = 0; i < numSamples; ++i) {
// Check the current state and ADC value with hysteresis
if (currentState == POSITIVE && signal[i] < (adcThreshold - hysteresis)) {
// Transition from positive to negative
currentState = NEGATIVE;
currentHalfCycle = NEGATIVE_HALF_CYCLE;
printf("Zero Crossing detected during Negative Half Cycle\n");
} else if (currentState == NEGATIVE && signal[i] > (adcThreshold + hysteresis)) {
// Transition from negative to positive
currentState = POSITIVE;
currentHalfCycle = POSITIVE_HALF_CYCLE;
printf("Zero Crossing detected during Positive Half Cycle\n");
}
}
}
int adcThreshold = 1500;
int hysteresis = 10;
SirHave you selected which STM32? single ADC has 16 ADC inputs.What are all your assumptions for ADC inputs, Vref, Vdd and outputs?
Please list these now.
View attachment 187259
Ok then ignore hysteresis for now.
Thanks sir ,Why we dont need Hysteresis ?
SirNow you almost have a software Phase locked loop for your ADC , so you might want to have a status bit = Locked within some tolerance error.
Thanks .Maybe there is code in some STM32 library for doing all this AC to DC rectified then RMS and PLL loop to sync ADC for ZCS (zero crossing signal) pointer to make better code.
Sir , Is there any example ,How to i find it ?
good luck and have fun. Imagine this will be a great product first, then do it.
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?