12F675 Mains Zero Crossing Detection Using Single Resistor.
-
- Matrix Staff
- Posts: 9521
- Joined: Sat May 05, 2007 2:27 pm
- Location: Northamptonshire, UK
- Has thanked: 2585 times
- Been thanked: 3815 times
12F675 Mains Zero Crossing Detection Using Single Resistor.
When simulated, only one half of mains is detected (falling edge). Have I done something wrong, or is it just simulated incorrectly ?
Here is the basic idea. I am utilising the inbuilt protection diodes on each pin, and connecting a high value resistance value resistor from mains live to GP2 this resistor value
is high enough not to cause any damage to chip though excessive current.
I have set up 2 interrupts. one for fall detection and one for rise detection.
On triggering of interrupt, ( at approx 0v of each 1/2 cycle), GP4 will either be off, will go high form 400*10us (4ms) to 900*10us, depending on setting of pot connected to ADC0.
Reason for X10us and not milliseconds, it enables more steps e.g. 5.2ms 5.8ms, 6.3ms etc, instead of just 5ms 6ms 7ms etc.
This will drive a FET, which via a bridge, control a mains light or AC motor. No hum method since FET is on at the start of each cycle, but only for a timed period, hence brightness or speed is controlled.
Here is the basic idea. I am utilising the inbuilt protection diodes on each pin, and connecting a high value resistance value resistor from mains live to GP2 this resistor value
is high enough not to cause any damage to chip though excessive current.
I have set up 2 interrupts. one for fall detection and one for rise detection.
On triggering of interrupt, ( at approx 0v of each 1/2 cycle), GP4 will either be off, will go high form 400*10us (4ms) to 900*10us, depending on setting of pot connected to ADC0.
Reason for X10us and not milliseconds, it enables more steps e.g. 5.2ms 5.8ms, 6.3ms etc, instead of just 5ms 6ms 7ms etc.
This will drive a FET, which via a bridge, control a mains light or AC motor. No hum method since FET is on at the start of each cycle, but only for a timed period, hence brightness or speed is controlled.
- Attachments
-
- AC zero x pwm dimmer2.fcf
- (6 KiB) Downloaded 587 times
Martin
-
- Matrix Staff
- Posts: 9521
- Joined: Sat May 05, 2007 2:27 pm
- Location: Northamptonshire, UK
- Has thanked: 2585 times
- Been thanked: 3815 times
Re: 12F675 Mains Zero Crossing Detection Using Single Resistor.
Perhaps INT cannot be setup for detecting rising and falling edge at the same time.
So I altered code to detect rising edge, then disable INT, then enable INT to detect falling edge.
This time no pwm pulses are produced on rising or falling edge
Reason I want to use INT is so the program can do other things and not just stuck waiting for a port change,
since its important no zero crossing points are missed.
So I altered code to detect rising edge, then disable INT, then enable INT to detect falling edge.
This time no pwm pulses are produced on rising or falling edge

