PIC Development Board with PK3

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
Just for a test, declare Result3 as volatile unsigned char. It may be that the compiler knows you are not doing anything with Result3 so there isn't any reason to generate the code. Sometimes XC8 is a little too aggressive that way. Declaring Result3 as 'volatile' tells the compiler to leave it alone. You can also look at the disassembler listing to see what code it actually generated, too.
I've made it volatile variable

C:
//
#define _XTAL_FREQ 20000000     // crystal 20MHz

// PIC18F45K80 Configuration Bit Settings
// CONFIG1L
#pragma config RETEN = ON       // VREG Sleep Enable bit (Ultra low-power regulator is Enabled (Controlled by SRETEN bit))
#pragma config INTOSCSEL = LOW  // LF-INTOSC Low-power Enable bit (LF-INTOSC in Low-power mode during Sleep)
// SOSCSEL = No Setting
#pragma config XINST = OFF      // Extended Instruction Set (Disabled)
// CONFIG1H
#pragma config FOSC = HS2       // HS oscillator (high power, 16 MHz-25 MHz
#pragma config PLLCFG = OFF     // PLL x4 Enable bit (Disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor (Disabled)
#pragma config IESO = OFF       // Internal External Oscillator Switch Over Mode (Disabled)
// CONFIG2L
#pragma config PWRTEN = ON      // Power Up Timer (Enabled)
#pragma config BOREN = OFF      // Brown Out Detect (Disabled in hardware, SBOREN disabled)
#pragma config BORV = 0         // Brown-out Reset Voltage bits (3.0V)
#pragma config BORPWR = LOW     // BORMV Power level (BORMV set to low power level)
// CONFIG2H
#pragma config WDTEN = OFF      // Watchdog Timer (WDT disabled in hardware; SWDTEN bit disabled)
#pragma config WDTPS = 1        // Watchdog Postscaler (1:1)
// CONFIG3H
#pragma config CANMX = PORTC    // ECAN Mux bit (ECAN TX and RX pins are located on RC6 and RC7, respectively)
#pragma config MSSPMSK = MSK5   // MSSP address masking (5 bit address masking mode)
#pragma config MCLRE = ON      // Master Clear Enable (MCLR Enabled, RE3 Disabled)
// CONFIG4L
#pragma config STVREN = OFF     // Stack Overflow Reset (Disabled)
#pragma config BBSIZ = BB1K     // Boot Block Size (1K word Boot Block size)
// CONFIG5L
#pragma config CP0 = ON         // Code Protect 00800-01FFF (Enabled)
#pragma config CP1 = ON         // Code Protect 02000-03FFF (Enabled)
#pragma config CP2 = ON         // Code Protect 04000-05FFF (Enabled)
#pragma config CP3 = ON         // Code Protect 06000-07FFF (Enabled)
// CONFIG5H
#pragma config CPB = ON         // Code Protect Boot (Enabled)
#pragma config CPD = ON         // Data EE Read Protect (Enabled)
// CONFIG6L
#pragma config WRT0 = ON        // Table Write Protect 00800-01FFF (Enabled)
#pragma config WRT1 = ON        // Table Write Protect 02000-03FFF (Enabled)
#pragma config WRT2 = ON        // Table Write Protect 04000-05FFF (Enabled)
#pragma config WRT3 = ON        // Table Write Protect 06000-07FFF (Enabled)
// CONFIG6H
#pragma config WRTC = ON        // Config. Write Protect (Enabled)
#pragma config WRTB = ON        // Table Write Protect Boot (Enabled)
#pragma config WRTD = ON        // Data EE Write Protect (Enabled)
// CONFIG7L
#pragma config EBTR0 = ON       // Table Read Protect 00800-01FFF (Enabled)
#pragma config EBTR1 = ON       // Table Read Protect 02000-03FFF (Enabled)
#pragma config EBTR2 = ON       // Table Read Protect 04000-05FFF (Enabled)
#pragma config EBTR3 = ON       // Table Read Protect 06000-07FFF (Enabled)
// CONFIG7H
#pragma config EBTRB = ON       // Table Read Protect Boot (Enabled)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#pragma warning disable 520

#include <xc.h>

unsigned char Result1;
unsigned char Result2;
volatile unsigned char Result3;
unsigned char Result4;

