วันศุกร์ที่ 8 กุมภาพันธ์ พ.ศ. 2562

ไมโครคอนโทลเลอร์ 19

How to Send E-mail using PIC Microcontroller and ESP8266

ELECTRONICS
ByAswinth Raj 14
Sending Email using ESP8266 and PIC MicrocontrollerSending Email using ESP8266 and PIC Microcontroller
In this tutorial let us learn how to send E-mails from PIC Microcontroller using famous WiFi module the ESP8266. This tutorial uses PIC16F877A IC and MPLABX and XC8 compiler for programming.
At the end of this tutorial you will be able to send E-mail from any normal E-mail ID like Gmail, yahoo etc to any other E-mail ID. Hence this tutorial assumes that you have some basic knowledge on ESP8266-01 Modules and PIC Microcontrollers. If not, the following tutorials will help you
  1. Getting Started with ESP8266
  2. Interfacing ESP8266 with PIC
So let us get started...

Getting ready with you E-mail ID:
Once you have decided from which mail ID you want to send the emails, follow the below steps
Step 1: Visit https://www.smtp2go.com/ and Sign up as a new user. Enter your name, E-mail address and password of your E-mail ID from which you want to send the mail.
smtp2go
This tutorial uses the Mail ID: aswinthcd@ gmail.com and Password: circuitdigest.
Step 2: Click on sign up and you will be sent a verification mail to your entered mail ID. In this case it is aswinthcd@ gmail.com. Open the mail and click on “ACTIVATE ACCOUNT”
smtp2go activate
Step 3: It might ask for a password again, if asked enter the previous password. In this case it is 'circuitdigest'. Then you will be logged in to the SMPT2GO website. That is it now your E-mail address is ready to send mails using the ESP8266 Module.
Step 4: The last step is to encode the E-mail ID and password into base 64 format by using this website https://www.base64encode.org/. We are going to use this in our PIC program
smtp2go encoding
In this case the encoded values will look as shown in table below.
Parameter
Normal format
Encoded in base 64
Mail ID
aswinthcd@ gmail.com
YXN3aW50aGNkQGdtYWlsLmNvbQ==
Password
circuitdigest
Y2lyY3VpdGRpZ2VzdA==

Getting your Hardware Ready:
The complete schematic of the project is shown below.
 Circuit Diagram for Sending Email using PIC Microcontroller with ESP8266
The LCD display is used here for debugging purpose. It is not mandatory for you to connect this. The program will work fine even without the LCD display. If you want to know more about the schematics you visit this tutorial. (Interfacing PIC with ESP).
You can simply assemble this circuit on a breadboard and then proceed with the programming.

Programming your PIC to send E-mail:

In order to send an E-mail from the ESP8266 a sequence of AT commands has to be sent to the ESP module. The following steps have to be followed to send an E-mail from ESP8266.
  1. Set the module in AP+STA (Access Point and station) mode
  2. Connect to an Access point to get internet connection
  3. Enable multiple connections
  4. Start a server on any specific port
  5. Establish a TCP connection  with SMPT2GO website
  6. Navigate to the Login section of the website
  7. Enter the E-mail ID and Password in base64 format
  8. Enter From mail ID
  9. Enter To mail ID
  10. Enter the Subject of the mail
  11. Enter the body of the mail
  12. Indicate the end of mail
  13. Send the mail
  14. Quit the TCP connection
It is a bit lengthy and tedious process but do not worry. I have simplified the process by creating a header file and you can use it directly by just calling some functions (explained below) which makes this task very easy. The complete code along with the header file can be downloaded from here.
Note: If you are using the code in a new project make sure you download the header file and add it in your project.
I have explained some important parts of the code below, the other parts are self explanatory. But if you have any doubts feel free to use the comment section.
/*Check if the ESP_PIC communication is successful*/

    do

    {

    Lcd_Set_Cursor(1,1);

    Lcd_Print_String("ESP not found");

    }while (!esp8266_isStarted()); //wait till the ESP send back "OK"

    Lcd_Set_Cursor(1,1);

    Lcd_Print_String("ESP is connected");

    __delay_ms(1500);

    Lcd_Clear();

    /*Yes ESP communication successful -Proceed*/
