Having peeled several layers of the debug onion on my 16F18044 project, I have hit another stone wall. I cannot get the ZCD to run as the datasheet says it should. Do any of you have helpful hints, or even better, known working setup example code?
I'm not a PIC or uC beginner, so I have flogged the datasheet, Microchip tech briefs and documents, online searches, etc., and tried many of the possibilities. None of them seem to make it work.
I ...think... it's a problem with enabling/setup on the RA2 pin (17 in this chip). The datasheet says this is an analog OUTPUT, and the ZCD section seems to say that enabling the ZCD forces the pin to be an analog output. The datasheet says that analog output use (like for the ZCD) should be a higher priority than analog input or digital I/O.
That is not what I see. I have become confused how TRISA.2, ANSELA.2, LATA.2, the WPUA register, and ZCDSEN might interact. This is because one combination of these let me get 0.6Vdc on pin17/RA2, but even this setting did not produce a readable ZCDOUT signal that I could echo as an output on a properly-set-up RA5.
I have disabled interrupts, and am just running a do loop that flips some LED pins as a side effect, and also does
LATA.5 = ZCDOUT to put the internal signal out on a pin so I can see it on an oscilloscope.
Can one of you help me with a known-working setup for the various port a control registers? I have found conflicting or incomplete advice from Microchip documents and examples in net searches.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I am not sure what is not working for you. Let us create a baseline to work from.
What happens when you try this?
Evan
// ---------------------------------------------------------// Zero Cross Detect (ZCD) Demo – POLLING VERSION// PIC16F18044// GCBASIC// --------------------------------------------------------- #chip 16F18044 #option explicit// ---------------------------------------------------------// Pin Setup// --------------------------------------------------------- // LED on RA0 DIR PORTA.0 OUT PORTA.0 = 0 // ZCD input is on RA2 for PIC16F18044 DIR PORTA.2 IN // Digital mode required for ZCD but as GCBASIC sets all ports to digital there is no action needed// ---------------------------------------------------------// ZCD Module Setup// --------------------------------------------------------- // ZCDCON register bits: // bit7 ZCDEN – Enable ZCD // bit6 ZCDOUT – Output state (read only) // bit5 ZCDPOL – Polarity select // bit1 ZCDINTN – Interrupt on falling edge (unused here) // bit0 ZCDINTP – Interrupt on rising edge (unused here) // Enable ZCD, normal polarity, NO interrupts ZCDCON = 0b10000000 // ZCDEN=1, all other bits 0// ---------------------------------------------------------// Variables for polling// --------------------------------------------------------- DIM lastState AS BYTE DIM currentState AS BYTE lastState = ZCDCON.ZCDOUT // Read initial state// ---------------------------------------------------------// Main Loop – Poll ZCDOUT// ---------------------------------------------------------Do currentState = ZCDCON.ZCDOUT // Detect a change (zero crossing) IF currentState <> lastState THEN PORTA.0 = NOT PORTA.0 // Toggle LED lastState = currentState END IF // Small delay to avoid excessive CPU usage wait 1 us Loop
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Copied and pasted your code into GCStudio.
Changed PORTA.0 to PORTC.1, which has an LED on my hardware.
Compiled and programmed. No changes on the LED pin, per oscilloscope.
Probed ZCD pin with oscilloscope, resulting in a 60Hz square-ish wave from slightly below Vss to slightly above. I interpreted this as the clamp diodes catching the incoming current.
Added to your code near the top:
config ZCD=On
to cause the ZCD to be on from POR.
No LED action, but the ZCD pin now shows a square-ish wave about 50-80mV above and below 620mV dc.
I interpret his as the config change forcing the ZCD pin to the correct analog output state, but with the DC level at 620mV, not the nominal 750mV per the data sheet.
So - no joy.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Per the oscilloscope traces, 578mV +/-4 to 618mV, also +/4, as the voltage is slightly different across the otherwise flat-ish bits of the wave. Photo GCHELP-2.PNG above shows a representative trace from the scope.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I have a background in both analog and digital hardware as well. The minor excursions above and below a DC level matches what I would expect for an analog circuit that is trying to switch current sources onto a pin to servo it to a DC level.
The datasheet electrical specs say that the ZCD input pin should sit at 0.9V typical, but gives no max or min, and further notes that
† Data in “Typ” column is at 3.0V, 25°C unless otherwise stated. These parameters are for design guidance only and are not tested.
I'm using it at 5V, 25C, so I expected some variance, especially with it not being a tested and guaranteed parameter. I also have a 10M pullup resistor to +5, intending to modify this value to bias the input toward the actual zero crossing time, per the datasheet section on the ZCD.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I do not have your circuit so this is likely to be a missing or insufficient series current-limiting resistor: The ZCD pin (RA2/ZCD1 on the PIC16F18044) must have a series resistor (typically 10kΩ to 100kΩ, depending on your signal amplitude and frequency) between your external signal source and the pin. Without it, the module "fights" the input drive by sinking/sourcing up to ~1mA (per datasheet specs), clamping the pin hard around ZCPINV. This creates those square edges and glitches as the input tries (and fails), to swing freely.
Your ~1V amplitude did suggest a low-voltage test signal ( between 0-5V), but the clamping is distorting it into pulses where the OUT bit flips internally.
Add the series resistor immediately: Start with 10kΩ in line with your signal source to the ZCD pin. This limits current to safe levels (<100μA) and lets the pin swing without clamping so aggressively. Recheck the scope— the waveform should smooth out to proper zero-cross transitions.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
There has always been a current limiting resistance there. Per the datasheet, I sized it for 100Vac to 140ac peaks, per the datasheet recommendations to keep peak current under 300uA. The resistance is 600K, two 300K resistors in series to get enough voltage rating for the resistances. (0805 resistors are rated for no more than 200V across each resistor.)
I can post the circuit as a picture, but it's not interesting - just two 300K resistances in series from the (isolated...) 120Vac nominal power line. The PIC is referenced to AC line Neutral, and the AC Line voltage swings nominally +/-170V peak around Neutral. (I have a background in AC power line design.)
I originally used a 100nF cap in series with the 600K of series resistance, again per the datasheet recommendations, as a way to correct the actual crossover point back to the real crossover point, but got the oscillation the datasheet mentions so I jumpered this out with a wire on the theory that getting a slightly-off ZCD signal would be better than not having one at all. But no luck, either way.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Ok. Let us rule out the GCASM. Attached is HEX same code as above but using PORTC.1 for signal.
This was generated by using PIC-AS from GCBASIC source ( this is all integrated but this rules out GCASM).
Hex files can be different yet function the same. The hexs are functionally the same. The is a different header statement which Microchip no longers complies with.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I am thinking you have tried this using another compiler? yes/no. If yes, results?
From my research everything points to the input side being incorrect.
I can open a support ticket to get some reference code but I do not think it will any different from what I have posted. But, I could be corrected ( often am ).
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I suppose I could transcode it into C for the Microchip X lab suite. I may just try to tinker the ASM listing, as assembler isn't all that difficult to write, just a pain.
I'm still kind of stuck on why the ZCD in pin seems to be acting kind of like the description of what it does, but the ZCDOUT bit in the ZCDCON register would be either not changing state or else unreadable by machine code. An interrupt driven setup can be more difficult to debug, but simply polling a bit in a readable register, as ZCDOUT is described, should be the simplest of simple.
That is in fact why I was assuming that I just didn't have the setup correct. I figured it was more likely that I just didn't understand something.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
If you are going to open a support ticket, could you instead open it for this circuit? I think that this one would actually be applicable to more people's projects:
An oddity popped up. While awaiting the microchip case comments (they are, reasonably, thinly staffed during the holidays) I decided to test whether I could read back the readable bits in ZCDCON - bits 7 and 4.
... and found that portc.3 toggles as expected, but both portc.7 and portc.4 show low, not high as I expected from portc.7 or toggling like I expect from portc.4 ; and that either I can't read the interrupt flag bits, or toggling the POL bit does not affect them as the datasheet says it does.
I tried my hand at manually dis-assembling the list file, but found it will take me too long to re-learn PIC asm language.
I get the same result from setting ZCDCON.7 off, which I interpret as the same problem with the other bits - my GCBasic code is not reading ZCDCON.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I have completed a BANKSEL analysis and there is an issue in the generated ASM as follows.
Lots of error caused by an incorrect mask.
Bank and Page Checker 1.02
Bank Analysis
59 CLRF TRISC : Bank map 0 - 0
62 BSF ZCDCON,7 : Bank map 32 - 32
64 BSF ZCDCON,4 : Bank map 32 - 32
68 CLRF SYSTEMP1 : Bad bank, requires 0 but could be in 32
69 BTFSC ZCDCON,4 : Bank map 32 - 32
70 INCF SYSTEMP1,F : Bad bank, requires 0 but could be in 32
71 COMF SYSTEMP1,F : Bad bank, requires 0 but could be in 32
72 BCF ZCDCON,4 : Bank map 32 - 32
73 BTFSC SYSTEMP1,0 : Bad bank, requires 0 but could be in 32
74 BSF ZCDCON,4 : Bank map 32 - 32
76 CLRF SYSTEMP1 : Bad bank, requires 0 but could be in 32
77 BTFSC LATC,3 : Bad bank, requires 0 but could be in 32
78 INCF SYSTEMP1,F : Bad bank, requires 0 but could be in 32
79 COMF SYSTEMP1,F : Bad bank, requires 0 but could be in 32
80 BCF LATC,3 : Bad bank, requires 0 but could be in 32
81 BTFSC SYSTEMP1,0 : Bad bank, requires 0 but could be in 32
82 BSF LATC,3 : Bad bank, requires 0 but could be in 32
84 BCF LATC,7 : Bad bank, requires 0 but could be in 32
85 BTFSC ZCDCON,7 : Bank map 32 - 32
86 BSF LATC,7 : Bad bank, requires 0 but could be in 32
88 BCF LATC,1 : Bad bank, requires 0 but could be in 32
89 BTFSC ZCDCON,1 : Bank map 32 - 32
90 BSF LATC,1 : Bad bank, requires 0 but could be in 32
92 BCF LATC,0 : Bad bank, requires 0 but could be in 32
93 BTFSC ZCDCON,0 : Bank map 32 - 32
94 BSF LATC,0 : Bad bank, requires 0 but could be in 32
134 CLRF OSCCON2 : Bank map 4 - 4
136 CLRF OSCCON3 : Bank map 4 - 4
140 MOVWF OSCFRQ : Bank map 4 - 4
145 BCF ADCON0,ADFM0 : Bank map 58 - 58
148 BCF ADCON0,ADON : Bank map 58 - 58
151 CLRF ANSELA : Bank map 61 - 61
153 CLRF ANSELB : Bank map 61 - 61
155 CLRF ANSELC : Bank map 61 - 61
159 BCF CM1CON0,C1EN : Bank map 33 - 33
163 CLRF PORTA : Bank map 0 - 0
165 CLRF PORTB : Bank map 0 - 0
167 CLRF PORTC : Bank map 0 - 0
Page Analysis
I will sort tomorrow. I have a version here that works but I need to build the compiler.
No errors.
Bank and Page Checker 1.02
Bank Analysis
55 CLRF TRISC : Bank map 0 - 0
58 BSF ZCDCON,7 : Bank map 32 - 32
60 BSF ZCDCON,4 : Bank map 32 - 32
65 CLRF SYSTEMP1 : Bank map 0 - 0
67 BTFSS ZCDCON,4 : Bank map 32 - 32
70 INCF SYSTEMP1,F : Bank map 0 - 0
73 COMF SYSTEMP1,F : Bank map 0 - 0
75 BCF ZCDCON,4 : Bank map 32 - 32
77 BTFSS SYSTEMP1,0 : Bank map 0 - 0
80 BSF ZCDCON,4 : Bank map 32 - 32
84 CLRF SYSTEMP1 : Bank map 0 - 0
85 BTFSC LATC,3 : Bank map 0 - 0
86 INCF SYSTEMP1,F : Bank map 0 - 0
87 COMF SYSTEMP1,F : Bank map 0 - 0
88 BCF LATC,3 : Bank map 0 - 0
89 BTFSC SYSTEMP1,0 : Bank map 0 - 0
90 BSF LATC,3 : Bank map 0 - 0
92 BCF LATC,7 : Bank map 0 - 0
94 BTFSS ZCDCON,7 : Bank map 32 - 32
97 BSF LATC,7 : Bank map 0 - 0
101 BCF LATC,1 : Bank map 0 - 0
103 BTFSS ZCDCON,1 : Bank map 32 - 32
106 BSF LATC,1 : Bank map 0 - 0
110 BCF LATC,0 : Bank map 0 - 0
112 BTFSS ZCDCON,0 : Bank map 32 - 32
115 BSF LATC,0 : Bank map 0 - 0
131 CLRF OSCCON2 : Bank map 4 - 4
133 CLRF OSCCON3 : Bank map 4 - 4
137 MOVWF OSCFRQ : Bank map 4 - 4
142 BCF ADCON0,ADFM0 : Bank map 58 - 58
145 BCF ADCON0,ADON : Bank map 58 - 58
148 CLRF ANSELA : Bank map 61 - 61
150 CLRF ANSELB : Bank map 61 - 61
152 CLRF ANSELC : Bank map 61 - 61
156 BCF CM1CON0,C1EN : Bank map 33 - 33
160 CLRF PORTA : Bank map 0 - 0
162 CLRF PORTB : Bank map 0 - 0
164 CLRF PORTC : Bank map 0 - 0
Page Analysis
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Download and double click to automatically update your system. You will need a recent install of GCSTUDIO but do try first. This will update your compiler and a support file.
It has been a very happy new year - the mpk_build_1546 cured the problem with accessing the ZCD control register completely.
Anobium, thank you so very much for turning around that fix, expecially during the "lost days" between Christmas and New Years. I'm impressed - and very thankful.
The best of the new year to you and yours!!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Having peeled several layers of the debug onion on my 16F18044 project, I have hit another stone wall. I cannot get the ZCD to run as the datasheet says it should. Do any of you have helpful hints, or even better, known working setup example code?
I'm not a PIC or uC beginner, so I have flogged the datasheet, Microchip tech briefs and documents, online searches, etc., and tried many of the possibilities. None of them seem to make it work.
I ...think... it's a problem with enabling/setup on the RA2 pin (17 in this chip). The datasheet says this is an analog OUTPUT, and the ZCD section seems to say that enabling the ZCD forces the pin to be an analog output. The datasheet says that analog output use (like for the ZCD) should be a higher priority than analog input or digital I/O.
That is not what I see. I have become confused how TRISA.2, ANSELA.2, LATA.2, the WPUA register, and ZCDSEN might interact. This is because one combination of these let me get 0.6Vdc on pin17/RA2, but even this setting did not produce a readable ZCDOUT signal that I could echo as an output on a properly-set-up RA5.
I have disabled interrupts, and am just running a do loop that flips some LED pins as a side effect, and also does
LATA.5 = ZCDOUT to put the internal signal out on a pin so I can see it on an oscilloscope.
Can one of you help me with a known-working setup for the various port a control registers? I have found conflicting or incomplete advice from Microchip documents and examples in net searches.
I am not sure what is not working for you. Let us create a baseline to work from.
What happens when you try this?
Evan
Copied and pasted your code into GCStudio.
Changed PORTA.0 to PORTC.1, which has an LED on my hardware.
Compiled and programmed. No changes on the LED pin, per oscilloscope.
Probed ZCD pin with oscilloscope, resulting in a 60Hz square-ish wave from slightly below Vss to slightly above. I interpreted this as the clamp diodes catching the incoming current.
Added to your code near the top:
to cause the ZCD to be on from POR.