// The code should set the R/W bit according to its function
#define SLAVE_ADDRESS        0x90         //I2C slave address of ADS1115 (8 bit format)
#define Word_Address        0x01         // Points to Config register


#define LCD_RS              LATBbits.LATB4
#define LCD_TRIS_RS         TRISBbits.TRISB4
#define LCD_RW              LATBbits.LATB5
#define LCD_TRIS_RW         TRISBbits.TRISB5
#define LCD_E               LATBbits.LATB6
#define LCD_TRIS_E          TRISBbits.TRISB6

#define  LCDPORT            LATD
#define  LCDTRISD           LATD

void Port_Initialized (void);
void WriteNibble(unsigned char command);
void WaitLCDBusy(void);
void WriteCommand(unsigned char command);

void Port_Initialized (void)
{
// LATx registers
    LATA =  0x00;
    LATB =  0x00;
    LATC =  0x00;
    LATD =  0x00;
    LATE =  0x00;

//  TRISx registers
    TRISA = 0x00;      // All are output, Unused
    TRISB = 0x00;      // all are output, Unused
    TRISC = 0x18;      // Slave SDA and CLOCK
    TRISD = 0x00;      // LCD
    TRISE = 0x00;      // All are output, Unused

    ANCON0 = 0x00;     // set to digital port
    ANCON1 = 0x00;     // Set to digital port
    CM1CON = 0x00;     // Comparator off
    CM2CON = 0x00;     // Comparator off
    ADCON0 = 0x00;     // A/D conversion Disabled
    ADCON1 = 0x00;     // A/D conversion Disabled
    ADCON2 = 0x00;     // A/D conversion Disabled
}

// Wait for 5 ms
void WaitLCDBusy(void)
{
    __delay_ms(5);
}

//Send a command to the LCD
void WriteCommand(unsigned char command)
{
    WaitLCDBusy();                               //wait until not busy
    LCD_RS = 0;                                  //setup to send command
    WriteNibble(command);                        //write the high nibble
    WriteNibble( (unsigned char)(command<<4) );  //then the low nibble
}

//Initialized  LCD
void LCD_Initialized()
{
    LCDTRISD &=0x0f;                //ensure data bits are output
    LCD_E=0;                        //clear enable
    LCD_RS = 0;                     //going to write command
    LCD_TRIS_E=0;                   //Set enable to output
    LCD_TRIS_RS=0;                  //set RS to output
    LCD_TRIS_RW=0;
    LCD_RW=0;
    __delay_ms(30);                 //delay for LCD to initialize.
    WriteNibble(0x30);              //Required for initialization
    __delay_ms(5);                  //required delay
    WriteNibble(0x30);              //Required for initialization
    __delay_ms(1);                  //required delay
    WriteCommand(0x20);             //set to 4 bit interface
    WriteCommand(0x2c);             //set to 4 bit interface, 2 line and 5*10 font
    WriteCommand(0x01);             //clear display
    WriteCommand(0x06);             //move cursor right after write
    WriteCommand(0x0C);             //turn on display
}

//Send a character to the LCD
void WriteChar(unsigned char chr)
{
    WaitLCDBusy();                         //wait until not busy
    LCD_RS=1;                              //Setup to send character
    WriteNibble(chr);                      //write the high nibble     
    WriteNibble( (unsigned char)(chr<<4)); //then the low nibble
}

//Send any 4 bits to the LCD
void WriteNibble(unsigned char command)
{
    LCDPORT &= 0x0f;                        //clear the data bits
    LCDPORT|=((command & 0xf0));            //or in the new data
    LCD_E = 1;                              //enable the LCD interface
    NOP();                                  // delay of 1uS
    NOP();
    NOP();
    LCD_E = 0;                              //disable it
}

void LCD_Data( unsigned char *string)
{
    while (*string != '\0')
    {
      WriteChar(*string);
        string++;
    }
}

//Initialize I2C in master mode
void I2C_Initialized(void)
{
    SSPSTAT=0x80; //Slew rate control is disabled for Standard Speed mode (100 kHz and 1 MHz)
    SSPCON1=0x28; // I2C Master mode, clock = FOSC/(4 * (SSPADD + 1))
    SSPCON2=0x00;
    SSPADD = 49;
    //100kHz clock @ 20MHz Fosc SSPADD = ( (Fosc/4) / BiteRate )-1
   // SSPADD = ( 20MHz / 100KHz ) - 1 = 49
}