This part of the code is used to check if there is a proper communication established between the PIC and ESP8266. Only if, both of them could send and receive data through USART the program will proceed to next step.

esp8266_mode(3);
This function will set the ESP8266 in mode 3. Meaning the module can now act as a Access point and also as a server.

esp8266_connect("BPAS home","cracksun");
This function is used to connect your ESP8266 module to your Wifi Router. In this case “BPAS home” is the name of my Wifi signal and “cracksun” is my password. You have to use your own Wifi signal details.

_esp8266_enale_MUX(); //Enable multiple connections

_esp8266_create_server(); //Create a server on port 80
These two functions are used to enable multiple connections and create a server on port 80.

 _esp8266_connect_SMPT2GO();
Now, using this function we can establish a TCP connection with SMPT2GO. Once the connection is establish this function also moves to the Login page of the website.

_esp8266_login_mail("YXN3aW50aGNkQGdtYWlsLmNvbQ==","Y2lyY3VpdGRpZ2VzdA==");
Use this function to enter your Email ID and password in base 64 format. As you can see these encoded values are same as that shown in the table above. Your encoded values will vary based on your E-mail ID and password.

_esp8266_mail_sendID("aswinthcd@ gmail.com");
This function is used to define the name of the sender ID. In this tutorial I am sending the mail using my Gmail ID aswinthcd@ gmail.com hence I have passed it as a parameter.

_esp8266_mail_recID("mailtoaswinth@ gmail.com");
This function is used to define the name of the receiver ID. I would like to send my mails to another Gmail account of mine, hence I have passed the parameter as mailtoasiwnth@ gmail.com. You can use your desired mail ID

_esp8266_start_mail();
This function instructs the SMPT2GO server that we are going to feed in the subject and body of the mail and makes it prepared for the same.

_esp8266_mail_subject("Mail from ESP8266");
You can use this function to define the subject of the mail. As an example I have used “Mail from ESP8266” as the subject of the mail.

_esp8266_mail_body("Testing Success -CircuitDigest");
After entering the subject you can enter the body of the mail using this function. As an example I have set “Testing Success –CircuitDigest” as the body of my mail.

   _esp8266_End_mail();
Now that we have entered the subject and body of the mail we have to instruct the SMPT2GO server that we are done with adding details to the mail. This can be done by using the function
_esp8266_End_mail();

_esp8266_disconnect_SMPT2GO();
Finally after sending the mail, we have to terminate the TCP connection with the SMPT2GO server. This is done by using the above function.

Working:

Once you are done with your hardware and program. Simply dump the code into you PIC MCU. Then power ON your circuit. If everything goes as expected, your LCD should display the status of the process and finally end up saying “Mail sent” as shown in the video below. Your hardware might look something like this.
Once the LCD shows that the mail is sent, check your Inbox and Spam folder for the sent mail. You should have received the mail as shown below..
email sent from pic microcontroller
That is it now you can make your own IOT projects by reading a sensor data and sending them to your mail ID. Create a Security alert system for your home or automobiles by triggering an alert through mail.
If you have any doubt or go stuck in the middle kindly use the comment section and I will be happy to help you out. 
[Note: make sure to replace the email address and password in the source code]
Code
#define _XTAL_FREQ 20000000
#define RS RD2
#define EN RD3
#define D4 RD4
#define D5 RD5
#define D6 RD6
#define D7 RD7
#include <xc.h>
#include "esp8266_functions.h"
#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF       // Power-up Timer Enable bit (PWRT enabled)
#pragma config BOREN = ON       // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF        // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

