Power factor – zero crossing detector

ted
Mon Jun 18, 2018 9:14 pm
This code is working fine under condition that amplitude of the signal is 3.3V which is 1/2 of voltage bias on PA7.
It is eliminating two op amp.
How to make this code to make working for any signal amplitude, wchich is the purpose of zero crossing detector ?
Another words how to get the pulse at 1/2 amplitude of applayed signal ?

//unsigned long time;
const int buttonPin = PA7;
void setup() {
pinMode(PB1, OUTPUT);
pinMode(buttonPin, INPUT_PULLDOWN);
//pinMode(buttonPin, INPUT_PULLUP);
}
void loop() {

if (digitalRead(buttonPin) == HIGH)
{
while (digitalRead(buttonPin) == HIGH) {

}
digitalWrite(PB1, HIGH);
//delay micros(50);
delayMicroseconds(100);
//delay(1000);
digitalWrite(PB1, LOW);
delayMicroseconds(100);

}
}


fredbox
Mon Jun 18, 2018 10:23 pm
This is more of a hardware problem. I don’t believe the LM358 is designed to work as a comparator in the manner you have it connected. You need resistors at the inputs to set the voltage to about half of your power supply. You also need a device designed to operate on 3.3V. If I were doing this, I’d probably use an optocoupler instead of opamps. An H11AA1 comes to mind, but there are many others. See http://www.bristolwatch.com/ele2/zero_crossing.htm

ted
Mon Jun 18, 2018 11:07 pm
The idea is: replace hardware by software

Pito
Tue Jun 19, 2018 7:47 am
You have to shift the input voltage level such its “zero” will fit somewhere into the ADC range.

The “zero crossing” means you get from positive to negative (or vice versa) where the “negative” means negative against “ground”.

You do not have hardware in STM32 handy which can work with negative voltages against ground.


ted
Tue Jun 19, 2018 12:58 pm
You mean – shift the bias on PA7 ?
That will work for another fixed amplitude only, so detector will be still amplitude dependent.
I can add a voltmeter to code which wil measure amplitude then I will know the value 1/2 of it, wchich give the triggering point.
I know how to add meter, but dont know how to inplement triggering point.
Or use a peak detector as triggering point ?

heisan
Tue Jun 19, 2018 2:26 pm
What exactly are you trying to measure? Most signals which you would want to measure power factor on would be dangerous to directly connect a ground reference. Never mind the difficulty of shifting and scaling the signals.

The simple opto isolated circuits show above should work very well in most real world situations.


heisan
Tue Jun 19, 2018 2:47 pm
This is about the simplest ‘level shifter’ I can think of.

Screenshot_2018-06-19_16-39-29.png
Screenshot_2018-06-19_16-39-29.png (10.74 KiB) Viewed 818 times

heisan
Tue Jun 19, 2018 3:04 pm
I lied, this is the simplest, but can obviously only work if input is isolated from arduino supply…

Screenshot_2018-06-19_17-03-28.png
Screenshot_2018-06-19_17-03-28.png (7.03 KiB) Viewed 812 times

ted
Tue Jun 19, 2018 3:26 pm
Thanks heisan
I know that, the problem is with modification of the code not in electronics.

dannyf
Tue Jun 19, 2018 6:48 pm
The simplest zc circuit would consist of one resistor.

In most cases, however, a resistor plus a zener would do the job.


ted
Wed Jun 20, 2018 12:02 am
Now I am trying to combine two programs, this is what I did and original of the second program, for some reason I have no respond on PB1 to signal applied to PA7.
Can someone help me to find mistake ?
const int sampleWindow = 250; // Sample window width in mS (250 mS = 4Hz)
unsigned int knock;
//int ledPin = 13;
/////////////////////
int ledPin = PB1;
/////////////////////
void setup()
{
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
}

void loop()
{
unsigned long start= millis(); // Start of sample window
unsigned int peakToPeak = 0; // peak-to-peak level

unsigned int signalMax = 0;
unsigned int signalMin = 1024;

// collect data for 250 miliseconds
while (millis() - start < sampleWindow)
{
//////////////////////////////////
// knock = analogRead(0);
knock = analogRead(PA7);
/////////////////////
if (knock < 1024) //This is the max of the 10-bit ADC so this loop will include all readings
{
if (knock > signalMax)
{
signalMax = knock; // save just the max levels
}
else if (knock < signalMin)
{
signalMin = knock; // save just the min levels
}
}
}
peakToPeak = signalMax - signalMin; // max - min = peak-peak amplitude
double volts = (peakToPeak * 3.3) / 1024; // convert to volts

Serial.println(volts);
if (volts >=1.0)
{
//turn on LED
digitalWrite(ledPin, HIGH);
delay(500);
Serial.println("Knock Knock");
}
else
{
//turn LED off
digitalWrite(ledPin, LOW);
}
}


heisan
Wed Jun 20, 2018 3:09 pm
analogRead returns a number 0..4095 (12 bits).

Replace every occurrence of ‘1024’ with ‘4096’ and it may work?


ted
Thu Jun 21, 2018 2:23 am
I made like this = it is sine amplitude detector, not a sine crossing detector
//Replace every occurrence of '1024' with '4096' and it may work?
//http://stm32duino.com/viewtopic.php?f=19&t=3778&start=10

const int sampleWindow = 250; // Sample window width in mS (250 mS = 4Hz)
unsigned int knock;
//int ledPin = 13;
/////////////////////
int ledPin = PB1;
int analog = PA7;
/////////////////////
void setup()
{
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
}

void loop()
{
unsigned long start= millis(); // Start of sample window
unsigned int peakToPeak = 0; // peak-to-peak level

unsigned int signalMax = 0;
unsigned int signalMin = 1024;

// collect data for 250 miliseconds
while (millis() - start < sampleWindow)
{
//////////////////////////////////
// knock = analogRead(0);
knock = analogRead(PA7);
/////////////////////
// if (knock < 1024) //This is the max of the 10-bit ADC so this loop will include all readings
if (knock < 4096) //This is the max of the 10-bit ADC so this loop will include all readings
{
if (knock > signalMax)
{
signalMax = knock; // save just the max levels
}
else if (knock < signalMin)
{
signalMin = knock; // save just the min levels
}
}
}
peakToPeak = signalMax - signalMin; // max - min = peak-peak amplitude
// double volts = (peakToPeak * 3.3) / 1024; // convert to volts
double volts = (peakToPeak * 3.3) / 4096; // convert to volts

Serial.println(volts);
if (volts >=1.0)
{
//turn on LED
digitalWrite(ledPin, HIGH);
delay(5);
Serial.println("Knock Knock");
}
else
{
//turn LED off
digitalWrite(ledPin, LOW);
}
}


RogerClark
Sun Jun 24, 2018 9:46 pm
It’s all been done before

Just search for the open energy project

Aka emonlib

Works perfectly on STM32 I have at least multiple people using boards I built which are monitoring power and power factor etc


ted
Mon Jun 25, 2018 7:24 pm
I did search , all the time signal is converted to rectangles before entering microcontroller. Please look at my second post, I am trying to eliminate op amp LM358 as shown in the first post.

stevestrong
Wed Jun 27, 2018 12:40 pm
I would use the STM32ADC library, wherein you have the possibility to set a watch-dog threshold level to trigger an interrupt when the input analog signal level goes beyond that value.

ted
Wed Jun 27, 2018 12:53 pm
Thanks for pointing that, now I have to find examples how this is done.

Leave a Reply

Your email address will not be published. Required fields are marked *