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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers PCF8591.cpp Source File

PCF8591.cpp

00001 /* PCF8591 - I2C 8 bit 4 channel A/D and 8 bit 1 channel D/A converter
00002  * Copyright (c) 2013 Wim Huiskamp
00003  *
00004  * Released under the MIT License: http://mbed.org/license/mit
00005  *
00006  * version 0.2 Initial Release
00007 */
00008 #include "mbed.h"
00009 #include "PCF8591.h"
00010 
00011 
00012 /** Create a PCF8591 AD and DA object using a specified I2C bus and slaveaddress
00013   *
00014   * @param I2C &i2c the I2C port to connect to 
00015   * @param char deviceAddress the address of the PCF8591
00016   */  
00017 PCF8591::PCF8591(I2C *i2c, uint8_t deviceAddress) : _i2c(i2c) {
00018     
00019   _slaveAddress = deviceAddress;
00020   _init(); 
00021 }
00022 
00023 
00024 #if(0)
00025 //These methods are disabled since they interfere with normal expected behaviour for mbed type Analog I/O
00026 //
00027   
00028 /** Set ADC mode
00029   *
00030   * @param adc_mode      ADC Channel mode, valid Range (PCF8591_4S, PCF8591_3D, PCF8591_2S_1D, PCF8591_2D)
00031   */  
00032 void PCF8591::setADCMode(uint8_t mode){
00033   uint8_t data[6];
00034   
00035   _mode = _mode & ~PCF8591_2D; // Clear ADC mode bits
00036   
00037   switch (mode) {
00038     case PCF8591_4S:
00039                 _mode = _mode | PCF8591_4S;
00040                 break; 
00041     case PCF8591_3D:
00042                 _mode = _mode | PCF8591_3D;
00043                 break;    
00044     case PCF8591_2S_1D:
00045                 _mode = _mode | PCF8591_2S_1D;
00046                 break;    
00047     case PCF8591_2D:
00048                 _mode = _mode | PCF8591_2D;
00049                 break;    
00050     default:
00051                 _mode = _mode | PCF8591_4S;    
00052                 break; 
00053   }    
00054         
00055   data[0] = _mode;             // Control Reg
00056   
00057   // write data to the device
00058   _i2c->write(_slaveAddress, (char*) data, 1);  
00059    
00060 };
00061 
00062 /** Set DAC mode
00063   *
00064   * @param dac_mode      DAC Channel mode, valid Range (false=disable, true=enable)
00065   */  
00066 void PCF8591::setDACMode(bool mode) {
00067   uint8_t data[6];
00068    
00069   if (mode) 
00070     _mode = _mode | PCF8591_AOUT;  // Enable DAC output
00071   else
00072     _mode = _mode & ~PCF8591_AOUT; // Disable DAC output
00073 
00074   data[0] = _mode;             // Control Reg
00075   
00076   // write data to the device
00077   _i2c->write(_slaveAddress, (char*) data, 1);  
00078   
00079 };
00080 #endif
00081 
00082 
00083 /** Write Analog Output
00084   *
00085   * @param  analogOut  output value (0..255)
00086   */  
00087 void PCF8591::write(uint8_t analogOut) {
00088   uint8_t data[6];
00089    
00090   data[0] = _mode;             // Control Reg
00091   data[1] = analogOut;         // DAC Channel
00092   
00093   // write data to the device
00094   _i2c->write(_slaveAddress, (char*) data, 2);  
00095 };        
00096 
00097 /** Read Analog Channel 
00098   *
00099   * @param Channel   ADC channel, valid range PCF8591_ADC0, PCF8591_ADC1, PCF8591_ADC2 or PCF8591_ADC3
00100   * @return value    uint8_t AD converted value (0..255, representing 0V..Vcc)   
00101   */  
00102 #if(0)
00103 // I2C block operations test
00104 // Causes problems with Ticker and printf on LPC812. No issues found on LPC1768
00105 uint8_t PCF8591::read(uint8_t channel) {
00106 //  uint8_t data[6];
00107   uint8_t data[6] = {123,123,123,123,123,123}; //test to check failed read
00108     
00109   _mode   = _mode & ~PCF8591_CHMSK;            // Clear ADC Channel bits
00110   _mode   = _mode | (channel & PCF8591_CHMSK); // Set ADC Channel bits
00111     
00112   data[0] = _mode;             // Init Control Reg
00113   
00114   // write data to the device to select the ADC channel
00115   _i2c->write(_slaveAddress, (char*) data, 1);  
00116  
00117   // read selected ADC channel
00118   // note that first byte is a 'dummy' and should be ignored
00119   _i2c->read(_slaveAddress, (char*) data, 2);  
00120   return data[1];
00121 };
00122 
00123 #else
00124 // I2C single byte operations test
00125 // No issues found on LPC812
00126 uint8_t PCF8591::read(uint8_t channel) {
00127   uint8_t data[6];
00128 //  uint8_t data[6] = {123,123,123,123,123,123}; //test to check failed read
00129     
00130   _mode   = _mode & ~PCF8591_CHMSK;            // Clear ADC Channel bits
00131   _mode   = _mode | (channel & PCF8591_CHMSK); // Set ADC Channel bits
00132     
00133   data[0] = _mode;             // Init Control Reg
00134   
00135   // write data to the device to select the ADC channel
00136   _i2c->start();  
00137   _i2c->write(_slaveAddress);        // Slave write address 
00138   _i2c->write(data[0]);  
00139   _i2c->stop();  
00140    
00141   // read selected ADC channel
00142   // note that first byte is a 'dummy' and should be ignored
00143   _i2c->start();  
00144   _i2c->write(_slaveAddress | 0x01); // Slave read address 
00145   data[0]=_i2c->read(1);  //ack
00146   data[1]=_i2c->read(0);  //nack  
00147   _i2c->stop();  
00148   
00149   return data[1];
00150 };
00151 
00152 #endif
00153 
00154 
00155 /** Initialise AD and DA driver 
00156   *
00157   */  
00158 void PCF8591::_init() {
00159   uint8_t data[6];
00160   
00161   _mode   = PCF8591_CTRL_DEF;  // Init mode
00162   
00163   data[0] = _mode;             // Init Control Reg
00164   data[1] = 0x00;              // Init DAC Channel to 0
00165   
00166   // write data to the device
00167   _i2c->write(_slaveAddress, (char*) data, 2);  
00168 }; 
00169 
00170 
00171 
00172 
00173 
00174 /** Create a PCF8591 AnalogOut object connected to the specified I2C bus and deviceAddress
00175  *
00176  */
00177 PCF8591_AnalogOut::PCF8591_AnalogOut(I2C *i2c, uint8_t deviceAddress) : _i2c(i2c) {
00178     
00179   _slaveAddress = deviceAddress;
00180   _init(); 
00181 }
00182  
00183 
00184 /** Write Analog Output
00185   *
00186   * @param  analogOut value (0 .. 1.0)
00187   */  
00188 void PCF8591_AnalogOut::write(float analogOut) {
00189   uint8_t data[6];
00190 
00191   data[0] = _mode;             // Control Reg
00192 
00193   // DAC Channel
00194   if (analogOut < 0.0) data[1] = 0;
00195   else if (analogOut >= 1.0) data[1] = 255;
00196        else data[1] = uint8_t (analogOut * 255.0);      
00197    
00198   // write data to the device
00199   _i2c->write(_slaveAddress, (char*) data, 2);  
00200 };        
00201 
00202 /** Operator = Analog Output
00203   *
00204   * @param  analogOut value (0.0f .. 1.0f)
00205   */  
00206 PCF8591_AnalogOut& PCF8591_AnalogOut::operator= (float value){  
00207   write(value);     
00208   return *this;   
00209 }
00210  
00211 
00212 /** Initialise DAC driver 
00213   *
00214   */  
00215 void PCF8591_AnalogOut::_init() {
00216   uint8_t data[6];
00217   
00218   _mode   = PCF8591_CTRL_DEF;  // Init mode
00219   
00220   data[0] = _mode;             // Init Control Reg
00221   data[1] = 0x00;              // Init DAC Channel to 0
00222   
00223   // write data to the device
00224   _i2c->write(_slaveAddress, (char*) data, 2);  
00225 }; 
00226 
00227 
00228 
00229 /** Create a PCF8591 AnalogIn object connected to the specified I2C bus and deviceAddress
00230  *
00231  */
00232 PCF8591_AnalogIn::PCF8591_AnalogIn(I2C *i2c, uint8_t channel, uint8_t deviceAddress) : _i2c(i2c) {
00233     
00234   _slaveAddress = deviceAddress;
00235   _channel = channel;  
00236   _init(); 
00237 }
00238  
00239 
00240 /** Read Analog input
00241   *
00242   * @return analogIn value (0 .. 1.0)
00243   */  
00244 float PCF8591_AnalogIn::read() {
00245   uint8_t data[6];
00246     
00247   data[0] = _mode;             // Init Control Reg
00248   
00249   // write data to the device to select the ADC channel
00250   _i2c->start();  
00251   _i2c->write(_slaveAddress);        // Slave write address 
00252   _i2c->write(data[0]);  
00253   _i2c->stop();  
00254    
00255   // read selected ADC channel
00256   // note that first byte is a 'dummy' and should be ignored
00257   _i2c->start();  
00258   _i2c->write(_slaveAddress | 0x01); // Slave read address 
00259   data[0]=_i2c->read(1);  //ack
00260   data[1]=_i2c->read(0);  //nack  
00261   _i2c->stop();  
00262   
00263  
00264   // ADC Channel
00265   return ((float) data[1] / 255.0);       
00266   
00267 };
00268 
00269 
00270 /** Operator float Analog Input
00271   *
00272   * @return analogIn value (0 .. 1.0)
00273   */  
00274 PCF8591_AnalogIn::operator float(){
00275   return (read());    
00276 }
00277  
00278 
00279 /** Initialise ADC driver 
00280   *
00281   */  
00282 void PCF8591_AnalogIn::_init() {
00283   uint8_t data[6];
00284   
00285   _mode   = PCF8591_CTRL_DEF;  // Init mode
00286   _mode   = _mode & ~PCF8591_CHMSK;             // Clear ADC Channel bits
00287   _mode   = _mode | (_channel & PCF8591_CHMSK); // Set ADC Channel bits
00288       
00289   data[0] = _mode;             // Init Control Reg
00290   
00291   // write data to the device
00292   _i2c->write(_slaveAddress, (char*) data, 1);  
00293 };