//****LCD Functions Developed by Circuit Digest.***///
void Lcd_SetBit(char data_bit) //Based on the Hex value Set the Bits of the Data Lines
{
    if(data_bit& 1) 
        D4 = 1;
    else
        D4 = 0;
    if(data_bit& 2)
        D5 = 1;
    else
        D5 = 0;
    if(data_bit& 4)
        D6 = 1;
    else
        D6 = 0;
    if(data_bit& 8) 
        D7 = 1;
    else
        D7 = 0;
}
void Lcd_Cmd(char a)
{
    RS = 0;           
    Lcd_SetBit(a); //Incoming Hex value
    EN  = 1;         
        __delay_ms(4);
        EN  = 0;         
}
Lcd_Clear()
{
    Lcd_Cmd(0); //Clear the LCD
    Lcd_Cmd(1); //Move the curser to first position
}
void Lcd_Set_Cursor(char a, char b)
{
    char temp,z,y;
    if(a== 1)
    {
      temp = 0x80 + b - 1; //80H is used to move the curser
        z = temp>>4; //Lower 8-bits
        y = temp & 0x0F; //Upper 8-bits
        Lcd_Cmd(z); //Set Row
        Lcd_Cmd(y); //Set Column
    }
    else if(a== 2)
    {
        temp = 0xC0 + b - 1;
        z = temp>>4; //Lower 8-bits
        y = temp & 0x0F; //Upper 8-bits
        Lcd_Cmd(z); //Set Row
        Lcd_Cmd(y); //Set Column
    }
}
void Lcd_Start()
{
  Lcd_SetBit(0x00);
  for(int i=1065244; i<=0; i--)  NOP();  
  Lcd_Cmd(0x03);
    __delay_ms(5);
  Lcd_Cmd(0x03);
    __delay_ms(11);
  Lcd_Cmd(0x03); 
  Lcd_Cmd(0x02); //02H is used for Return home -> Clears the RAM and initializes the LCD
  Lcd_Cmd(0x02); //02H is used for Return home -> Clears the RAM and initializes the LCD
  Lcd_Cmd(0x08); //Select Row 1
  Lcd_Cmd(0x00); //Clear Row 1 Display
  Lcd_Cmd(0x0C); //Select Row 2
  Lcd_Cmd(0x00); //Clear Row 2 Display
  Lcd_Cmd(0x06);
}
void Lcd_Print_Char(char data)  //Send 8-bits through 4-bit mode
{
   char Lower_Nibble,Upper_Nibble;
   Lower_Nibble = data&0x0F;
   Upper_Nibble = data&0xF0;
   RS = 1;             // => RS = 1
   Lcd_SetBit(Upper_Nibble>>4);             //Send upper half by shifting by 4
   EN = 1;
   for(int i=2130483; i<=0; i--)  NOP(); 
   EN = 0;
   Lcd_SetBit(Lower_Nibble); //Send Lower half
   EN = 1;
   for(int i=2130483; i<=0; i--)  NOP();
   EN = 0;
}
void Lcd_Print_String(char *a)
{
    int i;
    for(i=0;a[i]!='\0';i++)
       Lcd_Print_Char(a[i]);  //Split the string using pointers and call the Char function 
}
//***End of LCD functions***//