Reason I want to use INT is so the program can do other things and not just stuck waiting for a port change,
since its important no zero crossing points are missed.
- Attachments
-
- AC zero x pwm dimmer2a.fcf
- (7.5 KiB) Downloaded 518 times
Martin
- Benj
- Matrix Staff
- Posts: 15312
- Joined: Mon Oct 16, 2006 10:48 am
- Location: Matrix TS Ltd
- Has thanked: 4803 times
- Been thanked: 4314 times
- Contact:
Re: 12F675 Mains Zero Crossing Detection Using Single Resistor.
Hello
Yes the INT interrupt can only detect either a low to high or a high to low transition at a time. You can switch the logic but as you say it is then possible for you to miss an interrupt while the logic is being updated. However the PORT change interrupt will fire every time the part value changes. This means it will interrupt on both transitions of the pin. However when using this interrupt there are sometimes no options available for selecting which pins get included in the interrupt so you may have to be careful. Luckily the 12F675 does have the mask that can be enabled for the interrupt so you can limit the interrupt source to a single pin.
Yes the INT interrupt can only detect either a low to high or a high to low transition at a time. You can switch the logic but as you say it is then possible for you to miss an interrupt while the logic is being updated. However the PORT change interrupt will fire every time the part value changes. This means it will interrupt on both transitions of the pin. However when using this interrupt there are sometimes no options available for selecting which pins get included in the interrupt so you may have to be careful. Luckily the 12F675 does have the mask that can be enabled for the interrupt so you can limit the interrupt source to a single pin.
Regards Ben Rowland - MatrixTSL
Flowcode Product Page - Flowcode Help Wiki - Flowcode Examples - Flowcode Blog - Flowcode Course - My YouTube Channel
Flowcode Product Page - Flowcode Help Wiki - Flowcode Examples - Flowcode Blog - Flowcode Course - My YouTube Channel
-
- Matrix Staff
- Posts: 9521
- Joined: Sat May 05, 2007 2:27 pm
- Location: Northamptonshire, UK
- Has thanked: 2585 times
- Been thanked: 3815 times
Re: 12F675 Mains Zero Crossing Detection Using Single Resistor.
Thanks Ben, I will alter my program tonight and see how it goes. I was puzzled to why second program did not work. If osc. frequency is set at 4MHz, it should not miss any INT triggers since period it’s detection is 10ms, so in theory software should of worked. Would you know by looking at 2nd attachment the problem of no detection?
Martin
- Benj
- Matrix Staff
- Posts: 15312
- Joined: Mon Oct 16, 2006 10:48 am
- Location: Matrix TS Ltd
- Has thanked: 4803 times
- Been thanked: 4314 times
- Contact:
Re: 12F675 Mains Zero Crossing Detection Using Single Resistor.
Hello
The reason your previous program did not work is as follows.
You have multiple calls to the enable / disable interrupt function and the macro that gets called by the functions changes. This works fine in Flowcode but in the hardware only the first macro specified is ran. This is down as one of our known bugs.
Here is the Interrupt routine from the generated C code. Note that only the first call will ever be processed.
You could make this functionality work by calling the same macro everytime whether the interrupt is falling edge or raising edge.
The reason your previous program did not work is as follows.
You have multiple calls to the enable / disable interrupt function and the macro that gets called by the functions changes. This works fine in Flowcode but in the hardware only the first macro specified is ran. This is down as one of our known bugs.
Here is the Interrupt routine from the generated C code. Note that only the first call will ever be processed.
Code: Select all
void interrupt(void)
{
if (intcon & (1 << INTF))
{
FCM_Rising_Edge_routine();
clear_bit(intcon, INTF);
}
if (intcon & (1 << INTF))
{
FCM_Falling_Edge_Routine();
clear_bit(intcon, INTF);
}
if (intcon & (1 << INTF))
{
FCM_Rising_Edge_routine();
clear_bit(intcon, INTF);
}
}
Regards Ben Rowland - MatrixTSL
Flowcode Product Page - Flowcode Help Wiki - Flowcode Examples - Flowcode Blog - Flowcode Course - My YouTube Channel
Flowcode Product Page - Flowcode Help Wiki - Flowcode Examples - Flowcode Blog - Flowcode Course - My YouTube Channel
-
- Matrix Staff
- Posts: 9521
- Joined: Sat May 05, 2007 2:27 pm
- Location: Northamptonshire, UK
- Has thanked: 2585 times
- Been thanked: 3815 times
Re: 12F675 Mains Zero Crossing Detection Using Single Resistor.
Thanks Ben.
I need to do two things.
How do I set up Flowcode to:
1) Call a macro on GP1 changing from 0 to 1, and call a different macro with GP1 changing form 1 to 0.
Macro is not called if any other GP bit changes. I have a look at INT on port change, and got a bit confused with: 2) On a different application but still using 12F675, I need to measure a PWM i/p to a port e.g. GP5.
Then determine duty and then have 12F675 have a duty output of:
Duty=Duty_in+15.
So if duty at GP5 = 10, then duty out form 12F675 = 25%
If It can’t be achieved on 12F675, then I can use 12F615, but want to avoid that chip at the mo.
I need to do two things.
How do I set up Flowcode to:
1) Call a macro on GP1 changing from 0 to 1, and call a different macro with GP1 changing form 1 to 0.
Macro is not called if any other GP bit changes. I have a look at INT on port change, and got a bit confused with: 2) On a different application but still using 12F675, I need to measure a PWM i/p to a port e.g. GP5.
Then determine duty and then have 12F675 have a duty output of:
Duty=Duty_in+15.
So if duty at GP5 = 10, then duty out form 12F675 = 25%
If It can’t be achieved on 12F675, then I can use 12F615, but want to avoid that chip at the mo.
Martin
- Benj
- Matrix Staff
- Posts: 15312
- Joined: Mon Oct 16, 2006 10:48 am
- Location: Matrix TS Ltd
- Has thanked: 4803 times
- Been thanked: 4314 times
- Contact:
Re: 12F675 Mains Zero Crossing Detection Using Single Resistor.
Hello
1) Use the same macro. Simply make a desicion depending on whether the pine starts off as a 1 or a 0 and act accordingly.
2) The 12F675 should be able to do the PWM capture by means of using a timer interrupt on a fairly fast timeout. Depends on the rate of PWM that you need to be able to detect.
1) Use the same macro. Simply make a desicion depending on whether the pine starts off as a 1 or a 0 and act accordingly.
2) The 12F675 should be able to do the PWM capture by means of using a timer interrupt on a fairly fast timeout. Depends on the rate of PWM that you need to be able to detect.
Regards Ben Rowland - MatrixTSL
Flowcode Product Page - Flowcode Help Wiki - Flowcode Examples - Flowcode Blog - Flowcode Course - My YouTube Channel
Flowcode Product Page - Flowcode Help Wiki - Flowcode Examples - Flowcode Blog - Flowcode Course - My YouTube Channel
-
- Matrix Staff
- Posts: 9521
- Joined: Sat May 05, 2007 2:27 pm
- Location: Northamptonshire, UK
- Has thanked: 2585 times
- Been thanked: 3815 times
Re: 12F675 Mains Zero Crossing Detection Using Single Resistor.
Ben,
Can you explain in a bit more detail please?
1 β€Use the same macro. Simply make a decision depending on whether the pine starts off as a 1 or a 0 and act accordinglyβ€
As I stated I was confused with port change interrupt. Are you saying use the GP2 INT, but set both rising, and falling edge to call same macro, or are you saying use Port change interrupt?
If latter, how is it set for just one pin? When it looks like you need to set for RB1 , RB3 an RB5.
2) β€The 12F675 should be able to do the PWM capture by means of using a timer interrupt on a fairly fast timeout. Depends on the rate of PWM that you need to be able to detect.β€
Is that enough information for a beginner to compile a compete Flowcode?
Frequency is 3KHz.
I have a theory on how to detect duty: wait until port changes form 0 to 1, start timer a (ta),port changes from 1 to 0, stop timer(a) and start timer(b), wait till port changes from 0 to 1, stop timer b (tb), then use formula Duty = ta /(ta + tb) * 100
I guess if I can set-up port 0 to 1 and 1 to 0 interrupt then I can sort rest out.
I’m not experienced with Flowcode, so I am looking for that extra pointer in the right direction.
Can you explain in a bit more detail please?
1 β€Use the same macro. Simply make a decision depending on whether the pine starts off as a 1 or a 0 and act accordinglyβ€
As I stated I was confused with port change interrupt. Are you saying use the GP2 INT, but set both rising, and falling edge to call same macro, or are you saying use Port change interrupt?
If latter, how is it set for just one pin? When it looks like you need to set for RB1 , RB3 an RB5.
2) β€The 12F675 should be able to do the PWM capture by means of using a timer interrupt on a fairly fast timeout. Depends on the rate of PWM that you need to be able to detect.β€
Is that enough information for a beginner to compile a compete Flowcode?
Frequency is 3KHz.
I have a theory on how to detect duty: wait until port changes form 0 to 1, start timer a (ta),port changes from 1 to 0, stop timer(a) and start timer(b), wait till port changes from 0 to 1, stop timer b (tb), then use formula Duty = ta /(ta + tb) * 100
I guess if I can set-up port 0 to 1 and 1 to 0 interrupt then I can sort rest out.
I’m not experienced with Flowcode, so I am looking for that extra pointer in the right direction.
Martin
- Benj
- Matrix Staff
- Posts: 15312
- Joined: Mon Oct 16, 2006 10:48 am
- Location: Matrix TS Ltd
- Has thanked: 4803 times
- Been thanked: 4314 times
- Contact:
Re: 12F675 Mains Zero Crossing Detection Using Single Resistor.
Hello
1) If you use the port change interrupt then the interrupt will occur every time the data is changed on the pin eg so you wont have to mess about changing the polarity of the INT interrupt. The port change interrupt will then call a single macro when the pin changes state. At the start of your interrupt if you need to do different things depending on the current state then you can read the pin and process as required. Look at the properties for the port change interrupt and you should see that you can enable and disable every pin using the drop down options.
2) Are you using the port change interrupt mentioned above to do the PWM input or are you using a different pin. If you are using the port change interrupt then inside the interrupt macro you can do the following.
Read pin into pin variable
If pin = 1
reset your count variable to 0
else if pin = 0
assign the count variable to a capture variable.
Then in your main routine you can do the following
while 1
count = count + 1
C code - delay_10us(1);
The value you will get in the capture variable will then be equal to the mark time in 10uS increments.
1) If you use the port change interrupt then the interrupt will occur every time the data is changed on the pin eg so you wont have to mess about changing the polarity of the INT interrupt. The port change interrupt will then call a single macro when the pin changes state. At the start of your interrupt if you need to do different things depending on the current state then you can read the pin and process as required. Look at the properties for the port change interrupt and you should see that you can enable and disable every pin using the drop down options.
2) Are you using the port change interrupt mentioned above to do the PWM input or are you using a different pin. If you are using the port change interrupt then inside the interrupt macro you can do the following.
Read pin into pin variable
If pin = 1
reset your count variable to 0
else if pin = 0
assign the count variable to a capture variable.
Then in your main routine you can do the following
while 1
count = count + 1
C code - delay_10us(1);
The value you will get in the capture variable will then be equal to the mark time in 10uS increments.
Regards Ben Rowland - MatrixTSL
Flowcode Product Page - Flowcode Help Wiki - Flowcode Examples - Flowcode Blog - Flowcode Course - My YouTube Channel
Flowcode Product Page - Flowcode Help Wiki - Flowcode Examples - Flowcode Blog - Flowcode Course - My YouTube Channel
-
- Matrix Staff
- Posts: 9521
- Joined: Sat May 05, 2007 2:27 pm
- Location: Northamptonshire, UK
- Has thanked: 2585 times
- Been thanked: 3815 times
Re: 12F675 Mains Zero Crossing Detection Using Single Resistor.
Thank you Ben. I will have another go tonight.
Martin
-
- Matrix Staff
- Posts: 9521
- Joined: Sat May 05, 2007 2:27 pm
- Location: Northamptonshire, UK
- Has thanked: 2585 times
- Been thanked: 3815 times
Re: 12F675 Mains Zero Crossing Detection Using Single Resistor.
Ben. Thanks for all your help. I re-looked at port change as you suggested, and I can see now how easy it is
. I was just have a off day when I first tried to work it out. That's my excuse and I'm sticking to it 


