1
\$\begingroup\$

I have interfaced PCF8591P 8-bit ADC IC to my PIC24F application board. My PIC runs at 2.8v which is sufficient for ADC input voltage provided from datasheet. I have connected LM35 and LDR sensor to the analog 0 and analog 1 pins respectively.

Code works well, but I am getting the constant output 128 for all channels, even when the sensor output level changes. Please help me for the issue.

#include <stdio.h>
#include "p24FJ128GA202.h"
#include "uart.h"
// calculate baud rate of I2C
#define Fosc      32000000
#define Fcy       (Fosc/2)
#define Fsck      100000
#define I2C_BRG  ((Fcy/2/Fsck)-1)

int main()
{
    unsigned int Adc_pcf=0;
    InitProcessor();
    Delayms();
    while(1)
    {
        Adc_pcf = I2C_read(0x90,0x00);
        Delayms(1000);
        uart1str("ADC0=");
        uart1str(int_char(Adc_pcf));
        uart1str("\r\n");
        Adc_pcf = I2C_read(0x90,0x01);
        Delayms(1000);
        uart1str("ADC1=");
        uart1str(int_char(Adc_pcf));
        uart1str("\r\n");
    }
}

void InitProcessor(void)
{
    // Oscillator    8mhz no pll
    OSCCON = 0x0011;
    CLKDIV = 0x0000; 

    // Configure Digital pins
    ANSA = 0x0003;
    ANSB = 0x0000;

    //  Assign  IO values for Ports
    PORTA = 0x0000;
    TRISA = 0x001B;
    TRISB = 0x468f;                   // 7 as receive and 8 as transmitter
    //PORTB = 0x0000;


    // Interrupt Bits 
    INTCON1 = 0x0000;                                               // Disable  Interrupts
    INTCON2 = 0x0000;

    // Init I2C
    I2C2CONL = 0x8000;
    I2C2CONH = 0x0000;
    I2C2STAT = 0x0000;
    I2C2BRG = I2C_BRG;
    //I2C2BRG = 79;

    Delayms(1000);
    Init_rtc();
}

void Init_rtc()
{
    I2c_Write(0xde, 0x07, 0x10);
    I2c_Write(0xde, 0x06, 0x00);
    Delayms(20);
}



/* Function to Read and return a data through I2C  */
unsigned char I2C_read(unsigned char DeviceAddress,unsigned int Addr)
{   unsigned char db, ReadState=0,I2CFlag;
    ReadState = 0;
    IFS3 &= ~0x0004;                                                        // Master I2C interrupt flag
    I2CFlag = 1;
    I2C2CONL |= 0x0001;         // SEN = 1;
    I2cTimer = 0;
    while(I2CFlag){
        if(I2cTimer > 30){                                              // Exit routine
            I2CFlag = 0;
        }
        //uart1tx('r');
        if(IFS3 & 0x0004)
        {       
            I2cTimer = 0;
            IFS3 &= ~0x0004;
            if(ReadState == 0)
            {
                I2C2TRN = (DeviceAddress & 0xfe);
                if(DeviceAddress == 0x90)
                    ReadState = 1;
            }
            else if(ReadState == 1)
                I2C2TRN = Addr >> 8;
            else if(ReadState == 2)
                I2C2TRN = Addr & 0xff;
            else if(ReadState == 3)I2C2CONL |= 0x0002;  
            else if(ReadState == 4)I2C2TRN = (DeviceAddress | 0x01);
            else if(ReadState == 5){
                I2C2CONL |= 0x0008;                             // RCEN = 1, Enable data receive
                db = I2C2RCV;
            }
            else if(ReadState == 6){
                db = I2C2RCV;                                                       // Read Data
                I2C2CONL |= 0x0020;                                                 // ACKDT = 1, Set Acknowledge bit (No Acknowledge)
                Delayms(5);
                I2C2CONL |= 0x0010;                                                 // ACKEN = 1
            }
            else if(ReadState == 7)I2C2CONL |= 0x04;                                // PEN = 1, Stop enable bit forI2C
            else{ReadState = 100; I2CFlag = 0;}                                     
            ReadState++;
        }
    }
    if(db)
        return db;
    else
        return 0;
}

But I am getting the o/p as:
ADC0=128
ADC1=128

ADC to PIC pin configuration:
adc0 - temperature sensor
adc1 - LDR
adc2 - left
adc3 - left
A0 - ground
A1 - ground
A2 - ground
VSS - ground & PIC ground
SDA - PIC SDA
SCL - PIC SCL
OSC - ground
EXT - left open
agnd - ground
vref - 2.8V
aout - left open
VDD - 2.8V supply from PIC power source

pic schematic

PCF8591

Update: After suggestion from SamGibson for adc read cycle i have updated the read function