void main()
{
    TRISD = 0x00;
    Lcd_Start();
    Initialize_ESP8266() ; 
    Lcd_Set_Cursor(1,1);
    Lcd_Print_String("Circuit Digest");
    Lcd_Set_Cursor(2,1);
    Lcd_Print_String("Mail using ESP");
    __delay_ms(1500);
    Lcd_Clear();
    
    
   
    /*Check if the ESP_PIC communication is successful*/
    do
    {
    Lcd_Set_Cursor(1,1);
    Lcd_Print_String("ESP not found");
    }while (!esp8266_isStarted()); //wait till the ESP send back "OK"
    Lcd_Set_Cursor(1,1);
    Lcd_Print_String("ESP is connected");
    __delay_ms(1500);
    Lcd_Clear();
    /*Yes ESP communication successful -Proceed*/
    
    
    /*Put the module in AP+STA*/
    esp8266_mode(3);
    Lcd_Set_Cursor(1,1);
    Lcd_Print_String("ESP set AP+STA");
    __delay_ms(1500);
    Lcd_Clear();
    /*Module set as AP+STA*/
    
    
    /*Connect to a AccesPoint*/
    esp8266_connect("BPAS home","cracksun"); //Enter you WiFi name and password here, here BPAS home is the name and cracksun is the pas
    Lcd_Set_Cursor(1,1);
    Lcd_Print_String("Connected 2 WIFI"); //Print on LCD for debugging. 
    __delay_ms(1500);
    Lcd_Clear();
    /*Connected to WiFi*/
    
    
    
    _esp8266_enale_MUX(); //Enable multiple connections
    _esp8266_create_server(); //Create a server on port 80
    _esp8266_connect_SMPT2GO(); //Establish TCP connection with SMPT2GO
    
    
    /*LOG IN with your SMPT2GO approved mail ID*/
    /*Visit the page https://www.smtp2go.com/ and sign up using any Gmail ID
     * Once you gmail ID is SMPT2GO approved convert your mail ID and password in 64 base format
     * visit https://www.base64encode.org/ for converting 64 base format online
     * FORMAT -> _esp8266_login_mail("mailID in base 64","Password in base 64");
     * This program uses the ID-> aswinthcd@ gmail.com and password -> circuitdigest as an example
     */
    _esp8266_login_mail("YXN3aW50aGNkQGdtYWlsLmNvbQ==","Y2lyY3VpdGRpZ2VzdA==");
    Lcd_Set_Cursor(1,1);
    Lcd_Print_String("Login Successful"); //display on LCD for debugging
    __delay_ms(1500);
    Lcd_Clear();
    /*End of Login*/
    
    
    _esp8266_mail_sendID("aswinthcd@ gmail.com"); //The sender mail ID
    _esp8266_mail_recID("mailtoaswinth@ gmail.com"); //The Receiver mail ID
    
    _esp8266_start_mail();
    _esp8266_mail_subject("Mail from ESP8266"); //Enter the subject of your mail
    _esp8266_mail_body("Testing Success -CircuitDigest"); //Enter the body of your mail       
    _esp8266_End_mail();
    
    _esp8266_disconnect_SMPT2GO();
    
    
    Lcd_Set_Cursor(1,1);
    Lcd_Print_String("Mail Sent"); //Print on LCD for debugging
 
            
    while(1)
    {
        //do nothing 
    }
}

ไมโครคอนโทลเลอร์ 18

High/Low Voltage Detection and Protection Circuit using PIC Microcontroller

EMBEDDED
BySaddam 6
High and Low Voltage Power Detector Circuit with Message Alert using PIC MicrocontrollerHigh and Low Voltage Power Detector Circuit with Message Alert using PIC Microcontroller
We often see voltage fluctuations in electricity supply at our home, which may cause malfunction in our home AC appliances. Today we are building a low cost High and Low Voltage Protection Circuit, which will cut off the power supply to the appliances in case of High or Low voltage. It will also show a alert message on 16x2 LCD. In this project, we have used PIC Microcontroller to read and compare the input voltage to the reference voltage and take the action accordingly.
We have made this circuit on PCB and added a additional circuit on PCB for the same purpose, but this time using op-amp LM358 (without microcontroller). For demonstration purpose, we have chosen Low Voltage limit as 150v and high voltage limit as 200v. Here in this project, we haven’t used any relay for cut off, we just demonstrated it using LCD, check the Video at the end of this Article. But the user may attach a relay with this circuit and connect it with PIC’s GPIO.
Further check our other PCB projects here.

Components Required:

  1. PIC Microcontroller PIC18F2520                
  2. PCB (ordered from EasyEDA)
  3. IC LM358            
  4. 3 pin Terminal Connector (optional)
  5. 16x2 LCD                           
  6. BC547 Transistor
  7. 1k resistor
  8. 2k2 resistor
  9. 30K resistor SMD
  10. 10k SMD
  11. Capacitors- 0.1uf, 10uF, 1000uF                               
  12. 28 pin IC base
  13. Male/female burgsticks
  14. 7805 Voltage regulators- 7805, 7812
  15. Pickit2 Programmer
  16. LED
  17. Zener diode- 5.1v, 7.5v, 9.2v
  18. Transformer 12-0-12
  19. 12MHz Crystal
  20. 33pF capacitor
  21. Voltage regulator(fan speed regulator)