No LED action, but the ZCD pin now shows a square-ish wave about 50-80mV above and below 620mV dc.
I interpret his as the config change forcing the ZCD pin to the correct analog output state, but with the DC level at 620mV, not the nominal 750mV per the data sheet.
So - no joy.
Tried inserting images will add attachments to this comment
How much is 'slightly' ? What is the real voltage?
Per the oscilloscope traces, 578mV +/-4 to 618mV, also +/4, as the voltage is slightly different across the otherwise flat-ish bits of the wave. Photo GCHELP-2.PNG above shows a representative trace from the scope.
I have a background in both analog and digital hardware as well. The minor excursions above and below a DC level matches what I would expect for an analog circuit that is trying to switch current sources onto a pin to servo it to a DC level.
The datasheet electrical specs say that the ZCD input pin should sit at 0.9V typical, but gives no max or min, and further notes that
† Data in “Typ” column is at 3.0V, 25°C unless otherwise stated. These parameters are for design guidance only and are not tested.
I'm using it at 5V, 25C, so I expected some variance, especially with it not being a tested and guaranteed parameter. I also have a 10M pullup resistor to +5, intending to modify this value to bias the input toward the actual zero crossing time, per the datasheet section on the ZCD.
Good to have you here!
I do not have your circuit so this is likely to be a missing or insufficient series current-limiting resistor: The ZCD pin (RA2/ZCD1 on the PIC16F18044) must have a series resistor (typically 10kΩ to 100kΩ, depending on your signal amplitude and frequency) between your external signal source and the pin. Without it, the module "fights" the input drive by sinking/sourcing up to ~1mA (per datasheet specs), clamping the pin hard around ZCPINV. This creates those square edges and glitches as the input tries (and fails), to swing freely.
Your ~1V amplitude did suggest a low-voltage test signal ( between 0-5V), but the clamping is distorting it into pulses where the OUT bit flips internally.
Add the series resistor immediately: Start with 10kΩ in line with your signal source to the ZCD pin. This limits current to safe levels (<100μA) and lets the pin swing without clamping so aggressively. Recheck the scope— the waveform should smooth out to proper zero-cross transitions.
There has always been a current limiting resistance there. Per the datasheet, I sized it for 100Vac to 140ac peaks, per the datasheet recommendations to keep peak current under 300uA. The resistance is 600K, two 300K resistors in series to get enough voltage rating for the resistances. (0805 resistors are rated for no more than 200V across each resistor.)
I can post the circuit as a picture, but it's not interesting - just two 300K resistances in series from the (isolated...) 120Vac nominal power line. The PIC is referenced to AC line Neutral, and the AC Line voltage swings nominally +/-170V peak around Neutral. (I have a background in AC power line design.)
I originally used a 100nF cap in series with the 600K of series resistance, again per the datasheet recommendations, as a way to correct the actual crossover point back to the real crossover point, but got the oscillation the datasheet mentions so I jumpered this out with a wire on the theory that getting a slightly-off ZCD signal would be better than not having one at all. But no luck, either way.
Ok. Let us rule out the GCASM. Attached is HEX same code as above but using PORTC.1 for signal.
This was generated by using PIC-AS from GCBASIC source ( this is all integrated but this rules out GCASM).
Thanks! I'll go take a look.
The hex files do not match. I haven't run the PIC-AS.hex file yet, but will in the next few minutes.
Hex files can be different yet function the same. The hexs are functionally the same. The is a different header statement which Microchip no longers complies with.
Just ran the PIC-AS code. No change in operation, still no blinking light.
I am thinking you have tried this using another compiler? yes/no. If yes, results?
From my research everything points to the input side being incorrect.
I can open a support ticket to get some reference code but I do not think it will any different from what I have posted. But, I could be corrected ( often am ).
I suppose I could transcode it into C for the Microchip X lab suite. I may just try to tinker the ASM listing, as assembler isn't all that difficult to write, just a pain.
I'm still kind of stuck on why the ZCD in pin seems to be acting kind of like the description of what it does, but the ZCDOUT bit in the ZCDCON register would be either not changing state or else unreadable by machine code. An interrupt driven setup can be more difficult to debug, but simply polling a bit in a readable register, as ZCDOUT is described, should be the simplest of simple.
That is in fact why I was assuming that I just didn't have the setup correct. I figured it was more likely that I just didn't understand something.
There is no point of recoding. PIC-AS compilation is using the MPLAB-X XC8 compiler. So, this will not improve.
Everything still points to incorrect hardware/resistors and biasing.
I can open a Microchip Support Ticket asking for a reference solution at -5v/5v signal.
Last edit: Anobium 2025-12-28
If you are going to open a support ticket, could you instead open it for this circuit? I think that this one would actually be applicable to more people's projects:
Done - Case Number : 01680157
An oddity popped up. While awaiting the microchip case comments (they are, reasonably, thinly staffed during the holidays) I decided to test whether I could read back the readable bits in ZCDCON - bits 7 and 4.
So I did:
DIR PORTC OUT
Set ZCDCON.7 On
Set ZCDCON.4 On
Do
Loop
... and found that portc.3 toggles as expected, but both portc.7 and portc.4 show low, not high as I expected from portc.7 or toggling like I expect from portc.4 ; and that either I can't read the interrupt flag bits, or toggling the POL bit does not affect them as the datasheet says it does.
I tried my hand at manually dis-assembling the list file, but found it will take me too long to re-learn PIC asm language.
I get the same result from setting ZCDCON.7 off, which I interpret as the same problem with the other bits - my GCBasic code is not reading ZCDCON.
OK. I have the issue root cause. I have run the generated HEX back into our new debugger. I cannot resolve until tomorrow London time.
I have completed a BANKSEL analysis and there is an issue in the generated ASM as follows.
Lots of error caused by an incorrect mask.
I will sort tomorrow. I have a version here that works but I need to build the compiler.
No errors.
Wooo-- Hoooooo!!!
I had actually pondered banksel as an issue, but didn't even get close to that. Nice debugger, by the way.
Download and double click to automatically update your system. You will need a recent install of GCSTUDIO but do try first. This will update your compiler and a support file.
It has been a very happy new year - the mpk_build_1546 cured the problem with accessing the ZCD control register completely.
Anobium, thank you so very much for turning around that fix, expecially during the "lost days" between Christmas and New Years. I'm impressed - and very thankful.
The best of the new year to you and yours!!