初始化提交
This commit is contained in:
282
arduino-cli/libraries/PCF8574_Soft/PCF8574_Soft.cpp
Normal file
282
arduino-cli/libraries/PCF8574_Soft/PCF8574_Soft.cpp
Normal file
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
* See header file for details
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify\n
|
||||
* it under the terms of the GNU General Public License as published by\n
|
||||
* the Free Software Foundation, either version 3 of the License, or\n
|
||||
* (at your option) any later version.\n
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,\n
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of\n
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n
|
||||
* GNU General Public License for more details.\n
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License\n
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.\n
|
||||
*/
|
||||
|
||||
/* Dependencies */
|
||||
#include <SoftwareWire.h>
|
||||
#include "PCF8574_Soft.h"
|
||||
#ifdef PCF8574_Soft_INTERRUPT_SUPPORT
|
||||
#include "PCint.h"
|
||||
#endif
|
||||
|
||||
PCF8574_Soft::PCF8574_Soft() :
|
||||
_PORT(0), _PIN(0), _DDR(0), _address(0)
|
||||
#ifdef PCF8574_Soft_INTERRUPT_SUPPORT
|
||||
, _oldPIN(0), _isrIgnore(0), _pcintPin(0), _intMode(), _intCallback()
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
void PCF8574_Soft::begin(uint8_t address, SoftwareWire *theWire) {
|
||||
|
||||
/* Store the I2C address and init the Wire library */
|
||||
_wire = theWire;
|
||||
_address = address;
|
||||
_wire->begin();
|
||||
readGPIO();
|
||||
}
|
||||
|
||||
void PCF8574_Soft::pinMode(uint8_t pin, uint8_t mode) {
|
||||
|
||||
/* Switch according mode */
|
||||
switch (mode) {
|
||||
case INPUT:
|
||||
_DDR &= ~(1 << pin);
|
||||
_PORT &= ~(1 << pin);
|
||||
break;
|
||||
|
||||
case INPUT_PULLUP:
|
||||
_DDR &= ~(1 << pin);
|
||||
_PORT |= (1 << pin);
|
||||
break;
|
||||
|
||||
case OUTPUT:
|
||||
_DDR |= (1 << pin);
|
||||
_PORT &= ~(1 << pin);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Update GPIO values */
|
||||
updateGPIO();
|
||||
}
|
||||
|
||||
void PCF8574_Soft::digitalWrite(uint8_t pin, uint8_t value) {
|
||||
|
||||
/* Set PORT bit value */
|
||||
if (value)
|
||||
_PORT |= (1 << pin);
|
||||
else
|
||||
_PORT &= ~(1 << pin);
|
||||
|
||||
/* Update GPIO values */
|
||||
updateGPIO();
|
||||
}
|
||||
|
||||
uint8_t PCF8574_Soft::digitalRead(uint8_t pin) {
|
||||
|
||||
/* Read GPIO */
|
||||
readGPIO();
|
||||
|
||||
#ifdef PCF8574_Soft_INTERRUPT_SUPPORT
|
||||
/* Check for interrupt (manual detection) */
|
||||
//checkForInterrupt();
|
||||
#endif
|
||||
|
||||
/* Read and return the pin state */
|
||||
return (_PIN & (1 << pin)) ? HIGH : LOW;
|
||||
}
|
||||
|
||||
void PCF8574_Soft::write(uint8_t value) {
|
||||
|
||||
/* Store pins values and apply */
|
||||
_PORT = value;
|
||||
|
||||
/* Update GPIO values */
|
||||
updateGPIO();
|
||||
}
|
||||
|
||||
uint8_t PCF8574_Soft::read() {
|
||||
|
||||
/* Read GPIO */
|
||||
readGPIO();
|
||||
|
||||
#ifdef PCF8574_Soft_INTERRUPT_SUPPORT
|
||||
/* Check for interrupt (manual detection) */
|
||||
//checkForInterrupt();
|
||||
#endif
|
||||
|
||||
/* Return current pins values */
|
||||
return _PIN;
|
||||
}
|
||||
|
||||
void PCF8574_Soft::pullUp(uint8_t pin) {
|
||||
|
||||
/* Same as pinMode(INPUT_PULLUP) */
|
||||
pinMode(pin, INPUT_PULLUP); // /!\ pinMode form THE LIBRARY
|
||||
}
|
||||
|
||||
void PCF8574_Soft::pullDown(uint8_t pin) {
|
||||
|
||||
/* Same as pinMode(INPUT) */
|
||||
pinMode(pin, INPUT); // /!\ pinMode form THE LIBRARY
|
||||
}
|
||||
|
||||
void PCF8574_Soft::clear() {
|
||||
|
||||
/* User friendly wrapper for write() */
|
||||
write(0x00);
|
||||
}
|
||||
|
||||
void PCF8574_Soft::set() {
|
||||
|
||||
/* User friendly wrapper for write() */
|
||||
write(0xFF);
|
||||
}
|
||||
|
||||
void PCF8574_Soft::toggle(uint8_t pin) {
|
||||
|
||||
/* Toggle pin state */
|
||||
_PORT ^= (1 << pin);
|
||||
|
||||
/* Update GPIO values */
|
||||
updateGPIO();
|
||||
}
|
||||
|
||||
void PCF8574_Soft::blink(uint8_t pin, uint16_t count, uint32_t duration) {
|
||||
|
||||
/* Compute steps duration */
|
||||
duration /= count * 2;
|
||||
|
||||
/* Loop n times */
|
||||
while (count--) {
|
||||
|
||||
/* Toggle pin 2 times */
|
||||
toggle(pin);
|
||||
delay(duration);
|
||||
toggle(pin);
|
||||
delay(duration);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef PCF8574_Soft_INTERRUPT_SUPPORT
|
||||
void PCF8574_Soft::enableInterrupt(uint8_t pin, void (*selfCheckFunction)(void)) {
|
||||
|
||||
/* Store interrupt pin number */
|
||||
_pcintPin = pin;
|
||||
|
||||
/* Setup interrupt pin */
|
||||
#if ARDUINO >= 100
|
||||
::pinMode(pin, INPUT_PULLUP); // /!\ pinMode form THE ARDUINO CORE
|
||||
#else
|
||||
::pinMode(pin, INPUT); // /!\ pinMode form THE ARDUINO CORE
|
||||
::digitalWrite(pin, HIGH); // /!\ digitalWrite form THE ARDUINO CORE
|
||||
#endif
|
||||
|
||||
/* Attach interrupt handler */
|
||||
PCattachInterrupt(pin, selfCheckFunction, FALLING);
|
||||
}
|
||||
|
||||
void PCF8574_Soft::disableInterrupt() {
|
||||
|
||||
/* Detach interrupt handler */
|
||||
PCdetachInterrupt(_pcintPin);
|
||||
}
|
||||
|
||||
void PCF8574_Soft::checkForInterrupt() {
|
||||
|
||||
/* Avoid nested interrupt triggered by I2C read/write */
|
||||
if(_isrIgnore)
|
||||
return;
|
||||
else
|
||||
_isrIgnore = 1;
|
||||
|
||||
/* Re-enable interrupts to allow Wire library to work */
|
||||
sei();
|
||||
|
||||
/* Read current pins values */
|
||||
readGPIO();
|
||||
|
||||
/* Check all pins */
|
||||
for (uint8_t i = 0; i < 8; ++i) {
|
||||
|
||||
/* Check for interrupt handler */
|
||||
if (!_intCallback[i])
|
||||
continue;
|
||||
|
||||
/* Check for interrupt event */
|
||||
switch (_intMode[i]) {
|
||||
case CHANGE:
|
||||
if ((1 << i) & (_PIN ^ _oldPIN))
|
||||
_intCallback[i]();
|
||||
break;
|
||||
|
||||
case LOW:
|
||||
if (!(_PIN & (1 << i)))
|
||||
_intCallback[i]();
|
||||
break;
|
||||
|
||||
case FALLING:
|
||||
if ((_oldPIN & (1 << i)) && !(_PIN & (1 << i)))
|
||||
_intCallback[i]();
|
||||
break;
|
||||
|
||||
case RISING:
|
||||
if (!(_oldPIN & (1 << i)) && (_PIN & (1 << i)))
|
||||
_intCallback[i]();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Turn off ISR ignore flag */
|
||||
_isrIgnore = 0;
|
||||
}
|
||||
|
||||
void PCF8574_Soft::attachInterrupt(uint8_t pin, void (*userFunc)(void),
|
||||
uint8_t mode) {
|
||||
|
||||
/* Store interrupt mode and callback */
|
||||
_intMode[pin] = mode;
|
||||
_intCallback[pin] = userFunc;
|
||||
}
|
||||
|
||||
void PCF8574_Soft::detachInterrupt(uint8_t pin) {
|
||||
|
||||
/* Void interrupt handler */
|
||||
_intCallback[pin] = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void PCF8574_Soft::readGPIO() {
|
||||
|
||||
#ifdef PCF8574_Soft_INTERRUPT_SUPPORT
|
||||
/* Store old _PIN value */
|
||||
_oldPIN = _PIN;
|
||||
#endif
|
||||
|
||||
/* Start request, wait for data and receive GPIO values as byte */
|
||||
_wire->requestFrom(_address, (uint8_t) 0x01);
|
||||
while (_wire->available() < 1)
|
||||
;
|
||||
_PIN = _wire->read();
|
||||
}
|
||||
|
||||
void PCF8574_Soft::updateGPIO() {
|
||||
|
||||
/* Read current GPIO states */
|
||||
//readGPIO(); // Experimental
|
||||
|
||||
/* Compute new GPIO states */
|
||||
//uint8_t value = ((_PIN & ~_DDR) & ~(~_DDR & _PORT)) | _PORT; // Experimental
|
||||
uint8_t value = (_PIN & ~_DDR) | _PORT;
|
||||
|
||||
/* Start communication and send GPIO values as byte */
|
||||
_wire->beginTransmission(_address);
|
||||
_wire->write(value);
|
||||
_wire->endTransmission();
|
||||
}
|
||||
Reference in New Issue
Block a user