// Send an I2C START
// Return 0 if all ok, 1 if bus collision
__bit I2C_Start(void)
{
    BCLIF = 0;  //Clear 'Bus collision" flag
    SEN = 1;    //initiate a START cycle
    while (SEN);    //wait until it has been sent
    return BCLIF;   //return value of BCLIF flag
}
// Send an I2C STOP
void I2C_Stop(void)
{
    PEN = 1;    //initiate a STOP cycle
    while (PEN);    //wait until it has been sent
}

// Send an I2C REPEATED START
void I2C_Restart(void)
{
    RSEN = 1;    //initiate a REPEATED START cycle
    while (RSEN);    //wait until it has been sent
}

//Receive one byte. ackflag=0 to send ACK, or 1 to send NAK in reply
//Send one byte. Return 0 if ACK received, or 1 if NAK received
__bit I2C_Write(unsigned char dat)
{
    SSPBUF = dat;

    asm("nop");     // wait a little for R_W to be set

    while (R_W);    //wait until byte sent and ACK/NAK received
    return ACKSTAT;
}

unsigned char I2C_Read(unsigned char ackflag)
{
    RCEN = 1;   // initiate a RECEIVE cycle
    ACKDT =(__bit)ackflag;    //specify if we should send ACK or NAK after receiving
    while (RCEN);   //wait until RECEIVE has completed
    ACKEN = 1;  //initiate an ACK cycle
    while (ACKEN);  //wait until it has completed
    return SSPBUF;
}

//Send an array of data to an I2C device.
//Return 0 if all OK, 1 if bus error, 2 if slave address NAK, 3 if slave register NAK, 4 if slave data NAK
unsigned char Write_I2C_Device(unsigned char slave_address, unsigned char start_reg, unsigned char buflen, const unsigned char * bufptr)
{
    if (I2C_Start() )   //send a start, and check if it succeeded
        return 1;   //abort if bus collision
    //send the I2C slave address (force R/W bit low)
    if (I2C_Write(slave_address & 0xfe))
    {
        I2C_Stop(); //if address was NAKed, terminate the cycle
        return 2;   //and return error code
    }
    //send the device register index
    if (I2C_Write(start_reg))
    {
        I2C_Stop(); //if register was NAKed, terminate the cycle
        return 3;   //and return error code
    }
    //send the data. buflen might be zero!
    for (; buflen>0; --buflen)
    {
        if (I2C_Write(*bufptr++))
        {
            I2C_Stop(); //if register was NAKed, terminate the cycle
            return 4;   //and return error code
        }
    }
    I2C_Stop();
    return 0;   //no error
}

//Receive an array of data from an I2C device.
//Return 0 if all OK, 1 if bus error, 2 if slave address NAK, 3 if slave register NAK
unsigned char Read_I2C_Device(unsigned char slave_address, unsigned char start_reg, unsigned char buflen, unsigned char * bufptr)
{
    //do a dummy zero length write cycle to set the register address
    unsigned char retval = Write_I2C_Device(slave_address, start_reg, 0, 0);
    if (retval)
    {
        return retval;  //abort if there was an error
    }
    //now start the READ cycle
    if (I2C_Start() )   //send a start, and check if it succeeded
        return 1;   //abort if bus collision
    //send the I2C slave address (force the R/W bit high)
    if (I2C_Write(slave_address | 0x01))
    {
        I2C_Stop(); //if address was NAKed, terminate the cycle
        return 2;   //and return error code
    }
    //receive the data.
    for (; buflen>0; --buflen)
    {
        unsigned char ackflag = (buflen == 1);   //1 if this is the last byte to receive => send NAK

        *bufptr++ = I2C_Read(ackflag);
    }
    I2C_Stop();
    return 0;   //no error
}
const unsigned char ADS1115_data[] =
{
    0x84,  // MSB of the Config register to be written
    0x83,  // LSB of the Config register to be written
};

unsigned char rd_buf[2];

