Electronics Zero crossing detection with PIC16F877A

Circuit Zero crossing detection with PIC16F877A schematics Circuit Electronics,
Zero crossing detection is very important, especially in power control circuits employing thyristors.

I have come across many people struggling with zero crossing detection with PIC microcontroller and thus they cannot fire triacs or SCRs as required.

So, here I have explained a simple method of detecting zero crossing with PIC16F877A, employing only two or three resistors, a bridge rectifier and an optocoupler for the hardware portion of zero cross detection. 

The PIC 16F877A detects the zero crossing using the RB0/INT external interrupt function. I have explained how the zero cross is detected and how the PIC acts upon detection, below.

Fig. 1 - Schematic, zero crossing signal and RD0 signals

Here is the code for PIC16F877A:
(You can download the source file from
https://rapidshare.com/files/604474700/ZeroCrossing.c )
//Programmer: Syed Tahmid Mahbub
//Compiler: mikroC PRO for PIC v4.60
//Target PIC: PIC16F877A
//Program for zero-cross detection
unsigned char FlagReg;
sbit ZC at FlagReg.B0;

void interrupt(){
     if (INTCON.INTF){          //INTF flag raised, so external interrupt occured
        ZC = 1;
        INTCON.INTF = 0;

void main() {
     PORTB = 0;
     TRISB = 0x01;              //RB0 input for interrupt
     PORTD = 0;
     TRISD = 0;                 //PORTD all output
     OPTION_REG.INTEDG = 0;      //interrupt on falling edge
     INTCON.INTF = 0;           //clear interrupt flag
     INTCON.INTE = 1;           //enable external interrupt
     INTCON.GIE = 1;            //enable global interrupt
     while (1){
           if (ZC){ //zero crossing occurred
              PORTD.B0 = 1; //Send a 1ms pulse
              PORTD.B0 = 0;
              ZC = 0;


     Fig. 2
     Yellow - AC signal
     Blue - signal on RB0

In yellow (in Figure 2), you can see the input AC voltage (sinusoidal waveform). BR1 rectifies this AC voltage to DC, but since there is no bulk smoothing capacitor, the output is not pure DC, but pulsating DC as shown below.

Fig. 3- The rectified pulsating DC

The output of the bridge rectifier BR1 is DC and current through optocoupler is limited by resistors R1 and R2 (you may use a single resistor instead of 2 if you want, but using 2 resistors distributes the power dissipation and thus generates less heat and lower power per resistor).

So, the optocoupler LED stays on for most of the cycle except when the AC sine wave "crosses zero" (is around zero). While the optocoupler LED is on, the transistor is on and so pulls pin RB0 of PIC16F877A low.

PIC16F877A is coded to enable the external interrupt. An interrupt is generated upon the falling edge of RB0. The diagram below will illustrate what I mean by falling edge.

       Yellow - signal on RB0
       Blue - signal from RD0

During most of the cycle, the optocoupler LED is on and so RB0 is low. When the optocoupler LED is off as the AC wave is about to cross "zero", RB0 goes high. The transition from low to high on RB0 is a rising edge. When the optocoupler LED is then again turned on as the AC wave crossed the "zero" level (zero crossing), RB0 goes low. This transition from high to low is a falling edge. And upon a falling edge, an interrupt is generated.

When an interrupt is generated, the ZC flag is set (see code above). In the main code, ZC flag is always checked (this is called polling a flag). When ZC flag is set (zero crossing occurred), a 1ms pulse is generated on RD0 (PORTD0) and then the ZC flag is cleared. For example's sake, I have produced a 1ms pulse. You can do whatever you want upon zero-cross detection. The ZC flag is then again continuously polled to check for next interrupt.

You can see all this illustrated in Figures 2, 3 and 4 above.

Schematics for Zero crossing detection with PIC16F877A Circuit Electronics
read more "Electronics Zero crossing detection with PIC16F877A"

Electronics Temperature Sensor (LM35 + PIC16F877A)

Circuit Temperature sensor (LM35 + PIC16F877A) schematics Circuit Electronics,
Here's one temperature sensor (thermometer) circuit that you can easily build. It uses the popular PIC 16F877A microcontroller. The temperature sensor is LM35. The LM35 outputs an analog voltage proportional to the temperature. The output from the LM35 is 0.1V/'C. So, when temperature sensed is 61'C, the output voltage is 0.61V. This analog voltage is read by the PIC and processed to display the corresponding temperature value on the LCD.

The temperature range for this circuit is 0'C to 150'C.

The analog to digital conversion is done by the PIC ADC module. In the code, I've used the mikroC library function for ADC. You can view the library file here: http://www.mikroe.com/download/eng/documents/compilers/mikroc/pro/pic/help/adc_library.htm

However, you should have a knowledge of how the ADC module works and how to use it. I had written a tutorial on modalities of operation of the PIC 16F877A ADC.

For LCD interfacing, I used the mikroC LCD library. You can view the library file here: http://www.mikroe.com/download/eng/documents/compilers/mikroc/pro/pic/help/lcd_library.htm

Here is the code for PIC16F877A:
(You can download the source file from: https://rapidshare.com/files/3044512089/LM35PIC16F877A.c)
//Programmer: Syed Tahmid Mahbub
//Compiler: mikroC PRO for PIC v4.60
//Target PIC: PIC16F877A
sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;

sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;

unsigned long ADRead;
unsigned int vDisp[3];
unsigned char Display[7];

void main() {

PORTA = 0;
TRISA = 0X01;
PORTB = 0;
TRISB = 0;
LCD_Out(1, 1, "Temp:");
//Display = "+125 'C";
Display[4] = 39; //'
Display[5]= 'C';
ADCON1 = 0x0E;
while (1){
ADRead = (ADC_Get_Sample(0) * 500) >> 10;
vDisp[0] = ADRead / 100;
vDisp[1] = (ADRead / 10) % 10;
vDisp[2] = ADRead % 10;
Display[1] = vDisp[0] + 48;
Display[2] = vDisp[1] + 48;
Display[3] = vDisp[2] + 48;
LCD_Chr(1, 8, Display[0]);
LCD_Chr(1, 9, Display[1]);
LCD_Chr(1, 10, Display[2]);
LCD_Chr(1, 11, Display[3]);
LCD_Chr(1, 12, Display[4]);
LCD_Chr(1, 13, Display[5]);
//LCD_Out(1, 8, ); // 'Show temperature
delay_ms(200); //200ms delay for waiting

Reference documents:
LM35 datasheet: www.ti.com/lit/ds/symlink/lm35.pdf
PIC16F877A datasheet: ww1.microchip.com/downloads/en/devicedoc/39582b.pdf

mikroC LCD library: http://www.mikroe.com/download/eng/documents/compilers/mikroc/pro/pic/help/lcd_library.htm
mikroC ADC library: http://www.mikroe.com/download/eng/documents/compilers/mikroc/pro/pic/help/adc_library.htm

Schematics for Temperature sensor (LM35 + PIC16F877A) Circuit Electronics
read more "Electronics Temperature Sensor (LM35 + PIC16F877A)"

Electronics MAGIC of knowledge

Circuit MAGIC of knowledge schematics Circuit Electronics,
I turned the switch on and BOOM! That noise, the tiny puff of smoke and the accompanying smell had become far too familiar.

I looked on in confusion at all the failed electronics components in front of me. I needed answers. Why did the H-bridge circuit not work as “claimed”? Books showed numerous such circuits. The Internet was not short of designs either. They were all similar though. I had done my research. I thought I understood the principles and modalities of operation. Then, where did the fault lie? Frustration was creeping in. But I just had to find the fault and fix it.

I wanted to make the SMPS based inverter because I could learn so much in a field completely new to me and then use the inverter at home during power cuts. In that one night of experimentation, I had failed repeatedly, damaging 24 IR2110’s and a lot more components. I had applied all I had learned thus far. Success, however, eluded me.

After repeated failures, I posted my problem on online electronics forums. Numerous members from around the world, engineers and non-engineers alike, joined in to contribute. I learnt and questioned. Heated discussions, arguments and counter-arguments took place. And I absorbed all I could. I did not get a direct solution to my problem but I felt I had become richer and perhaps, through discussion, helped make others richer.

 I spent hours reading documents and application notes, analyzing existing designs and testing the different concepts experimentally. However, the result was the same.

One day I stumbled upon a circuit on the internet, which had a different type of MOSFET gate protection, which employed a resistor between “gate” and “source”. Theoretically this resistor was not required. I redesigned the entire circuit with these resistors connected.

MAGIC! I got the required AC output. No BOOM, no smoke, no smell! 4 resistors (one between gate and source of each MOSFET) that, in total, cost less than $0.25, had been the difference! This was the magic of knowledge – the power of knowledge people refer to.

I then resorted to books and the Internet and learnt why the gate-to-source resistor stopped the MOSFET, and in turn the driver IR2110, from “blowing”.

After completing my inverter, I regularly posted on online electronics forums, especially www.edaboard.com – in the time I found between school, sports, electronics endeavors and other activities – to help others and to learn.

Many people later posted on www.edaboard.com regarding problems where the MOSFET and driver “blew”. I had been the one to suggest the use of the “gate-to-source” resistor and this had been the solution to most such problems.

My repeated failures had frustrated me, but also pushed me beyond the boundary of books to learn, acquire and share knowledge, to believe in the power of knowledge but most importantly to believe in myself and my capabilities. This belief and these teachings helped me in later endeavors to overcome obstacles in my way and achieve success.

Importance of the gate-to-source resistor:

It prevents accidental turn on of the MOSFET by external noise usually at startup when the gate is floating. The MOSFET may sometimes turn on with a floating gate because of the internal drain to gate "Miller" capacitance. A gate to source resistor acts as a pull-down to ensure a low level for the MOSFET. I have had MOSFETs blowing up in high voltage circuits, without the resistor in place. In most of the commercial power supplies / inverters I have seen, there is a 1k resistor used.

A similar experience is narrated in Sanajaya Maniktala's "Switching Power Supplies A to Z". This is also talked of in Raymond Mack's "Switching Power Supplies Demystified".

Schematics for MAGIC of knowledge Circuit Electronics
read more "Electronics MAGIC of knowledge"

Electronics Smart Sine - Software to generate sine table

Circuit Smart Sine - Software to generate sine table schematics Circuit Electronics,
Here is the software Smart Sine, that I created and now use to generate sine tables.

It is the improved and more developed version of the software I had previously created with a few more useful features. It is relatively simple to use and gives results quickly as opposed to manually calculating the table.

Here are a few screenshots:

Schematics for Smart Sine - Software to generate sine table Circuit Electronics
read more "Electronics Smart Sine - Software to generate sine table"

Electronics Generation of sine wave using SPWM in PIC16F684

Circuit Generation of sine wave using SPWM in PIC16F684 schematics Circuit Electronics,

I have previously shown how to calculate the values for the sine table. Now I will show you how to use that sine table for generating a sine wave using a PIC16F684. Why PIC16F684? It is a nice little 14-pin PIC that contains all that is needed for SPWM (sinusoidal pulse width modulation) – the ECCP module. Since the ADC or comparator or other peripherals are not used and there are enough pins, I selected the PIC16F684.

Let’s run the 16F684 from a 16MHz crystal oscillator and use a 16kHz switching frequency.

So, the required value of PR2 is 249.

The sine table (for half a cycle) is:

0, 25, 49, 73, 96, 118, 139, 159, 177, 193, 208, 220, 231, 239, 245, 249, 250, 249, 245, 239, 231, 220, 208, 193, 177, 159, 139, 118, 96, 73, 49, 25


Here is the code:

unsigned char sin_table[32]={0,25,49,73,96,118,137,




unsigned int TBL_temp;

unsigned char DUTY_CYCLE;

void interrupt(){

     if (TMR2IF_bit == 1){



           CCP1CON.P1M1 = ~CCP1CON.P1M1; //Reverse direction of full-bridge




        CCPR1L = sin_table[DUTY_CYCLE];


        TMR2IF_bit = 0;



void main() {

     SET_FREQ = 410;




     DUTY_CYCLE = 0;

     ANSEL = 0; //Disable ADC

     CMCON0 = 7; //Disable Comparator

     TRISC = 0x3F;

     CCP1CON = 0x4C;

     TMR2IF_bit = 0;

     T2CON = 4; //TMR2 on, prescaler and postscaler 1:1

     while (TMR2IF_bit == 0);

     TMR2IF_bit = 0;

     TRISC = 0;

     TMR2IE_bit = 1;

     GIE_bit = 1;

     PEIE_bit = 1;





Download the hex file from:

To make the process of updating sine table value simple, table pointer was used. The frequency here is set to 50Hz and the switching frequency is 16kHz. The 16F684 generates SPWM signals on P1A, P1B, P1C and P1D pins which should then be connected to a full-bridge stage for feeding into transformer.

16kHz frequency is used since it is toward the end of the audible spectrum and so the noise emitted will not be intolerable. Frequency above 20kHz is not used as 20kHz is the maximum frequency for the ECCP module of 16F684.

Since the ECCP module and interrupt take care of the SPWM, it is being executed by the hardware modules. So, while these are running, you can do other stuff as well by coding them in the while(1) loop, which, as you can see, is blank now, since no other task is being carried out besides SPWM.

Generating the sine table:

The SPWM signals:


The generated sine wave:

Schematics for Generation of sine wave using SPWM in PIC16F684 Circuit Electronics
read more "Electronics Generation of sine wave using SPWM in PIC16F684"