Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

I2C, ADC, LCD, pic18f258

bernage

New Member
I want to use two or more adc channel using I2C and lcd. Can someone help me where i am doing wrong?

I2c.c
C:
#include <xc.h>
#include "I2c.h"

unsigned char RS, i2c_add, BackLight_State = LCD_BACKLIGHT;

//---------------[ I2C Routines ]-------------------
//--------------------------------------------------
void I2C__Init()
{
  SSPCON1  = 0x38;
  SSPCON2 = 0x00;
  SSPSTAT = 0x00;
  SSPADD = ((_XTAL_FREQ/4)/I2C_BaudRate) - 1;
  SCL_D = 1;
  SDA_D = 1;
}

void I2C__Wait()
{
    while ((SSPSTAT & 0x04) || (SSPCON2 & 0x1F));
}

void I2C__Start()
{
    I2C__Wait();
    SEN = 1;
}

void I2C__RepeatedStart()
{
    I2C__Wait();
    RSEN = 1;
}

void I2C__Stop()
{
    I2C__Wait();
    PEN = 1;
}

void I2C_ACK(void)
{
    ACKDT = 0;            // 0 -> ACK
    I2C__Wait();
    ACKEN = 1;            // Send ACK
}

void I2C_NACK(void)
{
    ACKDT = 1;            // 1 -> NACK
    I2C__Wait();
    ACKEN = 1;            // Send NACK
}

unsigned char I2C__Write(unsigned char data)
{
    I2C__Wait();
    SSPBUF = data;
    while(!SSPIF);  // Wait Until Completion
    SSPIF = 0;
    return ACKSTAT;
}

unsigned char I2C_Read_Byte(void)
{
    //---[ Receive & Return A Byte ]---
    I2C__Wait();
    RCEN = 1;          // Enable & Start Reception
    while(!SSPIF);      // Wait Until Completion
    SSPIF = 0;          // Clear The Interrupt Flag Bit
    I2C__Wait();
    return SSPBUF;      // Return The Received Byte
}
//======================================================

//---------------[ LCD Routines ]----------------
//------------------------------------------------------

void LCD_Init(unsigned char I2C_Add)
{
  i2c_add = I2C_Add;
  IO_Expander_Write(0x00);
  __delay_ms(30);
  LCD_CMD(0x03);
  __delay_ms(5);
  LCD_CMD(0x03);
  __delay_ms(5);
  LCD_CMD(0x03);
  __delay_ms(5);
  LCD_CMD(LCD_RETURN_HOME);
  __delay_ms(5);
  LCD_CMD(0x20 | (LCD_TYPE << 2));
  __delay_ms(50);
  LCD_CMD(LCD_TURN_ON);
  __delay_ms(50);
  LCD_CMD(LCD_CLEAR);
  __delay_ms(50);
  LCD_CMD(LCD_ENTRY_MODE_SET | LCD_RETURN_HOME);
  __delay_ms(50);
}

void IO_Expander_Write(unsigned char Data)
{
  I2C__Start();
  I2C__Write(i2c_add);
  I2C__Write(Data | BackLight_State);
  I2C__Stop();
}

void LCD_Write_4Bit(unsigned char Nibble)
{
  // Get The RS Value To LSB OF Data
  Nibble |= RS;
  IO_Expander_Write(Nibble | 0x04);
  IO_Expander_Write(Nibble & 0xFB);
  __delay_us(50);
}

void LCD_CMD(unsigned char CMD)
{
  RS = 0; // Command Register Select
  LCD_Write_4Bit(CMD & 0xF0);
  LCD_Write_4Bit((CMD << 4) & 0xF0);
}

void LCD_Write_Char(char Data)
{
  RS = 1;  // Data Register Select
  LCD_Write_4Bit(Data & 0xF0);
  LCD_Write_4Bit((Data << 4) & 0xF0);
}

void LCD_Write_String(char* Str)
{
    for(int i=0; Str[I]!='\0'; i++)
       LCD_Write_Char(Str[I]);
}

void LCD_Set_Cursor(unsigned char ROW, unsigned char COL)
{   
  switch(ROW)
  {
    case 2:
      LCD_CMD(0xC0 + COL-1);
      break;
    case 3:
      LCD_CMD(0x94 + COL-1);
      break;
    case 4:
      LCD_CMD(0xD4 + COL-1);
      break;
    // Case 1 
    default:
      LCD_CMD(0x80 + COL-1);
  }
}

void Backlight()
{
  BackLight_State = LCD_BACKLIGHT;
  IO_Expander_Write(0);
}

void noBacklight()
{
  BackLight_State = LCD_NOBACKLIGHT;
  IO_Expander_Write(0);
}

void LCD_SL()
{
  LCD_CMD(0x18);
  __delay_us(40);
}

void LCD_SR()
{
  LCD_CMD(0x1C);
  __delay_us(40);
}