void main(void)
{
     unsigned char i = 0;

     unsigned char Data1 [10]="xx";

     Port_Initialized ();
     LCD_Initialized();
     I2C_Initialized();
 
    // Write to Config register
     Result1 = Write_I2C_Device(SLAVE_ADDRESS , Word_Address , sizeof(ADS1115_data), ADS1115_data);
     __delay_ms(10);

    while(1)
    {
     Result3 = Read_I2C_Device(SLAVE_ADDRESS, 0x00 , 2, rd_buf) ;
     __delay_ms(10);
    }
}
!
It breaks at 314 then you click the green arrow to run again and it does not break at 318?
If you run it after 314 then click pause, where does it show it is?
Image 1 :
green arrow at line 306
first breakpoint set at line 314
second breakpoint set at line 318

Next I click on continue button F5

Image 2 :
green arrow at line 314
first breakpoint set at line 314
second breakpoint set at line 318

Next I click on continue button F5
Image 3 :
green arrow at line 314
first breakpoint set at line 314
second breakpoint set at line 318
 

Attachments

JohnInTX

Joined Jun 26, 2012
4,787
!!

Remove the breakpoint on the delay on line 314 and see if it gets into the while loop. It may be breaking on the underlying loop in the delay.
 

JohnInTX

Joined Jun 26, 2012
4,787
I don't see any reason why it should not enter the while loop.
Use the Clean and Build for Debug (the little broom icon) then restart the debugger.

If that doesn't work, try a few of asm("nop"); instructions just before Result3=... compile and set a breakpoint on one of the nops.

I assume you are debugging with the PK3, not the simulator.
 
Last edited:

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
I assume you are debugging with the PK3, not the simulator.
Use the Clean and Build for Debug (the little broom icon) then restart the debugger
I'm using PK3 as debugger
I did Clean and Build for Debug

If that doesn't work, try a few of asm("nop"); instructions just before Result3=... compile and set a breakpoint on one of the nops.
I've added nop now it enter into while loop but it break at delay line

1625829254913.png
 
Last edited:

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
I've added few nops for testing after variable Result3

buffer value is 0x00 before to read

1625829624395.png

buffer value after read

1625829735970.png
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
Ok. Click in the VALUE field for rd_buf and change the display format to HEX. Change the pot and run the loop to the breakpoint. The hex value should chamge with the pot.
 

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
Ok. Click in the VALUE field for rd_buf and change the display format to HEX. Change the pot and run the loop to the breakpoint. The hex value should chamge with the pot.
It's seems to me ADC is working on the base of following tests

I Changed the pot and run the loop to the breakpoint.

1625839093030.png

I Changed the pot and run the loop to the breakpoint.

1625839112503.png

I Changed the pot and run the loop to the breakpoint.

1625839133041.png
 

JohnInTX

Joined Jun 26, 2012
4,787
Nice!
The 7fff in the middle shot is the maximum positive value for a 2's complement number.

So what's next?
This would be a good time to delete those extra nops and confirm that it still works. You can leave one nop in for a convenient breakpoint if you want.
 

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
So what's next?
This would be a good time to delete those extra nops and confirm that it still works. You can leave one nop in for a convenient breakpoint if you want.
Done
1625853454232.png

What should I do next ?
should I convert convert binary to ASCII decimal for display (itoa() or sprintf()) ?
should I need to first formatting the LCD display to get updated value ?
 

JohnInTX

Joined Jun 26, 2012
4,787
What should I do next ?
should I convert convert binary to ASCII decimal for display (itoa() or sprintf()) ?
should I need to first formatting the LCD display to get updated value ?
The LCD takes an ASCII character string (not binary numbers) so the next thing to do is generate that string. You can inspect the result just like you just did.

First, convert the 2 byte ADC result to a signed integer. I showed you how in #344, line 6.
Next use sprintf to convert that integer to a formatted ASCII value in a character buffer. Declare the buffer with enough bytes to handle all of the digits.
Break after sprintf and inspect the buffer. You should see an ASCII number formatted like you want.
Note that sprinf can format in decimal (%d) or hex (%H). You can try them both using 2 sprintf separated by nop breakpoints.

NOTE: Using sprintf, printf and other functions that use the 'formatted write' library is frequently discouraged in favor of ad-hoc functions that do some combination of divide and mod functions to form ASCII from integers like you did here:
Data1[0] = ((rd_buf[1] >> 4) & 0x0f) + '0';
Data1[1] = (rd_buf[1] & 0x0f) + '0';
itoa() is also sometimes used. The reason for this is that printf/sprintf etc. have historically used a lot of program memory because of their power and complexity. In fact, MikroC won't even compile printf in the code-limited free version.

