Shop OBEX P1 Docs P2 Docs Learn Events
right I2C driver for PCF8591 — Parallax Forums

right I2C driver for PCF8591

Rob v.d. bergRob v.d. berg Posts: 81
edited 2013-05-10 01:44 in Propeller 1
Hoi,

I want to convert javelin stuf to spin. For the javelin it was easy to read the analoge inputs·(AIN0 and·AIN1) of the·PCF8591.

*** JAVELIN CODE *******
··· PCF8591.write(0x04); // internal osc on, autoincrement·4-single ended measurements
····· // read
··· PCF8591_Chan_0 = PCF8591.read(); //throw the first away
··· PCF8591_Chan_0 = PCF8591.read(); //reading AIN0
··· PCF8591_Chan_1 = PCF8591.read(); //reading AIN1

I have done the same in spin with the basic I2C PCF8574_driver:
AIN0·> 3,65 volt 3,65/5volt * 255·must give 186
AIN1 > 3,37 volt 3,37/5volt * 255 must give 172
AIN2 > gnd
AIN3 > gnd
++++++++++++++++++++++++++++++++++++++++++++++++++++++++
con
·· ADC_Address = 72 'PCF8591 base·address $48

VAR
· long ADCval_ch0,ADCval_ch1

OBJ
··· IO·: "PCF8574_Driver"

repeat

··· IO.OUT(ADC_Address, %00000100) ' 0x04· / internal osc on, autoincrement 4-single
····················································'ended measurementscontrol byte
··· 'read channel 0
··· ADCval_ch0 := IO.IN(ADC_Address)
··· ADCval_ch0 := IO.IN(ADC_Address)
··· ADCval_ch1 := IO.IN(ADC_Address)
··· waitcnt(40_000_000 + cnt)

But the readings values are very strange.

chan0: 10100000 160 | chan1: 00000000 0
chan0: 00000000 0 | chan1: 11111111 -1

is there anyone who has·one is?,·maybe with a other I2C drive?

Rob.


