// PIC24F16KA102 Configuration Bit Settings

// 'C' source line config statements

// FBS
#pragma config BWRP = OFF               // Table Write Protect Boot (Boot segment may be written)
#pragma config BSS = OFF                // Boot segment Protect (No boot program Flash segment)

// FGS
#pragma config GWRP = OFF               // General Segment Code Flash Write Protection bit (General segment may be written)
#pragma config GCP = OFF                // General Segment Code Flash Code Protection bit (No protection)

// FOSCSEL
#pragma config FNOSC = PRI              // Oscillator Select (Primary oscillator (XT, HS, EC))
#pragma config IESO = OFF               // Internal External Switch Over bit (Internal External Switchover mode disabled (Two-Speed Start-up disabled))

// FOSC
#pragma config POSCMOD = HS             // Primary Oscillator Configuration bits (HS oscillator mode selected)
#pragma config OSCIOFNC = ON            // CLKO Enable Configuration bit (CLKO output disabled; pin functions as port I/O)
#pragma config POSCFREQ = HS            // Primary Oscillator Frequency Range Configuration bits (Primary oscillator/external clock input frequency greater than 8 MHz)
#pragma config SOSCSEL = SOSCHP         // SOSC Power Selection Configuration bits (Secondary oscillator configured for high-power operation)
#pragma config FCKSM = CSDCMD           // Clock Switching and Monitor Selection (Both Clock Switching and Fail-safe Clock Monitor are disabled)

// FWDT
#pragma config WDTPS = PS32768          // Watchdog Timer Postscale Select bits (1:32,768)
#pragma config FWPSA = PR128            // WDT Prescaler (WDT prescaler ratio of 1:128)
#pragma config WINDIS = OFF             // Windowed Watchdog Timer Disable bit (Standard WDT selected; windowed WDT disabled)
#pragma config FWDTEN = OFF             // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))

// FPOR
#pragma config BOREN = BOR2             // Brown-out Reset Enable bits (Brown-out Reset enabled only while device is active and disabled in Sleep; SBOREN bit disabled)
#pragma config PWRTEN = OFF             // Power-up Timer Enable bit (PWRT disabled)
#pragma config I2C1SEL = PRI            // Alternate I2C1 Pin Mapping bit (Default location for SCL1/SDA1 pins)
#pragma config BORV = V18               // Brown-out Reset Voltage bits (Brown-out Reset set to lowest voltage (1.8V))
#pragma config MCLRE = ON               // MCLR Pin Enable bit (MCLR pin enabled; RA5 input pin disabled)

// FICD
#pragma config ICS = PGx1               // ICD Pin Placement Select bits (PGC1/PGD1 are used for programming and debugging the device)

// FDS
#pragma config DSWDTPS = DSWDTPSF       // Deep Sleep Watchdog Timer Postscale Select bits (1:2,147,483,648 (25.7 Days))
#pragma config DSWDTOSC = LPRC          // DSWDT Reference Clock Select bit (DSWDT uses LPRC as reference clock)
#pragma config RTCOSC = SOSC            // RTCC Reference Clock Select bit (RTCC uses SOSC as reference clock)
#pragma config DSBOREN = OFF            // Deep Sleep Zero-Power BOR Enable bit (Deep Sleep BOR disabled in Deep Sleep)
#pragma config DSWDTEN = OFF            // Deep Sleep Watchdog Timer Enable bit (DSWDT disabled)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#include <xc.h> 


#define CRYSTAL_FRQUENCY   10000000             /*  10MHz crystal   */
#define FCY CRYSTAL_FRQUENCY/2UL                /*  Cycle frequency */

#include <libpic30.h>
#include <stdio.h>

    #define LCD_BUS     LATB                        /*  DATA BUS FOR LCD 8bits  */
    #define ENABLE_LCD  LATBbits.LATB9              /*  Enable pin of LCD       */
    #define RS_LCD      LATBbits.LATB8              /*  RS pin of LCD           */

    #define LCD_BUS_DIRECTION   TRISB               /*  DATA bus tristate register  */
    #define ENABLE_DIRECTION    TRISBbits.TRISB9    /*  Enable pin tristate register*/
    #define RS_DIRECTION        TRISBbits.TRISB8    /*  RS pin tristate register    */

    #define FirstLine   0x80
    #define SecondLine  0xC0

/*--------------------------------------------------------------------------------------------*/
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/

void WriteCmd_LCD(unsigned char Cmd);