Martin
-
- Matrix Staff
- Posts: 9521
- Joined: Sat May 05, 2007 2:27 pm
- Location: Northamptonshire, UK
- Has thanked: 2585 times
- Been thanked: 3815 times
Re: 12F675 Mains Zero Crossing Detection Using Single Resistor.
I am trying to use Flowcode to do the following:
Monitor o/p (using GP0) from an opto-isolator that will either have no o/p, or a PWM o/p duty varying from 29% to 98% at a frequency of 3.9KHz.
Since o/p is from an opto-isolator its inverted, i.e. mark = logic 0, space = logic1.
I need to convert any measured duty above 28% to a set time delay. (trigger GP5 for timed duration)
Any duty less than 29% = 0 time delay
29% duty = min time delay = 2.6 milliseconds
63% duty = 5.9 milliseconds = Β½ way between min and max etc.
98% duty = max time delay = 9.2 milliseconds.
Since frequency = 3.9KHZ then period = 256 microseconds.
Duty = space/256
Note duty would normally be: mark/256, but as already stated, PWM is inverted.
I am assuming what I would do is keep monitoring PWM o/p until it changes from 1 to 0
Start timer. When changes from 0 to 1 stop timer read time value(1=1microsecond) / 0.256 / 10.7 = Time delay (x10)milliseconds.
I and unable to test circuit for a few days, but would like to have a Flowcode generated hex file ASAP.
Is my theory correct please? If not, some pointers would be very useful…Thanks.
In calculating time delay, instead of using LUT, min time delay would workout at 2.9 ms.
I would prefer this value to be a bit higher than 2.6ms rather than max delay to be any different.
Also I was wondering if getting a timer interrupt every microsecond is even possible at a clock frequency of 4MHz?
Monitor o/p (using GP0) from an opto-isolator that will either have no o/p, or a PWM o/p duty varying from 29% to 98% at a frequency of 3.9KHz.
Since o/p is from an opto-isolator its inverted, i.e. mark = logic 0, space = logic1.
I need to convert any measured duty above 28% to a set time delay. (trigger GP5 for timed duration)
Any duty less than 29% = 0 time delay
29% duty = min time delay = 2.6 milliseconds
63% duty = 5.9 milliseconds = Β½ way between min and max etc.
98% duty = max time delay = 9.2 milliseconds.
Since frequency = 3.9KHZ then period = 256 microseconds.
Duty = space/256
Note duty would normally be: mark/256, but as already stated, PWM is inverted.
I am assuming what I would do is keep monitoring PWM o/p until it changes from 1 to 0
Start timer. When changes from 0 to 1 stop timer read time value(1=1microsecond) / 0.256 / 10.7 = Time delay (x10)milliseconds.
I and unable to test circuit for a few days, but would like to have a Flowcode generated hex file ASAP.
Is my theory correct please? If not, some pointers would be very useful…Thanks.
In calculating time delay, instead of using LUT, min time delay would workout at 2.9 ms.
I would prefer this value to be a bit higher than 2.6ms rather than max delay to be any different.
Also I was wondering if getting a timer interrupt every microsecond is even possible at a clock frequency of 4MHz?
Martin
- Benj
- Matrix Staff
- Posts: 15312
- Joined: Mon Oct 16, 2006 10:48 am
- Location: Matrix TS Ltd
- Has thanked: 4803 times
- Been thanked: 4314 times
- Contact:
Re: 12F675 Mains Zero Crossing Detection Using Single Resistor.
Hello
You may want to try playing with the timer1 interrupt. This can count in 16 bit so you should be able to get it on a fairly low prescaler. Use an interrupt to detect when the pulse starts and start the timer1 running using a line of C. When the interrupt fires again to tell you that the pulse has ended and you should then be able to disable the timer and read back the timer count registers using a C code block, also remember to reset the timer count registers to 0 to allow the process to start again correctly next time around.
Hope this helps.
You may want to try playing with the timer1 interrupt. This can count in 16 bit so you should be able to get it on a fairly low prescaler. Use an interrupt to detect when the pulse starts and start the timer1 running using a line of C. When the interrupt fires again to tell you that the pulse has ended and you should then be able to disable the timer and read back the timer count registers using a C code block, also remember to reset the timer count registers to 0 to allow the process to start again correctly next time around.
Hope this helps.
Regards Ben Rowland - MatrixTSL
Flowcode Product Page - Flowcode Help Wiki - Flowcode Examples - Flowcode Blog - Flowcode Course - My YouTube Channel
Flowcode Product Page - Flowcode Help Wiki - Flowcode Examples - Flowcode Blog - Flowcode Course - My YouTube Channel
-
- Matrix Staff
- Posts: 9521
- Joined: Sat May 05, 2007 2:27 pm
- Location: Northamptonshire, UK
- Has thanked: 2585 times
- Been thanked: 3815 times
Re: 12F675 Mains Zero Crossing Detection Using Single Resistor.
Since I am interested in measuring up to a maximum of 256ΞΌS, anything over this is classed as fully off (or interrupt routine could have been missed. I could use 8bit of timer 1 by setting tmr1h = 255
So I’m assuming I would need to set timer1 with a prescaler of 1:1 so with an internal osc set at 4MHz, timer increments 1 every microsecond. So C code would be:
tmr1h = 255;
tmr1l = 0;
t1con = 0x03;
Is this correct so far?
Would you have a sample Flowcode which uses timer1 to measure time of port change duration, e.g.
A variable called mark_time, which will have stored the total time in (microseconds) GP5 was low.
Any number over 255, should just be set at 255.
So I’m assuming I would need to set timer1 with a prescaler of 1:1 so with an internal osc set at 4MHz, timer increments 1 every microsecond. So C code would be:
tmr1h = 255;
tmr1l = 0;
t1con = 0x03;
Is this correct so far?
Would you have a sample Flowcode which uses timer1 to measure time of port change duration, e.g.
A variable called mark_time, which will have stored the total time in (microseconds) GP5 was low.
Any number over 255, should just be set at 255.
Martin
-
- Matrix Staff
- Posts: 9521
- Joined: Sat May 05, 2007 2:27 pm
- Location: Northamptonshire, UK
- Has thanked: 2585 times
- Been thanked: 3815 times
Re: 12F675 Mains Zero Crossing Detection Using Single Resistor.
Ben,
I have posted a nearly working version. Would you mind taking a look at what I have posted please, and suggest if you would of gone in a similar direction?
I have worked out to use t1con = 0x01 = timer1 start and t1con = 0x00 for timer1 stop.
There is problem I am trying to overcome. If variable for time delay(fet_on_time)=0x30.
Then Decimal = 48. So fet_on_time = 100us x 48 = 4.8ms = 4800us.
However using a simulator Real elapsed time = 23634us
Which took 94536 clock cycles and 17727 instructions
Note: these figures are for the port fet drive on time only.
Is there a workaround to get Flowcode simulator to simulate port change interrupt, since it does not work with 12f675, but works in other simulators after compiling to hex?
I have posted a nearly working version. Would you mind taking a look at what I have posted please, and suggest if you would of gone in a similar direction?
I have worked out to use t1con = 0x01 = timer1 start and t1con = 0x00 for timer1 stop.
There is problem I am trying to overcome. If variable for time delay(fet_on_time)=0x30.
Then Decimal = 48. So fet_on_time = 100us x 48 = 4.8ms = 4800us.
However using a simulator Real elapsed time = 23634us
Which took 94536 clock cycles and 17727 instructions
Note: these figures are for the port fet drive on time only.
Is there a workaround to get Flowcode simulator to simulate port change interrupt, since it does not work with 12f675, but works in other simulators after compiling to hex?
- Attachments
-
- PWM to AC4.fcf
- (10.5 KiB) Downloaded 503 times
Martin
-
- Matrix Staff
- Posts: 9521
- Joined: Sat May 05, 2007 2:27 pm
- Location: Northamptonshire, UK
- Has thanked: 2585 times
- Been thanked: 3815 times
Re: 12F675 Mains Zero Crossing Detection Using Single Resistor.
If a port is switched on for a set delay time.
E.g
port a(1)=1
delay 5 seconds
port a(1)=1
Does GP2 int interrupt stop timing short if triggered?
So if 5-second delay has started, then GP2 goes from low to high (will have interrupt set for rising edge) after 3 seconds, will int macro now be active, then delay continue with subroutine has finished?
E.g
port a(1)=1
delay 5 seconds
port a(1)=1
Does GP2 int interrupt stop timing short if triggered?
So if 5-second delay has started, then GP2 goes from low to high (will have interrupt set for rising edge) after 3 seconds, will int macro now be active, then delay continue with subroutine has finished?
Martin
-
- Matrix Staff
- Posts: 9521
- Joined: Sat May 05, 2007 2:27 pm
- Location: Northamptonshire, UK
- Has thanked: 2585 times
- Been thanked: 3815 times
Re: 12F675 Mains Zero Crossing Detection Using Single Resistor.
Two questions and no answers. Do I have to start a new thread in order to get a reply?
I know with the second question, in theory, timed delay should stop so GP2 INT would take priority.
So I am assuming if interrupt occurs after 2 seconds, then when interrupt routine has finished, the delay will occur for another 3 seconds?
I know with the second question, in theory, timed delay should stop so GP2 INT would take priority.
So I am assuming if interrupt occurs after 2 seconds, then when interrupt routine has finished, the delay will occur for another 3 seconds?
Martin