Skip to the content
PCBKitNew board
2 layers90 × 90 mmLogger pcb kicad, the printed circuit board in 3D

Logger pcb kicad

mrheltic/Logger5

Just a data acquisition system built using an ESP32 microcontroller board, using ADS1115 to acquire datas and save them on SD, plot them with Python or compute the mean on the OLED Display

Size
90 × 90 mm
Copper layers
2
Thickness
1.6 mm
Parts
40
Nets
54
Pads
167
Tracks, vias
419, 6
Routed
Yes
KiCad
KiCad 7 (file 20221018)
Created
24 Oct 2023
Updated
13 Jun 2024

Overview

Logger pcb kicad is an open-source printed circuit board by mrheltic, from the mrheltic/Logger repository on GitHub, published under the GPL-3.0 licence. It is a 2-layer board of 90 × 90 mm with 40 parts on 54 nets, routed with 419 tracks and 6 vias.

It is built around the ESP32-DEVKITC-VE, ADS1115IDGS and DS1302+, with the HT7333-A among its other parts. Its parts include 14 resistors, 7 connectors, 5 capacitors, 5 ICs and 4 switches. It belongs with the lEDs and displays boards and the ESP32 boards of this library.

Main components

4

README

README.md

Logger

C++ Visual Studio Code GitHub

Python Matplotlib NumPy SciPy

📝 Table of Contents

🧐 About

This project is a data acquisition system built using an ESP32 microcontroller board. The system incorporates an ADS1115 analog-to-digital converter, an SSD1306 display, and three buttons for user interaction. It is designed to store data on an SD card or send it to a pc for further analysis.

Features

  • Acquisition of analog sensor data using ADS1115 ADC
  • Real-time display of sensor readings on SSD1306 OLED display
  • User interaction through three buttons for control and configuration
  • Storage of acquired data on an SD card for offline access
  • Transmission of data to a computer for centralized analysis

🔧 Hardware Required

🏁 Getting Started

Prerequisites

  • Arduino IDE or Visual Studio Code (with PlatformIO)
  • ESP32 board manager for Arduino IDE
  • Libraries:
    • Adafruit ADS1X15 (for ADS1115)
    • Adafruit SSD1306 (for SSD1306 display)
    • SD (for SD card storage)

Installation

Installation using Arduino IDE
  • Clone or download the project repository from GitHub.
  • Open the Arduino IDE and install the ESP32 board manager if not already installed.
  • Connect the hardware components as per the provided circuit diagram.
  • Install the required libraries using the Arduino Library Manager.
  • Upload the code to the ESP32 board using the Arduino IDE.
  • Monitor the serial output to ensure successful connection to the sensors.
  • Verify the functionality by checking the sensor readings on the SSD1306 display and the data storage on the SD card.
Installation using Visual Studio Code
  • Clone or download the project repository from GitHub.
  • Open VS and compile the software (changing the details on platform.ini according to your hardware).
  • Connect the hardware components as per the provided circuit diagram.
  • Upload the code to the ESP32 board using the upload tool.
  • Monitor the serial output to ensure successful connection to the sensors.
  • Verify the functionality by checking the sensor readings on the SSD1306 display and the data storage on the SD card.

Description

⌨️ Code

All the code was written using the arduino Framework, for an ESP32. This gave us significant advantages in terms of ease of writing, online documentation, and especially in terms of click-through, which is considerably greater than for an arduino Uno. We followed a kind of MVC model, where each component is separate from the others and deals only with the things it is responsible for, invoking higher-level primitives. This allowed us to manage different components more smoothly.

Main

The main substantially is a method wrapper and deals at a higher level with handling scrolling through the various menus. Initially (in setup) it asks the controller to initialize devices (the basic ones, such as buttons, screen, ...)

cpp
while (!initializeDevices()){
}

updateMenu();

After this handles menu selection

cpp
if (stateMenu)
{
  if (goDown())
  {
    menu++;
  }
  if (goUp())
  {
    menu--;
  }
  if (select())
  {
    executeAction(); //Enters in the selected menu
  }
}

Controller

The controller is the component that manages all component behavior and is directly responsible for making measurements. Besides that it initializes all the devices and the serial. The initializations that are done can be blocking or non-blocking, depending on the type of component we want to initialize: a failure of the fundamental components results in a program block inside a loop, which will not allow the execution of the remaining code, while the other components may not be initialized at all. The reference with respect to the success or failure of initialization we have it by returning a boolean value true when the method is terminated, so it does not take into account subsequent failures. The whole initial part is devoted to declaring all pins connected to the board, and in case of custom configurations they can be changed before compilation.