One thing that XC8 gets right is that it only includes the minimum parts of the sprintf code required to do the job. It still is a little bigger than some of those other approaches but it is totally worth it. PLUS, once you use sprintf ONCE, the additional code requirements are minimal - it just uses the same code over and over. Those ad-hoc conversions each consume a chunk of code and using lots of them may even exceed the code used by sprintf. You have lots of codespace. Use it to make things easier.

After you get that all working, you'll have a buffer full of ASCII text that you can send directly to the LCD.

Nice!
 
Last edited:

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
First, convert the 2 byte ADC result to a signed integer. I showed you how in #344, line 6.
Next use sprintf to convert that integer to a formatted ASCII value in a character buffer. Declare the buffer with enough bytes to handle all of the digits.
Break after sprintf and inspect the buffer. You should see an ASCII number formatted like you want.
Note that sprinf can format in decimal (%d) or hex (%H). You can try them both using 2 sprintf separated by nop breakpoints.
Would it be something like this ?
C:
unsigned char rd_buf[2];

int ADC_Result;

void main(void)
{
     unsigned char i = 0;

     unsigned char Data1 [10]="xx";

     Port_Initialized ();
     LCD_Initialized();
     I2C_Initialized();

    // Write to Config register
     Result1 = Write_I2C_Device(SLAVE_ADDRESS , Word_Address , sizeof(ADS1115_data), ADS1115_data);
     __delay_ms(10);

    while(1)
    {      
       Result3 = Read_I2C_Device(SLAVE_ADDRESS, 0x00 , 2, rd_buf) ;
       __delay_ms(10);
        asm("nop");
       
        if(Result3 == 0)  // if successful read..
        {
           ADC_Result = (rd_buf[0] << 8) + rd_buf[1];
        }
        sprintf("%d",ADC_Result );
        Data1[0] = ((rd_buf[1] >> 4) & 0x0f) + '0';
        Data1[1] = (rd_buf[1] & 0x0f) + '0';
     
    }
}
 

JohnInTX

Joined Jun 26, 2012
4,787
Nope.
sprintf is incorrect. It is supposed to REPLACE that other stuff. Delete lines 30 and 31.
Did the compiler throw an error or warning about sprintf?
Also, you need to include ALL of the ADC processing between the brackets on lines 26 and 28. It is pointless to use the data if Result3 is not 0.
 
Last edited:

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
Nope.
sprintf is incorrect. It is supposed to REPLACE that other stuff. Delete lines 30 and 31.
Did the compiler throw an error or warning about sprintf?
Also, you need to include ALL of the ADC processing between the brackets on lines 26 and 28. It is pointless to use the data if Result3 is not 0.
done few changes
C:
//
#define _XTAL_FREQ 20000000     // crystal 20MHz