·

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2008-11-23 16:02
    I don't think there's a ready-made driver for the PCF8591. The closest one you can build on would be "i2cObjectv2". As you've seen, the PCF8574 is a very different device than the PCF8591 and you can't just use one driver with another device.
  • Rob v.d. bergRob v.d. berg Posts: 81
    edited 2008-11-23 18:15
    Hi Mike,

    I know but it was working by the Javelin direct. I will start to make it with·the·basic_I2C_driver object as basis.

    thanks for your reply

    Rob.
  • Mike GreenMike Green Posts: 23,101
    edited 2008-11-23 18:22
    Here's a suggestion using the "Basic_I2C_Driver" from the Object Exchange:
    OBJ i2c : "Basic_I2C_Driver"
    
    CON PCF8591Addr = %10010000
    
    PRI DoControl(SCL, AnalogOut, Mode, AutoIncr, Channel, DAC)
    ' SCL is the pin # of the clock line to the PCF8591.  The data line is the next highest pin #.
    ' AnalogOut is TRUE if the digital to analog converter is to be enabled, FALSE otherwise.
    ' Mode is a value from 0 to 3 as specified in the PCF8591 documentation.
    ' AutoIncr is TRUE if autoincrement mode is to be enabled, FALSE otherwise.
    ' Channel is the ADC channel to be used (0-3) for the next conversion.
    ' Note: This must be called at least once prior to attempting to read an analog channel.
       i2c.Start(SCL)
       i2c.Write(SCL, PCF8591Addr+i2c#Xmit)
       i2c.Write(SCL, ((AnalogOut & 1) << 6) | (Mode << 4) | ((AutoIncr & 1) << 2) | Channel)
       if AnalogOut
          i2c.Write(SCL, DAC)
       i2c.Stop(SCL)
    
    PRI GetAnalog(SCL)
    ' This returns the next value from the analog to digital converter set up by the last DoControl call.
    ' SCL is the pin # of the clock line to the PCF8591.  The data line is the next highest pin #.
    ' Note: The value returned is from the most recent conversion.  A new conversion is started and
    ' will be returned on the next call to GetAnalog.
       i2c.Start(SCL)
       i2c.Write(SCL, PCF8591Addr+i2c#Recv)
       result := i2c.Read(SCL, i2c#NAK)
       i2c.Stop(SCL)
    
  • Rob v.d. bergRob v.d. berg Posts: 81
    edited 2008-11-23 20:18
    Mike,

    Thanks, that push me in the right direction, as PUB i must think as:

    ·'get only channel 0,1,2 or 3
    __________________________________
    PUB GetSingleADC(SCL,Channel)

    · DoControl(SCl, 0, 0, 0, Channel, 0)

    · return GetAnalog(SCL)
    ___________________________________
  • Peter JakackiPeter Jakacki Posts: 10,193
    edited 2008-11-24 00:01
    Just a suggestion for some PCF8591 code by way of example if you embed this into the Basic_I2C_Driver. This driver use a ADC_SCAN to read the 4 channels all at once since this is a lot faster than calling all 4 channels individually. This is not tested but should work as it is based upon some really old code I once did with 8591s.

    *Peter*

    VAR
      byte adcdata[noparse][[/noparse] 4 ]
    
    PUB ADC_SCAN(SCL)
      Start(SCL)
      Write(SCL,$90)
      Write(SCL,$44)
      Start(SCL)
      Write(SCL,$91)
      adcdata[noparse][[/noparse] 0 ] := Read(SCL,0)
      adcdata[noparse][[/noparse] 1] := Read(SCL,0)
      adcdata[noparse][[/noparse] 2 ] := Read(SCL,0)
      adcdata[noparse][[/noparse] 3 ] := Read(SCL,1)
      Stop(SCL)
    
    PUB READ_ADC(ch) : adcdat
      adcdat := adcdata[noparse][[/noparse]ch]
    
    PUB DAC_OUT(SCL,dacdat)
      Start(SCL)
      Write(SCL,$90)
      Write(SCL,$40)
      Write(SCL,dacdat)
      Stop(SCL)
            
    
    
  • Rob v.d. bergRob v.d. berg Posts: 81
    edited 2008-11-24 11:18
    Peter, thanks, also good idea.

    Mike, great its works thanks a lot.

    Rob
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2013-05-10 01:44
    Thanks to all those that contributed to this thread :)

    Brief background - the PCF8591 is a chip that works on the I2C bus and gives you 1 analog output and 4 analog inputs. 8 bit resolution.

    I had a urgent need for a pump controller and I needed a display and some analog inputs and outputs. This thread has come to the rescue!

    After much work with many microcontrollers, in terms of a simple text display and it terms of dollars per character, nothing beats the Propeller driving a car reversing display. Essentially this is a little TV display and for those familiar with the propeller, driving such a display is three resistors and a RCA socket and ready made code in the Obex. Less wires and cheaper and more characters than, say, 20x4 LCD displays.

    And I want to read a pressure gauge to measure the height in a tank. The MPX5050 is perfect for this as it has an inbuilt amplifier so all the voltages are just right for the propeller.

    The standard analog input using two pins and a 100k and 150k and two 1nf caps stumped me though. I think it is probably because the components have to be surface mount and right up next to the chip. I can't do that on my setup and my components were 10cm awy and in any case, an evening of debugging got nowhere. So the PCF8591 came to the rescue.

    Well, it works brilliantly. Uses the I2C bus so it doesn't use any propeller pins as such as the I2C shares the EEPROM.

    Datasheet is here http://www.nxp.com/documents/data_sheet/PCF8591.pdf

    I modified Mike's code a little by adding some more comments.

    Mike, James Burrows added a package to the Obex based on your code http://obex.parallax.com/object/27

    I wonder if there is a way of adding the PCF8591 to the package? I don't want to duplicate what is already done, but what would be ideal is a search for PCF8591 comes up with a little working demo package.
    CON
            _clkmode = xtal1 + pll16x                                               'Standard clock mode * crystal frequency = 80 MHz
            _xinfreq = 5_000_000
    
    
    OBJ
       text: "tv_text"
       delay: "timing"
       i2c : "Basic_I2C_Driver"      
      
    PUB main
         text.start(16)
         text.clearscreen
         DoControl(28,true,%00,false,%00,128) ' set up PCF8591
         repeat
              delay.pause1ms(1000)  
              text.dec(GetAnalog(28)) ' display the value
              text.out(32) ' send a space
    
    ' PCF8591 driver
    ' see http://forums.parallax.com/showthread.php/108214-right-I2C-driver-for-PCF8591?highlight=pcf8591
        
    CON PCF8591Addr = %10010000
    
    PRI DoControl(SCL, AnalogOut, Mode, AutoIncr, Channel, DAC)
    ' SCL is the pin # of the clock line to the PCF8591.  The data line is the next highest pin #.
    ' AnalogOut is TRUE if the digital to analog converter is to be enabled, FALSE otherwise.
    ' Mode is a value from 0 to 3 as specified in the PCF8591 documentation.
    ' AutoIncr is TRUE if autoincrement mode is to be enabled, FALSE otherwise.
    ' Channel is the ADC channel to be used (0-3) for the next conversion.
    ' Note: This must be called at least once prior to attempting to read an analog channel.
    ' mode byte - 0xxx0xxx with bits 7,6,5,4,3,2,1,0
    ' bit 7 = don't care
    ' bit 6 is the analog output bit - true to enable analog out
    ' bit 5 and 4 - 00 = 4 single ended inputs, 01 = three differential inputs
    '               10 = single ended and differential mixed, 11 = two differential inputs
    ' bit 3=  don't care, bit 2 = auto increment if true (set to 0), bit 0 and 1 = which of 4 to select 
    ' DAC is the value to output (if AnalogOut is true)
       i2c.Start(SCL)
       i2c.Write(SCL, PCF8591Addr+i2c#Xmit)
       i2c.Write(SCL, ((AnalogOut & 1) << 6) | (Mode << 4) | ((AutoIncr & 1) << 2) | Channel)
       if AnalogOut
          i2c.Write(SCL, DAC)
       i2c.Stop(SCL)
    
    PRI GetAnalog(SCL)
    ' This returns the next value from the analog to digital converter set up by the last DoControl call.
    ' SCL is the pin # of the clock line to the PCF8591.  The data line is the next highest pin #.
    ' Note: The value returned is from the most recent conversion.  A new conversion is started and
    ' will be returned on the next call to GetAnalog.
       i2c.Start(SCL)
       i2c.Write(SCL, PCF8591Addr+i2c#Recv)
       result := i2c.Read(SCL, i2c#NAK)
       i2c.Stop(SCL)
    
Sign In or Register to comment.