void Initilize_LCD(void)
{
    /*  making Pins as output   */

    ENABLE_DIRECTION    = 0;
    RS_DIRECTION        = 0;
    LCD_BUS_DIRECTION   = 0;

    /*  Writing zero to pins and port   */

    ENABLE_LCD  = 0;
    RS_LCD      = 0;
    LCD_BUS     = 0;
  
   __delay_ms(10);          /*  ten miliseconds delay   */

   /*   writing commonds for initialization of LCD  */

   WriteCmd_LCD(0x38);  /*  Functions Set as Given in Datasheet */
   WriteCmd_LCD(0x0C);  /*  Display ON; Cursor OFF; Blink OFF   */
   WriteCmd_LCD(0x06);  /*  Display Shifting OFF                */
   WriteCmd_LCD(0x01);  /*  Clear Display                       */
  
}

/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/

void ClearScreen_LCD(void)
{
    WriteCmd_LCD(0x01);         /*  Clear Screen command    */
    __delay_ms(3);              /*  Delay for cursor to return home must be
                                 *  atleast 3ms menstioned in datasheet
                                 */
}

/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/

void Toggle_Enable_Pin_LCD(void)
{
    /*  toggling Enable PIN is must for data to be displayed on screen
        After every Command and data for more details see datasheet
    */
    ENABLE_LCD = 1;
    __delay_us(200);
    ENABLE_LCD = 0;
    __delay_us(200);
    
}

/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/

void WriteCmd_LCD(unsigned char Cmd)
{
    RS_LCD  = 0;        /*  For command RS must be low (0)      */
    LCD_BUS &= 0xFF00;  /*  Masking from 16bit register         */
    LCD_BUS |= Cmd;     /*  write Command to data bus of LCD    */

    Toggle_Enable_Pin_LCD();
}

/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/

void WriteData_LCD(unsigned char Data)
{
    RS_LCD  = 1;        /*  For data RS must be high (1)    */
    LCD_BUS &= 0xFF00;  /*  Masking from 16bit register     */
    LCD_BUS |= Data;    /*  write data to data bus of LCD   */
    
    Toggle_Enable_Pin_LCD();
}

/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/

void WriteString_LCD(const char *String)
{
    while(*String != NULL)
    {
        WriteData_LCD(*String++);   /*  Display data untill string ends */
    }
}
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/

unsigned char MoveCursorToPosition(unsigned char Address)
{
    /*  valid addresses are for line one 0x80 - 0x8F and line two are 0xC0 - 0xCF   */
    if ((Address >= 0x80 && Address <= 0x8F) || (Address >= 0xC0 && Address <= 0xCF))
    {
        WriteCmd_LCD(Address);
        return 1;
    }
    else
        return 0;
}
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/

unsigned char WriteLongAsFloatUptoFiveFigures(unsigned long Long32Bit)
{
    unsigned char Character[] = "0123456789";

    if (Long32Bit < 10)
    {
        WriteData_LCD(Character[Long32Bit]);
        return 0;
    }
        
    else if (Long32Bit > 9 && Long32Bit < 100)
    {
        WriteData_LCD(Character[Long32Bit/10]);
        WriteData_LCD(Character[Long32Bit%10]);
        return 0;
    }
    else if (Long32Bit > 99 && Long32Bit < 1000)
    {
        WriteData_LCD(Character[Long32Bit/100]);
        WriteData_LCD(Character[Long32Bit%100/10]);
        WriteData_LCD(Character[Long32Bit%100%10]);
        return 0;
    }
    else if (Long32Bit > 999 && Long32Bit < 10000)
    {
        WriteData_LCD(Character[Long32Bit/1000]);
        WriteData_LCD('.');
        WriteData_LCD(Character[Long32Bit%1000/100]);
        WriteData_LCD(Character[Long32Bit%1000%100/10]);
        WriteData_LCD(Character[Long32Bit%1000%100%10]);
        return 1;
    }
    else if (Long32Bit > 9999 && Long32Bit < 100000)
    {
        WriteData_LCD(Character[Long32Bit/10000]);
        WriteData_LCD(Character[Long32Bit%10000/1000]);
        WriteData_LCD('.');
        WriteData_LCD(Character[Long32Bit%10000%1000/100]);
        WriteData_LCD(Character[Long32Bit%10000%1000%100/10]);
        WriteData_LCD(Character[Long32Bit%10000%1000%100%10]);
        return 1;
    }
    else if (Long32Bit > 99999 && Long32Bit < 1000000)
    {
        WriteData_LCD(Character[Long32Bit/100000]);
        WriteData_LCD(Character[Long32Bit%100000/10000]);
        WriteData_LCD(Character[Long32Bit%100000%10000/1000]);
        WriteData_LCD('.');
        WriteData_LCD(Character[Long32Bit%100000%10000%1000/100]);
        WriteData_LCD(Character[Long32Bit%100000%10000%1000%100/10]);
        WriteData_LCD(Character[Long32Bit%100000%10000%1000%100%10]);
        return 1;
    }
    else if (Long32Bit > 999999 && Long32Bit < 10000000)
    {
        WriteData_LCD(Character[Long32Bit/1000000]);
        WriteData_LCD('.');
        WriteData_LCD(Character[Long32Bit%1000000/100000]);
        WriteData_LCD(Character[Long32Bit%1000000%100000/10000]);
        WriteData_LCD(Character[Long32Bit%1000000%100000%10000/1000]);
        return 2;
    }
    else
    {
        return 3;
    }
    
}