unsigned char pcfwrite(unsigned char DeviceAddress,unsigned int Addr)
{   unsigned char db, ReadState=0,I2CFlag;
    ReadState = 0;
    IFS3 &= ~0x0004;                                            // Master I2C interrupt flag
    I2CFlag = 1;
    I2C2CONL |= 0x0001;                                         // SEN = 1;
    I2cTimer = 0;
    while(I2CFlag)
    {
        if(I2cTimer > 30){                                      // Exit routine
            I2CFlag = 0;
            Error = 25; 
        }
        if(IFS3 & 0x0004)
        {       
            I2cTimer = 0;
            IFS3 &= ~0x0004;
            if(ReadState == 0)
            {
                I2C2TRN = DeviceAddress ;        // Device address
            }
            else if(ReadState == 1)
            {
                I2C2TRN = Addr;                  // control byte
            }
            else if(ReadState == 2)
            {
                I2C2CONL |= 0x0002;              // PEN = 1, Restart for I2C
            }
            else if(ReadState == 3)
            {
                I2C2CONL |= 0x0008;              // RCEN = 1, Enable data receive
                db = I2C2RCV;                    // dummy read which will be last adc written value

            }
            else if(ReadState == 4)
            {
                db = I2C2RCV;
                Delayms(5);
                I2C2CONL |= 0x0010;                                                 // ACKEN = 1
            }
            else if(ReadState == 5)I2C2CONL |= 0x04;                                // PEN = 1, Stop enable bit 
            else
            {
                ReadState = 100; 
                I2CFlag = 0;
                uart1str("I2c stopped\r\n");
            }                                       
            ReadState++;
        }
    }
    if(db)
        return db;
    else
        return 0;
}
\$\endgroup\$
2
  • \$\begingroup\$ Did the updated code work? \$\endgroup\$
    – JRE
    Oct 21, 2016 at 10:04
  • \$\begingroup\$ @JRE - Hi - In chat, the OP has asked me to review his new code (which I can't do to a deep level because, as I have already stated in my answer, I don't use the PIC24F). Therefore I doubt that his new code works, otherwise we wouldn't be asked to check it. :-( Feel free to join the chatroom - although I realise you may not want to / not have time etc. :-) \$\endgroup\$
    – SamGibson
    Oct 21, 2016 at 10:34

3 Answers 3

3
\$\begingroup\$

I am getting the constant output 128 for all channels

That is likely to be because of the way you have connected the PCF8591 ADC.

Although you have not included that ADC in the schematic, based on my interpretation of your words, pin EXT is unconnected and pin OSC is connected to ground.

That is a bad plan and it might have damaged the ADC, since OSC is an output pin, if the internal oscillator tries to run. :-( However you left EXT floating / unconnected, so we don't know if that will be seen as a logic low or a logic high!

Instead, assuming you want to use the ADC internal oscillator, you leave OSC unconnected and connect EXT to ground.

The starting value in the ADC output is 128, so until the ADC actually does any conversion cycle, then 128 is the value you will receive. Therefore receiving the value 128 continuously tells you that the ADC is not performing any conversions.


Update: Since you said earlier that "Code works well", I trusted that the code was tested and confirmed to be correct. However after your recent comments, I have looked at the code and found problems there too, in addition to the hardware problem which I explained above.

I don't use the PIC24F so I cannot check whether your I2C_read() function is correct or not, however the higher-level procedure to read from the ADC is definitely not correct. It should be similar to the question in your comment, where you said:

Start ->write(0x91)->write(0x00)->i2crestart->i2cread->i2cread->i2‌​c_stop

To read the current value from ADC0:

  • Write 0x00 to I2C address 0x90 (this value, called the "Control Byte", selects ADC0, no auto-increment, single-ended input - other options are described in the datasheet)
  • Then read 2 bytes from I2C address 0x90 (on the I2C bus, this will be address byte 0x91, of course).
  • Ignore the first of the 2 bytes read (that will be the previous ADC value, and will be 0x80 after a power-on). The current ADC value is the 2nd of the two bytes read.
\$\endgroup\$
9
  • \$\begingroup\$ After connecting the Ext pin to ground and osc pin open same results are getting.. \$\endgroup\$ Oct 20, 2016 at 6:00
  • \$\begingroup\$ @Pradeepkumark As SamGibson said the previous connexion could have damaged the ADC, try to use a new one with the proper connexion directly \$\endgroup\$
    – damien
    Oct 20, 2016 at 7:04
  • \$\begingroup\$ @damien After replacement of ADC IC also same results appear. When i flashed the light on top of LDR it shows 255 value , and doubt comes here (i.e) i think adc conversion done but how it could provide only constant output for all the channels irrespective of voltage changes in the analog pins. \$\endgroup\$ Oct 20, 2016 at 7:27
  • \$\begingroup\$ @damien I think some problem with reading method .. i have written coding according to a/d conversion cycle in datasheet. \$\endgroup\$ Oct 20, 2016 at 8:08
  • \$\begingroup\$ @Pradeepkumark - According to what you have said, your situation has now changed. "After connecting the Ext pin to ground and osc pin open same results are getting" - No, not the same results, because it was "constant output 128", but now you say "i flashed the light on top of LDR it shows 255 value". Therefore something has changed in your results, as you have said yourself! Therefore it is not clear to me why you say "constant output for all the channels irrespective of voltage changes in the analog pins", since you state the ADC output has changed (was 128, 256 with light on the LDR). \$\endgroup\$
    – SamGibson
    Oct 20, 2016 at 10:31
1
\$\begingroup\$

First, you seem to have mixed up the connections to the EXT and OSC pins. If you want to use the internal oscillator, put EXT to Vss and leave OSC open.

See page 10 (8.6) of the PCF8591 datasheet. http://www.nxp.com/documents/data_sheet/PCF8591.pdf

\$\endgroup\$
1
\$\begingroup\$

I was facing the same problem and I was able to fix it by simply removing the jumper from the PCF8591. The jumper connected AIN0 of the PCF8591 to Vcc (3.3V) in my case.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.