<< Click to Display Table of Contents >>

Navigation:  Bits and PCs Blog - 2025.11.19 >

AS3935 Lightning Detector Application for Windows 10/11 - 2025.10.25

Previous pageReturn to chapter overviewNext page

After reading the dramatic AS3935 Lightning Sensor exposé, you will undoubtedly be tempted to write a Windows application for AS3935 calibration, configuration and logging, since no such application exists. But to save time, you can use this one...

The AS3935 sensor is connected to a microcontroller card programmed as a USB-to-I2C gateway, allowing the Windows application to communicate with the AS3935 module via a USB connection.

Most microcontroller cards have a USB connection that looks like a standard COM port. The Windows application just sends and receives messages over the COM port, so no special USB programming is required. A simple binary communications protocol is used to talk to the USB-to-I2C gateway microcontroller.

The code in the gateway microcontroller knows nothing about the AS3935 - all it does is receive USB messages, pass them over the I2C connection and return the I2C response via USB. All the knowledge of AS3935 communications, registers and parameters is inside the Windows program. This was easy to do by translating the AS3935 driver code you can find here from C++ to C#, and replacing the readRegister() and writeRegister() methods to use the USB/COM communications instead of I2C.

 

AS3935 Data Sheet

This version of the AS3935 data sheet was used for development, v1-04 2016-Jan-13. All page references refer to this document. Here you can read the details of calibration and configuration, in particular how it handles 'disturbers' and 'noise'.

https://muman.ch/muman/AS3935-Data-Sheet.pdf

 

The Mattlabs AS3935 Application