void LCD_Clear()
{
  LCD_CMD(0x01);
  __delay_us(40);

.
.
.
.
.[/I][/I]
C:
[I][I]I2c .h

/* File: I2C_LCD.h */

#define _XTAL_FREQ             8000000

#define I2C_BaudRate           100000
#define SCL_D                  TRISC3
#define SDA_D                  TRISC4

#define LCD_BACKLIGHT          0x08
#define LCD_NOBACKLIGHT        0x00
#define LCD_FIRST_ROW          0x80
#define LCD_SECOND_ROW         0xC0
#define LCD_THIRD_ROW          0x94
#define LCD_FOURTH_ROW         0xD4
#define LCD_CLEAR              0x01
#define LCD_RETURN_HOME        0x02
#define LCD_ENTRY_MODE_SET     0x04
#define LCD_CURSOR_OFF         0x0C
#define LCD_UNDERLINE_ON       0x0E
#define LCD_BLINK_CURSOR_ON    0x0F
#define LCD_MOVE_CURSOR_LEFT   0x10
#define LCD_MOVE_CURSOR_RIGHT  0x14
#define LCD_TURN_ON            0x0C
#define LCD_TURN_OFF           0x08
#define LCD_SHIFT_LEFT         0x18
#define LCD_SHIFT_RIGHT        0x1E
#define LCD_TYPE               2       // 0 -> 5x7 | 1 -> 5x10 | 2 -> 2 lines

//-----------[ Functions' Prototypes ]--------------

//---[ I2C Routines ]---

void I2C__Init();
void I2C__Wait();
void I2C__Start();
void I2C__RepeatedStart();
void I2C__Stop();
void I2C_ACK();
void I2C_NACK();
unsigned char I2C__Write(unsigned char data);
unsigned char I2C_Read_Byte(void);

//---[ LCD Routines ]---

void LCD_Init(unsigned char I2C_Add);
void IO_Expander_Write(unsigned char Data);
void LCD_Write_4Bit(unsigned char Nibble);
void LCD_CMD(unsigned char CMD);
void LCD_Set_Cursor(unsigned char ROW, unsigned char COL);
void LCD_Write_Char(char);
void LCD_Write_String(char*);
void Backlight();
void noBacklight();
void LCD_SR();
void LCD_SL();
void LCD_Clear(void);
.
.

.
.
Mainc
C:
/*
 * File:   main.c
* Author: microdigisoft.com
*
 */
#include <xc.h>
#include "config.h"
#include "I2c.h"

unsigned char input;
int result_1;  
float Voltage1_result; 
int AN1_Result;  
 int AN0_Result;  
 int AN2_Result; 
 
void ADC_Init()
{
TRISA = 0xff; //*set as input port*/
ADCON1 =  0b11110000; //Right Justify, FRC Clock , All pins as Analog Input and setting Reference Voltages
ADCON0 = 0b00000001; //Turn ON ADC and Clock Selection

}

int ReadADC(unsigned char channel)
 
{   
 int AN_Val;
    
switch (channel)    {      
    case 1: //AN1          
        ADCON0 = 0x0D;          
        break;      
 
      case 2: //AN2          
          ADCON0 = 0x55;           
         break;      
 

      default: //Any other value will default to AN0   
    ADCON0 = 0x45;  
   }
__delay_us(10);

ADCON0&=0x81;
         ADCON0|= (channel <<2);
         GO_DONE=1;

      while (ADCON0 & 0x02); 
      AN_Val = (ADRESH*256 + ADRESL);
       return AN_Val;   
   }
void main(void) {
   
      // Initialize LCD module with I2C address = 0x4E
  
    LCD_Init(0x4E);
  
      I2C__Init();
       // Initialize I2C bus function
    ADC_Init(); //* initialize 10-bit ADC*/ 
LCD_Set_Cursor(1,4);
LCD_Write_String("Nikolas");
  
   

    while(1)
    {
        AN0_Result = ReadADC(0) ;      
       __delay_ms(10);      
      AN1_Result = ReadADC(1);      
      __delay_ms(10);      
      AN2_Result = ReadADC(2);      
     __delay_ms(10);       
//     
   LCD_Clear();
   LCD_Set_Cursor(1,1); 
LCD_Write_Char( ((AN1_Result)%100)/100 );
LCD_Set_Cursor(2, 1); 
LCD_Write_Char( ((AN0_Result)%100)/100 );
LCD_Write_String("dgdgj");
     }
    return;
}
 

Attachments

  • 22757211-D252-4172-81E0-EA777ADCE61D.png
    22757211-D252-4172-81E0-EA777ADCE61D.png
    64.3 KB · Views: 73
Last edited by a moderator:

sagor1

Active Member
What is not working???
I don't see where you initialize PortC as output for I2C. Not sure if one has to do that, but setting TRISC as output may help ensure that the port is at least set correctly.
Do you have pull-ups on the I2C lines?
 

bernage

New Member
What is not working???
I don't see where you initialize PortC as output for I2C. Not sure if one has to do that, but setting TRISC as output may help ensure that the port is at least set correctly.
Do you have pull-ups on the I2C lines?

Now I wrote trisc=0 in void main function’s first line. I can write to the lcd without using adc things. yes I did pull up. i'm trying in proteus and i can't measure voltage using adc pins. An0, An1, An2 pin are connected dc voltmeter. But this code is not working. I do not think the circuit connections are faulty.
 

upand_at_them

Active Member
What programming environment is being used? I don't see a header for the PIC being used. Start with something simple, like turning on an LED, and move up in steps to your goal. Also state exactly what isn't working. "Where am I wrong" isn't a helpful description.
 

sagor1

Active Member
I'm suspicious of line:

while (ADCON0 & 0x02)

While I don't do a lot of "C", you seem to be testing bit 1 of ADCON0, which is undefined. The "Done" bit is bit 2 (counting from 0). A test for Done would be using 0x04, and testing that it is low when A/D is complete. While it is high, A/D is still in progress.
 

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
I'm suspicious of line:
Should work... once the ADCON2 is clr the while expression fails..
What programming environment is being used?
Again XC8 picks that info from the IDE...

Can you do me a circuit as we have no idea how you are connected... IE.. what io expander are you using?
 

bernage

New Member
Should work... once the ADCON2 is clr the while expression fails..

Again XC8 picks that info from the IDE...

Can you do me a circuit as we have no idea how you are connected... IE.. what io expander are you using?

I want to give dc voltage to an0-an2 pins and see the measurement result on the LCD screen with serial connected i2c. I am definetly not sure but the signs in the proteus, i could not establish the connection between pic and i2c with this code.
 

Attachments

  • 03C095E6-00F9-45F5-A4AD-0968BE427760.png
    03C095E6-00F9-45F5-A4AD-0968BE427760.png
    64.3 KB · Views: 67

sagor1

Active Member
Should work... once the ADCON2 is clr the while expression fails..
That was my point Ian, he is testing an undefined pin, which reads zero all the time. to test bit 2 (third bit), it is 0x04 that should be "and" with the register. The way it is now, it will always be zero
 

bernage

New Member
That was my point Ian, he is testing an undefined pin, which reads zero all the time. to test bit 2 (third bit), it is 0x04 that should be "and" with the register. The way it is now, it will always be zero
But also I added LCD_Write_String("dgdgj") at the end of the mainc part. Even if program couldn't do the adc part, shouldn't it have to write to the screen?
 

Ian Rogers

User Extraordinaire
Forum Supporter
Most Helpful Member
Okay... I have it working..

Worst problem..

Looky here

Code:
    LCD_Init(0x4E);
  
      I2C__Init();

Cooo!! I wonder why the LCD doesn't initialize..

Once its round the right way it starts... I hade to remove LCDClear as it was jumpy as hell

I needed to re write the ADC read as it was not working

New one..
C:
int ReadADC(unsigned char channel)
    {
    int AN_Val;
        
    ADCON0&=0x81;
    ADCON0|= (channel << 2);
    __delay_us(500);
    GO_DONE=1;
    
    while (ADCON0 & 0x02); 
    AN_Val = (ADRESH*256 + ADRESL);
    return AN_Val;   
   }

I had to bring in delays to LCD write as it was far too fast
C:
void LCD_Write_4Bit(unsigned char Nibble)
{
  // Get The RS Value To LSB OF Data
    Nibble |= RS;
    IO_Expander_Write(Nibble | 0x04);
    __delay_us(50);
    IO_Expander_Write(Nibble & 0xFB);
    __delay_ms(2);    // too much but it works..
}
Lastly this----
LCD_Write_Char( ((AN1_Result)%100)/100 );
Doesn't generate a char... if it's a single char you need then add 48 to the total..

Those V meters do not generate a voltage in ISIS..
 

bernage

New Member
Okay... I have it working..

Worst problem..

Looky here

Code:
    LCD_Init(0x4E);
  
      I2C__Init();

Cooo!! I wonder why the LCD doesn't initialize..

Once its round the right way it starts... I hade to remove LCDClear as it was jumpy as hell

I needed to re write the ADC read as it was not working

New one..
C:
int ReadADC(unsigned char channel)
    {
    int AN_Val;
        
    ADCON0&=0x81;
    ADCON0|= (channel << 2);
    __delay_us(500);
    GO_DONE=1;
    
    while (ADCON0 & 0x02); 
    AN_Val = (ADRESH*256 + ADRESL);
    return AN_Val;   
   }

I had to bring in delays to LCD write as it was far too fast
C:
void LCD_Write_4Bit(unsigned char Nibble)
{
  // Get The RS Value To LSB OF Data
    Nibble |= RS;
    IO_Expander_Write(Nibble | 0x04);
    __delay_us(50);
    IO_Expander_Write(Nibble & 0xFB);
    __delay_ms(2);    // too much but it works..
}
Lastly this----

Doesn't generate a char... if it's a single char you need then add 48 to the total..

Those V meters do not generate a voltage in ISIS..
Thank you. Also i get an error like “direct function call made with an incomplete prototype (I2C__init)”.
 

Latest threads

Top