high low voltage detector PCB using PIC microcontroller

Working Explanation:

In this High and Low Voltage Cut Off Circuit, we have read the AC voltage by using PIC microcontroller with the help of transformer, bridge rectifier & voltage divider circuit and displayed over 16x2 LCD. Then we have compared the AC voltage with the predefined limits and displayed the alert message over the LCD accordingly. Like if voltage is below 150v then we have shown “Low Voltage” and if voltage is above 200v then we have shown “High Voltage” text over the LCD. We can change those limits in PIC code given at the end of this project. Here we have used Fan Regulator to increase and decrease the incoming voltage for demonstration purpose in the Video.
high low voltage detector using PIC microcontroller block-diagram
In this circuit, we have also added a Simple Under and Over Voltage Protection Circuit without using any microcontroller. In this simple circuit we have used LM358 comparator to compare the input and reference voltage. So here we have three options in this project:
  1. Measure and compare the AC voltage with the help of transformer, bridge rectifier, voltage divider circuit and PIC microcontroller.
  2. Detection of over and under voltage by using LM358 with the help of transformer, rectifier, and comparator LM358 (without Microcontroller)
  3. Detect under and over voltage by using a comparator LM358 and feed its output to PIC microcontroller for taking action by code.
Here we have demonstrated first option of this project. In which we have stepped down AC input voltage and then converted that into DC by using a bridge rectifier and then again mapped this DC voltage to 5v and then finally fed this voltage to PIC microcontroller for comparison and display.
In PIC microcontroller we have read this mapped DC voltage and based on that mapped value we have  calculated the incoming AC voltage with the help of given formula:
volt= ((adcValue*240)/1023)
where adcValue is equivalent DC input voltage value at PIC controller ADC pin and volt is the applied AC voltage. Here we have taken 240v as maximum input voltage.

or alternatively we can use given  method for mapping equivalent DC input value.
volt = map(adcVlaue, 530, 895, 100, 240)  
where adcValue is equivalent DC input voltage value at PIC controller ADC pin, 530 is minimum DC voltage equivalent and 895 is maximum DC voltage equivalent value. And 100v is minimum mapping voltage and 240v is maximum mapping voltage.
Means 10mV DC input at PIC ADC pin is equal to 2.046 ADC equivalent value. So here we have selected 530 as minimum value means, the voltage at PIC’s ADC pin will be:
(((530/2.046)*10)/1000) Volt
2.6v which will be mapped minimum value of 100VAC
(Same calculation for maximum limit).
Check the  map function is given in the PIC program code in the end. Learn more about Voltage Divider Circuit and mapping the Voltages using ADC here.
high low voltage protection using LM358 PIC microcontroller
Working of this project is easy. In this project, we have used an AC voltage fan regulator for demonstrating it. We have attached fan regulator to the input of transformer. And then by increasing or decreasing its resistance we got desired voltage output.

In the code, we have fixed maximum and minimum voltage values for High voltage and Low voltage detection. We have fixed 200v as overvoltage limit and 150v as lower voltage limit. Now after powering up the circuit, we can see the AC input voltage over the LCD. When input voltage increases then we can see voltage changes over LCD and if voltage becomes more than over voltage limit then LCD will alert us by “HIGH Voltage Alert” and if the voltage goes low than under voltage limit then LCD will alert us by showing “LOW Voltage Alert” message. This way it can be also used as Electronic Circuit breaker.
We can further add a relay to attach any AC appliances to auto cutoff on low or high voltages. We just need to add a line of code to switch off the appliance, below the LCD alert message showing code. Check here to use Relay with AC appliances.

Circuit Explanation:

