Add a useful sensor trend display to your prototype

A changing number tells you a sensor is responding. A short trend line tells you something more useful: whether the signal is settling, drifting, or responding to the action you just took. For a small team trying a sensor inside an enclosure, that can make a bench demonstration much easier to follow without a laptop attached.

We built a compact trend monitor on our bench: an ADS1115 analog-to-digital converter, a small OLED and a GraftPort RP2040 board running MicroPython 1.23, fed from a handheld test source. The software turns readings into a scrolling line and shows the latest raw code and calculated voltage above it. It works as a development aid for slowly changing signals. To decide whether it fits your prototype, follow the whole path from input voltage to screen pixel, because a chip's conversion-rate setting and the speed of the displayed curve are different things.

Choose the change you need to see

Picture a light sensor responding as a cover closes, or an analog control moving through its travel. A local trend helps you see direction and settling in cases like those. We did not test those specific sensors; we tested the acquisition-and-display path that could support them.

Start by asking how quickly the meaningful change happens. A signal that settles over seconds needs a different approach from an audio waveform or a short electrical pulse. A smooth-looking line does not prove that faster events between readings were captured.

A DFRobot forum discussion from January 2024 shows how this goes wrong. A builder wanted 10 Hz sensor readings but got about 1 Hz despite a faster ADC setting, and later improved it by changing delays in the library. That is a software-integration problem, not a reason to strip out conversion waits indiscriminately.

Wire the input and the display as separate parts

The ADS1115 module is on I2C0 at address 0x49, and the OLED on I2C1 at 0x3D. Match the firmware to the address selection on your own module rather than assuming every ADS1115 board ships with this setting. Our startup log confirmed both addresses before the task started. That is initialization evidence, not a calibration report.

The analog signal also needs a defined reference and a compatible voltage range. Our program reads single-ended channel 0 with a gain setting that the driver maps to a ±4.096 V conversion scale. That scale describes how results are represented. It does not permit an input above the chip's supply voltage or a negative single-ended input. Check your module's supply and input arrangement against the TI ADS1115 datasheet before connecting a source.

The battery cable we used is marked red for GND and black for VCC, the reverse of the usual convention. Confirm polarity from the connector markings and with a continuity check while unpowered. Then check the power indicator and bus communication before you interpret a flat line on the OLED as a sensor result.

When the parts go into an enclosure, keep the input, the reference connection and the display reachable, so you can repeat the same measurement with the cover closed. Otherwise a cable or connector change gets mixed up with the effect you meant to observe. On this board, RUN switch 2 must be on when no external watchdog module is fitted. None of this establishes battery life or measurement stability in a final product.

Follow one reading through the program

Each pass of the acquisition task gets a raw ADC result, converts it to volts, maps the raw code to a vertical screen position, and pushes that position into a 128-point circular buffer. The oldest point drops out as a new one enters. The display joins the points with lines and writes the latest value above them.

The ADC was configured for its 860 samples-per-second setting. But the read call we used returns the previous conversion result and starts the next one. It does not collect every conversion into a fast buffer. Startup, channel changes and resuming after a pause therefore need deliberate handling of the first result.

The task interval is set to 50 ms on a scheduler with a 20 ms tick. Our scheduler computes the interval with integer division, 50 // 20, which gives two ticks, so the nominal threshold is 40 ms before task execution and other delays are counted. Treat both "50 ms" and "860 SPS" as configuration, not as a measured timestamp for each plotted point.

If your test needs elapsed time, record a timestamp with each accepted sample and build the horizontal axis from those timestamps. Our buffer stores screen coordinates, not a reusable voltage-and-time record. It is a visual history, not a data logger you can use to reconstruct samples later.

For faster acquisition, separate sampling from drawing: collect validated samples at the cadence you need and refresh the screen less often. That is the direction we would take for a revised version; we have not built it, and the required rate should follow the sensor event you care about.

Make the scale understandable

The program maps raw codes from 0 to 32767 into the area below the text, with higher codes drawn higher. On a 64-pixel display with a 10-pixel text margin, only 54 vertical positions remain for the line. A 16-bit ADC does not give 16 bits of visible vertical detail on that screen.

The numerical voltage readout stays useful alongside the trend. Check it against known input levels across the range you actually need, using a suitable reference measurement, and label the range and units for whoever reads it. A "high precision" label is not a substitute for an error measurement of the assembled system. Our recording shows the monitor responding next to the test source; it is not a timestamped dataset, and it gives no input uncertainty or error sweep.

Test the states, not just the moving line

Try a steady input first, then a slow controlled change within the allowed input range. Compare the numerical reading, the line position and an external reference. Then try pausing and resuming.

Our pause handling has a bug worth learning from. The pause button handler calls a method on a variable name that does not match the object the main program creates. The resulting error is caught and suppressed, so the task pauses but the intended PAUSED label never appears. Fix that kind of integration detail, and test it, before handing the display to anyone else.

It matters because a frozen line can mean a stable input, a paused task or a failed update. Give each state a visible indication. The task tries to show ERR for some failures, but several display errors are silently ignored, so the code does not guarantee that every failure becomes visible.

Decide what the next prototype needs

If the goal is to watch a slow response while adjusting an enclosure or an analog control, a compact display like this is a practical aid once its input limits and behavior are verified. If the goal is to measure pulse timing, compare rapid events, or keep evidence for later analysis, specify the acquisition timing and the data record first. The display should then summarize that data rather than dictate how it is collected.