// PIC18F45K80 Configuration Bit Settings
// CONFIG1L
#pragma config RETEN = ON       // VREG Sleep Enable bit (Ultra low-power regulator is Enabled (Controlled by SRETEN bit))
#pragma config INTOSCSEL = LOW  // LF-INTOSC Low-power Enable bit (LF-INTOSC in Low-power mode during Sleep)
// SOSCSEL = No Setting
#pragma config XINST = OFF      // Extended Instruction Set (Disabled)
// CONFIG1H
#pragma config FOSC = HS2       // HS oscillator (high power, 16 MHz-25 MHz
#pragma config PLLCFG = OFF     // PLL x4 Enable bit (Disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor (Disabled)
#pragma config IESO = OFF       // Internal External Oscillator Switch Over Mode (Disabled)
// CONFIG2L
#pragma config PWRTEN = ON      // Power Up Timer (Enabled)
#pragma config BOREN = OFF      // Brown Out Detect (Disabled in hardware, SBOREN disabled)
#pragma config BORV = 0         // Brown-out Reset Voltage bits (3.0V)
#pragma config BORPWR = LOW     // BORMV Power level (BORMV set to low power level)
// CONFIG2H
#pragma config WDTEN = OFF      // Watchdog Timer (WDT disabled in hardware; SWDTEN bit disabled)
#pragma config WDTPS = 1        // Watchdog Postscaler (1:1)
// CONFIG3H
#pragma config CANMX = PORTC    // ECAN Mux bit (ECAN TX and RX pins are located on RC6 and RC7, respectively)
#pragma config MSSPMSK = MSK5   // MSSP address masking (5 bit address masking mode)
#pragma config MCLRE = ON      // Master Clear Enable (MCLR Enabled, RE3 Disabled)
// CONFIG4L
#pragma config STVREN = OFF     // Stack Overflow Reset (Disabled)
#pragma config BBSIZ = BB1K     // Boot Block Size (1K word Boot Block size)
// CONFIG5L
#pragma config CP0 = ON         // Code Protect 00800-01FFF (Enabled)
#pragma config CP1 = ON         // Code Protect 02000-03FFF (Enabled)
#pragma config CP2 = ON         // Code Protect 04000-05FFF (Enabled)
#pragma config CP3 = ON         // Code Protect 06000-07FFF (Enabled)
// CONFIG5H
#pragma config CPB = ON         // Code Protect Boot (Enabled)
#pragma config CPD = ON         // Data EE Read Protect (Enabled)
// CONFIG6L
#pragma config WRT0 = ON        // Table Write Protect 00800-01FFF (Enabled)
#pragma config WRT1 = ON        // Table Write Protect 02000-03FFF (Enabled)
#pragma config WRT2 = ON        // Table Write Protect 04000-05FFF (Enabled)
#pragma config WRT3 = ON        // Table Write Protect 06000-07FFF (Enabled)
// CONFIG6H
#pragma config WRTC = ON        // Config. Write Protect (Enabled)
#pragma config WRTB = ON        // Table Write Protect Boot (Enabled)
#pragma config WRTD = ON        // Data EE Write Protect (Enabled)
// CONFIG7L
#pragma config EBTR0 = ON       // Table Read Protect 00800-01FFF (Enabled)
#pragma config EBTR1 = ON       // Table Read Protect 02000-03FFF (Enabled)
#pragma config EBTR2 = ON       // Table Read Protect 04000-05FFF (Enabled)
#pragma config EBTR3 = ON       // Table Read Protect 06000-07FFF (Enabled)
// CONFIG7H
#pragma config EBTRB = ON       // Table Read Protect Boot (Enabled)
// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#pragma warning disable 520

#include <xc.h>
#include <stdio.h>
#include <conio.h>

unsigned char Result1;
unsigned char Result2;
volatile unsigned char Result3;
unsigned char Result4;

// The code should set the R/W bit according to its function
#define SLAVE_ADDRESS        0x90         //I2C slave address of ADS1115 (8 bit format)
#define Word_Address         0x01         // Points to Config register


#define LCD_RS              LATBbits.LATB4
#define LCD_TRIS_RS         TRISBbits.TRISB4
#define LCD_RW              LATBbits.LATB5
#define LCD_TRIS_RW         TRISBbits.TRISB5
#define LCD_E               LATBbits.LATB6
#define LCD_TRIS_E          TRISBbits.TRISB6

#define  LCDPORT            LATD
#define  LCDTRISD           LATD

void Port_Initialized (void);
void WriteNibble(unsigned char command);
void WaitLCDBusy(void);
void WriteCommand(unsigned char command);

void Port_Initialized (void)
{
// LATx registers
    LATA =  0x00;
    LATB =  0x00;
    LATC =  0x00;
    LATD =  0x00;
    LATE =  0x00;

//  TRISx registers
    TRISA = 0x00;      // All are output, Unused
    TRISB = 0x00;      // all are output, Unused
    TRISC = 0x18;      // Slave SDA and CLOCK
    TRISD = 0x00;      // LCD
    TRISE = 0x00;      // All are output, Unused

    ANCON0 = 0x00;     // set to digital port
    ANCON1 = 0x00;     // Set to digital port
    CM1CON = 0x00;     // Comparator off
    CM2CON = 0x00;     // Comparator off
    ADCON0 = 0x00;     // A/D conversion Disabled
    ADCON1 = 0x00;     // A/D conversion Disabled
    ADCON2 = 0x00;     // A/D conversion Disabled
}

// Wait for 5 ms
void WaitLCDBusy(void)
{
    __delay_ms(5);
}

//Send a command to the LCD
void WriteCommand(unsigned char command)
{
    WaitLCDBusy();                               //wait until not busy
    LCD_RS = 0;                                  //setup to send command
    WriteNibble(command);                        //write the high nibble
    WriteNibble( (unsigned char)(command<<4) );  //then the low nibble
}