/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/

void ConfigModuleADC(void)
{
    TRISAbits.TRISA0 = 1;       /*  ADC input PIN as        */
    
    AD1CON1bits.ADON = 0;
    AD1CON3bits.ADRC = 0;
    AD1CON3bits.SAMC = 0b1111;
    AD1CON3bits.ADCS = 0b0000000;

    AD1CON2bits.CSCNA = 0;
    AD1CON2bits.BUFS = 0;
    AD1CON2bits.SMPI = 0b00000;
    AD1CON2bits.BUFM = 0;
    AD1CON2bits.ALTS = 0;

    AD1CON1bits.ADSIDL = 0;
    AD1CON1bits.FORM = 0b00;
    AD1CON1bits.SSRC = 0b0000;
    AD1CON1bits.ASAM = 0;

}
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/

void ChangeChannelADC(unsigned char CHANNEL)
{
    AD1CON1bits.ADON = 0;                       /*  ADC OFF         */
    __delay_us(100);
    AD1CHSbits.CH0SA = (CHANNEL & 0b00011111);  /*  Channel Changed */
    __delay_us(100);
    AD1CON1bits.ADON = 1;                       /*  ADC ON          */
    
}
/*^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^*/

unsigned int SamplingAndConversionADC(void)
{
    AD1CON1bits.SAMP = 1;                       /*  Start sampling input    */
    while(!AD1CON1bits.SAMP);
    AD1CON1bits.SAMP = 0;                       /*  End sampling */
    while(AD1CON1bits.SAMP);
    while(!AD1CON1bits.DONE);
    return ADC1BUF0;
}

void DisplayResistance(void)
{
    const char Voltage[] = "Digital OhmMeter";
    unsigned char Unit = 0;
    const float R3 = 10000, Vcc = 5.0;               /*  vo = (10k/(90k + 10k)) vcc    */
    unsigned int ADC_Value = 0;
    float VoltageOutput = 0.0;
    unsigned long ResistanceMeasured = 0;           /*  32 bit wide data type          */



    ClearScreen_LCD();
    WriteString_LCD(Voltage);
    MoveCursorToPosition(SecondLine);
    ADC_Value = SamplingAndConversionADC();                 /*  Sampling                */

    VoltageOutput = ((float)(ADC_Value))* 0.0048828;        /* 0.0048828 = 5/1024       */
    

    ResistanceMeasured = (unsigned long)((VoltageOutput * R3)/(Vcc - VoltageOutput));
    
    //ResistanceMeasured *= 1000;                             /*  miliOhms conversion    */

    Unit = WriteLongAsFloatUptoFiveFigures(ResistanceMeasured);    /*  Printing integer value on LCD   */

    if (Unit ==2)
        WriteString_LCD(" MOhm");
    else if (Unit == 1)
        WriteString_LCD(" kOhm");
    else if (!Unit)
        WriteString_LCD(" Ohm");
    else
        WriteString_LCD("Too Large");

}

/******************************************************************************/
/*
 *
 */
int main(void)
{   
    Initilize_LCD();
    
    ConfigModuleADC();          /*  Configure ADC module    */
    ChangeChannelADC(0);        /*  AN0 channel             */
     
    while(1)
    {
        DisplayResistance();
        __delay_ms(100);                        /*  200m Second delay  */
    }
    return 0;
}