This application is written in C# using the [antique*] Windows Forms .NET framework. It runs on Windows 11, or Windows 10 with the .NET Framework v4.7.2 or later.
(* Despite being old, WinForms with C# remains the fastest, easiest and safest way to develop simple Windows desktop applications. Hours or days, instead of weeks or months. And I like C#.)

Download the executable, AS3935.exe, via the link at the end of this page.

The main window can be resized or maximized to increase the size of the Graphical View window which is rescaled according to the main window size.

lightning-detector-app-4

NOTE! In the above screen shot you can see the 'AFE Gain' is set to maximum gain (31), and the 'Watchdog Threshold' and 'Spike Rejection' set to minimum (0). This is NOT a valid configuration, but it does let you see lightning strikes occasionally even if there is no lightning. Normally you should use the default values (press 'Set Defaults' then 'Write Changes').

Windows Application Executable, AS3935.exe

Click on this link to download the .exe file (60KB). Windows Defender will do a comprehensive anti-virus test on the file. It does not need installation, just run AS3935.exe and delete it if you don't need it.

When you run it, you will hopefully see the encouraging "Windows has protected your PC" message. This is only because the program does not have a Software Signing Certificate yet, so you get 'Unknown Publisher' - but you know the publisher, it's muman.ch. Press 'More Info', then 'Run Anyway'.

Download AS3935.exe

 

 

User Manual

 

USB Serial Port

Choose the correct COM port from the drop-down list. The list is refreshed every second, so it will show the COM port when you connect the controller. You may see other COM ports here which are not the AS3935 device. To find out which is which, use the Window's 'Device Manager'. Right-click on the Start button and choose 'Device Manager' from the context menu, then expand the 'Ports (COM & LPT)' branch.

When connected, the red heart to the right of the 'USB Serial Port' text will by toggled on and off for every poll message sent to the sensor, so it pulses once a second while polling is running.

Connect/Disconnect button

Connects to the controller and starts polling the sensor. If already connected, it disconnects and stops polling. The sensor's settings, the Graphical View and the Event Log remain unchanged when you disconnect.

 

Action Buttons

Online Help button

Displays this page in your browser.

Load Settings... & Save Settings... buttons

The settings in the Calibration and Configuration groups can be saved and loaded to/from an INI file. This is useful because the sensor does not retain these settings (it has no non-volatile memory), so you must re-write the settings each time the sensor is powered up or reset. The default name of the INI file is the current date and time.

Radar Map button

Opens the MeteoSuisse "Précipitations (Radar)" page in your browser. Here you can see the rainfall radar map, with superimposed lightning strikes detected by the MeteoSuisse "lightning sensor array".
https://www.meteosuisse.admin.ch/services-et-publications/applications/precipitations.html
https://www.meteoswiss.admin.ch/weather/measurement-systems/atmosphere/lightning-detection-network.html

Reset button

Sends a 'reset' command to the sensor, which restores its default settings. The app's Calibration and Configuration settings are refreshed with the new values.

Clear Statistics button

Clears the statistics built up by the lightning distance estimation algorithm block. The storm detection algorithm starts rebuilding its statistics.

 

Calibration Group

Refer to 'Antenna Tuning' section in the data sheet, p35.

as3935-calibration-group

Values are changed by clicking in the right-hand value column to open a drop-down list. The first click selects the row. The second click, or first click on a selected row, displays the list.

Settings in this group are used to calibrate the resonant frequency of the LCO antenna oscillator, which must resonate at 500kHz, +-3.5%.

To tune the oscillator you must measure the frequency at the IRQ output and adjust the 'Tuning Capacitor' value (0..120pF) to be as close to 500kHz as possible. To measure the frequency accurately you will need a digital oscilloscope, like the Digilent Analog Discovery 2. I tried using a digital multimeter with a frequency measurement setting, but this was nowhere near accurate enough.

The oscillator frequency can be measured on the IQR output by setting 'IRQ Output' to 'LCO Antenna Osc, 500kHz'. The actual frequency of the signal you will see on this output is divided by the 'LOC Frequency Divider' value. The default divider is 16, so you will see '500kHz / 16' which should be 31.25hKz.

IRQ Output

Selects the oscillator frequency which will be routed to the IRQ Output pin. Normally you will select 'LCO Antenna Osc, 500kHz' with the 'LCO Frequency Divider' of '16 (31.25kHz)' and adjust the Tuning Capacitor value to give 31.25kHz on this output. You can also select the other two oscillator frequencies (SRCO or TRCO) to be output, but that's not needed for calibration, and they are apparently derived from the LCO antenna oscillator anyway. Don't forget to set it back to 'Normal' so the IRQ Output can be used as an event indicator.

LCO Frequency Divider

The frequency output on the IRQ pin is divided by this setting. The default is 16, for 31.25kHz if 'LCO Antenna Osc, 500kHz' is selected.

Tuning Capacitor (0..120pF)

Adjust this value so the LCO oscillator frequency is as close as possible to 500kHz by measuring 31.25kHz (div. 16) on the IRQ output. Unfortunately the AS3935 does not remember the Tuning Capacitor setting. It gets set back to 0 on each power up or reset, so you'll need to program it on every start-up. My sensor needed 120pF, the maximum value, to get to almost to 500kHz / 31.25kHz. I think about 125pF would have been optimal.

Set Defaults button

Sets the default data values in the view. It does not write the values to the sensor. You must press 'Write Changes' to write the values into the sensor.

Refresh button

Re-reads and displays the actual values from the sensor.

Write Changes button

Writes the changes made to the data values into the sensor and automatically re-reads and displays them for validation.

 

Configuration Group

After tuning the antenna's resonant frequency, you can adjust the configuration settings according to the location and RF environment.

as3935-configuration-group

AFE Gain (0..31)  p28

The gain of the 'Analog Front End' (AFE). This adjusts the sensitivity to lightning and also to noise and 'disturbers'. There are two recommended settings, '14 OUTDOOR' and '18 INDOOR'. But you can experiment with this, setting it to 31 (maximum gain) lets you detect lightning occasionally, even when there is none. The INDOOR setting has a higher sensitivity than OUTDOOR because of the attenuation of the walls when indoors.

'Disturbers' are man-made (machine-generated) interference signals which can disturb the lightning detection algorithm. You can adjust the 'Watchdog Threshold' and/or the 'Spike Rejection' if you see too many disturber events. Or you can disable the detection (of just the reporting?) of these events completely by setting the 'Disturber Enabled' option to 'No'.

Minimum Strikes (1,5,9,16)

The minimum number of strikes needed to generate the 'Lightning Detected' event. The default is 1.

Noise Floor Level (0..7)  p30

The output signal of the AFE is used to measure the noise floor level. The noise floor is continuously compared to a reference voltage (noise threshold). Whenever the noise floor level crosses the noise threshold, the AS3935 issues an interrupt (INT_NH). This indicates that the AS3935 cannot operate properly due to background noise received by the antenna. Increase this level if you see any 'Noise' events. A noise event disables lightning detection for 1.5 seconds.

Watchdog Threshold (0..15)  p28

The watchdog threshold level defines when the AS3935 enters signal verification mode. Increasing this threshold makes it less sensitive to disturber events, but also makes it less sensitive to weak signals from distant lightning events. Figure 40 on p29 shows the effect of the watchdog threshold on the detection radius.

Spike Rejection (0..15)  p31

In addition to the Noise Floor Level and Watchdog Threshold, the Spike Rejection setting reduces sensitivity to disturber events, but also reduces sensitivity to lighting events. Figure 42 on p32 shows the effect of the Spike Rejection value on the detection radius.

Disturber Enabled (Yes/No)

Disturber events are normally reported via the IRQ pin or register. Set this to 'No' to prevent disturber reporting. This sets the MASK_DIST bit which masks disturber events.

Decreasing sensitivity will reduce disturber events, but that also reduces sensitivity to lightning, so you may want to just turn off disturber reporting. Indoors I get about 5 disturber events an hour, even with quite high Noise Floor, Watchdog Threshold and Spike Rejection values. These occur when an electrical device with crude mechanical switches turns on or off, like the dishwasher, oven or kettle.

Set Defaults button

Sets the default data values in the view. It does not write the values to the sensor. You must press 'Write Changes' to write the values into the sensor.

Refresh button

Re-reads and displays the actual values from the sensor.

Write Changes button

Writes the changes made to the data values into the sensor and automatically re-reads and displays them for validation.

 

Graphical View

This view has a selectable time scale which defines the duration of events that are shown. The duration is also affected by the width of the window, because the graphical view is rescaled according to the main window size. The view stores up to 1024 events, then clears and starts again. The vertical gray line shows when the trace was started, which is useful if no events are occurring.

as3539-graphical-view

Scale setting

The graphical view has four scale settings which affect the duration shown in the graphical view. The actual maximum time on the horizontal axis depends on the size of the window.

1 minute per division : Shows about 35 minutes in a maximised window
2 minutes per division : Shows about 70 minutes
5 minutes per division : Shows about 180 minutes
10 minutes per division : Shows about 350 minutes

Three event types (INT_x) are shown in the graphical view. See data sheet p34.

Lightning strike, INT_L
Shown as a vertical red line. The height of the line is proportional to the 'strike energy', 0..2000000 over the vertical range. A big strike has a longer line.

Disturber event, INT_D
Shown as a small blue dot at the bottom of the trace. 'Disturbers' are man-made (machine-generated) interference signals which can disturb the lightning detection. A disturber event disables lighting detection for 1.5 seconds. The 'Watchdog Threshold' and 'Spike Rejection' settings can be adjusted to reduce the number of disturber events. Or you can disable the notification of these events completely by setting the 'Disturber Enabled' option to 'No'.

Noise event, INT_NH
Shown as a small black dot at the bottom of the trace. Adjust the 'Noise Floor Level' sensitivity if noise is detected. Lightning detection is disabled for the duration of the noise event. INT_NH persists as long as the noise level is above the threshold.

Storm distance
The distance (the radius) is shown as a value in green at the top right of the graphical view, e.g. 6km. The storm distance is also shown as a green horizontal line which relates to the km scale on the right-hand side of the view. This shows if the storm is moving closer or moving away. The sensor does not change the reported storm distance unless a new value is calculated. This means the graphical view would keep showing the same distance indefinitely if no further events occur. To fix this there's a 10-minute timeout - the distance measurement is turned off if no strikes are detected for 10 minutes.

Clear Graph button

Clears the graphical display.

 

Event Log

This is a circular list of the last 1024 events from the sensor. It also shows user actions enclosed in <angle brackets>. Each entry has a time stamp showing the date and time.

Lightning strikes are shown with the distance in km and the strike energy value. Disturbers and Noise are also logged, which helps to configure it to exclude noise and disturbances.

   2025.10.22 14:32:12   <connected to 'MattLabs Lightning Detector v1.0'>
   2025.10.22 15:51:52   Lightning   6km   126609
   2025.10.22 15:52:01   Disturber

Load Log... & Save Log... buttons

The log is saved as a CSV file which can be loaded into Excel, or read back into the Event Log and Graphical View. The 'Load Log' feature is not implemented in v1.0.

Clear Log button

This probably clears the event log.

 

USB-to-I2C Converter

For the Windows app to talk to the I2C sensor via a USB connection, we need an intelligent gateway to translate a simple binary serial protocol into I2C messages. A 'small message protocol' is used for USB communications. The windows application is the 'master' and the gateway is the 'slave'.

I used an STM-32F103 Nucleo board as the gateway, with the AS3935 sensor mounted on an Arduino shield prototype board. The sensor needs the power connected (3.3V and GND) plus the two I2C lines SDA and SCL. The IRQ output can be connected to D2, but this is not used because the sensor is polled with getIRQSource() which reads the INT bits.

I2C Pull-ups: The AS3935 board already has the I2C pull-up resistors, both 10K. The SCL pull-up is on the board and the SDA pull-up is in the chip (see data sheet p24), so you don't need to add the I2C pull-up resistors. The data sheet states, "please do not use 4K7 ohm resistors on both I2CD and I2CL" (SDA and SCL). This means if the microcontroller has pull-ups fitted they should be removed. The STM32F103 Nucleo board does not have pull-ups fitted, so it's ok. I tried an Arduino Zero and it did not work because it had two 4K7 pull-ups fitted and I did not want to unsolder them - but apparently some Zeros do not have them.

Here's the prototype shield showing the power and I2C connections to the Gravity board. IRQ is connected to D2, but it's not used. The Gravity module is stuck to the prototype board using thick double-sided mounting tape.

as3935-gateway

 

The Small Message Protocol

A simple 'state machine' is used by the master and the slave to receive and validate the USB serial messages.

Each binary message sent by the master (the PC) has the format:

 0  1  2   3   4...       word
|B7|C9|seq|len|data-bytes|csum|

B7|C9 = Start bytes. (Why use B7 C9 as the start bytes? You can use anything you like, but these seemed to be rare as consecutive bytes. It doesn't really matter because a state-machine is used to receive messages, so even if these bytes did occur in the data stream it would be unlikely to cause any problems.)
seq = Sequence number, 00..FF, incremented for each message. Use this to check the response is for the message that was sent, by comparing the seq numbers. This is not really necessary for USB/COM, but for some transport systems it can be important.
len = The length of the data-bytes.
data-bytes =  The message payload, max. 32 bytes.
csum = A two-byte XOR-and-rotate checksum, LS byte first.

For the I2C gateway, the data-bytes (message payload) has this format:

 0   1       2     3...

|cmd|i2cadds|txlen|txdata-bytes|rxlen|

cmd = A one-byte command, 01 = send I2C message.
i2cadds = The destination I2C address of the sensor.
txlen = The length of the I2C message to send.
txdata-bytes = The I2C message, usually a register number (read/write) and optional data byte (write).
rxlen = The number of bytes to be read from the sensor, either 0 or 1.

 

There is always an ACK/NAK response from the slave to the master, even if no response data is required.

Returned ACK response with data:

 0  1  2   3   4   5...          word

|B7|C9|seq|ack|len|data-bytes...|csum|

seq = The returned sequence number. The master compares this with the seq number of the message that was sent.
ack = ACK/NAK response value, 0x00 = ACK, >0x00 = NAK.
len = The number of data-bytes returned. This should match the bytes requested with rxlen. Always 1 or 0 for this app.
data-bytes = The requested data bytes.

NAK response with NAK reason 1..255:

 0  1  2   3   4   5 6
|B7|C9|seq|nak|len|csum|

nak = The NAK reason, e.g. 1 = invalid data-length, 2 = buffer overflow, ... see source code.
len = The data length is always 0x00 in a NAK response because no data is returned. The data could hold a description of the error, but the NAK reason is good enough.

The csum checksum is a simple XOR-and-rotate checksum of the seq, len and data-bytes, starting with csum = 0xFFFF. This is fast and reasonably reliable because it retains data from every byte, whereas an additive checksum loses data through overflow. (A real polynomial CRC is best, of course, but CRCs can be slow on slow MCUs and use many precious bytes of memory for a look-up table.)
 

  // 16-bit xor-and-rotate-right checksum of seq, len and data-bytes

  // start with csum = 0xffff

  uint SmallMessageProtocolSlave::calcCsum(uint csum, const byte* data, uint length)

  {

    while (length--) {

      csum ^= *data++;

      if (csum & 1) {   // rotate bit 0 to bit 15

        csum >>= 1;

        csum |= 0x8000;

      }

      else

        csum >>= 1;

    }

    return csum;

  }

 

USB-To-I2C Converter Source Code

This is the source code for the USB-to-I2C converter. It was developed for an STM-32F103 Nucleo board with built-in ST-LINK, but should run on most Arduino-style MCUs. Microsoft Visual Studio 2022 (free) with the Visual Micro Arduino IDE extension (about $20 for a single user non-commercial license) was used for the programming and debugging.

  SerialToI2C.ino   [Click to show/hide the code]

Here's an example sketch which polls the INT bits every 500ms.

  SmallMessageProtocolSlave.h   [Click to show/hide the code]

 

Here's the C# source code for the Small Message Protocol Master that's used by AS3935.exe

  SmallMessageProtocolMaster.cs   [Click to show/hide the code]

This is the code that talks to the AS3935 sensor using the small message protocol.

  AS3935LightningSensor.cs   [Click to show/hide the code]

 

The full source code for the AS3935 Windows application (C# Windows Forms for Microsoft Visual Studio 2022) is available on request (for non-commercial use) from info@muman.ch.

 

References

A detailed exposé of the AS3935 Lightning Sensor
AS3935 Lightning Sensor

Visual Micro Arduino IDE for Visual Studio 2022
Used for developing the USB-To-I2C converter. I recommend this, it's way better than the Arduino IDE.
https://www.visualmicro.com/

 

MeteoSuisse radar map which shows lightning strikes
https://www.meteosuisse.admin.ch/services-et-publications/applications/precipitations.html

Another lightning map for Switzerland
This map uses colours to indicate the approximate time of the strike. But it has some advertising.
https://www.blitzortung.org/en/live_lightning_maps.php?map=16