View previous topic :: View next topic |
Author |
Message |
edbfmi1
Joined: 18 Jul 2006 Posts: 103
|
Simple Zero Crossing Detector |
Posted: Wed Aug 19, 2015 4:08 pm |
|
|
Hello all,
I have something that is driving me crazy.
I am trying to detect the Zero Crossing of the AC Power line.
I have the circuit designed with a 6.2M Ohm resistor coming from the AC line into PIN BO with diodes between VDD and VSS. This gives a fairly nice 0 to 5VDC square wave on PIN B0
I am using PCM V4.140, and a PIC16F716.
The problem I am having is the program is only interrupting when the RB0 interrupt is positive. If I put a breakpoint in the interrupt routines if-else statement it never interrupts in the "else" portion.
I stripped the program to the bare bones.
Any help would be appreciated.
Code: | #include <16F716.h>
// Checksum 5fcd
#fuses XT,NOWDT,NOPROTECT,PUT
#use delay(clock=4000000)
#FILL_ROM 0x00
//#define INTERLOCK_IN PIN_A4
#define Z_CROSS_INPUT PIN_B0
//#define SENSOR PIN_B1
//#define PWR_SW PIN_B2
#define HEARTBEAT PIN_B3
//#define AC PIN_B4
//#define DC_TOP PIN_B5
//#define INTERLOCK_OUT PIN_B6
#define GATE PIN_B7
#BYTE intcon = 0x0B
int8 z_cross_counter; // Counts number of zero crossings
int8 StatusBits1;
#bit ac_top = StatusBits1.3 // top half of sinewave
#bit ac_bottom = StatusBits1.4 // bottom half of sinewave
//#bit gatehi = StatusBits1.5 // Set when gate is high
//#bit pwr_on = StatusBits1.6 // Power switch is on
//#bit startup = StatusBits1.7
#int_ext
void detect_Z_CROSS()
{
z_cross_counter++;
if(input(Z_CROSS_INPUT))
{
delay_cycles(1);
ac_top = TRUE;
ac_bottom = FALSE;
output_toggle(HEARTBEAT);
}
else
{
delay_cycles(1);
ac_top = FALSE;
ac_bottom = TRUE;
output_toggle(HEARTBEAT);
}
}
void main()
{
output_low(GATE);
enable_interrupts(GLOBAL);
enable_interrupts(INT_EXT);
// port_b_pullups(false);
while (1==1)
{
delay_cycles(1);
}
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Wed Aug 19, 2015 4:28 pm |
|
|
The external interrupt will only occur on one edge, either the positive or
negative edge. You should call the ext_int_edge() function to select the
desired edge. If you don't call it (as in your program), it defaults to the
positive edge. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9244 Location: Greensville,Ontario
|
|
Posted: Wed Aug 19, 2015 6:09 pm |
|
|
I'll assume the 'AC power line' is either 120 or 240 volts. If so you really should NOT tie the PIC directly to it rather use an optocoupler type device for isolation. You could also use a small transformer for this purpose. This is a safety issue. Should (when !) that resistor fails and blows up the PIC, it'll scare you and bam... the DVM you had in your hand is across the room going through the window in far less time that it takes you to read this.
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19541
|
|
Posted: Thu Aug 20, 2015 3:00 am |
|
|
There are quite a lot of circuits that use direct coupling like this.
First thing is though that you need to design the circuit so if a part fails it will fail safe. Simple thing like having a PCB fuse built in the line feeding the resistor, so that if this fails (they do...), the fuse will blow. Chose the clamp diodes to well exceed the rating of the fuse. Also look carefully at the voltage rating of the resistor (most are _not_ mains rated....).
Then though the critical thing. If designing a circuit like this, when working with it, you should be powering it through an isolation transformer. In many countries this is a _requirement_ when working on non-isolated circuits. After it is designed, it can then be encapsulated in a way that meets the insulation requirements for a non isolated circuit, and be 'legal', but this won't save you when designing it....
Then have you done anything like a high voltage 'working' course?. This will teach you basic techniques that reduce the chance of death. Things like avoiding jewellery when working, and putting one hand in your pocket when touching anything, so that there is not an electrical path across your chest, if something does go wrong.
Working safely with mains kit, needs to be done 'both eyes open', with a lot of thought, if it is not going to jump out and 'bite' you.....
To detect both edges, either have the interrupt routine reprogram the detection edge depending on the polarity of the signal, or use the interrupt on chance ability that does detect both edges.
Code: |
//For the EXT1 interrupt
#int_ext
void detect_Z_CROSS()
{
z_cross_counter++;
if(input(Z_CROSS_INPUT))
{
//signal is high so we want to detect falling edge
ext_int_edge(H_TO_L);
ac_top = TRUE;
ac_bottom = FALSE;
output_toggle(HEARTBEAT);
}
else
{
ext_int_edge(L_TO_H);
ac_top = FALSE;
ac_bottom = TRUE;
output_toggle(HEARTBEAT);
}
}
|
The delay_cycles seems rather pointless - it's going to be perhaps 30 cycles after the edge before it reaches this point.... |
|
|
edbfmi1
Joined: 18 Jul 2006 Posts: 103
|
|
Posted: Thu Aug 20, 2015 6:11 am |
|
|
Thanks for all the input.
This was just a rough design for proof of concept. The final design does have optical isolation to tie it to the AC mains.
As for the delay_cycles(1);
Quote: | The delay_cycles seems rather pointless - it's going to be perhaps 30 cycles after the edge before it reaches this point.... |
I use that as a "NOP" for a place to set breakpoints since the compiler does not have a NOP function. |
|
|
|