After all parameters have been selected, data acquisition will proceed. This involves an initial setup phase, in which, based on what parameters are selected (saved as global variables in the controller) it will go to set the mode (and consequently the channels to read from), the data rate, and calculate gain and offset. Depending on the output selected it could change significantly, but we will also have an output on the serial that tells us what is happening. Also in this part I am going to initialize the measurement object, which will handle the calculations made for mean and std.

cpp
void adcSetup()
{
  setRate(currentSampleRate); //Physically setting the sample rate with ADS function
  setChannel(); //Setting the channel, gain and other useful parameters

  K_value = calculateCoefficient();
  O_value = calculateOffset();

  Measurement measurement(currentSampleRate); //Instantiate the object
}

After running the setup you enter the loggerAct, which is the method that takes care of the measurement. Here, depending on the mode that will be selected it will have different behavior, but basically what it does is:

cpp
// The microcontroller is waiting for an interrupt from the ADC
if (!new_data)
  {
    return;
  }

// When the adc is alerted via the alert pin the code continues

if (!measurement.isArrayFull())
  {
    measurement.insertMeasurement(adcValue); // Get the misuration and stores in the array
  }

else
  {
    measurement.setArrayFull(false); // Empties the array and compute mean and std
    loggerGraphic(mode, channel, timestamp, mean); // Print on display the parameters
  }

new_data = false;

View

The view component deals with screen management. Here it is initialized and passing it the necessary parameters updates the screen. Bipmap images of the various modes and associated sliders are also saved here. The view also provides functions to be used directly by the controller, such as the one used during the loggerAct, which takes care of printing media (for each second), timestamp, mode, and output

Model

The model is the component that manages the "measurements" class and takes care of the array. This provides various functions to calculate different values useful for measurements, such as mean and standard deviation. In fact, when we go to initialize the object an array is created, of length equal to the data rate, and we go to calculate mean and std for each second. Each time the adc returns us the value, from the controller, we go to invoke a function that is used to insert the measured value (already possibly multiplied by the gain and summed with the offset) at the tail of the array.

cpp
class Measurement
{
private:
    int *measurements;
    float mean;
    float std; 
    bool arrayFull;

public:
    Measurement(int len);
    ~Measurement();
    void insertMeasurement(int value);
    void calculateMean();
    void calculateStd();
    void reset();
    bool isArrayFull();
    int getLength();
};

Theoretical Notions

Adc In this project we use the ADS1115 that is a very small, low-power, 16-bit, delta-sigma (ΔΣ) analog-to-digital converters (ADCs). There are many ADCs available on the market for various applications: Ramping, SAR, delta-sigma, Flash and so on. ΔΣ ADCs are now ideal for converting analog signals over a wide range of frequencies, from DC to several megahertz. Basically, these converters consist of an oversampling modulator followed by a digital filter that together produce a high-resolution data-stream output. The ADS1115 has an adjustable gain(PGA), an interal voltage reference, a clock oscillator, an I2C interface, and also a programmable digital comparator that provides an alert on a dedicated pin. The latter played an important role in carrying out the sampling at the maximum achievable speed of 860SPS. Thanks to the mux the adc has four single-ended(to measure each channel with respect to ground) or two differential inputs and two available conversion mode: single-shot mode(power saving mode) and continuous mode. In continuous conversion mode, the adc automatically begins a conversion of the input as soon as the previous conversion is completed and the rate is programmed by software. To achieve high accuracy measurements it's a mandatory following several step:
  • Use the Maximum Resolution in the readings
  • Adjust the PGA to match the voltage range of your input signal(all specifications can be found in the datasheet)
  • Use an external voltage reference instead of the integrated
  • Implement appropriate filtering and signal conditioning techniques to minimize noise and Interference
  • Periodically calibrate the system to compensate any drift
  • Avoid common source of error such as impedance mismatches
  • Select data rate based on dynamic meausurements or slow signals
  • Minimize signal path lengths.

🖥️ Display Mode

Usage

Performance Evaluation

💾 SD Mode

Usage

Performance Evaluation

💻 Serial Mode

Usage

Explanation