In High and low Voltage Protection Circuit, we have used an LM358 op-amp which has two outputs connected to 2 and 3 number pins of PIC microcontroller. And a voltage divider is used to divide voltage and connects its output at 4th number pin of PIC microcontroller. LCD is connected at PORTB of the PIC in 4-bit mode. RS and EN are directly connected at B0 and B1 and data pins D4, D5, D6 and D7of LCD are connected at B2, B3, B4 and B5 respectively. In this project, we have used two voltage regulator: 7805 for microcontroller supply and 7812 for the LM358 circuit. And a 12v-0-12v step-down transformer is also used to step down the AC voltage. Rest of the components are shown in the circuit diagram below.
 high low voltage protection using PIC microcontroller circuit

Programming Explanation:

Programming part of this project is easy. In this code, we just need to calculate AC voltage by using mapped 0-5v voltage coming from Voltage Divider Circuit and then compare it with predefined values. You can check the complete PIC code after this project.
First, in the code, we have included a header and configured the PIC microcontroller config bits. If you are new to PIC coding then learn PIC Microcontroller and its configuration bits here.

Then we have used some fucntions for driving LCD, like void lcdbegin()  for initializing the LCD, void lcdcmd(char ch)for sending a command to LCD, void lcdwrite(char ch) for sending data to LCD and void lcdprint(char *str) for sending string to LCD. Check all the functions in the code below.

Below given function is used for mapping the values:
long map(long x, long in_min, long in_max, long out_min, long out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}

Given int analogRead(int ch) function is used for initializing and reading ADC:
int analogRead(int ch)
{
    int adcData=0;
    if(ch == 0)
    ADCON0 = 0x03;       // adc channel 0
    else if(ch == 1)
    ADCON0 = 0x0b;       //select adc channel 1
    else if(ch == 2)    
    ADCON0 = 0x0b;        //select adc channel 2    
    ADCON1 = 0b00001100;     // select analog i/p     0,1 and 2 channel of ADC
    ADCON2 = 0b10001010;    //eqisation time holding cap time
    while(GODONE==1);       // start conversion adc value
    adcData = (ADRESL)+(ADRESH<<8);     //Store 10-bit output 
    ADON=0;            // adc off
    return adcData;
}

