Complete PCF8574 and PCF74A library with interrupt handling
Dependents: Nucleo_PCF8574_led_iic Dawson_Controller
PCF8574.cpp@0:6d75da25c179, 2012-07-14 (annotated)
- Committer:
- bborredon
- Date:
- Sat Jul 14 08:20:07 2012 +0000
- Revision:
- 0:6d75da25c179
[mbed] converted /I2c/PCF8574
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
bborredon | 0:6d75da25c179 | 1 | /*********************************************************** |
bborredon | 0:6d75da25c179 | 2 | Author: Bernard Borredon |
bborredon | 0:6d75da25c179 | 3 | Date: 27 december 2011 |
bborredon | 0:6d75da25c179 | 4 | Version: 1.0 |
bborredon | 0:6d75da25c179 | 5 | ************************************************************/ |
bborredon | 0:6d75da25c179 | 6 | #include "PCF8574.h" |
bborredon | 0:6d75da25c179 | 7 | |
bborredon | 0:6d75da25c179 | 8 | // Local object address |
bborredon | 0:6d75da25c179 | 9 | static PCF8574 *pt_pcf8574; |
bborredon | 0:6d75da25c179 | 10 | |
bborredon | 0:6d75da25c179 | 11 | // User callback function address |
bborredon | 0:6d75da25c179 | 12 | static void (*_ptf)(uint8_t data,PCF8574 *o)= NULL; |
bborredon | 0:6d75da25c179 | 13 | |
bborredon | 0:6d75da25c179 | 14 | // Callback |
bborredon | 0:6d75da25c179 | 15 | static void _InterruptCB(void) |
bborredon | 0:6d75da25c179 | 16 | { |
bborredon | 0:6d75da25c179 | 17 | uint8_t data = 0; |
bborredon | 0:6d75da25c179 | 18 | bitset<8> data_p,val; |
bborredon | 0:6d75da25c179 | 19 | bitset<8> changed; |
bborredon | 0:6d75da25c179 | 20 | uint8_t i; |
bborredon | 0:6d75da25c179 | 21 | |
bborredon | 0:6d75da25c179 | 22 | // Read PCF8574 port (to acknowledge interrupt) |
bborredon | 0:6d75da25c179 | 23 | data = pt_pcf8574->read(); |
bborredon | 0:6d75da25c179 | 24 | |
bborredon | 0:6d75da25c179 | 25 | // Set bits that have changed |
bborredon | 0:6d75da25c179 | 26 | pt_pcf8574->getIntrData(data_p,changed); |
bborredon | 0:6d75da25c179 | 27 | changed = 0; |
bborredon | 0:6d75da25c179 | 28 | val = data; |
bborredon | 0:6d75da25c179 | 29 | for(i = 0;i < 8;i++) { |
bborredon | 0:6d75da25c179 | 30 | if(val[i] != data_p[i]) |
bborredon | 0:6d75da25c179 | 31 | changed[i] = 1; |
bborredon | 0:6d75da25c179 | 32 | } |
bborredon | 0:6d75da25c179 | 33 | pt_pcf8574->setIntrData(val,changed); |
bborredon | 0:6d75da25c179 | 34 | |
bborredon | 0:6d75da25c179 | 35 | // Call user callback, if any with port value |
bborredon | 0:6d75da25c179 | 36 | if(_ptf != NULL) |
bborredon | 0:6d75da25c179 | 37 | _ptf(data,pt_pcf8574); |
bborredon | 0:6d75da25c179 | 38 | } |
bborredon | 0:6d75da25c179 | 39 | |
bborredon | 0:6d75da25c179 | 40 | // Constructor |
bborredon | 0:6d75da25c179 | 41 | PCF8574::PCF8574(PinName sda,PinName scl,uint8_t address, bool typeA) : _i2c(sda, scl) |
bborredon | 0:6d75da25c179 | 42 | { |
bborredon | 0:6d75da25c179 | 43 | _errnum = PCF8574_NoError; |
bborredon | 0:6d75da25c179 | 44 | _intr = NULL; |
bborredon | 0:6d75da25c179 | 45 | pt_pcf8574 = NULL; |
bborredon | 0:6d75da25c179 | 46 | _intr_data = 0xFF; |
bborredon | 0:6d75da25c179 | 47 | _intr_bits_changed = 0; |
bborredon | 0:6d75da25c179 | 48 | _intr_flag = 0; |
bborredon | 0:6d75da25c179 | 49 | |
bborredon | 0:6d75da25c179 | 50 | // Set the address |
bborredon | 0:6d75da25c179 | 51 | if(typeA) { // PCF8574A |
bborredon | 0:6d75da25c179 | 52 | _PCF8574_address = 0x70; |
bborredon | 0:6d75da25c179 | 53 | } |
bborredon | 0:6d75da25c179 | 54 | else { // PCF8574 |
bborredon | 0:6d75da25c179 | 55 | _PCF8574_address = 0x40; |
bborredon | 0:6d75da25c179 | 56 | } |
bborredon | 0:6d75da25c179 | 57 | |
bborredon | 0:6d75da25c179 | 58 | _address = address; |
bborredon | 0:6d75da25c179 | 59 | |
bborredon | 0:6d75da25c179 | 60 | // Check address validity (between 0 and 7) |
bborredon | 0:6d75da25c179 | 61 | if(address > 7) { |
bborredon | 0:6d75da25c179 | 62 | _errnum = PCF8574_BadAddress; |
bborredon | 0:6d75da25c179 | 63 | } |
bborredon | 0:6d75da25c179 | 64 | |
bborredon | 0:6d75da25c179 | 65 | // Shift address |
bborredon | 0:6d75da25c179 | 66 | _address = _address << 1; |
bborredon | 0:6d75da25c179 | 67 | |
bborredon | 0:6d75da25c179 | 68 | // Set I2C frequency (100 MHz) |
bborredon | 0:6d75da25c179 | 69 | _i2c.frequency(100000); |
bborredon | 0:6d75da25c179 | 70 | } |
bborredon | 0:6d75da25c179 | 71 | |
bborredon | 0:6d75da25c179 | 72 | // Read IO port |
bborredon | 0:6d75da25c179 | 73 | uint8_t PCF8574::read(void) |
bborredon | 0:6d75da25c179 | 74 | { |
bborredon | 0:6d75da25c179 | 75 | uint8_t data; |
bborredon | 0:6d75da25c179 | 76 | int ack; |
bborredon | 0:6d75da25c179 | 77 | |
bborredon | 0:6d75da25c179 | 78 | // Check error |
bborredon | 0:6d75da25c179 | 79 | if(_errnum) |
bborredon | 0:6d75da25c179 | 80 | return(0); |
bborredon | 0:6d75da25c179 | 81 | |
bborredon | 0:6d75da25c179 | 82 | // No error |
bborredon | 0:6d75da25c179 | 83 | _errnum = PCF8574_NoError; |
bborredon | 0:6d75da25c179 | 84 | |
bborredon | 0:6d75da25c179 | 85 | // Read port |
bborredon | 0:6d75da25c179 | 86 | ack = _i2c.read(_PCF8574_address | _address,(char *)&data,sizeof(data)); |
bborredon | 0:6d75da25c179 | 87 | |
bborredon | 0:6d75da25c179 | 88 | // Check error |
bborredon | 0:6d75da25c179 | 89 | if(ack != 0) { |
bborredon | 0:6d75da25c179 | 90 | _errnum = PCF8574_I2cError; |
bborredon | 0:6d75da25c179 | 91 | } |
bborredon | 0:6d75da25c179 | 92 | |
bborredon | 0:6d75da25c179 | 93 | return(data); |
bborredon | 0:6d75da25c179 | 94 | } |
bborredon | 0:6d75da25c179 | 95 | |
bborredon | 0:6d75da25c179 | 96 | // Write IO port |
bborredon | 0:6d75da25c179 | 97 | void PCF8574::write(uint8_t data) |
bborredon | 0:6d75da25c179 | 98 | { |
bborredon | 0:6d75da25c179 | 99 | int ack; |
bborredon | 0:6d75da25c179 | 100 | |
bborredon | 0:6d75da25c179 | 101 | // Check error |
bborredon | 0:6d75da25c179 | 102 | if(_errnum) |
bborredon | 0:6d75da25c179 | 103 | return; |
bborredon | 0:6d75da25c179 | 104 | |
bborredon | 0:6d75da25c179 | 105 | // No error |
bborredon | 0:6d75da25c179 | 106 | _errnum = PCF8574_NoError; |
bborredon | 0:6d75da25c179 | 107 | |
bborredon | 0:6d75da25c179 | 108 | // Write port |
bborredon | 0:6d75da25c179 | 109 | ack = _i2c.write(_PCF8574_address | _address,(char *)&data,sizeof(data)); |
bborredon | 0:6d75da25c179 | 110 | |
bborredon | 0:6d75da25c179 | 111 | // Check error |
bborredon | 0:6d75da25c179 | 112 | if(ack != 0) { |
bborredon | 0:6d75da25c179 | 113 | _errnum = PCF8574_I2cError; |
bborredon | 0:6d75da25c179 | 114 | } |
bborredon | 0:6d75da25c179 | 115 | } |
bborredon | 0:6d75da25c179 | 116 | |
bborredon | 0:6d75da25c179 | 117 | // Write IO pin |
bborredon | 0:6d75da25c179 | 118 | void PCF8574::write(uint8_t pin, uint8_t value) |
bborredon | 0:6d75da25c179 | 119 | { |
bborredon | 0:6d75da25c179 | 120 | uint8_t data; |
bborredon | 0:6d75da25c179 | 121 | |
bborredon | 0:6d75da25c179 | 122 | // Read IO port value |
bborredon | 0:6d75da25c179 | 123 | data = read(); |
bborredon | 0:6d75da25c179 | 124 | |
bborredon | 0:6d75da25c179 | 125 | // Change bit pin |
bborredon | 0:6d75da25c179 | 126 | if(value) |
bborredon | 0:6d75da25c179 | 127 | BIT_SET(data,pin); |
bborredon | 0:6d75da25c179 | 128 | else |
bborredon | 0:6d75da25c179 | 129 | BIT_CLEAR(data,pin); |
bborredon | 0:6d75da25c179 | 130 | |
bborredon | 0:6d75da25c179 | 131 | // Write new IO port data |
bborredon | 0:6d75da25c179 | 132 | write(data); |
bborredon | 0:6d75da25c179 | 133 | } |
bborredon | 0:6d75da25c179 | 134 | |
bborredon | 0:6d75da25c179 | 135 | // Write to IO pins with a bitset and a bitset mask |
bborredon | 0:6d75da25c179 | 136 | void PCF8574::write(bitset<8> data, bitset<8> mask) |
bborredon | 0:6d75da25c179 | 137 | { |
bborredon | 0:6d75da25c179 | 138 | uint8_t i; |
bborredon | 0:6d75da25c179 | 139 | bitset<8> nd; |
bborredon | 0:6d75da25c179 | 140 | |
bborredon | 0:6d75da25c179 | 141 | nd = (bitset<8>) read(); |
bborredon | 0:6d75da25c179 | 142 | for(i = 0;i < 8;i++) { |
bborredon | 0:6d75da25c179 | 143 | if(mask[i]) |
bborredon | 0:6d75da25c179 | 144 | nd[i] = data[i]; |
bborredon | 0:6d75da25c179 | 145 | } |
bborredon | 0:6d75da25c179 | 146 | |
bborredon | 0:6d75da25c179 | 147 | write((uint8_t) nd.to_ulong()); |
bborredon | 0:6d75da25c179 | 148 | } |
bborredon | 0:6d75da25c179 | 149 | |
bborredon | 0:6d75da25c179 | 150 | // Set pin and callback interrupt |
bborredon | 0:6d75da25c179 | 151 | void PCF8574::interrupt(PinName intr,void (*ftpr)(uint8_t, PCF8574 *)) |
bborredon | 0:6d75da25c179 | 152 | { |
bborredon | 0:6d75da25c179 | 153 | |
bborredon | 0:6d75da25c179 | 154 | // Check error |
bborredon | 0:6d75da25c179 | 155 | if(_errnum) |
bborredon | 0:6d75da25c179 | 156 | return; |
bborredon | 0:6d75da25c179 | 157 | |
bborredon | 0:6d75da25c179 | 158 | // No error |
bborredon | 0:6d75da25c179 | 159 | _errnum = PCF8574_NoError; |
bborredon | 0:6d75da25c179 | 160 | |
bborredon | 0:6d75da25c179 | 161 | // Create InterruptIn instance if needed |
bborredon | 0:6d75da25c179 | 162 | if(_intr == NULL) { |
bborredon | 0:6d75da25c179 | 163 | _intr = new InterruptIn(intr); |
bborredon | 0:6d75da25c179 | 164 | |
bborredon | 0:6d75da25c179 | 165 | // Set InterruptIn callback |
bborredon | 0:6d75da25c179 | 166 | if(_intr != NULL) |
bborredon | 0:6d75da25c179 | 167 | _intr->fall(_InterruptCB); |
bborredon | 0:6d75da25c179 | 168 | else |
bborredon | 0:6d75da25c179 | 169 | _errnum = PCF8574_IntrError; |
bborredon | 0:6d75da25c179 | 170 | } |
bborredon | 0:6d75da25c179 | 171 | |
bborredon | 0:6d75da25c179 | 172 | _ptf = ftpr; // User callback address |
bborredon | 0:6d75da25c179 | 173 | pt_pcf8574 = this; // Object instance |
bborredon | 0:6d75da25c179 | 174 | _intr_data = read(); // IO port value |
bborredon | 0:6d75da25c179 | 175 | _intr_flag = 1; // Function called |
bborredon | 0:6d75da25c179 | 176 | } |
bborredon | 0:6d75da25c179 | 177 | |
bborredon | 0:6d75da25c179 | 178 | // Get current error number |
bborredon | 0:6d75da25c179 | 179 | uint8_t PCF8574::getError(void) |
bborredon | 0:6d75da25c179 | 180 | { |
bborredon | 0:6d75da25c179 | 181 | return(_errnum); |
bborredon | 0:6d75da25c179 | 182 | } |
bborredon | 0:6d75da25c179 | 183 | |
bborredon | 0:6d75da25c179 | 184 | // Memorize IO port value and bits that have changed when interrupt |
bborredon | 0:6d75da25c179 | 185 | void PCF8574::setIntrData(bitset<8> data, bitset<8> changed) |
bborredon | 0:6d75da25c179 | 186 | { |
bborredon | 0:6d75da25c179 | 187 | _intr_data = data; |
bborredon | 0:6d75da25c179 | 188 | _intr_bits_changed = changed; |
bborredon | 0:6d75da25c179 | 189 | } |
bborredon | 0:6d75da25c179 | 190 | |
bborredon | 0:6d75da25c179 | 191 | // Get IO port value and bits that have changed when interrupt |
bborredon | 0:6d75da25c179 | 192 | void PCF8574::getIntrData(bitset<8>& data, bitset<8>& changed) |
bborredon | 0:6d75da25c179 | 193 | { |
bborredon | 0:6d75da25c179 | 194 | data = _intr_data; |
bborredon | 0:6d75da25c179 | 195 | changed = _intr_bits_changed; |
bborredon | 0:6d75da25c179 | 196 | } |
bborredon | 0:6d75da25c179 | 197 | |
bborredon | 0:6d75da25c179 | 198 | // Redefine () operator |
bborredon | 0:6d75da25c179 | 199 | PCF8574::operator uint8_t() |
bborredon | 0:6d75da25c179 | 200 | { |
bborredon | 0:6d75da25c179 | 201 | return read(); |
bborredon | 0:6d75da25c179 | 202 | } |
bborredon | 0:6d75da25c179 | 203 | |
bborredon | 0:6d75da25c179 | 204 | // Redefine = operator |
bborredon | 0:6d75da25c179 | 205 | PCF8574 &PCF8574::operator=(uint8_t data) |
bborredon | 0:6d75da25c179 | 206 | { |
bborredon | 0:6d75da25c179 | 207 | write((int)data); |
bborredon | 0:6d75da25c179 | 208 | |
bborredon | 0:6d75da25c179 | 209 | return(*this); |
bborredon | 0:6d75da25c179 | 210 | } |