In the data acquisition stage, data is sent to the pc, which is processed through python. The manufacturer of the module, in the datasheet indicates that the conversion time is exactly equivalent to 1/DR (worst case: 860SPS), so there will certainly be a small delay due to data processing due to the microcontroller. This, in turn, will have to be added to a time, albeit very small, due to communication via serial. We had initially opted to send the data via the Serial.println() function, but this route, following some testing, seemed impractical. This was because, while having a readable result directly from the serial would have made it easy and intuitive to retrieve the data, it introduced a considerable delay, far in excess of the 1/DR value, even orders of magnitude (about tenths of a second). We therefore opted for the Serial.write() function, but again there were problems, since the measured values are 16-bit integers, so they needed to be split in two and sent (so as to send 8 bits at a time).

cpp
Serial.write(0xCC);                   // Start byte
Serial.write((ADCvalue >> 8) & 0xFF); // High byte
Serial.write(ADCvalue & 0xFF);       // Low byte
  • Serial.write(0xCC) sends a start byte. The Serial.write() function writes binary data to the serial port. 0xCC is the hexadecimal representation of the start byte. The microcontroller need to send this to communicate that a new set of data is starting.

  • Serial.write((ADCvalue >> 8) & 0xFF) sends the high byte of ADCvalue. The >> 8 operation shifts the bits of ADCvalue 8 places to the right, effectively moving the high byte to the position of the low byte. The & 0xFF operation then masks the lower byte, so only the original high byte of ADCvalue remains.

  • Serial.write(ADCvalue & 0xFF) sends the low byte of ADCvalue. The & 0xFF operation masks the high byte of ADCvalue, so only the low byte remains.

After the microcontroller sends the measured value this way, python will have to deal with reconstructing it and converting it to a readable value, like this:

python
start_byte = ser.read(1)  # Read the start byte
    if start_byte == b'\xCC':  # Verify the start byte
        high_byte = ser.read(1)  # Read the high byte
        low_byte = ser.read(1)  # Read the low byte
        measurement = (ord(high_byte) << 8) | ord(low_byte)  # Merge the bytes
  • start_byte = ser.read(1) reads one byte from the serial port and assigns it to the variable start_byte.

  • if start_byte == b'\xCC' checks if the start byte is equal to b'\xCC', which is the byte representation of the hexadecimal number 0xCC. If the start byte is 0xCC, the code inside the if statement will be executed. This is used to verify that the data transmission is starting correctly.

  • high_byte = ser.read(1) reads the next byte (after the start byte) from the serial port, which is the high byte of the measurement.

  • low_byte = ser.read(1) reads the next byte from the serial port, which is the low byte of the measurement.

  • measurement = (ord(high_byte) << 8) | ord(low_byte) merges the high byte and the low byte to reconstruct the original measurement. The ord() function is used to get the integer value of a byte. The << 8 operation shifts the bits of the high byte 8 places to the left, effectively moving it to the position of the high byte in a 16-bit number. The | operation is a bitwise OR, which combines the high byte and the low byte into a single 16-bit number.

For more in-depth information you can visit the python code repository directly: Serial Mode Logger

Performance Evaluation

⛏️ Built Using

🫂 Contributing

Contributions to this project are welcome. If you encounter any issues or have ideas for improvements, please submit a pull request or open an issue on the project repository.

✍️ Authors

Repo Activity

Alt

License

Details about the license.

🎉 Acknowledgments

Any acknowledgments (optional).

Parts

