From 70efa9f99d9688bb728eb3ec8ebae2e2b814efd4 Mon Sep 17 00:00:00 2001 From: Jochen Schaeuble Date: Sun, 18 Aug 2019 19:14:55 +0200 Subject: [PATCH] Ported Raspberry Pi library to MicroPython --- MicroPython/DFRobot_AS3935_Lib.py | 245 ++++++++++++++++++ MicroPython/README.md | 153 +++++++++++ .../example/DFRobot_AS3935_detailed.py | 111 ++++++++ 3 files changed, 509 insertions(+) create mode 100644 MicroPython/DFRobot_AS3935_Lib.py create mode 100644 MicroPython/README.md create mode 100644 MicroPython/example/DFRobot_AS3935_detailed.py diff --git a/MicroPython/DFRobot_AS3935_Lib.py b/MicroPython/DFRobot_AS3935_Lib.py new file mode 100644 index 0000000..d47a080 --- /dev/null +++ b/MicroPython/DFRobot_AS3935_Lib.py @@ -0,0 +1,245 @@ +import utime +from machine import Pin, I2C + +class DFRobot_AS3935: + def __init__(self, address, i2c): + self.address = address + self.i2cbus = i2c + + def writeByte(self, register, value): + try: + self.i2cbus.writeto_mem(self.address, register, bytes([value])) + return 1 + except: + return 0 + + def readData(self, register): + self.register = self.i2cbus.readfrom_mem(self.address, register, 1) + + def manualCal(self, capacitance, location, disturber): + self.powerUp() + if location == 1: + self.setIndoors() + else: + self.setOutdoors() + + if disturber == 0: + self.disturberDis() + else: + self.disturberEn() + + self.setIrqOutputSource(0) + utime.sleep(0.5) + self.setTuningCaps(capacitance) + + def setTuningCaps(self, capVal): + #Assume only numbers divisible by 8 (because that's all the chip supports) + if capVal > 120: #cap_value out of range, assume highest capacitance + self.singRegWrite(0x08, 0x0F, 0x0F) #set capacitance bits to maximum + else: + self.singRegWrite(0x08, 0x0F, capVal >> 3) #set capacitance bits + + self.singRegRead(0x08) + #print('capacitance set to 8x%d'%(self.register[0] & 0x0F)) + + def powerUp(self): + #register 0x00, PWD bit: 0 (clears PWD) + self.singRegWrite(0x00, 0x01, 0x00) + self.calRCO() #run RCO cal cmd + self.singRegWrite(0x08, 0x20, 0x20) #set DISP_SRCO to 1 + utime.sleep(0.002) + self.singRegWrite(0x08, 0x20, 0x00) #set DISP_SRCO to 0 + + def powerDown(self): + #register 0x00, PWD bit: 0 (sets PWD) + self.singRegWrite(0x00, 0x01, 0x01) + + def calRCO(self): + self.writeByte(0x3D, 0x96) + utime.sleep(0.002) + + def setIndoors(self): + self.singRegWrite(0x00, 0x3E, 0x24) + print("set to indoors model") + + def setOutdoors(self): + self.singRegWrite(0x00, 0x3E, 0x1C) + print("set to outdoors model") + + def disturberDis(self): + #register 0x03, PWD bit: 5 (sets MASK_DIST) + self.singRegWrite(0x03, 0x20, 0x20) + print("disenable disturber detection") + + def disturberEn(self): + #register 0x03, PWD bit: 5 (sets MASK_DIST) + self.singRegWrite(0x03, 0x20, 0x00) + print("enable disturber detection") + + def singRegWrite(self, regAdd, dataMask, regData): + #start by reading original register data (only modifying what we need to) + self.singRegRead(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 + newRegData = (self.register[0] & ~dataMask)|(regData & dataMask) + #finally, write the data to the register + self.writeByte(regAdd, newRegData) + #print('wrt: %02x'%newRegData) + self.singRegRead(regAdd) + #print('Act: %02x'%self.register[0]) + + def singRegRead(self,regAdd): + self.readData(regAdd) + + def getInterruptSrc(self): + #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 + utime.sleep(0.03) #wait 3ms before reading (min 2ms per pg 22 of datasheet) + self.singRegRead(0x03) #read register, get rid of non-interrupt data + intSrc = self.register[0]&0x0F + if intSrc == 0x08: + return 1 #lightning caused interrupt + elif intSrc == 0x04: + return 2 #disturber detected + elif intSrc == 0x01: + return 3 #Noise level too high + else: + return 0 #interrupt result not expected + + def reset(self): + err = self.writeByte(0x3C, 0x96) + utime.sleep(0.002) #wait 2ms to complete + return err + + def setLcoFdiv(self,fdiv): + self.singRegWrite(0x03, 0xC0, (fdiv & 0x03) << 6) + + def setIrqOutputSource(self, irqSelect): + #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 irqSelect == 1: + self.singRegWrite(0x08, 0xE0, 0x20) #set only TRCO bit + elif irqSelect == 2: + self.singRegWrite(0x08, 0xE0, 0x40) #set only SRCO bit + elif irqSelect == 3: + self.singRegWrite(0x08, 0xE0, 0x80) #set only SRCO bit + else: + self.singRegWrite(0x08, 0xE0, 0x00) #clear IRQ pin display bits + + def getLightningDistKm(self): + self.singRegRead(0x07) #read register, get rid of non-distance data + return self.register[0]&0x3F + + def getStrikeEnergyRaw(self): + self.singRegRead(0x06) #MMSB, shift 8 bits left, make room for MSB + nrgyRaw = (self.register[0]&0x1F) << 8 + self.singRegRead(0x05) #read MSB + nrgyRaw |= self.register[0] + nrgyRaw <<= 8 #shift 8 bits left, make room for LSB + self.singRegRead(0x04) #read LSB, add to others + nrgyRaw |= self.register[0] + + return nrgyRaw/16777 + + def setMinStrikes(self, minStrk): + #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. + if minStrk < 5: + self.singRegWrite(0x02, 0x30, 0x00) + return 1 + elif minStrk < 9: + self.singRegWrite(0x02, 0x30, 0x10) + return 5 + elif minStrk < 16: + self.singRegWrite(0x02, 0x30, 0x20) + return 9 + else: + self.singRegWrite(0x02, 0x30, 0x30) + return 16 + + def clearStatistics(self): + #clear is accomplished by toggling CL_STAT bit 'high-low-high' (then set low to move on) + self.singRegWrite(0x02, 0x40, 0x40) #high + self.singRegWrite(0x02, 0x40, 0x00) #low + self.singRegWrite(0x02, 0x40, 0x40) #high + + def getNoiseFloorLv1(self): + #NF settings addres 0x01, bits 6:4 + #default setting of 010 at startup (datasheet, table 9) + self.singRegRead(0x01) #read register 0x01 + return (self.register[0] & 0x70) >> 4 #should return value from 0-7, see table 16 for info + + def setNoiseFloorLv1(self, nfSel): + #NF settings addres 0x01, bits 6:4 + #default setting of 010 at startup (datasheet, table 9) + if nfSel <= 7: #nfSel within expected range + self.singRegWrite(0x01, 0x70, (nfSel & 0x07) << 4) + else: #out of range, set to default (power-up value 010) + self.singRegWrite(0x01, 0x70, 0x20) + + def getWatchdogThreshold(self): + #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 0010 + #values should only be between 0x00 and 0x0F (0 and 7) + self.singRegRead(0x01) + return self.register[0] & 0x0F + + def setWatchdogThreshold(self, 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 0010 + #values should only be between 0x00 and 0x0F (0 and 7) + self.singRegWrite(0x01, 0x0F, wdth & 0x0F) + + def getSpikeRejection(self): + #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) + self.singRegRead(0x02) + return self.register[0] & 0x0F + + def setSpikeRejection(self, 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) + self.singRegWrite(0x02, 0x0F, srej & 0x0F) + + def printAllRegs(self): + self.singRegRead(0x00) + print("Reg 0x00: %02x"%self.register[0]) + self.singRegRead(0x01) + print("Reg 0x01: %02x"%self.register[0]) + self.singRegRead(0x02) + print("Reg 0x02: %02x"%self.register[0]) + self.singRegRead(0x03) + print("Reg 0x03: %02x"%self.register[0]) + self.singRegRead(0x04) + print("Reg 0x04: %02x"%self.register[0]) + self.singRegRead(0x05) + print("Reg 0x05: %02x"%self.register[0]) + self.singRegRead(0x06) + print("Reg 0x06: %02x"%self.register[0]) + self.singRegRead(0x07) + print("Reg 0x07: %02x"%self.register[0]) + self.singRegRead(0x08) + print("Reg 0x08: %02x"%self.register[0]) + self.singRegRead(0x3A) + print("Reg 0x3A: %02x"%self.register[0]) + self.singRegRead(0x3B) + print("Reg 0x3B: %02x"%self.register[0]) + + + diff --git a/MicroPython/README.md b/MicroPython/README.md new file mode 100644 index 0000000..ddfe1a7 --- /dev/null +++ b/MicroPython/README.md @@ -0,0 +1,153 @@ +## DFRobot_AS3935_Lib.py Library for MicroPython +--------------------------------------------------------- +This is the sample code for Gravity:Lightning Sensor, SKU: SEN0292. +## Table of Contents + +* [Installation](#installation) +* [Methods](#methods) + + + +## Installation +The Lightning Sensor should work with AS3935 +(https://github.com/DFRobot/DFRobot_AS3935/tree/master/MicroPython) + +Copy the library (DFRobot_AS3935_Lib.py) and the example code (DFRobot_AS3935_detailed.py as main.py) to a microcontroller running MicroPython (https://micropython.org): + +## Methods + +```python + +/* + * @brief Init The Lightning Sensor + * + * @param address I2C address(1~3) + * i2c I2C object (machine.I2C) + */ +DFRobot_AS3935(address, i2c); + +/* + * @brief Sensor reset + */ +def reset(self); + +/* + * @brief Configure sensor + * + * @param capacitance Antenna tuning capcitance (must be integer multiple of 8, 8 - 120 pf) + * location Indoor/outdoor mode selection + * disturber Enable/disable disturber detection + */ +def manualCal(self, capacitance, location, disturber); + +/* + * @brief Get mid-range type + * + * @return 0 Unknown src + * 1 Lightning detected + * 2 Disturber + * 3 Noise level too high + */ +def getInterruptSrc(self); + +/* + * @brief get lightning distance + * + * @return unit kilometer + */ +def getLightningDistKm(self); + +/* + * @brief get lightning energy intensity + * + * @return lightning energy intensity(0-1000) + */ +def getStrikeEnergyRaw(self); + +/* + * @brief Sets LCO_FDIV register + * + * @param fdiv Set 0, 1, 2 or 3 for ratios of 16, 32, 64 and 128, respectively + */ +def setLcoFdiv(self,fdiv); + +/* + * @brief Set interrupt source + * + * @param irqSelect 0 = NONE, 1 = TRCO, 2 = SRCO, 3 = LCO + */ +def setIrqOutputSource(self, irqSelect); + +/* + * @brief Set to the outdoor model + */ +def setOutdoors(self); + +/* + * @brief Set to the indoor model + */ +def setIndoors(self); + +/* + * @brief Disturber detection enabled + */ +def disturberEn(self); + +/* + * @brief Disturber detection disenabled + */ +def disturberDis(self); + +/* + * @brief Set the noise level + * + * @param 0~7,More than 7 will use the default value:2 + */ +def setNoiseFloorLv1(self, nfSel); + +/* + * @brief Get the noise level + * + * @return 0~7 + */ +def getNoiseFloorLv1(self); + +/* + * @brief Set an anti-interference rating + * + * @param 0~7,More than 7 will use the default value:2 + */ +def setWatchdogThreshold(self, wdth); + +/* + * @brief read WDTH + * + * @return 0~7 + */ +def getWatchdogThreshold(self); + +/* + * @brief Modify SREJ (spike rejection) + * + * @param 0~7,More than 7 will use the default value:2 + */ +def setSpikeRejection(self, srej); + +/* + * @brief read SREJ (spike rejection) + * + * @return 0~7 + */ +def getSpikeRejection(self); + +``` +## Credits + +Written by DFRobot_JH, 2018. (Welcome to our [website](https://www.dfrobot.com/)) + + + + + + + diff --git a/MicroPython/example/DFRobot_AS3935_detailed.py b/MicroPython/example/DFRobot_AS3935_detailed.py new file mode 100644 index 0000000..2728ee9 --- /dev/null +++ b/MicroPython/example/DFRobot_AS3935_detailed.py @@ -0,0 +1,111 @@ +# file DFRobot_AS3935_detailed.py +# +# SEN0290 Lightning Sensor +# This sensor can detect lightning and display the distance and intensity of the lightning within 40 km +# It can be set as indoor or outdoor mode. +# The module has three I2C, these addresses are: +# AS3935_ADD1 0x01 A0 = 1 A1 = 0 +# AS3935_ADD2 0x02 A0 = 0 A1 = 1 +# AS3935_ADD3 0x03 A0 = 1 A1 = 1 +# +# +# Copyright [DFRobot](http://www.dfrobot.com), 2018 +# Copyright GNU Lesser General Public License +# +# version V1.0 +# date 2018-11-28 + +from DFRobot_AS3935_Lib import DFRobot_AS3935 +from machine import Pin, I2C +import utime + +#I2C address +AS3935_I2C_ADDR1 = 0X01 +AS3935_I2C_ADDR2 = 0X02 +AS3935_I2C_ADDR3 = 0X03 + +# I2C HW ID or -1 for SW I2C +I2C_ID = 1 +I2C_SCL_PIN = 22 +I2C_SDA_PIN = 23 + +#Antenna tuning capcitance (must be integer multiple of 8, 8 - 120 pf) +AS3935_CAPACITANCE = 120 +IRQ_PIN = 12 + +# Initialize +i2c = I2C(I2C_ID, scl=Pin(I2C_SCL_PIN), sda=Pin(I2C_SDA_PIN), freq=400000) +sensor = DFRobot_AS3935(AS3935_I2C_ADDR3, i2c) +if (sensor.reset()): + print("init sensor sucess.") +else: + print("init sensor fail") + while True: + pass +#Configure sensor +sensor.powerUp() + +#set indoors or outdoors models +sensor.setIndoors() +#sensor.setOutdoors() + +#disturber detection +sensor.disturberEn() +#sensor.disturberDis() + +sensor.setIrqOutputSource(0) +utime.sleep(0.5) +#set capacitance +sensor.setTuningCaps(AS3935_CAPACITANCE) + +# Connect the IRQ and GND pin to the oscilloscope. +# uncomment the following sentences to fine tune the antenna for better performance. +# This will dispaly the antenna's resonance frequency/16 on IRQ pin (The resonance frequency will be divided by 16 on this pin) +# Tuning AS3935_CAPACITANCE to make the frequency within 500/16 kHz plus 3.5% to 500/16 kHz minus 3.5% +# +# sensor.setLcoFdiv(0) +# sensor.setIrqOutputSource(3) + +#Set the noise level,use a default value greater than 7 +sensor.setNoiseFloorLv1(2) +#noiseLv = sensor.getNoiseFloorLv1() + +#used to modify WDTH,alues should only be between 0x00 and 0x0F (0 and 7) +sensor.setWatchdogThreshold(2) +#wtdgThreshold = sensor.getWatchdogThreshold() + +#used to modify SREJ (spike rejection),values should only be between 0x00 and 0x0F (0 and 7) +sensor.setSpikeRejection(2) +#spikeRejection = sensor.getSpikeRejection() + +#view all register data +#sensor.printAllRegs() + +def callback_handle(channel): + global sensor + utime.sleep(0.005) + intSrc = sensor.getInterruptSrc() + if intSrc == 1: + lightningDistKm = sensor.getLightningDistKm() + print('Lightning occurs!') + print('Distance: %dkm'%lightningDistKm) + + lightningEnergyVal = sensor.getStrikeEnergyRaw() + print('Intensity: %d '%lightningEnergyVal) + elif intSrc == 2: + print('Disturber discovered!') + elif intSrc == 3: + print('Noise level too high!') + else: + pass + +#Set to input mode +pinirq = Pin(IRQ_PIN, Pin.IN) +#Set the interrupt pin, the interrupt function, rising along the trigger +pinirq.irq(trigger=Pin.IRQ_RISING, handler=callback_handle) +print("start lightning detect.") + +while True: + utime.sleep(1.0) + +