commit ddca4bf74f522d85e25448cbbc8647dfa409d753 Author: ouki-wang <358023925@qq.com> Date: Thu Sep 6 19:25:24 2018 +0800 V0.1 diff --git a/DFRobot_AS3935_I2C.cpp b/DFRobot_AS3935_I2C.cpp new file mode 100644 index 0000000..78e78bd --- /dev/null +++ b/DFRobot_AS3935_I2C.cpp @@ -0,0 +1,374 @@ +#include "DFRobot_AS3935_I2c.h" + +DF_AS3935_I2C::DF_AS3935_I2C(uint8_t IRQx, uint8_t SIx, uint8_t DEVADDx) +{ + _devadd = DEVADDx; + _si = SIx; + _irq = IRQx; + + // initalize the chip select pins + pinMode(_si, OUTPUT); + pinMode(_irq, INPUT); + + // set output pin initical condition + digitalWrite(_si, HIGH); // set pin high for I2C mode + +} + +void DF_AS3935_I2C::AS3935_SetI2CAddress(uint8_t DEVADDx) +{ + if (DEVADDx == AS3935_ADD1) + { + _devadd=DEVADDx; + } + else if (DEVADDx == AS3935_ADD2) + { + _devadd=DEVADDx; + } + else + { + _devadd=AS3935_ADD3; + } +} + +uint8_t DF_AS3935_I2C::_sing_reg_read(uint8_t RegAdd) +{ + // I2C address Register address num bytes + I2c.read((uint8_t)_devadd, (uint8_t)RegAdd, (uint8_t)0x01); // Use I2C library to read register + uint8_t RegData = I2c.receive(); // receive the I2C data + return RegData; +} + +void DF_AS3935_I2C::_sing_reg_write(uint8_t RegAdd, uint8_t DataMask, uint8_t RegData) +{ + // start by reading original register data (only modifying what we need to) + uint8_t OrigRegData = _sing_reg_read(RegAdd); + + // calculate new register data... 'delete' old targeted data, replace with new data + // note: 'DataMask' must be bits targeted for replacement + // add'l note: this function does NOT shift values into the proper place... they need to be there already + uint8_t NewRegData = ((OrigRegData & ~DataMask) | (RegData & DataMask)); + + // finally, write the data to the register + I2c.write(_devadd, RegAdd, NewRegData); + Serial.print("wrt: "); + Serial.print(NewRegData,HEX); + Serial.print(" Act: "); + Serial.println(_sing_reg_read(RegAdd),HEX); +} + +void DF_AS3935_I2C::AS3935_DefInit() +{ + _AS3935_Reset(); // reset registers to default +} + +void DF_AS3935_I2C::_AS3935_Reset() +{ + // run PRESET_DEFAULT Direct Command to set all registers in default state + I2c.write(_devadd, (uint8_t)0x3C, (uint8_t)0x96); + delay(2); // wait 2ms to complete +} + +void DF_AS3935_I2C::_CalRCO() +{ + // run ALIB_RCO Direct Command to cal internal RCO + I2c.write(_devadd, (uint8_t)0x3D, (uint8_t)0x96); + delay(2); // wait 2ms to complete +} + +void DF_AS3935_I2C::AS3935_PowerUp(void) +{ + // power-up sequence based on datasheet, pg 23/27 + // register 0x00, PWD bit: 0 (clears PWD) + _sing_reg_write(0x00, 0x01, 0x00); + _CalRCO(); // run RCO cal cmd + _sing_reg_write(0x08, 0x20, 0x20); // set DISP_SRCO to 1 + delay(2); + _sing_reg_write(0x08, 0x20, 0x00); // set DISP_SRCO to 0 +} + +void DF_AS3935_I2C::AS3935_PowerDown(void) +{ + // register 0x00, PWD bit: 0 (sets PWD) + _sing_reg_write(0x00, 0x01, 0x01); + Serial.println("AS3935 powered down"); +} + +void DF_AS3935_I2C::AS3935_DisturberEn(void) +{ + // register 0x03, PWD bit: 5 (sets MASK_DIST) + _sing_reg_write(0x03, 0x20, 0x00); + Serial.println("disturber detection enabled"); +} + +void DF_AS3935_I2C::AS3935_DisturberDis(void) +{ + // register 0x03, PWD bit: 5 (sets MASK_DIST) + _sing_reg_write(0x03, 0x20, 0x20); +} + +void DF_AS3935_I2C::AS3935_SetIRQ_Output_Source(uint8_t irq_select) +{ + // set interrupt source - what to display on IRQ pin + // reg 0x08, bits 5 (TRCO), 6 (SRCO), 7 (LCO) + // only one should be set at once, I think + // 0 = NONE, 1 = TRCO, 2 = SRCO, 3 = LCO + + if(1 == irq_select) + { + _sing_reg_write(0x08, 0xE0, 0x20); // set only TRCO bit + } + else if(2 == irq_select) + { + _sing_reg_write(0x08, 0xE0, 0x40); // set only SRCO bit + } + else if(3 == irq_select) + { + _sing_reg_write(0x08, 0xE0, 0x80); // set only LCO bit + } + else // assume 0 + { + _sing_reg_write(0x08, 0xE0, 0x00); // clear IRQ pin display bits + } + +} + +void DF_AS3935_I2C::AS3935_SetTuningCaps(uint8_t cap_val) +{ + // Assume only numbers divisible by 8 (because that's all the chip supports) + if(120 < cap_val) // cap_value out of range, assume highest capacitance + { + _sing_reg_write(0x08, 0x0F, 0x0F); // set capacitance bits to maximum + } + else + { + _sing_reg_write(0x08, 0x0F, (cap_val>>3)); // set capacitance bits + } + Serial.print("capacitance set to 8x"); + Serial.println((_sing_reg_read(0x08) & 0x0F)); +} + +uint8_t DF_AS3935_I2C::AS3935_GetInterruptSrc(void) +{ + // definition of interrupt data on table 18 of datasheet + // for this function: + // 0 = unknown src, 1 = lightning detected, 2 = disturber, 3 = Noise level too high + delay(10); // wait 3ms before reading (min 2ms per pg 22 of datasheet) + uint8_t int_src = (_sing_reg_read(0x03) & 0x0F); // read register, get rid of non-interrupt data + if(0x08 == int_src) + { + return 1; // lightning caused interrupt + } + else if(0x04 == int_src) + { + return 2; // disturber detected + } + else if(0x01 == int_src) + { + return 3; // Noise level too high + } + else{return 0;} // interrupt result not expected + +} + +uint8_t DF_AS3935_I2C::AS3935_GetLightningDistKm(void) +{ + uint8_t strike_dist = (_sing_reg_read(0x07) & 0x3F); // read register, get rid of non-distance data + return strike_dist; +} + +uint32_t DF_AS3935_I2C::AS3935_GetStrikeEnergyRaw(void) +{ + uint32_t nrgy_raw = ((_sing_reg_read(0x06) & 0x1F) << 8); // MMSB, shift 8 bits left, make room for MSB + nrgy_raw |= _sing_reg_read(0x05); // read MSB + nrgy_raw <<= 8; // shift 8 bits left, make room for LSB + nrgy_raw |= _sing_reg_read(0x04); // read LSB, add to others + + return nrgy_raw/16777; +} + +uint8_t DF_AS3935_I2C::AS3935_SetMinStrikes(uint8_t min_strk) +{ + // This function sets min strikes to the closest available number, rounding to the floor, + // where necessary, then returns the physical value that was set. Options are 1, 5, 9 or 16 strikes. + // see pg 22 of the datasheet for more info (#strikes in 17 min) + if(5 > min_strk) + { + _sing_reg_write(0x02, 0x30, 0x00); + return 1; + } + else if(9 > min_strk) + { + _sing_reg_write(0x02, 0x30, 0x10); + return 5; + } + else if(16 > min_strk) + { + _sing_reg_write(0x02, 0x30, 0x20); + return 9; + } + else + { + _sing_reg_write(0x02, 0x30, 0x30); + return 16; + } +} + +void DF_AS3935_I2C::AS3935_SetIndoors(void) +{ + // AFE settings addres 0x00, bits 5:1 (10010, based on datasheet, pg 19, table 15) + // this is the default setting at power-up (AS3935 datasheet, table 9) + _sing_reg_write(0x00, 0x3E, 0x24); + Serial.println("set up for indoor operation"); +} + +void DF_AS3935_I2C::AS3935_SetOutdoors(void) +{ + // AFE settings addres 0x00, bits 5:1 (01110, based on datasheet, pg 19, table 15) + _sing_reg_write(0x00, 0x3E, 0x1C); + Serial.println("set up for outdoor operation"); +} + +void DF_AS3935_I2C::AS3935_ClearStatistics(void) +{ + // clear is accomplished by toggling CL_STAT bit 'high-low-high' (then set low to move on) + _sing_reg_write(0x02, 0x40, 0x40); // high + _sing_reg_write(0x02, 0x40, 0x00); // low + _sing_reg_write(0x02, 0x40, 0x40); // high +} + +uint8_t DF_AS3935_I2C::AS3935_GetNoiseFloorLvl(void) +{ + // NF settings addres 0x01, bits 6:4 + // default setting of 010 at startup (datasheet, table 9) + uint8_t reg_raw = _sing_reg_read(0x01); // read register 0x01 + return ((reg_raw & 0x70)>>4); // should return value from 0-7, see table 16 for info +} + +void DF_AS3935_I2C::AS3935_SetNoiseFloorLvl(uint8_t nf_sel) +{ + // NF settings addres 0x01, bits 6:4 + // default setting of 010 at startup (datasheet, table 9) + if(7 >= nf_sel) // nf_sel within expected range + { + _sing_reg_write(0x01, 0x70, ((nf_sel & 0x07)<<4)); + } + else + { // out of range, set to default (power-up value 010) + _sing_reg_write(0x01, 0x70, 0x20); + } +} + +uint8_t DF_AS3935_I2C::AS3935_GetWatchdogThreshold(void) +{ + // This function is used to read WDTH. It is used to increase robustness to disturbers, + // though will make detection less efficient (see page 19, Fig 20 of datasheet) + // WDTH register: add 0x01, bits 3:0 + // default value of 0001 + // values should only be between 0x00 and 0x0F (0 and 7) + uint8_t reg_raw = _sing_reg_read(0x01); + return (reg_raw & 0x0F); +} + +void DF_AS3935_I2C::AS3935_SetWatchdogThreshold(uint8_t wdth) +{ + // This function is used to modify WDTH. It is used to increase robustness to disturbers, + // though will make detection less efficient (see page 19, Fig 20 of datasheet) + // WDTH register: add 0x01, bits 3:0 + // default value of 0001 + // values should only be between 0x00 and 0x0F (0 and 7) + _sing_reg_write(0x01, 0x0F, (wdth & 0x0F)); +} + +uint8_t DF_AS3935_I2C::AS3935_GetSpikeRejection(void) +{ + // This function is used to read SREJ (spike rejection). Similar to the Watchdog threshold, + // it is used to make the system more robust to disturbers, though will make general detection + // less efficient (see page 20-21, especially Fig 21 of datasheet) + // SREJ register: add 0x02, bits 3:0 + // default value of 0010 + // values should only be between 0x00 and 0x0F (0 and 7) + uint8_t reg_raw = _sing_reg_read(0x02); + return (reg_raw & 0x0F); +} + +void DF_AS3935_I2C::AS3935_SetSpikeRejection(uint8_t srej) +{ + // This function is used to modify SREJ (spike rejection). Similar to the Watchdog threshold, + // it is used to make the system more robust to disturbers, though will make general detection + // less efficient (see page 20-21, especially Fig 21 of datasheet) + // WDTH register: add 0x02, bits 3:0 + // default value of 0010 + // values should only be between 0x00 and 0x0F (0 and 7) + _sing_reg_write(0x02, 0x0F, (srej & 0x0F)); +} + +void DF_AS3935_I2C::AS3935_SetLCO_FDIV(uint8_t fdiv) +{ + // This function sets LCO_FDIV register. This is useful in the tuning of the antenna + // LCO_FDIV register: add 0x03, bits 7:6 + // default value: 00 + // set 0, 1, 2 or 3 for ratios of 16, 32, 64 and 128, respectively. + // See pg 23, Table 20 for more info. + _sing_reg_write(0x03, 0xC0, ((fdiv & 0x03) << 5)); +} + +void DF_AS3935_I2C::AS3935_PrintAllRegs(void) +{ + Serial.print("Reg 0x00: "); + Serial.println(_sing_reg_read(0x00)); + Serial.print("Reg 0x01: "); + Serial.println(_sing_reg_read(0x01)); + Serial.print("Reg 0x02: "); + Serial.println(_sing_reg_read(0x02)); + Serial.print("Reg 0x03: "); + Serial.println(_sing_reg_read(0x03)); + Serial.print("Reg 0x04: "); + Serial.println(_sing_reg_read(0x04)); + Serial.print("Reg 0x05: "); + Serial.println(_sing_reg_read(0x05)); + Serial.print("Reg 0x06: "); + Serial.println(_sing_reg_read(0x06)); + Serial.print("Reg 0x07: "); + Serial.println(_sing_reg_read(0x07)); + Serial.print("Reg 0x08: "); + Serial.println(_sing_reg_read(0x08)); + uint32_t nrgy_val = AS3935_GetStrikeEnergyRaw(); + Serial.println(nrgy_val); +} + +void DF_AS3935_I2C::AS3935_ManualCal(uint8_t capacitance, uint8_t location, uint8_t disturber) +{ + // start by powering up + AS3935_PowerUp(); + + // indoors/outdoors next... + if(1 == location) // set outdoors if 1 + { + AS3935_SetOutdoors(); + } + else // set indoors if anything but 1 + { + AS3935_SetIndoors(); + } + + // disturber cal + if(0 == disturber) // disabled if 0 + { + AS3935_DisturberDis(); + } + else // enabled if anything but 0 + { + AS3935_DisturberEn(); + } + + AS3935_SetIRQ_Output_Source(0); + + delay(500); + // capacitance first... directly write value here + AS3935_SetTuningCaps(capacitance); + + Serial.println("AS3935 manual cal complete"); +} +// a nice function would be to read the last 'x' strike data values.... + diff --git a/DFRobot_AS3935_I2C.h b/DFRobot_AS3935_I2C.h new file mode 100644 index 0000000..b4195ec --- /dev/null +++ b/DFRobot_AS3935_I2C.h @@ -0,0 +1,63 @@ +#ifndef DF_AS3935_I2C_h +#define DF_AS3935_I2C_h + +#include "Arduino.h" +#include "avr/pgmspace.h" +#include "util/delay.h" +#include "stdlib.h" +#include "I2C.h" + +// I2c address +#define AS3935_ADD3 0x03 // x03 - A0->high A1->high +#define AS3935_ADD2 0x02 // x02 - A0->low A1->high +#define AS3935_ADD1 0x01 // x01 - A0->high A1->low + +class DF_AS3935_I2C +{ + public: + DF_AS3935_I2C(uint8_t IRQx, uint8_t SIx, uint8_t DEVADDx); + /*! Set i2c address */ + void AS3935_SetI2CAddress(uint8_t DEVADDx); + /*! Manual calibration */ + void AS3935_ManualCal(uint8_t capacitance, uint8_t location, uint8_t disturber); + /*! reset registers to default */ + void AS3935_DefInit(void); + void AS3935_PowerUp(void); + void AS3935_PowerDown(void); + void AS3935_DisturberEn(void); + void AS3935_DisturberDis(void); + void AS3935_SetIRQ_Output_Source(uint8_t irq_select); + void AS3935_SetTuningCaps(uint8_t cap_val); + /*! 0 = unknown src, 1 = lightning detected, 2 = disturber, 3 = Noise level too high */ + uint8_t AS3935_GetInterruptSrc(void); + /*! Get rid of non-distance data */ + uint8_t AS3935_GetLightningDistKm(void); + /*! Get lightning energy intensity */ + uint32_t AS3935_GetStrikeEnergyRaw(void); + uint8_t AS3935_SetMinStrikes(uint8_t min_strk); + void AS3935_ClearStatistics(void); + void AS3935_SetIndoors(void); + void AS3935_SetOutdoors(void); + uint8_t AS3935_GetNoiseFloorLvl(void); + void AS3935_SetNoiseFloorLvl(uint8_t nf_sel); + uint8_t AS3935_GetWatchdogThreshold(void); + void AS3935_SetWatchdogThreshold(uint8_t wdth); + uint8_t AS3935_GetSpikeRejection(void); + void AS3935_SetSpikeRejection(uint8_t srej); + void AS3935_SetLCO_FDIV(uint8_t fdiv); + /*! View register data */ + void AS3935_PrintAllRegs(void); + + private: + uint8_t _irq, _si, _devadd; + uint8_t _sing_reg_read(uint8_t RegAdd); + void _sing_reg_write(uint8_t RegAdd, uint8_t DataMask, uint8_t RegData); + void _AS3935_Reset(void); + void _CalRCO(void); +}; + +#endif + + + + diff --git a/I2C.cpp b/I2C.cpp new file mode 100644 index 0000000..70765da --- /dev/null +++ b/I2C.cpp @@ -0,0 +1,728 @@ +/* + I2C.cpp - I2C library + Copyright (c) 2011-2012 Wayne Truchsess. All right reserved. + Rev 5.0 - January 24th, 2012 + - Removed the use of interrupts completely from the library + so TWI state changes are now polled. + - Added calls to lockup() function in most functions + to combat arbitration problems + - Fixed scan() procedure which left timeouts enabled + and set to 80msec after exiting procedure + - Changed scan() address range back to 0 - 0x7F + - Removed all Wire legacy functions from library + - A big thanks to Richard Baldwin for all the testing + and feedback with debugging bus lockups! + Rev 4.0 - January 14th, 2012 + - Updated to make compatible with 8MHz clock frequency + Rev 3.0 - January 9th, 2012 + - Modified library to be compatible with Arduino 1.0 + - Changed argument type from boolean to uint8_t in pullUp(), + setSpeed() and receiveByte() functions for 1.0 compatability + - Modified return values for timeout feature to report + back where in the transmission the timeout occured. + - added function scan() to perform a bus scan to find devices + attached to the I2C bus. Similar to work done by Todbot + and Nick Gammon + Rev 2.0 - September 19th, 2011 + - Added support for timeout function to prevent + and recover from bus lockup (thanks to PaulS + and CrossRoads on the Arduino forum) + - Changed return type for stop() from void to + uint8_t to handle timeOut function + Rev 1.0 - August 8th, 2011 + + This is a modified version of the Arduino Wire/TWI + library. Functions were rewritten to provide more functionality + and also the use of Repeated Start. Some I2C devices will not + function correctly without the use of a Repeated Start. The + initial version of this library only supports the Master. + + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#if(ARDUINO >= 100) +#include +#else +#include +#endif + +#include +#include "I2C.h" + +uint8_t I2C::bytesAvailable = 0; +uint8_t I2C::bufferIndex = 0; +uint8_t I2C::totalBytes = 0; +uint16_t I2C::timeOutDelay = 0; + +I2C::I2C() +{ +} + +////////////// Public Methods //////////////////////////////////////// + +void I2C::begin() +{ + #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega328P__) + // activate internal pull-ups for twi + // as per note from atmega8 manual pg167 + sbi(PORTC, 4); + sbi(PORTC, 5); + #else + // activate internal pull-ups for twi + // as per note from atmega128 manual pg204 + sbi(PORTD, 0); + sbi(PORTD, 1); + #endif + // initialize twi prescaler and bit rate + cbi(TWSR, TWPS0); + cbi(TWSR, TWPS1); + TWBR = ((F_CPU / 100000) - 16) / 2; + // enable twi module and acks + TWCR = _BV(TWEN) | _BV(TWEA); +} + +void I2C::end() +{ + TWCR = 0; +} + +void I2C::timeOut(uint16_t _timeOut) +{ + timeOutDelay = _timeOut; +} + +void I2C::setSpeed(uint8_t _fast) +{ + if(!_fast) + { + TWBR = ((F_CPU / 100000) - 16) / 2; + } + else + { + TWBR = ((F_CPU / 400000) - 16) / 2; + } +} + +void I2C::pullup(uint8_t activate) +{ + if(activate) + { + #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega328P__) + // activate internal pull-ups for twi + // as per note from atmega8 manual pg167 + sbi(PORTC, 4); + sbi(PORTC, 5); + #else + // activate internal pull-ups for twi + // as per note from atmega128 manual pg204 + sbi(PORTD, 0); + sbi(PORTD, 1); + #endif + } + else + { + #if defined(__AVR_ATmega168__) || defined(__AVR_ATmega8__) || defined(__AVR_ATmega328P__) + // deactivate internal pull-ups for twi + // as per note from atmega8 manual pg167 + cbi(PORTC, 4); + cbi(PORTC, 5); + #else + // deactivate internal pull-ups for twi + // as per note from atmega128 manual pg204 + cbi(PORTD, 0); + cbi(PORTD, 1); + #endif + } +} + +void I2C::scan() +{ + uint16_t tempTime = timeOutDelay; + timeOut(80); + uint8_t totalDevicesFound = 0; + Serial.println(F("Scanning for devices...please wait")); + Serial.println(); + for(uint8_t s = 0; s <= 0x7F; s++) + { + returnStatus = 0; + returnStatus = start(); + if(!returnStatus) + { + returnStatus = sendAddress(SLA_W(s)); + } + if(returnStatus) + { + if(returnStatus == 1) + { + Serial.println(F("There is a problem with the bus, could not complete scan")); + timeOutDelay = tempTime; + return; + } + } + else + { + Serial.print(F("Found device at address - ")); + Serial.print(F(" 0x")); + Serial.println(s,HEX); + totalDevicesFound++; + } + stop(); + } + if(!totalDevicesFound){Serial.println(F("No devices found"));} + timeOutDelay = tempTime; +} + + +uint8_t I2C::available() +{ + return(bytesAvailable); +} + +uint8_t I2C::receive() +{ + bufferIndex = totalBytes - bytesAvailable; + if(!bytesAvailable) + { + bufferIndex = 0; + return(0); + } + bytesAvailable--; + return(data[bufferIndex]); +} + +/*return values for new functions that use the timeOut feature + will now return at what point in the transmission the timeout + occurred. Looking at a full communication sequence between a + master and slave (transmit data and then readback data) there + a total of 7 points in the sequence where a timeout can occur. + These are listed below and correspond to the returned value: + 1 - Waiting for successful completion of a Start bit + 2 - Waiting for ACK/NACK while addressing slave in transmit mode (MT) + 3 - Waiting for ACK/NACK while sending data to the slave + 4 - Waiting for successful completion of a Repeated Start + 5 - Waiting for ACK/NACK while addressing slave in receiver mode (MR) + 6 - Waiting for ACK/NACK while receiving data from the slave + 7 - Waiting for successful completion of the Stop bit + + All possible return values: + 0 Function executed with no errors + 1 - 7 Timeout occurred, see above list + 8 - 0xFF See datasheet for exact meaning */ + +///////////////////////////////////////////////////// + +uint8_t I2C::write(uint8_t address, uint8_t registerAddress) +{ + returnStatus = 0; + returnStatus = start(); + if(returnStatus){return(returnStatus);} + returnStatus = sendAddress(SLA_W(address)); + if(returnStatus) + { + if(returnStatus == 1){return(2);} + return(returnStatus); + } + returnStatus = sendByte(registerAddress); + if(returnStatus) + { + if(returnStatus == 1){return(3);} + return(returnStatus); + } + returnStatus = stop(); + if(returnStatus) + { + if(returnStatus == 1){return(7);} + return(returnStatus); + } + return(returnStatus); +} + +uint8_t I2C::write(int address, int registerAddress) +{ + return(write((uint8_t) address, (uint8_t) registerAddress)); +} + +uint8_t I2C::write(uint8_t address, uint8_t registerAddress, uint8_t data) +{ + returnStatus = 0; + returnStatus = start(); + if(returnStatus){return(returnStatus);} + returnStatus = sendAddress(SLA_W(address)); + if(returnStatus) + { + if(returnStatus == 1){return(2);} + return(returnStatus); + } + returnStatus = sendByte(registerAddress); + if(returnStatus) + { + if(returnStatus == 1){return(3);} + return(returnStatus); + } + returnStatus = sendByte(data); + if(returnStatus) + { + if(returnStatus == 1){return(3);} + return(returnStatus); + } + returnStatus = stop(); + if(returnStatus) + { + if(returnStatus == 1){return(7);} + return(returnStatus); + } + return(returnStatus); +} + +uint8_t I2C::write(int address, int registerAddress, int data) +{ + return(write((uint8_t) address, (uint8_t) registerAddress, (uint8_t) data)); +} + +uint8_t I2C::write(uint8_t address, uint8_t registerAddress, char *data) +{ + uint8_t bufferLength = strlen(data); + returnStatus = 0; + returnStatus = write(address, registerAddress, (uint8_t*)data, bufferLength); + return(returnStatus); +} + +uint8_t I2C::write(uint8_t address, uint8_t registerAddress, uint8_t *data, uint8_t numberBytes) +{ + returnStatus = 0; + returnStatus = start(); + if(returnStatus){return(returnStatus);} + returnStatus = sendAddress(SLA_W(address)); + if(returnStatus) + { + if(returnStatus == 1){return(2);} + return(returnStatus); + } + returnStatus = sendByte(registerAddress); + if(returnStatus) + { + if(returnStatus == 1){return(3);} + return(returnStatus); + } + for (uint8_t i = 0; i < numberBytes; i++) + { + returnStatus = sendByte(data[i]); + if(returnStatus) + { + if(returnStatus == 1){return(3);} + return(returnStatus); + } + } + returnStatus = stop(); + if(returnStatus) + { + if(returnStatus == 1){return(7);} + return(returnStatus); + } + return(returnStatus); +} + +uint8_t I2C::read(int address, int numberBytes) +{ + return(read((uint8_t) address, (uint8_t) numberBytes)); +} + +uint8_t I2C::read(uint8_t address, uint8_t numberBytes) +{ + bytesAvailable = 0; + bufferIndex = 0; + if(numberBytes == 0){numberBytes++;} + nack = numberBytes - 1; + returnStatus = 0; + returnStatus = start(); + if(returnStatus){return(returnStatus);} + returnStatus = sendAddress(SLA_R(address)); + if(returnStatus) + { + if(returnStatus == 1){return(5);} + return(returnStatus); + } + for(uint8_t i = 0; i < numberBytes; i++) + { + if( i == nack ) + { + returnStatus = receiveByte(0); + if(returnStatus == 1){return(6);} + + if(returnStatus != MR_DATA_NACK){return(returnStatus);} + } + else + { + returnStatus = receiveByte(1); + if(returnStatus == 1){return(6);} + if(returnStatus != MR_DATA_ACK){return(returnStatus);} + } + data[i] = TWDR; + bytesAvailable = i+1; + totalBytes = i+1; + } + returnStatus = stop(); + if(returnStatus) + { + if(returnStatus == 1){return(7);} + return(returnStatus); + } + return(returnStatus); +} + +uint8_t I2C::read(int address, int registerAddress, int numberBytes) +{ + return(read((uint8_t) address, (uint8_t) registerAddress, (uint8_t) numberBytes)); +} + +uint8_t I2C::read(uint8_t address, uint8_t registerAddress, uint8_t numberBytes) +{ + bytesAvailable = 0; + bufferIndex = 0; + if(numberBytes == 0){numberBytes++;} + nack = numberBytes - 1; + returnStatus = 0; + returnStatus = start(); + if(returnStatus){return(returnStatus);} + returnStatus = sendAddress(SLA_W(address)); + if(returnStatus) + { + if(returnStatus == 1){return(2);} + return(returnStatus); + } + returnStatus = sendByte(registerAddress); + if(returnStatus) + { + if(returnStatus == 1){return(3);} + return(returnStatus); + } + returnStatus = start(); + if(returnStatus) + { + if(returnStatus == 1){return(4);} + return(returnStatus); + } + returnStatus = sendAddress(SLA_R(address)); + if(returnStatus) + { + if(returnStatus == 1){return(5);} + return(returnStatus); + } + for(uint8_t i = 0; i < numberBytes; i++) + { + if( i == nack ) + { + returnStatus = receiveByte(0); + if(returnStatus == 1){return(6);} + if(returnStatus != MR_DATA_NACK){return(returnStatus);} + } + else + { + returnStatus = receiveByte(1); + if(returnStatus == 1){return(6);} + if(returnStatus != MR_DATA_ACK){return(returnStatus);} + } + data[i] = TWDR; + bytesAvailable = i+1; + totalBytes = i+1; + } + returnStatus = stop(); + if(returnStatus) + { + if(returnStatus == 1){return(7);} + return(returnStatus); + } + return(returnStatus); +} + +uint8_t I2C::read(uint8_t address, uint8_t numberBytes, uint8_t *dataBuffer) +{ + bytesAvailable = 0; + bufferIndex = 0; + if(numberBytes == 0){numberBytes++;} + nack = numberBytes - 1; + returnStatus = 0; + returnStatus = start(); + if(returnStatus){return(returnStatus);} + returnStatus = sendAddress(SLA_R(address)); + if(returnStatus) + { + if(returnStatus == 1){return(5);} + return(returnStatus); + } + for(uint8_t i = 0; i < numberBytes; i++) + { + if( i == nack ) + { + returnStatus = receiveByte(0); + if(returnStatus == 1){return(6);} + if(returnStatus != MR_DATA_NACK){return(returnStatus);} + } + else + { + returnStatus = receiveByte(1); + if(returnStatus == 1){return(6);} + if(returnStatus != MR_DATA_ACK){return(returnStatus);} + } + dataBuffer[i] = TWDR; + bytesAvailable = i+1; + totalBytes = i+1; + } + returnStatus = stop(); + if(returnStatus) + { + if(returnStatus == 1){return(7);} + return(returnStatus); + } + return(returnStatus); +} + +uint8_t I2C::read(uint8_t address, uint8_t registerAddress, uint8_t numberBytes, uint8_t *dataBuffer) +{ + bytesAvailable = 0; + bufferIndex = 0; + if(numberBytes == 0){numberBytes++;} + nack = numberBytes - 1; + returnStatus = 0; + returnStatus = start(); + if(returnStatus){return(returnStatus);} + returnStatus = sendAddress(SLA_W(address)); + if(returnStatus) + { + if(returnStatus == 1){return(2);} + return(returnStatus); + } + returnStatus = sendByte(registerAddress); + if(returnStatus) + { + if(returnStatus == 1){return(3);} + return(returnStatus); + } + returnStatus = start(); + if(returnStatus) + { + if(returnStatus == 1){return(4);} + return(returnStatus); + } + returnStatus = sendAddress(SLA_R(address)); + if(returnStatus) + { + if(returnStatus == 1){return(5);} + return(returnStatus); + } + for(uint8_t i = 0; i < numberBytes; i++) + { + if( i == nack ) + { + returnStatus = receiveByte(0); + if(returnStatus == 1){return(6);} + if(returnStatus != MR_DATA_NACK){return(returnStatus);} + } + else + { + returnStatus = receiveByte(1); + if(returnStatus == 1){return(6);} + if(returnStatus != MR_DATA_ACK){return(returnStatus);} + } + dataBuffer[i] = TWDR; + bytesAvailable = i+1; + totalBytes = i+1; + } + returnStatus = stop(); + if(returnStatus) + { + if(returnStatus == 1){return(7);} + return(returnStatus); + } + return(returnStatus); +} + +/////////////// Private Methods //////////////////////////////////////// + +uint8_t I2C::start() +{ + unsigned long startingTime = millis(); + TWCR = (1<= timeOutDelay) + { + lockUp(); + return(1); + } + + } + if ((TWI_STATUS == START) || (TWI_STATUS == REPEATED_START)) + { + return(0); + } + if (TWI_STATUS == LOST_ARBTRTN) + { + uint8_t bufferedStatus = TWI_STATUS; + lockUp(); + return(bufferedStatus); + } + return(TWI_STATUS); +} + +uint8_t I2C::sendAddress(uint8_t i2cAddress) +{ + TWDR = i2cAddress; + unsigned long startingTime = millis(); + TWCR = (1<= timeOutDelay) + { + lockUp(); + return(1); + } + + } + if ((TWI_STATUS == MT_SLA_ACK) || (TWI_STATUS == MR_SLA_ACK)) + { + return(0); + } + uint8_t bufferedStatus = TWI_STATUS; + if ((TWI_STATUS == MT_SLA_NACK) || (TWI_STATUS == MR_SLA_NACK)) + { + stop(); + return(bufferedStatus); + } + else + { + lockUp(); + return(bufferedStatus); + } +} + +uint8_t I2C::sendByte(uint8_t i2cData) +{ + TWDR = i2cData; + unsigned long startingTime = millis(); + TWCR = (1<= timeOutDelay) + { + lockUp(); + return(1); + } + + } + if (TWI_STATUS == MT_DATA_ACK) + { + return(0); + } + uint8_t bufferedStatus = TWI_STATUS; + if (TWI_STATUS == MT_DATA_NACK) + { + stop(); + return(bufferedStatus); + } + else + { + lockUp(); + return(bufferedStatus); + } +} + +uint8_t I2C::receiveByte(uint8_t ack) +{ + unsigned long startingTime = millis(); + if(ack) + { + TWCR = (1<= timeOutDelay) + { + lockUp(); + return(1); + } + } + if (TWI_STATUS == LOST_ARBTRTN) + { + uint8_t bufferedStatus = TWI_STATUS; + lockUp(); + return(bufferedStatus); + } + return(TWI_STATUS); +} + +uint8_t I2C::receiveByte(uint8_t ack, uint8_t *target) +{ + uint8_t stat = I2C::receiveByte(ack); + if (stat == 1) + { + return(6); + } + if (ack) + { + if(stat != MR_DATA_ACK) + { + *target = 0x0; + return(stat); + } + } + else + { + if(stat != MR_DATA_NACK) + { + *target = 0x0; + return(stat); + } + } + *target = TWDR; + // I suppose that if we get this far we're ok + return 0; +} + +uint8_t I2C::stop() +{ + unsigned long startingTime = millis(); + TWCR = (1<= timeOutDelay) + { + lockUp(); + return(1); + } + + } + return(0); +} + +void I2C::lockUp() +{ + TWCR = 0; //releases SDA and SCL lines to high impedance + TWCR = _BV(TWEN) | _BV(TWEA); //reinitialize TWI +} + +I2C I2c = I2C(); + diff --git a/I2C.h b/I2C.h new file mode 100644 index 0000000..52999e1 --- /dev/null +++ b/I2C.h @@ -0,0 +1,76 @@ +#if(ARDUINO >= 100) +#include +#else +#include +#endif + +#include + +#ifndef I2C_h +#define I2C_h + +#define START 0x08 +#define REPEATED_START 0x10 +#define MT_SLA_ACK 0x18 +#define MT_SLA_NACK 0x20 +#define MT_DATA_ACK 0x28 +#define MT_DATA_NACK 0x30 +#define MR_SLA_ACK 0x40 +#define MR_SLA_NACK 0x48 +#define MR_DATA_ACK 0x50 +#define MR_DATA_NACK 0x58 +#define LOST_ARBTRTN 0x38 +#define TWI_STATUS (TWSR & 0xF8) +#define SLA_W(address) (address << 1) +#define SLA_R(address) ((address << 1) + 0x01) +#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) +#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) + +#define MAX_BUFFER_SIZE 32 + +class I2C +{ + public: + I2C(); + void begin(); + void end(); + void timeOut(uint16_t); + void setSpeed(uint8_t); + void pullup(uint8_t); + void scan(); + uint8_t available(); + uint8_t receive(); + uint8_t write(uint8_t, uint8_t); + uint8_t write(int, int); + uint8_t write(uint8_t, uint8_t, uint8_t); + uint8_t write(int, int, int); + uint8_t write(uint8_t, uint8_t, char*); + uint8_t write(uint8_t, uint8_t, uint8_t*, uint8_t); + uint8_t read(uint8_t, uint8_t); + uint8_t read(int, int); + uint8_t read(uint8_t, uint8_t, uint8_t); + uint8_t read(int, int, int); + uint8_t read(uint8_t, uint8_t, uint8_t*); + uint8_t read(uint8_t, uint8_t, uint8_t, uint8_t*); + + uint8_t start(); + uint8_t sendAddress(uint8_t); + uint8_t sendByte(uint8_t); + uint8_t receiveByte(uint8_t); + uint8_t receiveByte(uint8_t, uint8_t *target); + uint8_t stop(); + private: + void lockUp(); + uint8_t returnStatus; + uint8_t nack; + uint8_t data[MAX_BUFFER_SIZE]; + static uint8_t bytesAvailable; + static uint8_t bufferIndex; + static uint8_t totalBytes; + static uint16_t timeOutDelay; + +}; + +extern I2C I2c; + +#endif diff --git a/examples/DFRobot_AS3935_lightning_I2c/DFRobot_AS3935_lightning_I2c.ino b/examples/DFRobot_AS3935_lightning_I2c/DFRobot_AS3935_lightning_I2c.ino new file mode 100644 index 0000000..46bed32 --- /dev/null +++ b/examples/DFRobot_AS3935_lightning_I2c/DFRobot_AS3935_lightning_I2c.ino @@ -0,0 +1,111 @@ +/*! + * file as3935_lightning_i2c_nocal.ino + * + * On The Lightning Sensor + * This sensor can detect lightning and display the distance and intensity of the lightning without the + * disturbance of electric arc and noise.It can be set as indoor or outdoor mode. + * The module has three I2C, the addresses are: + * 0x03 A0-High A1-High + * 0x02 A0-Low A1-High + * 0x01 A0-High A1-Low + * + * Copyright [DFRobot](http://www.dfrobot.com), 2018 + * Copyright GNU Lesser General Public License + * + * version V0.1 + * date 2018-9-6 + */ + +#include "I2C.h" +#include "DFRobot_AS3935_I2C.h" + +volatile int8_t AS3935_ISR_Trig = 0; + +#define SI_PIN 9 +#define IRQ_PIN 2 + +#define AS3935_CAPACITANCE 72 + +#define AS3935_INDOORS 0 +#define AS3935_OUTDOORS 1 +#define AS3935_DIST_DIS 0 +#define AS3935_DIST_EN 1 + +void AS3935_ISR(); + +DF_AS3935_I2C lightning0((uint8_t)IRQ_PIN, (uint8_t)SI_PIN, (uint8_t)AS3935_ADD3); + +void setup() +{ + + Serial.begin(115200); + Serial.println("Playing With DFRobot: AS3935 Lightning Sensor"); + Serial.println("beginning boot procedure...."); + + // Setup for the the I2C library: (enable pullups, set speed to 400kHz) + I2c.begin(); + I2c.pullup(true); + I2c.setSpeed(1); + delay(2); + + //lightning0.AS3935_I2CAddress(AS3935_ADD1); // x01 - A0->high A1->low + //lightning0.AS3935_I2CAddress(AS3935_ADD2); // x02 - A0->low A1->high + //lightning0.AS3935_I2CAddress(AS3935_ADD3); // x03 - A0->high A1->high + lightning0.AS3935_SetI2CAddress(AS3935_ADD3); + + // Set registers to default + lightning0.AS3935_DefInit(); + // Now update sensor cal for your application and power up chip + lightning0.AS3935_ManualCal(AS3935_CAPACITANCE, AS3935_INDOORS, AS3935_DIST_EN); + // Enable interrupt (hook IRQ pin to Arduino Uno/Mega interrupt input: 0 -> pin 2, 1 -> pin 3 ) + attachInterrupt(0, AS3935_ISR, RISING); + // For debug, view register data + lightning0.AS3935_PrintAllRegs(); + // Clear trigger + AS3935_ISR_Trig = 0; + +} + +void loop() +{ + // It does nothing until an interrupt is detected on the IRQ pin. + while(0 == AS3935_ISR_Trig){} + delay(5); + + // Reset interrupt flag + AS3935_ISR_Trig = 0; + + // Now get interrupt source + uint8_t int_src = lightning0.AS3935_GetInterruptSrc(); + if(1 == int_src) + { + // Get rid of non-distance data + uint8_t lightning_dist_km = lightning0.AS3935_GetLightningDistKm(); + Serial.print("发生闪电啦! 闪电发生距离: "); + Serial.print(lightning_dist_km); + Serial.println(" km"); + // Get lightning energy intensity + uint32_t lightning_energy_val = lightning0.AS3935_GetStrikeEnergyRaw(); + Serial.print("雷电强度:"); + Serial.print(lightning_energy_val); + Serial.println(""); + } + else if(2 == int_src) + { + Serial.println("发现干扰源"); + } + else if(3 == int_src) + { + Serial.println("噪音强度过高"); + } + lightning0.AS3935_PrintAllRegs(); + Serial.println(""); +} + +// This is irq handler for AS3935 interrupts, has to return void and take no arguments +// always make code in interrupt handlers fast and short +void AS3935_ISR() +{ + AS3935_ISR_Trig = 1; +} + diff --git a/keywords.txt b/keywords.txt new file mode 100644 index 0000000..35f937d --- /dev/null +++ b/keywords.txt @@ -0,0 +1,60 @@ +####################################### +# Syntax Coloring DFRobot_AS3935 +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +DF_AS3935_I2C KEYWORD1 +I2C KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +end KEYWORD2 +timeOut KEYWORD2 +setSpeed KEYWORD2 +pullup KEYWORD2 +scan KEYWORD2 +write KEYWORD2 +read KEYWORD2 +available KEYWORD2 +receive KEYWORD2 +AS3935_DefInit KEYWORD2 +AS3935_DefInit KEYWORD2 +_AS3935_Reset KEYWORD2 +_CalRCO KEYWORD2 +AS3935_PowerUp KEYWORD2 +AS3935_PowerDown KEYWORD2 +AS3935_DisturberEn KEYWORD2 +AS3935_DisturberDis KEYWORD2 +AS3935_SetIRQ_Output_Source KEYWORD2 +AS3935_SetTuningCaps KEYWORD2 +AS3935_GetInterruptSrc KEYWORD2 +AS3935_GetLightningDistKm KEYWORD2 +AS3935_SetMinStrikes KEYWORD2 +AS3935_SetIndoors KEYWORD2 +AS3935_SetOutdoors KEYWORD2 +AS3935_ClearStatistics KEYWORD2 +AS3935_GetNoiseFloorLvl KEYWORD2 +AS3935_SetNoiseFloorLvl KEYWORD2 +AS3935_GetWatchdogThreshold KEYWORD2 +AS3935_SetWatchdogThreshold KEYWORD2 +AS3935_GetSpikeRejection KEYWORD2 +AS3935_SetSpikeRejection KEYWORD2 +AS3935_SetLCO_FDIV KEYWORD2 +AS3935_PrintAllRegs KEYWORD2 +AS3935_ManualCal KEYWORD2 +AS3935_SetI2CAddress KEYWORD2 + + +####################################### +# Constants (LITERAL1) +####################################### + +AS3935_ADD1 LITERAL1 +AS3935_ADD2 LITERAL1 +AS3935_ADD3 LITERAL1 diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..60f530c --- /dev/null +++ b/readme.md @@ -0,0 +1,114 @@ +# AS3935 + +AS3935 Lightning Sensor can detect lightning and display the distance and intensity of the lightning without the disturbance of electric arc and noise.
+It can be set as indoor or outdoor mode.
+ +## DFRobot_AS3934 Library for Arduino +--------------------------------------------------------- +Provide a library faciltates operations in the as3935 modules. + +## Table of Contents + +* [Summary](#summary) +* [Feature](#feature) +* [Installation](#installation) +* [Methods](#methods) + +* [Compatibility](#compatibility) +* [Credits](#credits) + + + +## Summary + +Input commands and read data from AS3935 modules + +## Feature + +1. test
+2. test
+3. test
+ +## Installation + +Download the library ZIP file and unzip it to the Arduino folder of the library.
+ +## Methods + +```C++ + +#include "DFRobot_AS3935_I2C.h" + +/* + * @brief AS3935 object + * + * @param IRQx irq pin + * SIx si pin + * DEVADDx i2c address + */ +DF_AS3935_I2C(uint8_t IRQx, uint8_t SIx, uint8_t DEVADDx); + +/* + * @brief reset registers to default + */ +void AS3935_DefInit(void); + +/* + * @brief set i2c address + * + * @param DEVADDx i2c address + */ +void AS3935_SetI2CAddress(uint8_t DEVADDx); + +/* + * @brief manual calibration + * + * @param capacitance capacitance + * location location + * disturber disturber + */ +void AS3935_ManualCal(uint8_t capacitance, uint8_t location, uint8_t disturber); + +/* + * @brief view register data + */ +void AS3935_PrintAllRegs(void); + +/* + * @brief get interrupt source + * + * @return 0 interrupt result not expected + * 1 lightning caused interrupt + * 2 disturber detected + * 3 Noise level too high + */ +uint8_t AS3935_GetInterruptSrc(void); + +/* + * @brief manual calibration + * + * @param + */ +uint8_t AS3935_GetLightningDistKm(void); + +/* + * @brief get rid of non-distance data + * + * @return Unit kilometer + */ +uint32_t AS3935_GetStrikeEnergyRaw(void); + +``` + + + +## Compatibility + +MCU | Work Well | Work Wrong | Untested | Remarks +------------------ | :----------: | :----------: | :---------: | ----- +Arduino uno | √ | | | + + +## Credits + +Written by DFRobot, 2018. (Welcome to our [website](https://www.dfrobot.com/))