40
QtyValueFootprintReferences
910kΩResistor_SMD:R_1206_3216MetricR1, R2, R3, R6, R7, R8, R13, R14, R15
310uFCapacitor_SMD:C_0805_2012MetricC2, C3, C4
3SW_PushButton_Switch_THT:SW_PUSH-12mmSW1, SW2, SW3
1100kΩResistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P10.16mm_HorizontalR10
110kΩResistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P10.16mm_HorizontalR5
11kΩResistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P10.16mm_HorizontalR12
122nFCapacitor_SMD:C_0805_2012MetricC1
122ufCapacitor_SMD:C_0805_2012MetricC5
127kΩResistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P10.16mm_HorizontalR11
132.768kHzCrystal:Crystal_C38-LF_D3.0mm_L8.0mm_HorizontalY1
133kΩResistor_THT:R_Axial_DIN0207_L6.3mm_D2.5mm_P10.16mm_HorizontalR4
1ADS1115IDGSPackage_SO:TSSOP-10_3x3mm_P0.5mmU3
1AudioJack3000mylib:Jack_3.5mm_CUI_SJ1-3525N_HorizontalJ4
1Battery_Cell000mylib:Battery_holder_cr2032BT1
1BuzzerBuzzer_Beeper:Buzzer_12x9.5RM7.6BZ1
1Conn_01x02Connector_PinHeader_2.54mm:PinHeader_1x02_P2.54mm_VerticalJ7
1Conn_01x02_SocketConnector_JST:JST_EH_B2B-EH-A_1x02_P2.50mm_VerticalJ5
1Conn_01x04000mylib:128x64OLEDJ2
1Conn_CoaxialConnector_Coaxial:BNC_TEConnectivity_1478035_HorizontalJ1
1DS1302+Package_DIP:DIP-8_W7.62mmU2
1ESP32-DEVKITCESP32-DEVKITC:MODULE_ESP32-DEVKITCU1
1HT7333-APackage_TO_SOT_SMD:SOT-89-3U6
1LED_Dual_AKALED_THT:LED_D3.0mm-3D3
1LOGOGraphic:poliba_logoG***
1Micro_SD_CardmicroSDcard_SMD:J_SD_Card-micro_socket_AJ3
1SW_DIP_x01000mylib:SW_CuK_JS202011AQN_DPDT_AngledSW4
1Screw_Terminal_01x02TerminalBlock:TerminalBlock_Altech_AK300-2_P5.00mmJ6
1TP4056ModuleTP4056-18650-master:TP4056-18650U4

Questions

How big is the Logger pcb kicad PCB?

It measures 90 × 90 mm and has 2 copper layers, 1.6 mm thick.

What parts does the Logger pcb kicad use?

40 parts, built around the ESP32-DEVKITC-VE, ADS1115IDGS, DS1302+ and HT7333-A. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.

Where can I download the Logger pcb kicad KiCad files?

From the mrheltic/Logger repository on GitHub, at the commit this page was made from: the board is logger_pcb_kicad/logger_pcb_kicad.kicad_pcb and its schematic logger_pcb_kicad/logger_pcb_kicad.kicad_sch. PCBKit opens the board in the browser, with nothing to install.

Can I use the Logger pcb kicad design in my own project?

Its repository publishes it under the GPL-3.0 licence: you may reuse it on that licence's terms (keep the author's notice, and for a copyleft licence share your changes alike).

Similar boards

  • 2 layers100 × 75 mmSmart roller gate controller, the printed circuit board in 3D

    Smart roller gate controller

    vooon/smart-roller-gate-controller

    ESP32 based roller gate controller with ZigBee remotes

    44 parts2GPL-3.0
  • 2 layers15.5 × 47 mmVelopath final, the printed circuit board in 3D

    Velopath final

    BananaGithubserfer/velopath

    Разработка устройств велосипедной навигации velopath

    66 partsGPL-3.0
  • 2 layers33.1 × 61.4 mmRainguage, the printed circuit board in 3D

    Rainguage

    fguiet/raingauge-v2

    This the Mark II of my Raingauge project

    27 partsGPL-3.0
  • 2 layers42.9 × 18.5 mmEsp12-dht22, the printed circuit board in 3D

    Esp12-dht22

    hpbock/esp12-environment-sensor

    Environment sensor that is powered by a 18650 battery using a dht22 to sense temperature and humidity. Connectivity is provided wireless using an esp12 sleeping deeply most of the time.

    13 partsMIT
  • 2 layers200 × 70 mmHybryd Radio, the printed circuit board in 3D

    Hybryd Radio

    Spok1978/hybrid-radio

    Radio that plays stations from FM and from internet

    89 parts
  • 2 layersKroneum, the printed circuit board in 3D

    Kroneum

    azasypkin/kroneum

    🕒 -.- .-. --- -. . ..- -- Kroneum -.- .-. --- -. . ..- -- 🕒

    22 parts47MIT
  • 2 layers90 × 50 mmF5418, the printed circuit board in 3D

    F5418

    grumat/glossy-msp430

    Glossy MSP430 - Embedded GDB Debugger for MSP430

    49 parts15GPL-2.0
  • 2 layers205.7 × 137.2 mmArdipool, the printed circuit board in 3D

    Ardipool

    golgoth31/domopool

    Swimming pool management with an esp32

    21 parts3GPL-3.0