//Initialized  LCD
void LCD_Initialized()
{
    LCDTRISD &=0x0f;                //ensure data bits are output
    LCD_E=0;                        //clear enable
    LCD_RS = 0;                     //going to write command
    LCD_TRIS_E=0;                   //Set enable to output
    LCD_TRIS_RS=0;                  //set RS to output
    LCD_TRIS_RW=0;
    LCD_RW=0;
    __delay_ms(30);                 //delay for LCD to initialize.
    WriteNibble(0x30);              //Required for initialization
    __delay_ms(5);                  //required delay
    WriteNibble(0x30);              //Required for initialization
    __delay_ms(1);                  //required delay
    WriteCommand(0x20);             //set to 4 bit interface
    WriteCommand(0x2c);             //set to 4 bit interface, 2 line and 5*10 font
    WriteCommand(0x01);             //clear display
    WriteCommand(0x06);             //move cursor right after write
    WriteCommand(0x0C);             //turn on display
}

//Send a character to the LCD
void WriteChar(unsigned char chr)
{
    WaitLCDBusy();                         //wait until not busy
    LCD_RS=1;                              //Setup to send character
    WriteNibble(chr);                      //write the high nibble   
    WriteNibble( (unsigned char)(chr<<4)); //then the low nibble
}

//Send any 4 bits to the LCD
void WriteNibble(unsigned char command)
{
    LCDPORT &= 0x0f;                        //clear the data bits
    LCDPORT|=((command & 0xf0));            //or in the new data
    LCD_E = 1;                              //enable the LCD interface
    NOP();                                  // delay of 1uS
    NOP();
    NOP();
    LCD_E = 0;                              //disable it
}

void LCD_Data( unsigned char *string)
{
    while (*string != '\0')
    {
      WriteChar(*string);
        string++;
    }
}

//Initialize I2C in master mode
void I2C_Initialized(void)
{
    SSPSTAT=0x80; //Slew rate control is disabled for Standard Speed mode (100 kHz and 1 MHz)
    SSPCON1=0x28; // I2C Master mode, clock = FOSC/(4 * (SSPADD + 1))
    SSPCON2=0x00;
    SSPADD = 49;
    //100kHz clock @ 20MHz Fosc SSPADD = ( (Fosc/4) / BiteRate )-1
   // SSPADD = ( 20MHz / 100KHz ) - 1 = 49
}

// Send an I2C START
// Return 0 if all ok, 1 if bus collision
__bit I2C_Start(void)
{
    BCLIF = 0;  //Clear 'Bus collision" flag
    SEN = 1;    //initiate a START cycle
    while (SEN);    //wait until it has been sent
    return BCLIF;   //return value of BCLIF flag
}
// Send an I2C STOP
void I2C_Stop(void)
{
    PEN = 1;    //initiate a STOP cycle
    while (PEN);    //wait until it has been sent
}

// Send an I2C REPEATED START
void I2C_Restart(void)
{
    RSEN = 1;    //initiate a REPEATED START cycle
    while (RSEN);    //wait until it has been sent
}

//Receive one byte. ackflag=0 to send ACK, or 1 to send NAK in reply
//Send one byte. Return 0 if ACK received, or 1 if NAK received
__bit I2C_Write(unsigned char dat)
{
    SSPBUF = dat;

    asm("nop");     // wait a little for R_W to be set

    while (R_W);    //wait until byte sent and ACK/NAK received
    return ACKSTAT;
}

unsigned char I2C_Read(unsigned char ackflag)
{
    RCEN = 1;   // initiate a RECEIVE cycle
    ACKDT =(__bit)ackflag;    //specify if we should send ACK or NAK after receiving
    while (RCEN);   //wait until RECEIVE has completed
    ACKEN = 1;  //initiate an ACK cycle
    while (ACKEN);  //wait until it has completed
    return SSPBUF;
}

