commit
ddca4bf74f
@ -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....
|
||||||
|
|
@ -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 |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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 <Arduino.h> |
||||||
|
#else |
||||||
|
#include <WProgram.h> |
||||||
|
#endif |
||||||
|
|
||||||
|
#include <inttypes.h> |
||||||
|
#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<<TWINT)|(1<<TWSTA)|(1<<TWEN); |
||||||
|
while (!(TWCR & (1<<TWINT))) |
||||||
|
{ |
||||||
|
if(!timeOutDelay){continue;} |
||||||
|
if((millis() - startingTime) >= 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<<TWINT) | (1<<TWEN); |
||||||
|
while (!(TWCR & (1<<TWINT))) |
||||||
|
{ |
||||||
|
if(!timeOutDelay){continue;} |
||||||
|
if((millis() - startingTime) >= 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<<TWINT) | (1<<TWEN); |
||||||
|
while (!(TWCR & (1<<TWINT))) |
||||||
|
{ |
||||||
|
if(!timeOutDelay){continue;} |
||||||
|
if((millis() - startingTime) >= 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<<TWINT) | (1<<TWEN) | (1<<TWEA); |
||||||
|
|
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
TWCR = (1<<TWINT) | (1<<TWEN); |
||||||
|
} |
||||||
|
while (!(TWCR & (1<<TWINT))) |
||||||
|
{ |
||||||
|
if(!timeOutDelay){continue;} |
||||||
|
if((millis() - startingTime) >= 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<<TWINT)|(1<<TWEN)| (1<<TWSTO); |
||||||
|
while ((TWCR & (1<<TWSTO))) |
||||||
|
{ |
||||||
|
if(!timeOutDelay){continue;} |
||||||
|
if((millis() - startingTime) >= 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(); |
||||||
|
|
@ -0,0 +1,76 @@ |
|||||||
|
#if(ARDUINO >= 100) |
||||||
|
#include <Arduino.h> |
||||||
|
#else |
||||||
|
#include <WProgram.h> |
||||||
|
#endif |
||||||
|
|
||||||
|
#include <inttypes.h> |
||||||
|
|
||||||
|
#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 |
@ -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; |
||||||
|
} |
||||||
|
|
@ -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 |
@ -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.<br> |
||||||
|
It can be set as indoor or outdoor mode.<br> |
||||||
|
|
||||||
|
## 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) |
||||||
|
<snippet> |
||||||
|
<content> |
||||||
|
|
||||||
|
## Summary |
||||||
|
|
||||||
|
Input commands and read data from AS3935 modules |
||||||
|
|
||||||
|
## Feature |
||||||
|
|
||||||
|
1. test <br> |
||||||
|
2. test <br> |
||||||
|
3. test <br> |
||||||
|
|
||||||
|
## Installation |
||||||
|
|
||||||
|
Download the library ZIP file and unzip it to the Arduino folder of the library.<br> |
||||||
|
|
||||||
|
## 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/)) |
Loading…
Reference in new issue