Given lines are used for getting ADC samples and calculate average of them and then calculating voltage:
while(1)
{
    long adcValue=0;
    int volt=0;
    for(int i=0;i<100;i++)   // taking samples
    {   
        adcValue+=analogRead(2);
        delay(1);
    }
    adcValue/=100;

    #if method == 1
    volt= (((float)adcValue*240.0)/1023.0);
    #else
    volt = map(adcValue, 530, 895, 100, 240);
    #endif
    sprintf(result,"%d",volt);

And finally given function is used for taking resulted action:
    if(volt > 200)
    {
        lcdcmd(1);
        lcdprint("High Voltage");
        lcdcmd(192);
        lcdprint("  Alert  ");
        delay(1000);
    }
    
    else if(volt < 150)
    {
        lcdcmd(1);
        lcdprint("Low Voltage");
        lcdcmd(192);
        lcdprint("  Alert  ");
        delay(1000);
    }

Circuit and PCB Design using EasyEDA:

To design this HIGH and LOW Voltage Detector Circuit, we have chosen the online EDA tool called EasyEDA. We have previously used EasyEDA many times and found it very convenient to use compared to other PCB fabricators. Check here our all the PCB projects. EasyEDA is not only the one stop solution for schematic capture, circuit simulation and PCB design, they also offer a low cost PCB Prototype and Components Sourcing service. They recently launched their component sourcing service where they have a large stock of electronic components and users can order their required components along with the PCB order.
While designing your circuits and PCBs, you can also make your circuit and PCB designs public so that other users can copy or edit them and can take benefit from there, we have also made our whole Circuit and PCB layouts public for this High and Low Voltage Protection Circuit, check the below link:
Below is the Snapshot of Top layer of PCB layout from EasyEDA, you can view any Layer (Top, Bottom, Topsilk, bottomsilk etc) of the PCB by selecting the layer form the ‘Layers’ Window.
high low voltage detector PCB using PIC microcontroller top view

You can also checkout the Photo view of PCB using EasyEDA:
high low voltage detector PCB using PIC microcontroller photo view

Calculating and Ordering PCBs online:

After completing the design of PCB, you can click the icon of Fabrication output above. Then you will access the page PCB order to download Gerber files of your PCB and send them to any manufacturer, it’s also a lot easier (and cheaper) to order it directly in EasyEDA. Here you can select the number of PCBs you want to order, how many copper layers you need, the PCB thickness, copper weight, and even the PCB color. After you have selected all of the options, click “Save to Cart” and complete your order, then you will get your PCBs a few days later. The user may also go with their local PCB vendor to make PCBs by using Gerber file.
ordering PCBs high low voltage detector using LM358 PIC

EasyEDA’s delivery is very fast and after few days of ordering PCB’s I got the PCB samples:
high low voltage detector using LM358 PIC microcontroller PCBs

Below are the pictures after soldering the components on PCB:
high low voltage protection using LM358 PIC microcontroller PCBs

This how we can easily build the Low-high voltage protection circuit for our home. Further you just need to add a relay to connect any AC appliances to it, to protect it from voltage fluctuations. Just connect the relay with any general purpose Pin of PIC MCU and write the code to make that pin High and low along with LCD alert message code.
Code
#include<xc.h>        //xc8 is compiler
#include<stdio.h>
#include<stdlib.h>
// CONFIG1H
#pragma config OSC = HS         // Oscillator Selection bits (HS oscillator)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF       // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)
// CONFIG2L
#pragma config PWRT = ON       // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = SBORDIS  // Brown-out Reset Enable bits (Brown-out Reset enabled in hardware only (SBOREN is disabled))
#pragma config BORV = 3         // Brown Out Reset Voltage bits (Minimum setting)
// CONFIG2H
#pragma config WDT = OFF        // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))
#pragma config WDTPS = 32768    // Watchdog Timer Postscale Select bits (1:32768)
// CONFIG3H
#pragma config CCP2MX = PORTC   // CCP2 MUX bit (CCP2 input/output is multiplexed with RB1)
#pragma config PBADEN = OFF     // PORTB A/D Enable bit (PORTB<4:0> pins are configured as digital I/O on Reset)
#pragma config LPT1OSC = OFF    // Low-Power Timer1 Oscillator Enable bit (Timer1 configured for higher power operation)
#pragma config MCLRE = ON       // MCLR Pin Enable bit (MCLR pin enabled; RE3 input pin disabled)
// CONFIG4L
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = OFF        // Single-Supply ICSP Enable bit (Single-Supply ICSP disabled)
#pragma config XINST = OFF      // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))
// CONFIG5L
#pragma config CP0 = OFF        // Code Protection bit (Block 0 (000800-001FFFh) not code-protected)
#pragma config CP1 = OFF        // Code Protection bit (Block 1 (002000-003FFFh) not code-protected)
#pragma config CP2 = OFF        // Code Protection bit (Block 2 (004000-005FFFh) not code-protected)
#pragma config CP3 = OFF        // Code Protection bit (Block 3 (006000-007FFFh) not code-protected)
// CONFIG5H
#pragma config CPB = OFF        // Boot Block Code Protection bit (Boot block (000000-0007FFh) not code-protected)
#pragma config CPD = OFF        // Data EEPROM Code Protection bit (Data EEPROM not code-protected)
// CONFIG6L
#pragma config WRT0 = OFF       // Write Protection bit (Block 0 (000800-001FFFh) not write-protected)
#pragma config WRT1 = OFF       // Write Protection bit (Block 1 (002000-003FFFh) not write-protected)
#pragma config WRT2 = OFF       // Write Protection bit (Block 2 (004000-005FFFh) not write-protected)
#pragma config WRT3 = OFF       // Write Protection bit (Block 3 (006000-007FFFh) not write-protected)
// CONFIG6H
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) not write-protected)
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot block (000000-0007FFh) not write-protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM not write-protected)
// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protection bit (Block 0 (000800-001FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF      // Table Read Protection bit (Block 1 (002000-003FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF      // Table Read Protection bit (Block 2 (004000-005FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR3 = OFF      // Table Read Protection bit (Block 3 (006000-007FFFh) not protected from table reads executed in other blocks)
// CONFIG7H
#pragma config EBTRB = OFF      // Boot Block Table Read Protection bit (Boot block (000000-0007FFh) not protected from table reads executed in other blocks)
#define rs RB0
#define en RB1
char result[10]; 
#define lcdport PORTB
#define method 0
void delay(unsigned int Delay)
{
    int i,j;
    for(i=0;i<Delay;i++)
        for(j=0;j<1000;j++);
}
void lcdcmd(char ch)
{
    lcdport= (ch>>2)& 0x3C;
    rs=0;
    en=1;
    delay(1);
    en=0;
    lcdport= (ch<<2) & 0x3c;
    rs=0;
    en=1;
    delay(1);
    en=0;
}
void lcdwrite(char ch)
{
    lcdport=(ch>>2) & 0x3c;
    rs=1;
    en=1;
    delay(1);
    en=0;
    lcdport=(ch<<2) & 0x3c;
    rs=1;
    en=1;
    delay(1);
    en=0;
}
void lcdprint(char *str)
{
    while(*str)
    {
        lcdwrite(*str);
        str++;
    }
}
void lcdbegin()
{
    lcdcmd(0x02);
    lcdcmd(0x28);
    lcdcmd(0x0e);
    lcdcmd(0x06);
    lcdcmd(0x01);
}
int analogRead(int ch)
{
    int adcData=0;
    if(ch == 0)
    ADCON0 = 0x03;       // adc channel 0
    else if(ch == 1)
    ADCON0 = 0x0b;       //select adc channel 1
    else if(ch == 2)    
    ADCON0 = 0x0b;        //select adc channel 2    
    ADCON1 = 0b00001100;     // select analog i/p     0,1 and 2 channel of ADC
    ADCON2 = 0b10001010;    //eqisation time holding cap time
    while(GODONE==1);       // start conversion adc value
    adcData = (ADRESL)+(ADRESH<<8);     //Store 10-bit output 
    ADON=0;            // adc off
    return adcData;
}
long map(long x, long in_min, long in_max, long out_min, long out_max)
{
  return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
void main()
{    
//ADCON1  = 0b0001111;      //all port is digital
TRISB=0x00;
TRISC=0x00;
TRISA=0xff;
lcdbegin();
lcdprint("HIGH/LOW Volt");
lcdcmd(192);
lcdprint("Detector by PIC");
delay(1000);
lcdcmd(1);
lcdprint("CircuitDigest");
lcdcmd(192);
lcdprint("Welcomes You");
delay(1000);
while(1)
{
    long adcValue=0;
    int volt=0;
    for(int i=0;i<100;i++)   // taking samples
    {   
        adcValue+=analogRead(2);
        delay(1);
    }
    adcValue/=100;
    #if method == 1
    volt= (((float)adcValue*240.0)/1023.0);
    #else
    volt = map(adcValue, 530, 895, 100, 240);
    #endif
    sprintf(result,"%d",volt);
    
    lcdcmd(0x80);
    lcdprint("H>200V  L<150V");
    lcdcmd(0xc0);
    lcdprint("Voltage:");
    lcdprint(result);
    lcdprint(" V   ");
    delay(1000);
    if(volt > 200)
    {
        lcdcmd(1);
        lcdprint("High Voltage");
        lcdcmd(192);
        lcdprint("  Alert  ");
        delay(1000);
    }
    
    else if(volt < 150)
    {
        lcdcmd(1);
        lcdprint("Low Voltage");
        lcdcmd(192);
        lcdprint("  Alert  ");
        delay(1000);
    } 
}
}