Library for NXP (Philips) PCF8591 I2C 4 Channel, 8bit Analog to Digital converter and a 1 Channel, 8bit Digital to Analog converter.
Dependents: 812_hello PCF8591_test_LAAS
Revision 0:1116b0d151fc, committed 2013-09-21
- Comitter:
- wim
- Date:
- Sat Sep 21 19:25:09 2013 +0000
- Commit message:
- Extended functionality to include mbed type AnalogIn and AnalogOut; Fixed issue related to LPC812 I2C bug
Changed in this revision
PCF8591.cpp | Show annotated file Show diff for this revision Revisions of this file |
PCF8591.h | Show annotated file Show diff for this revision Revisions of this file |
diff -r 000000000000 -r 1116b0d151fc PCF8591.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PCF8591.cpp Sat Sep 21 19:25:09 2013 +0000 @@ -0,0 +1,293 @@ +/* PCF8591 - I2C 8 bit 4 channel A/D and 8 bit 1 channel D/A converter + * Copyright (c) 2013 Wim Huiskamp + * + * Released under the MIT License: http://mbed.org/license/mit + * + * version 0.2 Initial Release +*/ +#include "mbed.h" +#include "PCF8591.h" + + +/** Create a PCF8591 AD and DA object using a specified I2C bus and slaveaddress + * + * @param I2C &i2c the I2C port to connect to + * @param char deviceAddress the address of the PCF8591 + */ +PCF8591::PCF8591(I2C *i2c, uint8_t deviceAddress) : _i2c(i2c) { + + _slaveAddress = deviceAddress; + _init(); +} + + +#if(0) +//These methods are disabled since they interfere with normal expected behaviour for mbed type Analog I/O +// + +/** Set ADC mode + * + * @param adc_mode ADC Channel mode, valid Range (PCF8591_4S, PCF8591_3D, PCF8591_2S_1D, PCF8591_2D) + */ +void PCF8591::setADCMode(uint8_t mode){ + uint8_t data[6]; + + _mode = _mode & ~PCF8591_2D; // Clear ADC mode bits + + switch (mode) { + case PCF8591_4S: + _mode = _mode | PCF8591_4S; + break; + case PCF8591_3D: + _mode = _mode | PCF8591_3D; + break; + case PCF8591_2S_1D: + _mode = _mode | PCF8591_2S_1D; + break; + case PCF8591_2D: + _mode = _mode | PCF8591_2D; + break; + default: + _mode = _mode | PCF8591_4S; + break; + } + + data[0] = _mode; // Control Reg + + // write data to the device + _i2c->write(_slaveAddress, (char*) data, 1); + +}; + +/** Set DAC mode + * + * @param dac_mode DAC Channel mode, valid Range (false=disable, true=enable) + */ +void PCF8591::setDACMode(bool mode) { + uint8_t data[6]; + + if (mode) + _mode = _mode | PCF8591_AOUT; // Enable DAC output + else + _mode = _mode & ~PCF8591_AOUT; // Disable DAC output + + data[0] = _mode; // Control Reg + + // write data to the device + _i2c->write(_slaveAddress, (char*) data, 1); + +}; +#endif + + +/** Write Analog Output + * + * @param analogOut output value (0..255) + */ +void PCF8591::write(uint8_t analogOut) { + uint8_t data[6]; + + data[0] = _mode; // Control Reg + data[1] = analogOut; // DAC Channel + + // write data to the device + _i2c->write(_slaveAddress, (char*) data, 2); +}; + +/** Read Analog Channel + * + * @param Channel ADC channel, valid range PCF8591_ADC0, PCF8591_ADC1, PCF8591_ADC2 or PCF8591_ADC3 + * @return value uint8_t AD converted value (0..255, representing 0V..Vcc) + */ +#if(0) +// I2C block operations test +// Causes problems with Ticker and printf on LPC812. No issues found on LPC1768 +uint8_t PCF8591::read(uint8_t channel) { +// uint8_t data[6]; + uint8_t data[6] = {123,123,123,123,123,123}; //test to check failed read + + _mode = _mode & ~PCF8591_CHMSK; // Clear ADC Channel bits + _mode = _mode | (channel & PCF8591_CHMSK); // Set ADC Channel bits + + data[0] = _mode; // Init Control Reg + + // write data to the device to select the ADC channel + _i2c->write(_slaveAddress, (char*) data, 1); + + // read selected ADC channel + // note that first byte is a 'dummy' and should be ignored + _i2c->read(_slaveAddress, (char*) data, 2); + return data[1]; +}; + +#else +// I2C single byte operations test +// No issues found on LPC812 +uint8_t PCF8591::read(uint8_t channel) { + uint8_t data[6]; +// uint8_t data[6] = {123,123,123,123,123,123}; //test to check failed read + + _mode = _mode & ~PCF8591_CHMSK; // Clear ADC Channel bits + _mode = _mode | (channel & PCF8591_CHMSK); // Set ADC Channel bits + + data[0] = _mode; // Init Control Reg + + // write data to the device to select the ADC channel + _i2c->start(); + _i2c->write(_slaveAddress); // Slave write address + _i2c->write(data[0]); + _i2c->stop(); + + // read selected ADC channel + // note that first byte is a 'dummy' and should be ignored + _i2c->start(); + _i2c->write(_slaveAddress | 0x01); // Slave read address + data[0]=_i2c->read(1); //ack + data[1]=_i2c->read(0); //nack + _i2c->stop(); + + return data[1]; +}; + +#endif + + +/** Initialise AD and DA driver + * + */ +void PCF8591::_init() { + uint8_t data[6]; + + _mode = PCF8591_CTRL_DEF; // Init mode + + data[0] = _mode; // Init Control Reg + data[1] = 0x00; // Init DAC Channel to 0 + + // write data to the device + _i2c->write(_slaveAddress, (char*) data, 2); +}; + + + + + +/** Create a PCF8591 AnalogOut object connected to the specified I2C bus and deviceAddress + * + */ +PCF8591_AnalogOut::PCF8591_AnalogOut(I2C *i2c, uint8_t deviceAddress) : _i2c(i2c) { + + _slaveAddress = deviceAddress; + _init(); +} + + +/** Write Analog Output + * + * @param analogOut value (0 .. 1.0) + */ +void PCF8591_AnalogOut::write(float analogOut) { + uint8_t data[6]; + + data[0] = _mode; // Control Reg + + // DAC Channel + if (analogOut < 0.0) data[1] = 0; + else if (analogOut >= 1.0) data[1] = 255; + else data[1] = uint8_t (analogOut * 255.0); + + // write data to the device + _i2c->write(_slaveAddress, (char*) data, 2); +}; + +/** Operator = Analog Output + * + * @param analogOut value (0.0f .. 1.0f) + */ +PCF8591_AnalogOut& PCF8591_AnalogOut::operator= (float value){ + write(value); + return *this; +} + + +/** Initialise DAC driver + * + */ +void PCF8591_AnalogOut::_init() { + uint8_t data[6]; + + _mode = PCF8591_CTRL_DEF; // Init mode + + data[0] = _mode; // Init Control Reg + data[1] = 0x00; // Init DAC Channel to 0 + + // write data to the device + _i2c->write(_slaveAddress, (char*) data, 2); +}; + + + +/** Create a PCF8591 AnalogIn object connected to the specified I2C bus and deviceAddress + * + */ +PCF8591_AnalogIn::PCF8591_AnalogIn(I2C *i2c, uint8_t channel, uint8_t deviceAddress) : _i2c(i2c) { + + _slaveAddress = deviceAddress; + _channel = channel; + _init(); +} + + +/** Read Analog input + * + * @return analogIn value (0 .. 1.0) + */ +float PCF8591_AnalogIn::read() { + uint8_t data[6]; + + data[0] = _mode; // Init Control Reg + + // write data to the device to select the ADC channel + _i2c->start(); + _i2c->write(_slaveAddress); // Slave write address + _i2c->write(data[0]); + _i2c->stop(); + + // read selected ADC channel + // note that first byte is a 'dummy' and should be ignored + _i2c->start(); + _i2c->write(_slaveAddress | 0x01); // Slave read address + data[0]=_i2c->read(1); //ack + data[1]=_i2c->read(0); //nack + _i2c->stop(); + + + // ADC Channel + return ((float) data[1] / 255.0); + +}; + + +/** Operator float Analog Input + * + * @return analogIn value (0 .. 1.0) + */ +PCF8591_AnalogIn::operator float(){ + return (read()); +} + + +/** Initialise ADC driver + * + */ +void PCF8591_AnalogIn::_init() { + uint8_t data[6]; + + _mode = PCF8591_CTRL_DEF; // Init mode + _mode = _mode & ~PCF8591_CHMSK; // Clear ADC Channel bits + _mode = _mode | (_channel & PCF8591_CHMSK); // Set ADC Channel bits + + data[0] = _mode; // Init Control Reg + + // write data to the device + _i2c->write(_slaveAddress, (char*) data, 1); +};
diff -r 000000000000 -r 1116b0d151fc PCF8591.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PCF8591.h Sat Sep 21 19:25:09 2013 +0000 @@ -0,0 +1,221 @@ +/* PCF8591 - I2C 8 bit, 4 channel A/D and 8 bit, 1 channel D/A converter + * Copyright (c) 2013 Wim Huiskamp + * + * Released under the MIT License: http://mbed.org/license/mit + * + * version 0.2 Initial Release +*/ +#ifndef _PCF8591_H +#define _PCF8591_H + +/** Driver for PCF8591 I2C I2C A/D and D/A converter + * + * @code + * #include "mbed.h" + * #include "PCF8591.h" + * + * // I2C Communication + * I2C i2c_adcdac(p28,p27); // SDA, SCL for LPC1768 + * //I2C i2c_adcdac(P0_10,P0_11); // SDA, SCL for LPC812 + * + * //Declare a composite ADC and DAC device that may be used through public methods + * PCF8591 adc_dac(&i2c_adcdac); // I2C bus, Default PCF8591 Slaveaddress + * + * //Declare independent ADC and DAC objects that may be used similar to mbed AnalogIn and AnalogOut pins + * //PCF8591_AnalogOut anaOut(&i2c_bus); + * // + * //PCF8591_AnalogIn anaIn(&i2c_bus, PCF8591_ADC0); + * + * + * int main() { + * uint8_t count = 0; + * uint8_t analog; + * + * while(1) { + * wait(0.2); + * count++; + * + * // Composite device methods + * adc_dac.write(count); // write D/A value + * analog = adc_dac.read(PCF8591_ADC0); // read A/D value for Channel 0 + * + * // mbed pin type methods + * //anaOut = (float)count / 255.0; // write D/A value using range 0.0f .. 1.0f + * //analog = anaIn * 33.0; // read A/D value for Channel 0 in (Volts*10) + * } + * + * } + * @endcode + */ + + +//Address Defines for PCF8591 +#define PCF8591_SA0 0x90 +#define PCF8591_SA1 0x92 +#define PCF8591_SA2 0x94 +#define PCF8591_SA3 0x96 +#define PCF8591_SA4 0x98 +#define PCF8591_SA5 0x9A +#define PCF8591_SA6 0x9C +#define PCF8591_SA7 0x9E + +//Register Defines for PCF8591 +#define PCF8591_CTRL 0x00 +#define PCF8591_ADR0 0x01 +#define PCF8591_ADR1 0x02 +#define PCF8591_ADR2 0x03 +#define PCF8591_ADR3 0x04 +#define PCF8591_DAR 0x01 + +//Control Register Defines for PCF8591 +//AD Channels +#define PCF8591_ADC0 0x00 +#define PCF8591_ADC1 0x01 +#define PCF8591_ADC2 0x02 +#define PCF8591_ADC3 0x03 +//AD Channel Mask +#define PCF8591_CHMSK 0x03 + +//Auto Increment flag (0=disable, 1=enable) +#define PCF8591_AIF 0x04 + +//AD Channels Input modes +//4 Single Channels (Chan0=AIN0, Chan1=AIN0, Chan2=AIN0, Chan3=AIN0) +#define PCF8591_4S 0x00 +//3 Diff Channels (Chan0=AIN0-AIN3, Chan1=AIN1-AIN3, Chan2=AIN2-AIN3) +#define PCF8591_3D 0x10 +//2 Single Channels (Chan0=AIN0, Chan1=AIN1) +//1 Diff Channel (Chan2=AIN2-AIN3) +#define PCF8591_2S_1D 0x20 +//2 Diff Channels (Chan0=AIN0-AIN1, Chan1=AIN2-AIN3) +#define PCF8591_2D 0x30 +//ChannelMode Mask +#define PCF8591_CHMDMSK 0x30 + +//Analog Output enable flag (0=disable, 1=enable) +#define PCF8591_AOUT 0x40 + +//Default Mode: ADC0, AutoIncr Off, 4 Single Chan, AnalogOut On +#define PCF8591_CTRL_DEF (PCF8591_ADC0 | PCF8591_4S | PCF8591_AOUT) + + +/** Create a PCF8591 object connected to the specified I2C bus and deviceAddress + * +*/ +class PCF8591 { +public: + /** Create a PCF8591 AD and DA object using a specified I2C bus and slaveaddress + * + * @param I2C &i2c the I2C port to connect to + * @param char deviceAddress the address of the PCF8591 + */ + PCF8591(I2C *i2c, uint8_t deviceAddress = PCF8591_SA0); + +#if(0) +//These methods are disabled since they interfere with normal expected behaviour for mbed type Analog I/O +// + /** Set ADC mode + * + * @param adc_mode ADC Channel mode, valid Range (PCF8591_4S, PCF8591_3D, PCF8591_2S_1D, PCF8591_2D) + */ + void setADCMode(uint8_t mode); + + /** Set DAC mode + * + * @param dac_mode DAC Channel mode, valid Range (false=disable, true=enable) + */ + void setDACMode(bool mode); +#endif + +/** Write Analog Output + * + * @param analogOut output value (0..255) + */ + void write(uint8_t analogOut); + +/** Read Analog Channel + * + * @param Channel ADC channel, valid range PCF8591_ADC0, PCF8591_ADC1, PCF8591_ADC2 or PCF8591_ADC3 + * @return value uint8_t AD converted value (0..255, representing 0V..Vcc) + */ + uint8_t read(uint8_t channel); + + + +protected: + I2C *_i2c; //I2C bus reference + uint8_t _slaveAddress; //I2C Slave address of device + uint8_t _mode; //Device mode + +/** Initialise AD and DA driver + * + */ + void _init(); +}; + + +/** Create a PCF8591 AnalogOut object connected to the specified I2C bus and deviceAddress + * +*/ +class PCF8591_AnalogOut { +public: + /** Create a PCF8591 Analogout object using a specified I2C bus and slaveaddress + * + * @param I2C &i2c the I2C port to connect to + * @param char deviceAddress the address of the PCF8591 + */ + PCF8591_AnalogOut(I2C *i2c, uint8_t deviceAddress = PCF8591_SA0); + + void write(float value); + #ifdef MBED_OPERATORS + /** An operator shorthand for write() + */ + PCF8591_AnalogOut& operator= (float value); + #endif + +protected: + I2C *_i2c; //I2C bus reference + uint8_t _slaveAddress; //I2C Slave address of device + uint8_t _mode; //Device mode + +/** Initialise DAC driver + * + */ + void _init(); +}; + + +/** Create a PCF8591 AnalogIn object connected to the specified I2C bus and deviceAddress + * +*/ +class PCF8591_AnalogIn { +public: + /** Create a PCF8591 AnalogIn object using a specified I2C bus and slaveaddress + * + * @param I2C &i2c the I2C port to connect to + * @param channel ADC channel of the PCF8591 + * @param char deviceAddress the address of the PCF8591 + */ + PCF8591_AnalogIn(I2C *i2c, uint8_t channel, uint8_t deviceAddress = PCF8591_SA0); + + float read(); + #ifdef MBED_OPERATORS + /** An operator shorthand for read() + */ + operator float(); + #endif + +protected: + I2C *_i2c; //I2C bus reference + uint8_t _slaveAddress; //I2C Slave address of device + uint8_t _mode; //Device mode + uint8_t _channel; //Channel + +/** Initialise DAC driver + * + */ + void _init(); +}; + + +#endif \ No newline at end of file