//Send an array of data to an I2C device.
//Return 0 if all OK, 1 if bus error, 2 if slave address NAK, 3 if slave register NAK, 4 if slave data NAK
unsigned char Write_I2C_Device(unsigned char slave_address, unsigned char start_reg, unsigned char buflen, const unsigned char * bufptr)
{
    if (I2C_Start() )   //send a start, and check if it succeeded
        return 1;   //abort if bus collision
    //send the I2C slave address (force R/W bit low)
    if (I2C_Write(slave_address & 0xfe))
    {
        I2C_Stop(); //if address was NAKed, terminate the cycle
        return 2;   //and return error code
    }
    //send the device register index
    if (I2C_Write(start_reg))
    {
        I2C_Stop(); //if register was NAKed, terminate the cycle
        return 3;   //and return error code
    }
    //send the data. buflen might be zero!
    for (; buflen>0; --buflen)
    {
        if (I2C_Write(*bufptr++))
        {
            I2C_Stop(); //if register was NAKed, terminate the cycle
            return 4;   //and return error code
        }
    }
    I2C_Stop();
    return 0;   //no error
}

//Receive an array of data from an I2C device.
//Return 0 if all OK, 1 if bus error, 2 if slave address NAK, 3 if slave register NAK
unsigned char Read_I2C_Device(unsigned char slave_address, unsigned char start_reg, unsigned char buflen, unsigned char * bufptr)
{
    //do a dummy zero length write cycle to set the register address
    unsigned char retval = Write_I2C_Device(slave_address, start_reg, 0, 0);
    if (retval)
    {
        return retval;  //abort if there was an error
    }
    //now start the READ cycle
    if (I2C_Start() )   //send a start, and check if it succeeded
        return 1;   //abort if bus collision
    //send the I2C slave address (force the R/W bit high)
    if (I2C_Write(slave_address | 0x01))
    {
        I2C_Stop(); //if address was NAKed, terminate the cycle
        return 2;   //and return error code
    }
    //receive the data.
    for (; buflen>0; --buflen)
    {
        unsigned char ackflag = (buflen == 1);   //1 if this is the last byte to receive => send NAK

        *bufptr++ = I2C_Read(ackflag);
    }
    I2C_Stop();
    return 0;   //no error
}
const unsigned char ADS1115_data[] =
{
    0x84,  // MSB of the Config register to be written
    0x83,  // LSB of the Config register to be written
};

unsigned char rd_buf[2];
char A_buffer[2];

int ADC_Result;

void main(void)
{
     unsigned char i = 0;

     unsigned char Data1 [10]="xx";

     Port_Initialized ();
     LCD_Initialized();
     I2C_Initialized();

    // Write to Config register
     Result1 = Write_I2C_Device(SLAVE_ADDRESS , Word_Address , sizeof(ADS1115_data), ADS1115_data);
     __delay_ms(10);

    while(1)
    {     
       Result3 = Read_I2C_Device(SLAVE_ADDRESS, 0x00 , 2, rd_buf) ;
       __delay_ms(10);
        asm("nop");
      
        if(Result3 == 0)  // if successful read..
        {
           ADC_Result = (rd_buf[0] << 8) + rd_buf[1];
           sprintf(A_buffer,"ADC value: %d\n\r", ADC_Result );
           asm("nop");
           asm("nop");
           asm("nop");
        }
    
    }
  
  
}
This gives constant output AD

1625895551076.png
 
Last edited:

trebla

Joined Jun 29, 2019
599
Look at the size of A_buffer. This array must be able to store all bytes from the generated string ("ADC value: %d\n\r", ADC_Result). Two bytes array can't do this.
 

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
Look at the size of A_buffer. This array must be able to store all bytes from the generated string ("ADC value: %d\n\r", ADC_Result). Two bytes array can't do this.
1 byte is equal to 8 bit
ADC generate 2 bytes data
ADC result = 16 bit = 2 bytes = HIGH byte + LOW byte
That's why I kept A_buffer[2];

What size it should be?
 

Thread Starter

Djsarakar

Joined Jul 26, 2020
489
Count all characters, including spaces and escape characters (\n, \r) plus ADC_Result two bytes and the string ending zero character
I think string size is 17 including spaces and escape characters (\n, \r) plus ADC_Result two bytes and the string ending zero
 

ericgibbs

Joined Jan 29, 2010
21,448
hi Dj,
If I am reading your post correctly ref escape characters.

They are not escape characters, the \r is a 'line return' char [also known as a carriage return ]and the \n is 'new line' char.

ie: 0x0D and 0x0A , sometimes referred to as 'crlf'

E
 
Top